[SCM] proftpd-dfsg branch, master, updated. upstream/1.3.4a-72-g33937f4
Francesco Paolo Lovergine
frankie at debian.org
Tue Jan 8 12:55:33 UTC 2013
The following commit has been merged in the master branch:
commit 33937f4b36b0b4b92e26e063bd29eafe545e8b63
Author: Francesco Paolo Lovergine <frankie at debian.org>
Date: Tue Jan 8 12:10:55 2013 +0100
Fixed CVE-2012-6095
diff --git a/debian/changelog b/debian/changelog
index 1ca7377..6d23904 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,12 @@
+proftpd-dfsg (1.3.4a-3) unstable; urgency=low
+
+ [SECURITY] New patch 3841 fixes CVE-2012-6095: a possible race
+ condition in the handling of the MKD/XMKD FTP commands, when the UserOwner
+ directive is involved, and the attacker is on the same physical
+ machine as a running proftpd.
+
+ -- Francesco Paolo Lovergine <frankie at debian.org> Tue, 08 Jan 2013 12:08:47 +0100
+
proftpd-dfsg (1.3.4a-2) unstable; urgency=low
[ Mahyuddin Susanto ]
diff --git a/debian/patches/3841 b/debian/patches/3841
new file mode 100644
index 0000000..46c759a
--- /dev/null
+++ b/debian/patches/3841
@@ -0,0 +1,307 @@
+Index: proftpd-dfsg/contrib/mod_sftp/fxp.c
+===================================================================
+--- proftpd-dfsg.orig/contrib/mod_sftp/fxp.c 2013-01-08 12:03:49.000000000 +0100
++++ proftpd-dfsg/contrib/mod_sftp/fxp.c 2013-01-08 12:06:31.000000000 +0100
+@@ -6093,7 +6093,7 @@
+ (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;
+Index: proftpd-dfsg/contrib/mod_sftp/scp.c
+===================================================================
+--- proftpd-dfsg.orig/contrib/mod_sftp/scp.c 2013-01-08 12:03:50.000000000 +0100
++++ proftpd-dfsg/contrib/mod_sftp/scp.c 2013-01-08 12:06:31.000000000 +0100
+@@ -731,7 +731,7 @@
+ * recursive directory uploads via SCP?
+ */
+
+- 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,
+Index: proftpd-dfsg/include/fsio.h
+===================================================================
+--- proftpd-dfsg.orig/include/fsio.h 2013-01-08 12:03:50.000000000 +0100
++++ proftpd-dfsg/include/fsio.h 2013-01-08 12:06:31.000000000 +0100
+@@ -243,6 +243,7 @@
+ 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);
+Index: proftpd-dfsg/modules/mod_core.c
+===================================================================
+--- proftpd-dfsg.orig/modules/mod_core.c 2013-01-08 12:03:50.000000000 +0100
++++ proftpd-dfsg/modules/mod_core.c 2013-01-08 12:07:43.000000000 +0100
+@@ -4617,7 +4617,8 @@
+ 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): "
+@@ -4631,71 +4632,6 @@
+ 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));
+
+Index: proftpd-dfsg/src/fsio.c
+===================================================================
+--- proftpd-dfsg.orig/src/fsio.c 2013-01-08 12:03:50.000000000 +0100
++++ proftpd-dfsg/src/fsio.c 2013-01-08 12:06:31.000000000 +0100
+@@ -29,6 +29,7 @@
+ */
+
+ #include "conf.h"
++#include "privs.h"
+
+ #ifdef HAVE_SYS_STATVFS_H
+ # include <sys/statvfs.h>
+@@ -2498,6 +2499,170 @@
+ return res;
+ }
+
++/* "secure 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;
++ char *tmpl_path;
++#ifdef HAVE_MKDTEMP
++ mode_t mask, *dir_umask;
++ char *dst_dir, *tmpl, *ptr;
++ size_t tmpl_len;
++ struct stat st;
++#endif /* HAVE_MKDTEMP */
++
++ if (path == NULL) {
++ errno = EINVAL;
++ return -1;
++ }
++
++#ifdef HAVE_MKDTEMP
++ ptr = strrchr(path, '/');
++ if (ptr == NULL) {
++ errno = EINVAL;
++ return -1;
++ }
++
++ dst_dir = pstrndup(p, path, (ptr - path));
++ res = lstat(dst_dir, &st);
++ if (res < 0) {
++ return -1;
++ }
++
++ if (!S_ISDIR(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(path) + 14;
++ tmpl = pcalloc(p, tmpl_len);
++ snprintf(tmpl, tmpl_len-1, "%s/dstXXXXXXXXX", 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);
++
++#endif /* HAVE_MKDTEMP */
++
++ if (uid != (uid_t) -1) {
++ int xerrno;
++
++ 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;
++ int use_root_privs = TRUE, xerrno;
++
++ /* 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);
++ }
++ }
++
++#ifdef HAVE_MKDTEMP
++ /* 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;
++ }
++
++ res = chmod(tmpl_path, mode & ~mask);
++ if (res < 0) {
++ int xerrno = errno;
++
++ (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) {
++ int xerrno = errno;
++
++ (void) rmdir(tmpl_path);
++
++ errno = xerrno;
++ return -1;
++ }
++#endif /* HAVE_MKDTEMP */
++
++ return 0;
++}
++
+ int pr_fsio_rmdir(const char *path) {
+ int res;
+ pr_fs_t *fs;
diff --git a/debian/patches/series b/debian/patches/series
index da36ad9..8d0f684 100644
--- a/debian/patches/series
+++ b/debian/patches/series
@@ -10,3 +10,4 @@ mod_cap
odbc
silent
use_hypen_in_manpage
+3841
--
ProFTPD core package
More information about the Pkg-proftpd-maintainers
mailing list