From d031ffa623203b1dc756a1e02e06f261fdc30872 Mon Sep 17 00:00:00 2001 From: Denis Vlasenko Date: Fri, 24 Nov 2006 21:54:44 +0000 Subject: [PATCH] tar: sanitize option handling --- archival/Config.in | 4 +- archival/tar.c | 208 ++++++++++++++++++-------------------------- include/usage.h | 2 +- libbb/getopt32.c | 68 +++++++-------- libbb/mtab_file.c | 4 +- libbb/procps.c | 64 +++++++------- libbb/safe_strtol.c | 42 +++++---- runit/chpst.c | 2 +- 8 files changed, 177 insertions(+), 217 deletions(-) diff --git a/archival/Config.in b/archival/Config.in index bc87573b1..de493efa2 100644 --- a/archival/Config.in +++ b/archival/Config.in @@ -292,9 +292,9 @@ config FEATURE_DEB_TAR_LZMA depends on DPKG || DPKG_DEB help This allows dpkg and dpkg-deb to extract deb's that are compressed - internally with lzma instead of gzip. + internally with lzma instead of gzip. You only want this if you are creating your own custom debian - packages that use an internal control.tar.lzma or data.tar.lzma. + packages that use an internal control.tar.lzma or data.tar.lzma. endmenu diff --git a/archival/tar.c b/archival/tar.c index be661cc32..4d237f880 100644 --- a/archival/tar.c +++ b/archival/tar.c @@ -28,7 +28,7 @@ #include #include -#ifdef CONFIG_FEATURE_TAR_CREATE +#if ENABLE_FEATURE_TAR_CREATE /* Tar file constants */ @@ -289,7 +289,7 @@ static int writeTarHeader(struct TarBallInfo *tbInfo, return TRUE; } -# ifdef CONFIG_FEATURE_TAR_FROM +# if ENABLE_FEATURE_TAR_FROM static int exclude_file(const llist_t *excluded_files, const char *file) { while (excluded_files) { @@ -534,7 +534,7 @@ int writeTarFile(const int tar_fd, const int verboseFlag, const llist_t *exclude, const int gzip); #endif /* tar_create */ -#ifdef CONFIG_FEATURE_TAR_FROM +#if ENABLE_FEATURE_TAR_FROM static llist_t *append_file_list_to_list(llist_t *list) { FILE *src_stream; @@ -562,7 +562,7 @@ static llist_t *append_file_list_to_list(llist_t *list) #define append_file_list_to_list(x) 0 #endif -#ifdef CONFIG_FEATURE_TAR_COMPRESS +#if ENABLE_FEATURE_TAR_COMPRESS static char get_header_tar_Z(archive_handle_t *archive_handle) { /* Can't lseek over pipes */ @@ -587,88 +587,38 @@ static char get_header_tar_Z(archive_handle_t *archive_handle) #define get_header_tar_Z 0 #endif -#define CTX_TEST (1 << 0) -#define CTX_EXTRACT (1 << 1) -#define TAR_OPT_BASEDIR (1 << 2) -#define TAR_OPT_TARNAME (1 << 3) -#define TAR_OPT_2STDOUT (1 << 4) -#define TAR_OPT_P (1 << 5) -#define TAR_OPT_VERBOSE (1 << 6) -#define TAR_OPT_KEEP_OLD (1 << 7) - -#define TAR_OPT_AFTER_START 8 - -#define CTX_CREATE (1 << (TAR_OPT_AFTER_START)) -#define TAR_OPT_DEREFERENCE (1 << (TAR_OPT_AFTER_START + 1)) -#ifdef CONFIG_FEATURE_TAR_CREATE -# define TAR_OPT_STR_CREATE "ch" -# define TAR_OPT_AFTER_CREATE TAR_OPT_AFTER_START + 2 -#else -# define TAR_OPT_STR_CREATE "" -# define TAR_OPT_AFTER_CREATE TAR_OPT_AFTER_START -#endif - -#define TAR_OPT_BZIP2 (1 << (TAR_OPT_AFTER_CREATE)) -#ifdef CONFIG_FEATURE_TAR_BZIP2 -# define TAR_OPT_STR_BZIP2 "j" -# define TAR_OPT_AFTER_BZIP2 TAR_OPT_AFTER_CREATE + 1 -#else -# define TAR_OPT_STR_BZIP2 "" -# define TAR_OPT_AFTER_BZIP2 TAR_OPT_AFTER_CREATE -#endif - -#define TAR_OPT_LZMA (1 << (TAR_OPT_AFTER_BZIP2)) -#ifdef CONFIG_FEATURE_TAR_LZMA -# define TAR_OPT_STR_LZMA "a" -# define TAR_OPT_AFTER_LZMA TAR_OPT_AFTER_BZIP2 + 1 -#else -# define TAR_OPT_STR_LZMA "" -# define TAR_OPT_AFTER_LZMA TAR_OPT_AFTER_BZIP2 -#endif - -#define TAR_OPT_INCLUDE_FROM (1 << (TAR_OPT_AFTER_LZMA)) -#define TAR_OPT_EXCLUDE_FROM (1 << (TAR_OPT_AFTER_LZMA + 1)) -#ifdef CONFIG_FEATURE_TAR_FROM -# define TAR_OPT_STR_FROM "T:X:" -# define TAR_OPT_AFTER_FROM TAR_OPT_AFTER_LZMA + 2 -#else -# define TAR_OPT_STR_FROM "" -# define TAR_OPT_AFTER_FROM TAR_OPT_AFTER_LZMA -#endif - -#define TAR_OPT_GZIP (1 << (TAR_OPT_AFTER_FROM)) -#ifdef CONFIG_FEATURE_TAR_GZIP -# define TAR_OPT_STR_GZIP "z" -# define TAR_OPT_AFTER_GZIP TAR_OPT_AFTER_FROM + 1 -#else -# define TAR_OPT_STR_GZIP "" -# define TAR_OPT_AFTER_GZIP TAR_OPT_AFTER_FROM -#endif - -#define TAR_OPT_UNCOMPRESS (1 << (TAR_OPT_AFTER_GZIP)) -#ifdef CONFIG_FEATURE_TAR_COMPRESS -# define TAR_OPT_STR_COMPRESS "Z" -# define TAR_OPT_AFTER_COMPRESS TAR_OPT_AFTER_GZIP + 1 -#else -# define TAR_OPT_STR_COMPRESS "" -# define TAR_OPT_AFTER_COMPRESS TAR_OPT_AFTER_GZIP -#endif - -#define TAR_OPT_NOPRESERVE_OWN (1 << (TAR_OPT_AFTER_COMPRESS)) -#define TAR_OPT_NOPRESERVE_PERM (1 << (TAR_OPT_AFTER_COMPRESS + 1)) -#define TAR_OPT_STR_NOPRESERVE "\203\213" -#define TAR_OPT_AFTER_NOPRESERVE TAR_OPT_AFTER_COMPRESS + 2 - -static const char tar_options[] = "txC:f:Opvk" \ - TAR_OPT_STR_CREATE \ - TAR_OPT_STR_BZIP2 \ - TAR_OPT_STR_LZMA \ - TAR_OPT_STR_FROM \ - TAR_OPT_STR_GZIP \ - TAR_OPT_STR_COMPRESS \ - TAR_OPT_STR_NOPRESERVE; - -#ifdef CONFIG_FEATURE_TAR_LONG_OPTIONS +enum { + OPTBIT_KEEP_OLD = 7, + USE_FEATURE_TAR_CREATE( OPTBIT_CREATE ,) + USE_FEATURE_TAR_CREATE( OPTBIT_DEREFERENCE ,) + USE_FEATURE_TAR_BZIP2( OPTBIT_BZIP2 ,) + USE_FEATURE_TAR_LZMA( OPTBIT_LZMA ,) + USE_FEATURE_TAR_FROM( OPTBIT_INCLUDE_FROM,) + USE_FEATURE_TAR_FROM( OPTBIT_EXCLUDE_FROM,) + USE_FEATURE_TAR_GZIP( OPTBIT_GZIP ,) + USE_FEATURE_TAR_COMPRESS(OPTBIT_COMPRESS ,) + OPTBIT_NOPRESERVE_OWN, + OPTBIT_NOPRESERVE_PERM, + OPT_TEST = 1 << 0, // t + OPT_EXTRACT = 1 << 1, // x + OPT_BASEDIR = 1 << 2, // C + OPT_TARNAME = 1 << 3, // f + OPT_2STDOUT = 1 << 4, // O + OPT_P = 1 << 5, // p + OPT_VERBOSE = 1 << 6, // v + OPT_KEEP_OLD = 1 << 7, // k + OPT_CREATE = USE_FEATURE_TAR_CREATE( (1<flags = ARCHIVE_CREATE_LEADING_DIRS | ARCHIVE_PRESERVE_DATE | ARCHIVE_EXTRACT_UNCONDITIONAL; + tar_handle->flags = ARCHIVE_CREATE_LEADING_DIRS + | ARCHIVE_PRESERVE_DATE + | ARCHIVE_EXTRACT_UNCONDITIONAL; /* Prepend '-' to the first argument if required */ - opt_complementary = ENABLE_FEATURE_TAR_CREATE ? - "--:X::T::\n::c:t:x:?:c--tx:t--cx:x--ct" : - "--:X::T::\n::t:x:?:t--x:x--t"; + opt_complementary = "--:" // first arg is options + "?:" // bail out with usage instead of error return + "X::T::" // cumulative lists + "\xfd::" // cumulative lists for --exclude + USE_FEATURE_TAR_CREATE("c:") "t:x:" // at least one of these is reqd + USE_FEATURE_TAR_CREATE("c--tx:t--cx:x--ct") // mutually exclusive + SKIP_FEATURE_TAR_CREATE("t--x:x--t"); // mutually exclusive if (ENABLE_FEATURE_TAR_LONG_OPTIONS) applet_long_options = tar_long_options; - opt = getopt32(argc, argv, tar_options, - &base_dir, /* Change to dir */ - &tar_filename /* archive filename */ -#ifdef CONFIG_FEATURE_TAR_FROM - , &(tar_handle->accept), - &(tar_handle->reject), - &excludes -#endif - ); - - if (opt & CTX_TEST) { + opt = getopt32(argc, argv, + "txC:f:Opvk" + USE_FEATURE_TAR_CREATE( "ch" ) + USE_FEATURE_TAR_BZIP2( "j" ) + USE_FEATURE_TAR_LZMA( "a" ) + USE_FEATURE_TAR_FROM( "T:X:") + USE_FEATURE_TAR_GZIP( "z" ) + USE_FEATURE_TAR_COMPRESS("Z" ) + , + &base_dir, // -C dir + &tar_filename, // -f filename + USE_FEATURE_TAR_FROM(&(tar_handle->accept),) // T + USE_FEATURE_TAR_FROM(&(tar_handle->reject),) // X + USE_FEATURE_TAR_FROM(&excludes ) // --exclude + ); + + if (opt & OPT_TEST) { if (tar_handle->action_header == header_list || tar_handle->action_header == header_verbose_list ) { @@ -744,13 +706,13 @@ int tar_main(int argc, char **argv) } else tar_handle->action_header = header_list; } - if ((opt & CTX_EXTRACT) && tar_handle->action_data != data_extract_to_stdout) + if ((opt & OPT_EXTRACT) && tar_handle->action_data != data_extract_to_stdout) tar_handle->action_data = data_extract_all; - if (opt & TAR_OPT_2STDOUT) + if (opt & OPT_2STDOUT) tar_handle->action_data = data_extract_to_stdout; - if (opt & TAR_OPT_VERBOSE) { + if (opt & OPT_VERBOSE) { if (tar_handle->action_header == header_list || tar_handle->action_header == header_verbose_list ) { @@ -758,25 +720,25 @@ int tar_main(int argc, char **argv) } else tar_handle->action_header = header_list; } - if (opt & TAR_OPT_KEEP_OLD) + if (opt & OPT_KEEP_OLD) tar_handle->flags &= ~ARCHIVE_EXTRACT_UNCONDITIONAL; - if (opt & TAR_OPT_NOPRESERVE_OWN) + if (opt & OPT_NOPRESERVE_OWN) tar_handle->flags |= ARCHIVE_NOPRESERVE_OWN; - if (opt & TAR_OPT_NOPRESERVE_PERM) + if (opt & OPT_NOPRESERVE_PERM) tar_handle->flags |= ARCHIVE_NOPRESERVE_PERM; - if (ENABLE_FEATURE_TAR_GZIP && (opt & TAR_OPT_GZIP)) + if (opt & OPT_GZIP) get_header_ptr = get_header_tar_gz; - if (ENABLE_FEATURE_TAR_BZIP2 && (opt & TAR_OPT_BZIP2)) + if (opt & OPT_BZIP2) get_header_ptr = get_header_tar_bz2; - if (ENABLE_FEATURE_TAR_LZMA && (opt & TAR_OPT_LZMA)) + if (opt & OPT_LZMA) get_header_ptr = get_header_tar_lzma; - if (ENABLE_FEATURE_TAR_COMPRESS && (opt & TAR_OPT_UNCOMPRESS)) + if (opt & OPT_COMPRESS) get_header_ptr = get_header_tar_Z; if (ENABLE_FEATURE_TAR_FROM) { @@ -816,7 +778,7 @@ int tar_main(int argc, char **argv) FILE *tar_stream; int flags; - if (ENABLE_FEATURE_TAR_CREATE && (opt & CTX_CREATE)) { + if (opt & OPT_CREATE) { /* Make sure there is at least one file to tar up. */ if (tar_handle->accept == NULL) bb_error_msg_and_die("empty archive"); @@ -842,7 +804,7 @@ int tar_main(int argc, char **argv) xchdir(base_dir); /* create an archive */ - if (ENABLE_FEATURE_TAR_CREATE && (opt & CTX_CREATE)) { + if (opt & OPT_CREATE) { int verboseFlag = FALSE; int zipMode = 0; @@ -856,7 +818,7 @@ int tar_main(int argc, char **argv) ) { verboseFlag = TRUE; } - writeTarFile(tar_handle->src_fd, verboseFlag, opt & TAR_OPT_DEREFERENCE, + writeTarFile(tar_handle->src_fd, verboseFlag, opt & OPT_DEREFERENCE, tar_handle->accept, tar_handle->reject, zipMode); /* NB: writeTarFile() closes tar_handle->src_fd */ diff --git a/include/usage.h b/include/usage.h index 7ba79ff87..e7e46beab 100644 --- a/include/usage.h +++ b/include/usage.h @@ -2975,7 +2975,7 @@ USE_FEATURE_START_STOP_DAEMON_FANCY( \ "-[" USE_FEATURE_TAR_CREATE("c") USE_FEATURE_TAR_GZIP("z") \ USE_FEATURE_TAR_BZIP2("j") USE_FEATURE_TAR_LZMA("a") \ USE_FEATURE_TAR_COMPRESS("Z") "xtvO] " \ - USE_FEATURE_TAR_FROM("[-X FILE]") \ + USE_FEATURE_TAR_FROM("[-X FILE] ") \ "[-f TARFILE] [-C DIR] [FILE(s)] ..." #define tar_full_usage \ "Create, extract, or list files from a tar file.\n\n" \ diff --git a/libbb/getopt32.c b/libbb/getopt32.c index f442933a3..dddf8121a 100644 --- a/libbb/getopt32.c +++ b/libbb/getopt32.c @@ -147,6 +147,40 @@ const char *opt_complementary Special characters: + "-" A dash as the first char in a opt_complementary group forces + all arguments to be treated as options, even if they have + no leading dashes. Next char in this case can't be a digit (0-9), + use ':' or end of line. For example: + + opt_complementary = "-:w-x:x-w"; + getopt32(argc, argv, "wx"); + + Allows any arguments to be given without a dash (./program w x) + as well as with a dash (./program -x). + + "--" A double dash at the beginning of opt_complementary means the + argv[1] string should always be treated as options, even if it isn't + prefixed with a "-". This is useful for special syntax in applets + such as "ar" and "tar": + tar xvf foo.tar + + "-N" A dash as the first char in a opt_complementary group followed + by a single digit (0-9) means that at least N non-option + arguments must be present on the command line + + "=N" An equal sign as the first char in a opt_complementary group followed + by a single digit (0-9) means that exactly N non-option + arguments must be present on the command line + + "?N" A "?" as the first char in a opt_complementary group followed + by a single digit (0-9) means that at most N arguments must be present + on the command line. + + "V-" An option with dash before colon or end-of-line results in + bb_show_usage being called if this option is encountered. + This is typically used to implement "print verbose usage message + and exit" option. + "-" A dash between two options causes the second of the two to be unset (and ignored) if it is given on the command line. @@ -173,30 +207,6 @@ Special characters: if (opt & 4) printf("Detected odd -x usage\n"); - "-" A dash as the first char in a opt_complementary group forces - all arguments to be treated as options, even if they have - no leading dashes. Next char in this case can't be a digit (0-9), - use ':' or end of line. For example: - - opt_complementary = "-:w-x:x-w"; - getopt32(argc, argv, "wx"); - - Allows any arguments to be given without a dash (./program w x) - as well as with a dash (./program -x). - - "-N" A dash as the first char in a opt_complementary group followed - by a single digit (0-9) means that at least N non-option - arguments must be present on the command line - - "=N" An equal sign as the first char in a opt_complementary group followed - by a single digit (0-9) means that exactly N non-option - arguments must be present on the command line - - "V-" An option with dash before colon or end-of-line results in - bb_show_usage being called if this option is encountered. - This is typically used to implement "print verbose usage message - and exit" option. - "--" A double dash between two options, or between an option and a group of options, means that they are mutually exclusive. Unlike the "-" case above, an error will be forced if the options @@ -221,10 +231,6 @@ Special characters: if BB_GETOPT_ERROR is detected, don't return, call bb_show_usage and exit instead. Next char after '?' can't be a digit. - "?N" A "?" as the first char in a opt_complementary group followed - by a single digit (0-9) means that at most N arguments must be present - on the command line. - "::" A double colon after a char in opt_complementary means that the option can occur multiple times. Each occurrence will be saved as a llist_t element instead of char*. @@ -245,12 +251,6 @@ Special characters: root:x:0:0:root:/root:/bin/bash user:x:500:500::/home/user:/bin/bash - "--" A double dash at the beginning of opt_complementary means the - argv[1] string should always be treated as options, even if it isn't - prefixed with a "-". This is useful for special syntax in applets - such as "ar" and "tar": - tar xvf foo.tar - "?" An "?" between an option and a group of options means that at least one of them is required to occur if the first option occurs in preceding command line arguments. diff --git a/libbb/mtab_file.c b/libbb/mtab_file.c index 3181d6d58..67367e3d7 100644 --- a/libbb/mtab_file.c +++ b/libbb/mtab_file.c @@ -13,5 +13,5 @@ /* Busybox mount uses either /proc/mounts or /etc/mtab to * get the list of currently mounted filesystems */ -const char bb_path_mtab_file[] = USE_FEATURE_MTAB_SUPPORT("/etc/mtab") - SKIP_FEATURE_MTAB_SUPPORT("/proc/mounts"); +const char bb_path_mtab_file[] = +USE_FEATURE_MTAB_SUPPORT("/etc/mtab")SKIP_FEATURE_MTAB_SUPPORT("/proc/mounts"); diff --git a/libbb/procps.c b/libbb/procps.c index 2581d03b2..ee4f5e53f 100644 --- a/libbb/procps.c +++ b/libbb/procps.c @@ -216,39 +216,39 @@ procps_status_t* procps_scan(procps_status_t* sp, int flags) } /* from kernel: // pid comm S ppid pgid sid tty_nr tty_pgrp flg - sprintf(buffer,"%d (%s) %c %d %d %d %d %d %lu %lu \ + sprintf(buffer,"%d (%s) %c %d %d %d %d %d %lu %lu \ %lu %lu %lu %lu %lu %ld %ld %ld %ld %d 0 %llu %lu %ld %lu %lu %lu %lu %lu \ %lu %lu %lu %lu %lu %lu %lu %lu %d %d %lu %lu %llu\n", - task->pid, - tcomm, - state, - ppid, - pgid, - sid, - tty_nr, - tty_pgrp, - task->flags, - min_flt, - - cmin_flt, - maj_flt, - cmaj_flt, - cputime_to_clock_t(utime), - cputime_to_clock_t(stime), - cputime_to_clock_t(cutime), - cputime_to_clock_t(cstime), - priority, - nice, - num_threads, - // 0, - start_time, - vsize, - mm ? get_mm_rss(mm) : 0, - rsslim, - mm ? mm->start_code : 0, - mm ? mm->end_code : 0, - mm ? mm->start_stack : 0, - esp, - eip, + task->pid, + tcomm, + state, + ppid, + pgid, + sid, + tty_nr, + tty_pgrp, + task->flags, + min_flt, + + cmin_flt, + maj_flt, + cmaj_flt, + cputime_to_clock_t(utime), + cputime_to_clock_t(stime), + cputime_to_clock_t(cutime), + cputime_to_clock_t(cstime), + priority, + nice, + num_threads, + // 0, + start_time, + vsize, + mm ? get_mm_rss(mm) : 0, + rsslim, + mm ? mm->start_code : 0, + mm ? mm->end_code : 0, + mm ? mm->start_stack : 0, + esp, + eip, the rest is some obsolete cruft */ diff --git a/libbb/safe_strtol.c b/libbb/safe_strtol.c index a7f012fbc..d3bb29cdd 100644 --- a/libbb/safe_strtol.c +++ b/libbb/safe_strtol.c @@ -102,40 +102,38 @@ int safe_strtol(const char *arg, long* value) # define strong_alias(name, aliasname) _strong_alias (name, aliasname) # define _strong_alias(name, aliasname) \ - __asm__(".global " __C_SYMBOL_PREFIX__ #aliasname "\n" \ - ".set " __C_SYMBOL_PREFIX__ #aliasname "," __C_SYMBOL_PREFIX__ #name); + __asm__(".global " __C_SYMBOL_PREFIX__ #aliasname "\n" \ + ".set " __C_SYMBOL_PREFIX__ #aliasname "," __C_SYMBOL_PREFIX__ #name); #endif #endif int safe_strtoi(const char *arg, int* value) { - if (sizeof(long) == sizeof(int)) { + int error; + long lvalue; + if (sizeof(long) == sizeof(int)) return safe_strtol(arg, (long*)value); - } else { - int error; - long lvalue = *value; - error = safe_strtol(arg, &lvalue); - if (lvalue < INT_MIN || lvalue > INT_MAX) - return 1; - *value = (int) lvalue; - return error; - } + lvalue = *value; + error = safe_strtol(arg, &lvalue); + if (lvalue < INT_MIN || lvalue > INT_MAX) + return 1; + *value = (int) lvalue; + return error; } int safe_strtou(const char *arg, unsigned* value) { - if (sizeof(unsigned long) == sizeof(unsigned)) { + int error; + unsigned long lvalue; + if (sizeof(unsigned long) == sizeof(unsigned)) return safe_strtoul(arg, (unsigned long*)value); - } else { - int error; - unsigned long lvalue = *value; - error = safe_strtoul(arg, &lvalue); - if (lvalue > UINT_MAX) - return 1; - *value = (unsigned) lvalue; - return error; - } + lvalue = *value; + error = safe_strtoul(arg, &lvalue); + if (lvalue > UINT_MAX) + return 1; + *value = (unsigned) lvalue; + return error; } int BUG_safe_strtou32_unimplemented(void); diff --git a/runit/chpst.c b/runit/chpst.c index 3fcef8eec..f8e63031f 100644 --- a/runit/chpst.c +++ b/runit/chpst.c @@ -261,7 +261,7 @@ int chpst_main(int argc, char **argv) if (applet_name[1] == 'o') softlimit(argc, argv); if (applet_name[0] == 's') setuidgid(argc, argv); if (applet_name[0] == 'e') envuidgid(argc, argv); - // otherwise we are.......... chpst + // otherwise we are chpst { char *m,*d,*o,*p,*f,*c,*r,*t,*n; -- 2.25.1