1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
|
Index: postfix-2.4.7/src/util/safe_open.c
===================================================================
--- postfix-2.4.7.orig/src/util/safe_open.c
+++ postfix-2.4.7/src/util/safe_open.c
@@ -83,6 +83,7 @@
#include <msg.h>
#include <vstream.h>
#include <vstring.h>
+#include <stringops.h>
#include <safe_open.h>
/* safe_open_exist - open existing file */
@@ -138,13 +139,30 @@ static VSTREAM *safe_open_exist(const ch
* for symlinks owned by root. NEVER, NEVER, make exceptions for symlinks
* owned by a non-root user. This would open a security hole when
* delivering mail to a world-writable mailbox directory.
+ *
+ * The semantics of link(symlink, target) has changed over time.
+ * Traditionally, UNIX systems hardlink the target of the symlink.
+ * However, some systems hardlink the symlink itself. The latter behavior
+ * was introduced with Solaris 2.0, and with Linux kernel 2.0. Sebastian
+ * Krahmer of SuSE found that hardlinks to symlinks could be used to
+ * append mail for root to a sensitive file. For this reason, we not
+ * only require that a symlink is owned by root, but we now also require
+ * that its parent directory is writable only by root.
*/
else if (lstat(path, &lstat_st) < 0) {
vstring_sprintf(why, "file status changed unexpectedly: %m");
errno = EPERM;
} else if (S_ISLNK(lstat_st.st_mode)) {
- if (lstat_st.st_uid == 0)
- return (fp);
+ if (lstat_st.st_uid == 0) {
+ struct stat parent_st;
+ const char *parent;
+
+ parent = sane_dirname((VSTRING *) 0, path);
+ if (stat(parent, &parent_st) == 0 /* real parent */
+ && parent_st.st_uid == 0
+ && (parent_st.st_mode & (S_IWGRP | S_IWOTH)) == 0)
+ return (fp);
+ }
vstring_sprintf(why, "file is a symbolic link");
errno = EPERM;
} else if (fstat_st->st_dev != lstat_st.st_dev
|