diff options
Diffstat (limited to 'gnu')
-rw-r--r-- | gnu/usr.bin/cpio/copyout.c | 111 | ||||
-rw-r--r-- | gnu/usr.bin/tar/create.c | 34 | ||||
-rw-r--r-- | gnu/usr.bin/tar/tar.c | 2 |
3 files changed, 142 insertions, 5 deletions
diff --git a/gnu/usr.bin/cpio/copyout.c b/gnu/usr.bin/cpio/copyout.c index 35682e1b7453..933e4dad0778 100644 --- a/gnu/usr.bin/cpio/copyout.c +++ b/gnu/usr.bin/cpio/copyout.c @@ -35,6 +35,7 @@ static void add_link_defer (); static void writeout_other_defers (); static void writeout_final_defers(); static void writeout_defered_file (); +static int check_rdev (); /* Write out header FILE_HDR, including the file name, to file descriptor OUT_DES. */ @@ -337,6 +338,21 @@ process_copy_out () error (0, 0, "%s: file name too long", file_hdr.c_name); continue; } + switch (check_rdev (&file_hdr)) + { + case 1: + error (0, 0, "%s not dumped: major number would be truncated", + file_hdr.c_name); + continue; + case 2: + error (0, 0, "%s not dumped: minor number would be truncated", + file_hdr.c_name); + continue; + case 4: + error (0, 0, "%s not dumped: device number would be truncated", + file_hdr.c_name); + continue; + } /* Copy the named file to the output. */ switch (file_hdr.c_mode & CP_IFMT) @@ -799,3 +815,98 @@ writeout_defered_file (header, out_file_des) } return; } + +static int +check_rdev (file_hdr) + struct new_cpio_header *file_hdr; +{ + if (archive_format == arf_newascii || archive_format == arf_crcascii) + { + if ((file_hdr->c_rdev_maj & 0xFFFFFFFF) != file_hdr->c_rdev_maj) + return 1; + if ((file_hdr->c_rdev_min & 0xFFFFFFFF) != file_hdr->c_rdev_min) + return 2; + } + else if (archive_format == arf_oldascii || archive_format == arf_hpoldascii) + { +#ifndef __MSDOS__ + dev_t rdev; + + rdev = makedev (file_hdr->c_rdev_maj, file_hdr->c_rdev_min); + if (archive_format == arf_oldascii) + { + if ((rdev & 0xFFFF) != rdev) + return 4; + } + else + { + switch (file_hdr->c_mode & CP_IFMT) + { + case CP_IFCHR: + case CP_IFBLK: +#ifdef CP_IFSOCK + case CP_IFSOCK: +#endif +#ifdef CP_IFIFO + case CP_IFIFO: +#endif + /* We could handle one more bit if longs are >= 33 bits. */ + if ((rdev & 037777777777) != rdev) + return 4; + break; + default: + if ((rdev & 0xFFFF) != rdev) + return 4; + break; + } + } +#endif + } + else if (archive_format == arf_tar || archive_format == arf_ustar) + { + /* The major and minor formats are limited to 7 octal digits in ustar + format, and to_oct () adds a gratuitous trailing blank to further + limit the format to 6 octal digits. */ + if ((file_hdr->c_rdev_maj & 0777777) != file_hdr->c_rdev_maj) + return 1; + if ((file_hdr->c_rdev_min & 0777777) != file_hdr->c_rdev_min) + return 2; + } + else + { +#ifndef __MSDOS__ + dev_t rdev; + + rdev = makedev (file_hdr->c_rdev_maj, file_hdr->c_rdev_min); + if (archive_format != arf_hpbinary) + { + if ((rdev & 0xFFFF) != rdev) + return 4; + } + else + { + switch (file_hdr->c_mode & CP_IFMT) + { + case CP_IFCHR: + case CP_IFBLK: +#ifdef CP_IFSOCK + case CP_IFSOCK: +#endif +#ifdef CP_IFIFO + case CP_IFIFO: +#endif + if ((rdev & 0xFFFFFFFF) != rdev) + return 4; + file_hdr->c_filesize = rdev; + rdev = makedev (0, 1); + break; + default: + if ((rdev & 0xFFFF) != rdev) + return 4; + break; + } + } +#endif + } + return 0; +} diff --git a/gnu/usr.bin/tar/create.c b/gnu/usr.bin/tar/create.c index 5d1b71c94b6d..c3be00cb1a1d 100644 --- a/gnu/usr.bin/tar/create.c +++ b/gnu/usr.bin/tar/create.c @@ -875,10 +875,20 @@ dump_file (p, curdev, toplevel) #if defined(S_IFBLK) || defined(S_IFCHR) if (type != LF_FIFO) { - to_oct ((long) major (hstat.st_rdev), 8, - header->header.devmajor); - to_oct ((long) minor (hstat.st_rdev), 8, - header->header.devminor); + if (checked_to_oct ((long) major (hstat.st_rdev), 8, + header->header.devmajor)) + { + msg ("%s: major number too large; not dumped", p); + critical_error = 1; + goto badfile; + } + if (checked_to_oct ((long) minor (hstat.st_rdev), 8, + header->header.devminor)) + { + msg ("%s: minor number too large; not dumped", p); + critical_error = 1; + goto badfile; + } } #endif @@ -1397,6 +1407,22 @@ to_oct (value, digs, where) /* + * Call to_oct (), then return nonzero iff the conversion failed. + */ +int +checked_to_oct (value, digs, where) + register long value; + register int digs; + register char *where; +{ + long from_oct (); + + to_oct (value, digs, where); + return from_oct (digs, where) != value; +} + + +/* * Write the EOT record(s). * We actually zero at least one record, through the end of the block. * Old tar writes garbage after two zeroed records -- and PDtar used to. diff --git a/gnu/usr.bin/tar/tar.c b/gnu/usr.bin/tar/tar.c index 638598667e6b..84e2b94283ce 100644 --- a/gnu/usr.bin/tar/tar.c +++ b/gnu/usr.bin/tar/tar.c @@ -281,7 +281,7 @@ main (argc, argv) } if (f_volno_file) closeout_volume_number (); - exit (errors); + exit (errors ? EX_ARGSBAD : 0); /* FIXME (should be EX_NONDESCRIPT) */ /* NOTREACHED */ } |