[proftpd/el5] Fix possible symlink race (CVE-2012-6095)

Paul Howarth pghmcfc at fedoraproject.org
Fri Jan 18 16:39:30 UTC 2013


commit fb7fda2ce311ab3d0a51c87c5629131d8b8a7820
Author: Paul Howarth <paul at city-fan.org>
Date:   Fri Jan 18 16:07:18 2013 +0000

    Fix possible symlink race (CVE-2012-6095)
    
    - Fix possible symlink race when applying UserOwner to newly created directory
      (CVE-2012-6095, #892715, http://bugs.proftpd.org/show_bug.cgi?id=3841)
    - Add -fno-strict-aliasing, needed for mod_radius
    - Drop %defattr, redundant since rpm 4.4

 .gitignore                            |   10 +
 proftpd-1.3.3g-bug3841.patch          |  511 +++++++++++++++++++++++++++++++++
 proftpd-mod-vroot-0.8.5-bug3841.patch |   98 +++++++
 proftpd.spec                          |   21 +-
 4 files changed, 634 insertions(+), 6 deletions(-)
---
diff --git a/.gitignore b/.gitignore
index c8f5632..25551de 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,13 @@
+# master/f18/f17/f16
+/proftpd-1.3.4b.tar.gz
+/proftpd-mod-geoip-0.3.tar.gz
+/proftpd-mod-vroot-0.9.2.tar.gz
+/Test-Unit-0.14.tar.gz
+# el6
+/proftpd-1.3.3g.tar.bz2
+/proftpd-mod-geoip-0.2.tar.gz
+/proftpd-mod-vroot-0.9.2.tar.gz
+# el5
 /proftpd-1.3.3g.tar.bz2
 /proftpd-mod-geoip-0.2.tar.gz
 /proftpd-mod-vroot-0.8.5.tar.gz
diff --git a/proftpd-1.3.3g-bug3841.patch b/proftpd-1.3.3g-bug3841.patch
new file mode 100644
index 0000000..fa95e25
--- /dev/null
+++ b/proftpd-1.3.3g-bug3841.patch
@@ -0,0 +1,511 @@
+--- configure.in
++++ configure.in
+@@ -1399,7 +1399,7 @@ AC_PROG_GCC_TRADITIONAL
+ AC_FUNC_SETPGRP
+ AC_TYPE_SIGNAL
+ AC_FUNC_VPRINTF
+-AC_CHECK_FUNCS(bcopy crypt fdatasync fgetgrent fgetpwent fgetspent flock fpathconf freeaddrinfo futimes getpgid getpgrp nl_langinfo)
++AC_CHECK_FUNCS(bcopy crypt fdatasync fgetgrent fgetpwent fgetspent flock fpathconf freeaddrinfo futimes getpgid getpgrp mkdtemp nl_langinfo)
+ AC_CHECK_FUNC(gai_strerror,
+   AC_DEFINE(HAVE_GAI_STRERROR, 1,
+     [Define if you have the gai_strerror() function]),
+--- configure
++++ configure
+@@ -26526,7 +26526,8 @@ done
+ 
+ 
+ 
+-for ac_func in bcopy crypt fdatasync fgetgrent fgetpwent fgetspent flock fpathconf freeaddrinfo futimes getpgid getpgrp nl_langinfo
++
++for ac_func in bcopy crypt fdatasync fgetgrent fgetpwent fgetspent flock fpathconf freeaddrinfo futimes getpgid getpgrp mkdtemp nl_langinfo
+ do
+ as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh`
+ { echo "$as_me:$LINENO: checking for $ac_func" >&5
+--- config.h.in
++++ config.h.in
+@@ -357,6 +357,9 @@
+ /* Define if you have the mkdir function.  */
+ #undef HAVE_MKDIR
+ 
++/* Define if you have the mkdtemp function.  */
++#undef HAVE_MKDTEMP
++
+ /* Define if you have the mkstemp function.  */
+ #undef HAVE_MKSTEMP
+ 
+--- contrib/mod_sftp/fxp.c
++++ contrib/mod_sftp/fxp.c
+@@ -5498,7 +5498,7 @@ static int fxp_handle_mkdir(struct fxp_p
+   (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
+     "creating directory '%s' with mode 0%o", path, (unsigned int) dir_mode);
+ 
+-  res = pr_fsio_mkdir(path, dir_mode);
++  res = pr_fsio_smkdir(fxp->pool, path, dir_mode, (uid_t) -1, (gid_t) -1);
+   if (res < 0) {
+     const char *reason;
+     int xerrno = errno;
+--- contrib/mod_sftp/scp.c
++++ contrib/mod_sftp/scp.c
+@@ -711,7 +711,7 @@ static int recv_finfo(pool *p, uint32_t
+       if (xerrno == ENOENT) {
+         pr_trace_msg(trace_channel, 5, "creating directory '%s'", sp->filename);
+ 
+-        if (pr_fsio_mkdir(sp->filename, 0777) < 0) {
++        if (pr_fsio_smkdir(p, sp->filename, 0777, (uid_t) -1, (gid_t) -1) < 0) {
+           xerrno = errno;
+ 
+           (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
+--- include/fsio.h
++++ include/fsio.h
+@@ -129,6 +129,7 @@ struct fs_rec {
+   int (*fchmod)(pr_fh_t *, int, mode_t);
+   int (*chown)(pr_fs_t *, const char *, uid_t, gid_t);
+   int (*fchown)(pr_fh_t *, int, uid_t, gid_t);
++  int (*lchown)(pr_fs_t *, const char *, uid_t, gid_t);
+   int (*access)(pr_fs_t *, const char *, int, uid_t, gid_t, array_header *);
+   int (*faccess)(pr_fh_t *, int, uid_t, gid_t, array_header *);
+   int (*utimes)(pr_fs_t *, const char *, struct timeval *);
+@@ -249,6 +250,7 @@ int pr_fsio_mkdir(const char *, mode_t);
+ int pr_fsio_rmdir(const char *);
+ int pr_fsio_rename(const char *, const char *);
+ int pr_fsio_rename_canon(const char *, const char *);
++int pr_fsio_smkdir(pool *, const char *, mode_t, uid_t, gid_t);
+ int pr_fsio_unlink(const char *);
+ int pr_fsio_unlink_canon(const char *);
+ pr_fh_t *pr_fsio_open(const char *, int);
+@@ -270,6 +272,7 @@ int pr_fsio_fchmod(pr_fh_t *, mode_t);
+ int pr_fsio_chmod_canon(const char *, mode_t);
+ int pr_fsio_chown(const char *, uid_t, gid_t);
+ int pr_fsio_fchown(pr_fh_t *, uid_t, gid_t);
++int pr_fsio_lchown(const char *, uid_t, gid_t);
+ int pr_fsio_chown_canon(const char *, uid_t, gid_t);
+ int pr_fsio_chroot(const char *);
+ int pr_fsio_access(const char *, int, uid_t, gid_t, array_header *);
+@@ -278,6 +281,11 @@ int pr_fsio_utimes(const char *, struct
+ int pr_fsio_futimes(pr_fh_t *, struct timeval *);
+ off_t pr_fsio_lseek(pr_fh_t *, off_t, int);
+ 
++/* Set a flag determining whether to use mkdtemp(3) (if available) or not.
++ * Returns the previously-set value.
++ */
++int pr_fsio_set_use_mkdtemp(int);
++
+ /* FS-related functions */
+ 
+ char *pr_fsio_getline(char *, int, pr_fh_t *, unsigned int *);
+--- modules/mod_core.c
++++ modules/mod_core.c
+@@ -3744,7 +3744,7 @@ int core_chgrp(cmd_rec *cmd, char *dir,
+   }
+   cmd->argv[0] = cmd_name;
+ 
+-  return pr_fsio_chown(dir, uid, gid);
++  return pr_fsio_lchown(dir, uid, gid);
+ }
+ 
+ int core_chmod(cmd_rec *cmd, char *dir, mode_t mode) {
+@@ -4002,7 +4002,6 @@ MODRET core_rmd(cmd_rec *cmd) {
+ MODRET core_mkd(cmd_rec *cmd) {
+   int res;
+   char *dir;
+-  struct stat st;
+ 
+   CHECK_CMD_MIN_ARGS(cmd, 2);
+ 
+@@ -4043,7 +4042,8 @@ MODRET core_mkd(cmd_rec *cmd) {
+     return PR_ERROR(cmd);
+   }
+ 
+-  if (pr_fsio_mkdir(dir, 0777) < 0) {
++  if (pr_fsio_smkdir(cmd->tmp_pool, dir, 0777, session.fsuid,
++      session.fsgid) < 0) {
+     int xerrno = errno;
+ 
+     (void) pr_trace_msg("fileperms", 1, "%s, user '%s' (UID %lu, GID %lu): "
+@@ -4055,71 +4055,6 @@ MODRET core_mkd(cmd_rec *cmd) {
+     return PR_ERROR(cmd);
+   }
+ 
+-  /* Check to see if we need to change the ownership (user and/or group) of
+-   * the newly created directory.
+-   */
+-  if (session.fsuid != (uid_t) -1) {
+-    int err = 0, iserr = 0;
+-
+-    pr_fsio_stat(dir, &st);
+-
+-    PRIVS_ROOT
+-    if (pr_fsio_chown(dir, session.fsuid, session.fsgid) == -1) {
+-      iserr++;
+-      err = errno;
+-    }
+-    PRIVS_RELINQUISH
+-
+-    if (iserr) {
+-      pr_log_pri(PR_LOG_WARNING, "chown() as root failed: %s", strerror(err));
+-
+-    } else {
+-      if (session.fsgid != (gid_t) -1) {
+-        pr_log_debug(DEBUG2, "root chown(%s) to uid %lu, gid %lu successful",
+-          dir, (unsigned long) session.fsuid, (unsigned long) session.fsgid);
+-
+-      } else {
+-        pr_log_debug(DEBUG2, "root chown(%s) to uid %lu successful", dir,
+-          (unsigned long) session.fsuid);
+-      }
+-    }
+-
+-  } else if (session.fsgid != (gid_t) -1) {
+-    register unsigned int i;
+-    int use_root_privs = TRUE;
+-
+-    pr_fsio_stat(dir, &st);
+-
+-    /* Check if session.fsgid is in session.gids.  If not, use root privs.  */
+-    for (i = 0; i < session.gids->nelts; i++) {
+-      gid_t *group_ids = session.gids->elts;
+-
+-      if (group_ids[i] == session.fsgid) {
+-        use_root_privs = FALSE;
+-        break;
+-      }
+-    }
+-
+-    if (use_root_privs) {
+-      PRIVS_ROOT
+-    }
+-
+-    res = pr_fsio_chown(dir, (uid_t) -1, session.fsgid);
+-
+-    if (use_root_privs) {
+-      PRIVS_RELINQUISH
+-    }
+-
+-    if (res == -1) {
+-      pr_log_pri(PR_LOG_WARNING, "%schown() failed: %s",
+-        use_root_privs ? "root " : "", strerror(errno));
+-
+-    } else { 
+-      pr_log_debug(DEBUG2, "%schown(%s) to gid %lu successful",
+-        use_root_privs ? "root " : "", dir, (unsigned long) session.fsgid);
+-    }
+-  }
+-
+   pr_response_add(R_257, _("\"%s\" - Directory successfully created"),
+     quote_dir(cmd, dir));
+ 
+--- src/fsio.c
++++ src/fsio.c
+@@ -29,6 +29,7 @@
+  */
+ 
+ #include "conf.h"
++#include "privs.h"
+ 
+ #ifdef HAVE_REGEX_H
+ # include <regex.h>
+@@ -84,6 +85,13 @@ static unsigned char chk_fs_map = FALSE;
+ static char vwd[PR_TUNABLE_PATH_MAX + 1] = "/";
+ static char cwd[PR_TUNABLE_PATH_MAX + 1] = "/";
+ 
++/* Runtime enabling/disabling of mkdtemp(3) use. */
++#ifdef HAVE_MKDTEMP
++static int use_mkdtemp = TRUE;
++#else
++static int use_mkdtemp = FALSE;
++#endif /* HAVE_MKDTEMP */
++
+ /* Runtime enabling/disabling of encoding of paths. */
+ static int use_encoding = TRUE;
+ 
+@@ -179,6 +187,10 @@ static int sys_fchown(pr_fh_t *fh, int f
+   return fchown(fd, uid, gid);
+ }
+ 
++static int sys_lchown(pr_fs_t *fs, const char *path, uid_t uid, gid_t gid) {
++  return lchown(path, uid, gid);
++}
++
+ /* We provide our own equivalent of access(2) here, rather than using
+  * access(2) directly, because access(2) uses the real IDs, rather than
+  * the effective IDs, of the process.
+@@ -2477,6 +2489,213 @@ int pr_fsio_mkdir(const char *path, mode
+   return res;
+ }
+ 
++int pr_fsio_set_use_mkdtemp(int value) {
++  int prev_value;
++
++  prev_value = use_mkdtemp;
++
++#ifdef HAVE_MKDTEMP
++  use_mkdtemp = value;
++#endif /* HAVE_MKDTEMP */
++
++  return prev_value;
++}
++
++/* "safe mkdir" variant of mkdir(2), uses mkdtemp(3), lchown(2), and
++ * rename(2) to create a directory which cannot be hijacked by a symlink
++ * race (hopefully) before the UserOwner/GroupOwner ownership changes are
++ * applied.
++ */
++int pr_fsio_smkdir(pool *p, const char *path, mode_t mode, uid_t uid,
++    gid_t gid) {
++  int res, use_root_privs = TRUE, xerrno = 0;
++  char *tmpl_path;
++  char *dst_dir, *tmpl;
++  size_t dst_dirlen, tmpl_len;
++
++  if (path == NULL) {
++    errno = EINVAL;
++    return -1;
++  }
++
++#ifdef HAVE_MKDTEMP
++  if (use_mkdtemp == TRUE) {
++    char *ptr;
++    struct stat st;
++
++    ptr = strrchr(path, '/');
++    if (ptr == NULL) {
++      errno = EINVAL;
++      return -1;
++    }
++
++    if (ptr != path) {
++      dst_dirlen = (ptr - path);
++      dst_dir = pstrndup(p, path, dst_dirlen);
++
++    } else {
++      dst_dirlen = 1;
++      dst_dir = "/";
++    }
++
++    res = lstat(dst_dir, &st);
++    if (res < 0) {
++      return -1;
++    }
++
++    if (!S_ISDIR(st.st_mode) &&
++        !S_ISLNK(st.st_mode)) {
++      errno = EPERM;
++      return -1;
++    }
++
++    /* Allocate enough space for the temporary name: the length of the
++     * destination directory, a slash, 9 X's, 3 for the prefix, and 1 for the
++     * trailing NUL.
++     */
++    tmpl_len = strlen(dst_dir) + 14;
++    tmpl = pcalloc(p, tmpl_len);
++    snprintf(tmpl, tmpl_len-1, "%s/dstXXXXXXXXX",
++      dst_dirlen > 1 ? dst_dir : "");
++
++    /* Use mkdtemp(3) to create the temporary directory (in the same destination
++     * directory as the target path).
++     */
++    tmpl_path = mkdtemp(tmpl);
++    if (tmpl_path == NULL) {
++      return -1;
++    }
++
++  } else {
++    res = pr_fsio_mkdir(path, mode);
++    if (res < 0) {
++      return -1;
++    }
++
++    tmpl_path = pstrdup(p, path);
++  }
++#else
++
++  res = pr_fsio_mkdir(path, mode);
++  if (res < 0) {
++    return -1;
++  }
++
++  tmpl_path = pstrdup(p, path);
++#endif /* HAVE_MKDTEMP */
++
++  if (uid != (uid_t) -1) {
++    PRIVS_ROOT
++    res = pr_fsio_lchown(tmpl_path, uid, gid);
++    xerrno = errno;
++    PRIVS_RELINQUISH
++
++    if (res < 0) {
++      pr_log_pri(PR_LOG_WARNING, "lchown(%s) as root failed: %s", tmpl_path,
++        strerror(xerrno));
++
++    } else {
++      if (gid != (gid_t) -1) {
++        pr_log_debug(DEBUG2, "root lchown(%s) to UID %lu, GID %lu successful",
++          tmpl_path, (unsigned long) uid, (unsigned long) gid);
++
++      } else {
++        pr_log_debug(DEBUG2, "root lchown(%s) to UID %lu successful",
++          tmpl_path, (unsigned long) uid);
++      }
++    }
++
++  } else if (gid != (gid_t) -1) {
++    register unsigned int i;
++
++    /* Check if session.fsgid is in session.gids.  If not, use root privs.  */
++    for (i = 0; i < session.gids->nelts; i++) {
++      gid_t *group_ids = session.gids->elts;
++
++      if (group_ids[i] == gid) {
++        use_root_privs = FALSE;
++        break;
++      }
++    }
++
++    if (use_root_privs) {
++      PRIVS_ROOT
++    }
++
++    res = pr_fsio_lchown(tmpl_path, (uid_t) -1, gid);
++    xerrno = errno;
++
++    if (use_root_privs) {
++      PRIVS_RELINQUISH
++    }
++
++    if (res < 0) {
++      pr_log_pri(PR_LOG_WARNING, "%slchown(%s) failed: %s",
++        use_root_privs ? "root " : "", tmpl_path, strerror(xerrno));
++
++    } else {
++      pr_log_debug(DEBUG2, "%slchown(%s) to GID %lu successful",
++        use_root_privs ? "root " : "", tmpl_path, (unsigned long) gid);
++    }
++  }
++
++  if (use_mkdtemp == TRUE) {
++    mode_t mask, *dir_umask;
++
++    /* Use chmod(2) to set the permission that we want.
++     *
++     * mkdtemp(3) creates a directory with 0700 perms; we are given the
++     * target mode (modulo the configured Umask).
++     */
++    dir_umask = get_param_ptr(CURRENT_CONF, "DirUmask", FALSE);
++    if (dir_umask) {
++      mask = *dir_umask;
++
++    } else {
++      mask = (mode_t) 0022;
++    }
++
++    if (use_root_privs) {
++      PRIVS_ROOT
++    }
++
++    res = chmod(tmpl_path, mode & ~mask);
++    xerrno = errno;
++
++    if (use_root_privs) {
++      PRIVS_RELINQUISH
++    }
++
++    if (res < 0) {
++      pr_log_pri(PR_LOG_WARNING, "%schmod(%s) failed: %s",
++        use_root_privs ? "root " : "", tmpl_path, strerror(xerrno));
++
++      (void) rmdir(tmpl_path);
++
++      errno = xerrno;
++      return -1;
++    }
++
++    /* Use rename(2) to move the temporary directory into place at the
++     * target path.
++     */
++    res = rename(tmpl_path, path);
++    if (res < 0) {
++      xerrno = errno;
++
++      pr_log_pri(PR_LOG_WARNING, "renaming '%s' to '%s' failed: %s", tmpl_path,
++        path, strerror(xerrno));
++
++      (void) rmdir(tmpl_path);
++    
++      errno = xerrno;
++      return -1;
++    }
++  }
++
++  return 0;
++}
++
+ int pr_fsio_rmdir(const char *path) {
+   int res;
+   pr_fs_t *fs;
+@@ -3336,6 +3555,33 @@ int pr_fsio_fchown(pr_fh_t *fh, uid_t ui
+   return res;
+ }
+ 
++int pr_fsio_lchown(const char *name, uid_t uid, gid_t gid) {
++  int res;
++  pr_fs_t *fs;
++
++  fs = lookup_file_fs(name, NULL, FSIO_FILE_CHOWN);
++  if (fs == NULL) {
++    return -1;
++  }
++
++  /* Find the first non-NULL custom lchown handler.  If there are none,
++   * use the system chown.
++   */
++  while (fs && fs->fs_next && !fs->lchown) {
++    fs = fs->fs_next;
++  }
++
++  pr_trace_msg(trace_channel, 8, "using %s lchown() for path '%s'",
++    fs->fs_name, name);
++  res = (fs->lchown)(fs, name, uid, gid);
++
++  if (res == 0) {
++    pr_fs_clear_cache();
++  }
++
++  return res;
++}
++
+ int pr_fsio_access(const char *path, int mode, uid_t uid, gid_t gid,
+     array_header *suppl_gids) {
+   pr_fs_t *fs;
+@@ -3955,6 +4201,7 @@ int init_fs(void) {
+   root_fs->fchmod = sys_fchmod;
+   root_fs->chown = sys_chown;
+   root_fs->fchown = sys_fchown;
++  root_fs->lchown = sys_lchown;
+   root_fs->access = sys_access;
+   root_fs->faccess = sys_faccess;
+   root_fs->utimes = sys_utimes;
+@@ -4036,6 +4283,12 @@ static const char *get_fs_hooks_str(pool
+   if (fs->chown)
+     hooks = pstrcat(p, hooks, *hooks ? ", " : "", "chown(2)", NULL);
+ 
++  if (fs->fchown)
++    hooks = pstrcat(p, hooks, *hooks ? ", " : "", "fchown(2)", NULL);
++
++  if (fs->lchown)
++    hooks = pstrcat(p, hooks, *hooks ? ", " : "", "lchown(2)", NULL);
++
+   if (fs->access)
+     hooks = pstrcat(p, hooks, *hooks ? ", " : "", "access(2)", NULL);
+ 
+--- src/Makefile.in
++++ src/Makefile.in
+@@ -294,7 +294,7 @@ filter.o: ../include/event.h ../include/
+ filter.o: ../include/trace.h ../include/encode.h ../include/compat.h
+ filter.o: ../include/proctitle.h ../include/pidfile.h ../include/env.h
+ filter.o: ../include/pr-syslog.h
+-fsio.o: ../include/conf.h ../include/version.h ../config.h
++fsio.o: ../include/conf.h ../include/privs.h ../include/version.h ../config.h
+ fsio.o: ../include/default_paths.h ../include/options.h ../include/pool.h
+ fsio.o: ../include/str.h ../include/regexp.h ../include/table.h
+ fsio.o: ../include/proftpd.h ../include/class.h ../include/netacl.h
diff --git a/proftpd-mod-vroot-0.8.5-bug3841.patch b/proftpd-mod-vroot-0.8.5-bug3841.patch
new file mode 100644
index 0000000..e134c93
--- /dev/null
+++ b/proftpd-mod-vroot-0.8.5-bug3841.patch
@@ -0,0 +1,98 @@
+From f2b7c3c6bc47ba547863a66d558dae7b9ed0ce63 Mon Sep 17 00:00:00 2001
+From: TJ Saunders <tj at castaglia.org>
+Date: Sun, 13 Jan 2013 16:43:07 -0800
+Subject: [PATCH] Add use of the new pr_fsio_set_use_mkdtemp() API, to work
+ around issues seen with mod_vroot due to the fix for
+ Bug#3841.
+
+---
+ mod_vroot.c |   35 ++++++++++++++++++++++++++++++++---
+ 1 file changed, 32 insertions(+), 3 deletions(-)
+
+diff --git mod_vroot/mod_vroot.c mod_vroot/mod_vroot.c
+index e31f11d..2fba410 100644
+--- contrib/mod_vroot.c
++++ contrib/mod_vroot.c
+@@ -50,6 +50,8 @@
+ static pool *vroot_alias_pool = NULL;
+ static pr_table_t *vroot_alias_tab = NULL;
+ 
++static int vroot_use_mkdtemp = FALSE;
++
+ static unsigned int vroot_opts = 0;
+ #define	VROOT_OPT_ALLOW_SYMLINKS	0x0001
+ 
+@@ -538,6 +540,25 @@
+   return chown(vpath, uid, gid);
+ }
+ 
++static int vroot_lchown(pr_fs_t *fs, const char *path, uid_t uid, gid_t gid) {
++  char vpath[PR_TUNABLE_PATH_MAX + 1];
++
++  if (session.curr_phase == LOG_CMD ||
++      session.curr_phase == LOG_CMD_ERR ||
++      (session.sf_flags & SF_ABORT) ||
++      *vroot_base == '\0') {
++    /* NOTE: once stackable FS modules are supported, have this fall through
++     * to the next module in the stack.
++     */
++    return lchown(path, uid, gid);
++  }
++
++  if (vroot_lookup_path(vpath, sizeof(vpath), path) < 0)
++    return -1;
++
++  return lchown(vpath, uid, gid);
++}
++
+ static int vroot_chroot(pr_fs_t *fs, const char *path) {
+   char *chroot_path = "/", *tmp = NULL;
+   config_rec *c;
+@@ -850,6 +871,26 @@
+ /* Command handlers
+  */
+ 
++MODRET vroot_pre_mkd(cmd_rec *cmd) {
++  if (vroot_engine == FALSE ||
++      session.chroot_path == NULL) {
++    return PR_DECLINED(cmd);
++  }
++
++  vroot_use_mkdtemp = pr_fsio_set_use_mkdtemp(FALSE);
++  return PR_DECLINED(cmd);
++}
++
++MODRET vroot_post_mkd(cmd_rec *cmd) {
++  if (vroot_engine == FALSE ||
++      session.chroot_path == NULL) {
++    return PR_DECLINED(cmd);
++  }
++
++  pr_fsio_set_use_mkdtemp(vroot_use_mkdtemp);
++  return PR_DECLINED(cmd);
++}
++
+ MODRET vroot_pre_pass(cmd_rec *cmd) {
+   pr_fs_t *fs = NULL;
+   unsigned char *use_vroot = NULL;
+@@ -893,6 +934,7 @@
+   fs->truncate = vroot_truncate;
+   fs->chmod = vroot_chmod;
+   fs->chown = vroot_chown;
++  fs->lchown = vroot_lchown;
+   fs->chdir = vroot_chdir;
+   fs->chroot = vroot_chroot;
+   fs->opendir = vroot_opendir;
+@@ -1024,6 +1066,12 @@
+   { PRE_CMD,		C_PASS,	G_NONE,	vroot_pre_pass, FALSE, FALSE },
+   { POST_CMD,		C_PASS,	G_NONE,	vroot_post_pass, FALSE, FALSE },
+   { POST_CMD_ERR,	C_PASS,	G_NONE,	vroot_post_pass_err, FALSE, FALSE },
++  { PRE_CMD,		C_MKD,	G_NONE,	vroot_pre_mkd, FALSE, FALSE },
++  { POST_CMD,		C_MKD,	G_NONE,	vroot_post_mkd, FALSE, FALSE },
++  { POST_CMD_ERR,	C_MKD,	G_NONE,	vroot_post_mkd, FALSE, FALSE },
++  { PRE_CMD,		C_XMKD,	G_NONE,	vroot_pre_mkd, FALSE, FALSE },
++  { POST_CMD,		C_XMKD,	G_NONE,	vroot_post_mkd, FALSE, FALSE },
++  { POST_CMD_ERR,	C_XMKD,	G_NONE,	vroot_post_mkd, FALSE, FALSE },
+   { 0, NULL }
+ };
+ 
diff --git a/proftpd.spec b/proftpd.spec
index 9d75a66..0e35559 100644
--- a/proftpd.spec
+++ b/proftpd.spec
@@ -7,7 +7,7 @@
 %endif
 
 #global prever rc4
-%global rpmrel 1
+%global rpmrel 2
 
 Summary:		Flexible, stable and highly-configurable FTP server
 Name:			proftpd
@@ -26,6 +26,8 @@ Source6:		proftpd.pam
 Source9:		proftpd.sysconfig
 Source10:		http://www.castaglia.org/proftpd/modules/proftpd-mod-vroot-0.8.5.tar.gz
 Source11:		http://www.castaglia.org/proftpd/modules/proftpd-mod-geoip-0.2.tar.gz
+Patch0:			proftpd-1.3.3g-bug3841.patch
+Patch1:			proftpd-mod-vroot-0.8.5-bug3841.patch
 BuildRoot:		%{_tmppath}/%{name}-%{version}-%{release}-root
 Requires(post):		/sbin/chkconfig
 Requires(preun):	/sbin/service, /sbin/chkconfig, coreutils, findutils
@@ -83,6 +85,11 @@ cp -p mod_geoip/mod_geoip.html doc/contrib/
 # Avoid documentation name conflicts
 mv contrib/README contrib/README.contrib
 
+# Fix possible symlink race when applying UserOwner to newly created directory
+# (CVE-2012-6095, #892715, http://bugs.proftpd.org/show_bug.cgi?id=3841)
+%patch0
+%patch1
+
 # Set up directory names in config file
 sed -e 's#@PKIDIR@#%{pkidir}#g' \
 	%{SOURCE1} > proftpd.conf
@@ -141,7 +148,7 @@ SMOD6=mod_sftp:mod_sftp_pam:mod_sftp_sql:mod_tls_shmcache
 	--with-modules=mod_readme:mod_auth_pam:mod_tls:mod_vroot \
 	--with-shared=${SMOD1}:${SMOD2}:${SMOD3}:${SMOD4}:${SMOD5}:${SMOD6}:mod_ifsession
 
-make %{?_smp_mflags}
+make %{?_smp_mflags} CFLAGS="%{optflags} -fno-strict-aliasing"
 
 %install
 rm -rf %{buildroot}
@@ -191,7 +198,6 @@ if [ $1 -ge 1 ]; then
 fi
 
 %files -f proftpd.lang
-%defattr(-,root,root,-)
 %doc COPYING CREDITS ChangeLog NEWS README
 %doc README.DSO README.modules README.IPv6 README.PAM
 %doc README.capabilities README.classes README.controls README.facl
@@ -262,20 +268,23 @@ fi
 %attr(750, root, root) %dir %{_localstatedir}/log/proftpd/
 
 %files ldap
-%defattr(-,root,root,-)
 %doc README.LDAP contrib/mod_quotatab_ldap.ldif contrib/mod_quotatab_ldap.schema
 %{_libexecdir}/proftpd/mod_ldap.so
 %{_libexecdir}/proftpd/mod_quotatab_ldap.so
 
 %files mysql
-%defattr(-,root,root,-)
 %{_libexecdir}/proftpd/mod_sql_mysql.so
 
 %files postgresql
-%defattr(-,root,root,-)
 %{_libexecdir}/proftpd/mod_sql_postgres.so
 
 %changelog
+* Fri Jan 18 2013 Paul Howarth <paul at city-fan.org> 1.3.3g-2
+- Fix possible symlink race when applying UserOwner to newly created directory
+  (CVE-2012-6095, #892715, http://bugs.proftpd.org/show_bug.cgi?id=3841)
+- Add -fno-strict-aliasing, needed for mod_radius
+- Drop %%defattr, redundant since rpm 4.4
+
 * Thu Nov 10 2011 Paul Howarth <paul at city-fan.org> 1.3.3g-1
 - Update to 1.3.3g, fixing the following bugs:
   - ProFTPD with mod_sql_mysql dies of "Alarm clock" on FreeBSD (bug 3702)


More information about the scm-commits mailing list