Package: davfs2 Version: 1.4.6-1.1 Severity: critical Tags: patch, security, upstream
davfs2 calls function system several times. Because davfs2 is setuid root in many cases this will allow for privilege escalation. Appended are patches for version 1.4.6 and 1.4.7 that will fix this bug. Note: as a consequence davfs2 will no longer try to insert required kernel modules or create device special files /dev/fuse or /dev/codaX. So the user has to make sure that one of these devices exists before mounting a davfs2 file system. As far as I can see /dev/fuse is created by default on Debian systems. davfs2 uses /dev/fuse by default (and not /dev/codaX). So this bug fix should not cause any problem on Debian systems. Werner (upstream maintainer)
diff -ur davfs2-1.4.6/ChangeLog davfs2-1.4.6.new/ChangeLog --- davfs2-1.4.6/ChangeLog 2010-04-30 21:17:15.000000000 +0200 +++ davfs2-1.4.6.new/ChangeLog 2013-09-15 11:05:42.000000000 +0200 @@ -1,6 +1,11 @@ ChangeLog for davfs2 -------------------- +2013-09-08 Werner Baumann (werner.baum...@onlinehome.de) + * kernel_interface.c, mount_davfs.c: + Don't create /dev/coda and /dev/fuse. + Remove insecure calls of system(). + 2010-04-30 Werner Baumann (werner.baum...@onlinehome.de) * Released version 1.4.6 Nur in davfs2-1.4.6.new: ChangeLog~. diff -ur davfs2-1.4.6/src/kernel_interface.c davfs2-1.4.6.new/src/kernel_interface.c --- davfs2-1.4.6/src/kernel_interface.c 2010-02-16 20:29:54.000000000 +0100 +++ davfs2-1.4.6.new/src/kernel_interface.c 2013-09-15 11:07:07.000000000 +0200 @@ -168,27 +168,6 @@ } if (*dev <= 0) { - system("/sbin/modprobe coda &>/dev/null"); - minor = 0; - while (*dev <= 0 && minor < MAX_CODADEVS) { - char *path; - if (asprintf(&path, "%s/%s%i", - DAV_DEV_DIR, CODA_DEV_NAME, minor) < 0) - abort(); - *dev = open(path, O_RDWR | O_NONBLOCK); - if (*dev <= 0) { - if (mknod(path, S_IFCHR, makedev(CODA_MAJOR, minor)) == 0) { - chown(path, 0, 0); - chmod(path, S_IRUSR | S_IWUSR); - *dev = open(path, O_RDWR | O_NONBLOCK); - } - } - free(path); - ++minor; - } - } - - if (*dev <= 0) { error(0, 0, _("no free coda device to mount")); return -1; } @@ -223,24 +202,6 @@ abort(); *dev = open(path, O_RDWR | O_NONBLOCK); - if (*dev <= 0) { - system("/sbin/modprobe fuse &>/dev/null"); - *dev = open(path, O_RDWR | O_NONBLOCK); - } - if (*dev <= 0) { - if (mknod(path, S_IFCHR, makedev(FUSE_MAJOR, FUSE_MINOR)) == 0) { - chown(path, 0, 0); - chmod(path, S_IRUSR | S_IWUSR); - *dev = open(path, O_RDWR | O_NONBLOCK); - } - } - - free(path); - if (*dev <= 0) { - error(0, 0, _("can't open fuse device")); - return -1; - } - if (*buf_size < (FUSE_MIN_READ_BUFFER + 4096)) { *buf_size = FUSE_MIN_READ_BUFFER + 4096; } Nur in davfs2-1.4.6.new/src: kernel_interface.c~. diff -ur davfs2-1.4.6/src/mount_davfs.c davfs2-1.4.6.new/src/mount_davfs.c --- davfs2-1.4.6/src/mount_davfs.c 2010-01-21 19:50:15.000000000 +0100 +++ davfs2-1.4.6.new/src/mount_davfs.c 2013-09-15 11:13:18.000000000 +0200 @@ -170,6 +170,9 @@ static int arg_to_int(const char *arg, int base, const char *opt); +static void +cp_file(const char *src, const char *dest); + static int debug_opts(const char *s); @@ -533,10 +536,7 @@ char *file_name = ne_concat(path, "/", DAV_CONFIG, NULL); if (access(file_name, F_OK) != 0) { char *template = ne_concat(DAV_DATA_DIR, "/", DAV_CONFIG, NULL); - char *command = ne_concat("cp ", template, " ", file_name, - NULL); - system(command); - free(command); + cp_file(template, file_name); free(template); } free(file_name); @@ -545,11 +545,7 @@ if (access(file_name, F_OK) != 0) { char *template = ne_concat(DAV_DATA_DIR, "/", DAV_SECRETS, NULL); - char *command = ne_concat("cp ", template, " ", file_name, - NULL); - if (system(command) == 0) - chmod(file_name, S_IRUSR | S_IWUSR); - free(command); + cp_file(template, file_name); free(template); } free(file_name); @@ -1333,6 +1329,34 @@ } +/* Creates a copy of src with name dest. */ +static void +cp_file(const char *src, const char *dest) +{ + FILE *in = fopen(src, "r"); + if (!in) + error(EXIT_FAILURE, errno, _("can't open file %s"), src); + + FILE *out = fopen(dest, "w"); + if (!out) + error(EXIT_FAILURE, errno, _("can't open file %s"), dest); + + size_t n = 0; + char *line = NULL; + int length = getline(&line, &n, in); + while (length > 0) { + if (fputs(line, out) == EOF) + error(EXIT_FAILURE, errno, _("error writing to file %s"), dest); + length = getline(&line, &n, in); + } + + if (line) + free(line); + fclose(out); + fclose(in); +} + + /* Converts a debug option string s into numerical value. If s is not a valid debug option, it returns 0. */ static int Nur in davfs2-1.4.6.new/src: mount_davfs.c~.
diff -ur davfs2-1.4.7/ChangeLog davfs2-1.4.7.new/ChangeLog --- davfs2-1.4.7/ChangeLog 2012-07-19 13:37:52.000000000 +0200 +++ davfs2-1.4.7.new/ChangeLog 2013-09-15 10:19:12.000000000 +0200 @@ -1,6 +1,11 @@ ChangeLog for davfs2 -------------------- +2013-09-08 Werner Baumann (werner.baum...@onlinehome.de) + * kernel_interface.c, mount_davfs.c: + Don't create /dev/coda and /dev/fuse. + Remove insecure calls of system(). + 2012-07-19 Werner Baumann (werner.baum...@onlinehome.de) * Release version 1.4.7. diff -ur davfs2-1.4.7/src/kernel_interface.c davfs2-1.4.7.new/src/kernel_interface.c --- davfs2-1.4.7/src/kernel_interface.c 2012-07-19 12:58:48.000000000 +0200 +++ davfs2-1.4.7.new/src/kernel_interface.c 2013-09-15 10:15:07.000000000 +0200 @@ -167,29 +167,6 @@ ++minor; } - if (*dev <= 0 && system("/sbin/modprobe coda &>/dev/null") == 0) { - minor = 0; - while (*dev <= 0 && minor < MAX_CODADEVS) { - char *path; - if (asprintf(&path, "%s/%s%i", - DAV_DEV_DIR, CODA_DEV_NAME, minor) < 0) - abort(); - *dev = open(path, O_RDWR | O_NONBLOCK); - if (*dev <= 0) { - if (mknod(path, S_IFCHR, makedev(CODA_MAJOR, minor)) == 0) { - if (chown(path, 0, 0) == 0 - && chmod(path, S_IRUSR | S_IWUSR) == 0) { - *dev = open(path, O_RDWR | O_NONBLOCK); - } else { - remove(path); - } - } - } - free(path); - ++minor; - } - } - if (*dev <= 0) { error(0, 0, _("no free coda device to mount")); return -1; @@ -225,20 +202,6 @@ abort(); *dev = open(path, O_RDWR | O_NONBLOCK); - if (*dev <= 0 && system("/sbin/modprobe fuse &>/dev/null") == 0) { - *dev = open(path, O_RDWR | O_NONBLOCK); - } - if (*dev <= 0) { - if (mknod(path, S_IFCHR, makedev(FUSE_MAJOR, FUSE_MINOR)) == 0) { - if (chown(path, 0, 0) == 0 - && chmod(path, S_IRUSR | S_IWUSR) == 0) { - *dev = open(path, O_RDWR | O_NONBLOCK); - } else { - remove(path); - } - } - } - free(path); if (*dev <= 0) { error(0, 0, _("can't open fuse device")); diff -ur davfs2-1.4.7/src/mount_davfs.c davfs2-1.4.7.new/src/mount_davfs.c --- davfs2-1.4.7/src/mount_davfs.c 2012-07-19 13:35:11.000000000 +0200 +++ davfs2-1.4.7.new/src/mount_davfs.c 2013-09-15 10:15:22.000000000 +0200 @@ -170,6 +170,9 @@ static int arg_to_int(const char *arg, int base, const char *opt); +static void +cp_file(const char *src, const char *dest); + static int debug_opts(const char *s); @@ -530,10 +533,7 @@ char *file_name = ne_concat(path, "/", DAV_CONFIG, NULL); if (access(file_name, F_OK) != 0) { char *template = ne_concat(DAV_DATA_DIR, "/", DAV_CONFIG, NULL); - char *command = ne_concat("cp ", template, " ", file_name, - NULL); - if (system(command) != 0); - free(command); + cp_file(template, file_name); free(template); } free(file_name); @@ -542,11 +542,7 @@ if (access(file_name, F_OK) != 0) { char *template = ne_concat(DAV_DATA_DIR, "/", DAV_SECRETS, NULL); - char *command = ne_concat("cp ", template, " ", file_name, - NULL); - if (system(command) == 0) - chmod(file_name, S_IRUSR | S_IWUSR); - free(command); + cp_file(template, file_name); free(template); } free(file_name); @@ -1304,6 +1300,7 @@ opt : name of the option, arg belongs to. Used in the error message. return value: the value of the integer number in arg */ static int + arg_to_int(const char *arg, int base, const char *opt) { char *tail = NULL; @@ -1325,6 +1322,34 @@ } +/* Creates a copy of src with name dest. */ +static void +cp_file(const char *src, const char *dest) +{ + FILE *in = fopen(src, "r"); + if (!in) + error(EXIT_FAILURE, errno, _("can't open file %s"), src); + + FILE *out = fopen(dest, "w"); + if (!out) + error(EXIT_FAILURE, errno, _("can't open file %s"), dest); + + size_t n = 0; + char *line = NULL; + int length = getline(&line, &n, in); + while (length > 0) { + if (fputs(line, out) == EOF) + error(EXIT_FAILURE, errno, _("error writing to file %s"), dest); + length = getline(&line, &n, in); + } + + if (line) + free(line); + fclose(out); + fclose(in); +} + + /* Converts a debug option string s into numerical value. If s is not a valid debug option, it returns 0. */ static int