Submitted By: Ken Moffat Date: 2005-07-29 Initial Package Version: 2.6 Upstream Status: Unknown Origin: from Mandrake Description: Vulnerability fixes, rediffed so that they all apply with -p1 and consolidated to single patch. Also applicable to earlier versions. (1.) CAN-1999-1572 (still seems to apply to 2.6) cpio uses a 0 umask when creating files with -O or -F options, which creates the files with mode 0666 and allows local users to overwrite them. Fix originally fom debian. (2.) CAN-2005-1111 Race condition in 2.6 and earlier allows local users to modify permissions of arbitrary files via a hard-link attack. Fix originally from fedora. (3.) CAN-2005-1229 Directory traversal vulnerability allows remote attackers to write to arbitrary directories via a dot dot in a cpio file. Fix by Peter Vrabec at RedHat. diff -Naur cpio-2.6.vanilla/doc/cpio.1 cpio-2.6/doc/cpio.1 --- cpio-2.6.vanilla/doc/cpio.1 2004-08-30 17:21:48.000000000 +0100 +++ cpio-2.6/doc/cpio.1 2005-07-29 13:46:42.000000000 +0100 @@ -20,7 +20,7 @@ [\-\-unconditional] [\-\-verbose] [\-\-block-size=blocks] [\-\-swap-halfwords] [\-\-io-size=bytes] [\-\-pattern-file=file] [\-\-format=format] [\-\-owner=[user][:.][group]] [\-\-no-preserve-owner] [\-\-message=message] -[\-\-force\-local] [\-\-no\-absolute\-filenames] [\-\-sparse] +[\-\-force\-local] [\-\-absolute\-filenames] [\-\-sparse] [\-\-only\-verify\-crc] [\-\-quiet] [\-\-rsh-command=command] [\-\-help] [\-\-version] [pattern...] [< archive] diff -Naur cpio-2.6.vanilla/doc/cpio.info cpio-2.6/doc/cpio.info --- cpio-2.6.vanilla/doc/cpio.info 2004-02-27 12:42:01.000000000 +0000 +++ cpio-2.6/doc/cpio.info 2005-07-29 13:46:42.000000000 +0100 @@ -203,7 +203,7 @@ [--swap-halfwords] [--io-size=bytes] [--pattern-file=file] [--format=format] [--owner=[user][:.][group]] [--no-preserve-owner] [--message=message] [--help] [--version] - [-no-absolute-filenames] [--sparse] [-only-verify-crc] [-quiet] + [--absolute-filenames] [--sparse] [-only-verify-crc] [-quiet] [--rsh-command=command] [pattern...] [< archive]  @@ -358,9 +358,9 @@ Show numeric UID and GID instead of translating them into names when using the `--verbose option'. -`--no-absolute-filenames' - Create all files relative to the current directory in copy-in - mode, even if they have an absolute file name in the archive. +`--absolute-filenames' + Do not strip leading file name components that contain ".." + and leading slashes from file names in copy-in mode `--no-preserve-owner' Do not change the ownership of the files; leave them owned by the diff -Naur cpio-2.6.vanilla/src/copyin.c cpio-2.6/src/copyin.c --- cpio-2.6.vanilla/src/copyin.c 2004-09-08 12:10:02.000000000 +0100 +++ cpio-2.6/src/copyin.c 2005-07-29 13:46:42.000000000 +0100 @@ -25,6 +25,7 @@ #include "dstring.h" #include "extern.h" #include "defer.h" +#include "dirname.h" #include #ifndef FNM_PATHNAME #include @@ -389,19 +390,26 @@ continue; } - if (close (out_file_des) < 0) - error (0, errno, "%s", d->header.c_name); - + /* + * Avoid race condition. + * Set chown and chmod before closing the file desc. + * pvrabec@redhat.com + */ + /* File is now copied; set attributes. */ if (!no_chown_flag) - if ((chown (d->header.c_name, + if ((fchown (out_file_des, set_owner_flag ? set_owner : d->header.c_uid, set_group_flag ? set_group : d->header.c_gid) < 0) && errno != EPERM) error (0, errno, "%s", d->header.c_name); /* chown may have turned off some permissions we wanted. */ - if (chmod (d->header.c_name, (int) d->header.c_mode) < 0) + if (fchmod (out_file_des, (int) d->header.c_mode) < 0) error (0, errno, "%s", d->header.c_name); + + if (close (out_file_des) < 0) + error (0, errno, "%s", d->header.c_name); + if (retain_time_flag) { times.actime = times.modtime = d->header.c_mtime; @@ -557,6 +565,25 @@ write (out_file_des, "", 1); delayed_seek_count = 0; } + + /* + * Avoid race condition. + * Set chown and chmod before closing the file desc. + * pvrabec@redhat.com + */ + + /* File is now copied; set attributes. */ + if (!no_chown_flag) + if ((fchown (out_file_des, + set_owner_flag ? set_owner : file_hdr->c_uid, + set_group_flag ? set_group : file_hdr->c_gid) < 0) + && errno != EPERM) + error (0, errno, "%s", file_hdr->c_name); + + /* chown may have turned off some permissions we wanted. */ + if (fchmod (out_file_des, (int) file_hdr->c_mode) < 0) + error (0, errno, "%s", file_hdr->c_name); + if (close (out_file_des) < 0) error (0, errno, "%s", file_hdr->c_name); @@ -567,18 +594,6 @@ file_hdr->c_name, crc, file_hdr->c_chksum); } - /* File is now copied; set attributes. */ - if (!no_chown_flag) - if ((chown (file_hdr->c_name, - set_owner_flag ? set_owner : file_hdr->c_uid, - set_group_flag ? set_group : file_hdr->c_gid) < 0) - && errno != EPERM) - error (0, errno, "%s", file_hdr->c_name); - - /* chown may have turned off some permissions we wanted. */ - if (chmod (file_hdr->c_name, (int) file_hdr->c_mode) < 0) - error (0, errno, "%s", file_hdr->c_name); - if (retain_time_flag) { struct utimbuf times; /* For setting file times. */ @@ -589,7 +604,7 @@ if (utime (file_hdr->c_name, ×) < 0) error (0, errno, "%s", file_hdr->c_name); } - + tape_skip_padding (in_file_des, file_hdr->c_filesize); if (file_hdr->c_nlink > 1 && (archive_format == arf_newascii || archive_format == arf_crcascii) ) @@ -1335,6 +1350,53 @@ } } +/* Return a safer suffix of FILE_NAME, or "." if it has no safer + suffix. Check for fully specified file names and other atrocities. */ + +static const char * +safer_name_suffix (char const *file_name) +{ + char const *p; + + /* Skip file system prefixes, leading file name components that contain + "..", and leading slashes. */ + + size_t prefix_len = FILE_SYSTEM_PREFIX_LEN (file_name); + + for (p = file_name + prefix_len; *p;) + { + if (p[0] == '.' && p[1] == '.' && (ISSLASH (p[2]) || !p[2])) + prefix_len = p + 2 - file_name; + + do + { + char c = *p++; + if (ISSLASH (c)) + break; + } + while (*p); + } + + for (p = file_name + prefix_len; ISSLASH (*p); p++) + continue; + prefix_len = p - file_name; + + if (prefix_len) + { + char *prefix = alloca (prefix_len + 1); + memcpy (prefix, file_name, prefix_len); + prefix[prefix_len] = '\0'; + + + error (0, 0, _("Removing leading `%s' from member names"), prefix); + } + + if (!*p) + p = "."; + + return p; +} + /* Read the collection from standard input and create files in the file system. */ @@ -1445,18 +1507,11 @@ /* Do we have to ignore absolute paths, and if so, does the filename have an absolute path? */ - if (no_abs_paths_flag && file_hdr.c_name && file_hdr.c_name [0] == '/') + if (!abs_paths_flag && file_hdr.c_name && file_hdr.c_name [0]) { - char *p; + const char *p = safer_name_suffix (file_hdr.c_name); - p = file_hdr.c_name; - while (*p == '/') - ++p; - if (*p == '\0') - { - strcpy (file_hdr.c_name, "."); - } - else + if (p != file_hdr.c_name) { /* Debian hack: file_hrd.c_name is sometimes set to point to static memory by code in tar.c. This diff -Naur cpio-2.6.vanilla/src/copypass.c cpio-2.6/src/copypass.c --- cpio-2.6.vanilla/src/copypass.c 2004-09-06 13:09:04.000000000 +0100 +++ cpio-2.6/src/copypass.c 2005-07-29 13:46:07.000000000 +0100 @@ -181,19 +181,25 @@ } if (close (in_file_des) < 0) error (0, errno, "%s", input_name.ds_string); - if (close (out_file_des) < 0) - error (0, errno, "%s", output_name.ds_string); - + /* + * Avoid race condition. + * Set chown and chmod before closing the file desc. + * pvrabec@redhat.com + */ /* Set the attributes of the new file. */ if (!no_chown_flag) - if ((chown (output_name.ds_string, + if ((fchown (out_file_des, set_owner_flag ? set_owner : in_file_stat.st_uid, set_group_flag ? set_group : in_file_stat.st_gid) < 0) && errno != EPERM) error (0, errno, "%s", output_name.ds_string); /* chown may have turned off some permissions we wanted. */ - if (chmod (output_name.ds_string, in_file_stat.st_mode) < 0) + if (fchmod (out_file_des, in_file_stat.st_mode) < 0) + error (0, errno, "%s", output_name.ds_string); + + if (close (out_file_des) < 0) error (0, errno, "%s", output_name.ds_string); + if (reset_time_flag) { times.actime = in_file_stat.st_atime; diff -Naur cpio-2.6.vanilla/src/extern.h cpio-2.6/src/extern.h --- cpio-2.6.vanilla/src/extern.h 2004-09-08 11:49:57.000000000 +0100 +++ cpio-2.6/src/extern.h 2005-07-29 13:47:34.000000000 +0100 @@ -46,7 +46,7 @@ extern int sparse_flag; extern int quiet_flag; extern int only_verify_crc_flag; -extern int no_abs_paths_flag; +extern int abs_paths_flag; extern unsigned int warn_option; /* Values for warn_option */ @@ -91,6 +91,7 @@ extern char input_is_seekable; extern char output_is_seekable; extern char *program_name; +extern mode_t sys_umask; extern int (*xstat) (); extern void (*copy_function) (); diff -Naur cpio-2.6.vanilla/src/global.c cpio-2.6/src/global.c --- cpio-2.6.vanilla/src/global.c 2004-09-08 11:23:44.000000000 +0100 +++ cpio-2.6/src/global.c 2005-07-29 13:47:34.000000000 +0100 @@ -100,7 +100,7 @@ int only_verify_crc_flag = false; /* If true, don't use any absolute paths, prefix them by `./'. */ -int no_abs_paths_flag = false; +int abs_paths_flag = false; #ifdef DEBUG_CPIO /* If true, print debugging information. */ @@ -195,6 +195,9 @@ /* The name this program was run with. */ char *program_name; +/* Debian hack to make the -d option honor the umask. */ +mode_t sys_umask; + /* A pointer to either lstat or stat, depending on whether dereferencing of symlinks is done for input files. */ int (*xstat) (); diff -Naur cpio-2.6.vanilla/src/main.c cpio-2.6/src/main.c --- cpio-2.6.vanilla/src/main.c 2004-11-23 00:42:18.000000000 +0000 +++ cpio-2.6/src/main.c 2005-07-29 13:47:34.000000000 +0100 @@ -41,6 +41,7 @@ enum cpio_options { NO_ABSOLUTE_FILENAMES_OPTION=256, + ABSOLUTE_FILENAMES_OPTION, NO_PRESERVE_OWNER_OPTION, ONLY_VERIFY_CRC_OPTION, RENAME_BATCH_FILE_OPTION, @@ -134,6 +135,8 @@ N_("In copy-in mode, read additional patterns specifying filenames to extract or list from FILE"), 210}, {"no-absolute-filenames", NO_ABSOLUTE_FILENAMES_OPTION, 0, 0, N_("Create all files relative to the current directory"), 210}, + {"absolute-filenames", ABSOLUTE_FILENAMES_OPTION, 0, 0, + N_("do not strip leading file name components that contain \"..\" and leading slashes from file names"), 210}, {"only-verify-crc", ONLY_VERIFY_CRC_OPTION, 0, 0, N_("When reading a CRC format archive in copy-in mode, only verify the CRC's of each file in the archive, don't actually extract the files"), 210}, {"rename", 'r', 0, 0, @@ -392,7 +395,11 @@ break; case NO_ABSOLUTE_FILENAMES_OPTION: /* --no-absolute-filenames */ - no_abs_paths_flag = true; + abs_paths_flag = false; + break; + + case ABSOLUTE_FILENAMES_OPTION: /* --absolute-filenames */ + abs_paths_flag = true; break; case NO_PRESERVE_OWNER_OPTION: /* --no-preserve-owner */ @@ -631,7 +638,7 @@ _("--append is used but no archive file name is given (use -F or -O options"))); CHECK_USAGE(rename_batch_file, "--rename-batch-file", "--create"); - CHECK_USAGE(no_abs_paths_flag, "--no-absolute-pathnames", "--create"); + CHECK_USAGE(abs_paths_flag, "--absolute-pathnames", "--create"); CHECK_USAGE(input_archive_name, "-I", "--create"); if (archive_name && output_archive_name) USAGE_ERROR ((0, 0, _("Both -O and -F are used in copy-out mode"))); @@ -658,7 +665,7 @@ CHECK_USAGE(rename_flag, "--rename", "--pass-through"); CHECK_USAGE(append_flag, "--append", "--pass-through"); CHECK_USAGE(rename_batch_file, "--rename-batch-file", "--pass-through"); - CHECK_USAGE(no_abs_paths_flag, "--no-absolute-pathnames", + CHECK_USAGE(abs_paths_flag, "--absolute-pathnames", "--pass-through"); CHECK_USAGE(to_stdout_option, "--to-stdout", "--pass-through"); @@ -740,7 +747,6 @@ textdomain (PACKAGE); program_name = argv[0]; - umask (0); #ifdef __TURBOC__ _fmode = O_BINARY; /* Put stdin and stdout in binary mode. */ @@ -751,6 +757,7 @@ #endif process_args (argc, argv); + sys_umask = umask (0); initialize_buffers ();