diff -Naur postfix-2.5.3.orig/src/util/safe_open.c postfix-2.5.3/src/util/safe_open.c --- postfix-2.5.3.orig/src/util/safe_open.c 2006-06-05 01:04:49.000000000 +0200 +++ postfix-2.5.3/src/util/safe_open.c 2008-08-03 16:42:10.882440950 +0200 @@ -83,6 +83,7 @@ #include #include #include +#include #include /* safe_open_exist - open existing file */ @@ -138,13 +139,30 @@ * 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