From 18e781dc02cfc293d33b02f924ef70513c2f205a Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Wed, 2 Aug 2017 14:12:48 +0200 Subject: config: do not use `a' quoting in help texts Signed-off-by: Denys Vlasenko --- archival/bbunzip.c | 2 +- coreutils/chroot.c | 2 +- coreutils/dd.c | 2 +- coreutils/printf.c | 2 +- coreutils/yes.c | 2 +- networking/telnet.c | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/archival/bbunzip.c b/archival/bbunzip.c index d2b162d5e..9b9fdc87b 100644 --- a/archival/bbunzip.c +++ b/archival/bbunzip.c @@ -317,7 +317,7 @@ int uncompress_main(int argc UNUSED_PARAM, char **argv) //config: select FEATURE_GZIP_DECOMPRESS //config: help //config: gunzip is used to decompress archives created by gzip. -//config: You can use the `-t' option to test the integrity of +//config: You can use the '-t' option to test the integrity of //config: an archive, without decompressing it. //config: //config:config ZCAT diff --git a/coreutils/chroot.c b/coreutils/chroot.c index 44a587fe0..5645d72df 100644 --- a/coreutils/chroot.c +++ b/coreutils/chroot.c @@ -11,7 +11,7 @@ //config: default y //config: help //config: chroot is used to change the root directory and run a command. -//config: The default command is `/bin/sh'. +//config: The default command is '/bin/sh'. //applet:IF_CHROOT(APPLET(chroot, BB_DIR_USR_SBIN, BB_SUID_DROP)) diff --git a/coreutils/dd.c b/coreutils/dd.c index 43545c010..d302f35d3 100644 --- a/coreutils/dd.c +++ b/coreutils/dd.c @@ -19,7 +19,7 @@ //config: default y //config: depends on DD //config: help -//config: Sending a SIGUSR1 signal to a running `dd' process makes it +//config: Sending a SIGUSR1 signal to a running 'dd' process makes it //config: print to standard error the number of records read and written //config: so far, then to resume copying. //config: diff --git a/coreutils/printf.c b/coreutils/printf.c index d3fc72adb..d1ff183d0 100644 --- a/coreutils/printf.c +++ b/coreutils/printf.c @@ -43,7 +43,7 @@ //config: default y //config: help //config: printf is used to format and print specified strings. -//config: It's similar to `echo' except it has more options. +//config: It's similar to 'echo' except it has more options. //applet:IF_PRINTF(APPLET_NOFORK(printf, printf, BB_DIR_USR_BIN, BB_SUID_DROP, printf)) diff --git a/coreutils/yes.c b/coreutils/yes.c index 493b7b1c3..ea35d146c 100644 --- a/coreutils/yes.c +++ b/coreutils/yes.c @@ -15,7 +15,7 @@ //config: default y //config: help //config: yes is used to repeatedly output a specific string, or -//config: the default string `y'. +//config: the default string 'y'. //applet:IF_YES(APPLET_NOFORK(yes, yes, BB_DIR_USR_BIN, BB_SUID_DROP, yes)) diff --git a/networking/telnet.c b/networking/telnet.c index 9f191f7ad..e1c259579 100644 --- a/networking/telnet.c +++ b/networking/telnet.c @@ -44,7 +44,7 @@ //config: Setting this option will forward the USER environment variable to the //config: remote host you are connecting to. This is useful when you need to //config: log into a machine without telling the username (autologin). This -//config: option enables `-a' and `-l USER' arguments. +//config: option enables '-a' and '-l USER' arguments. //config: //config:config FEATURE_TELNET_WIDTH //config: bool "Enable window size autodetection" -- cgit v1.2.3-55-g6feb From 95f7953f2c46c7b9c799250aa8dc6eb10cc5c726 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Wed, 2 Aug 2017 14:26:33 +0200 Subject: do not use `a' quoting style in comments Signed-off-by: Denys Vlasenko --- coreutils/date.c | 2 +- coreutils/echo.c | 2 +- coreutils/env.c | 2 +- coreutils/nohup.c | 4 ++-- coreutils/od.c | 2 +- e2fsprogs/e2fs_lib.h | 2 +- editors/awk.c | 2 +- findutils/find.c | 2 +- libbb/change_identity.c | 2 +- libbb/correct_password.c | 2 +- libbb/dump.c | 2 +- libbb/progress.c | 2 +- libbb/pw_encrypt_des.c | 2 +- libbb/run_shell.c | 2 +- libbb/setup_environment.c | 2 +- libpwdgrp/uidgid_get.c | 2 +- miscutils/adjtimex.c | 2 +- miscutils/time.c | 10 +++++----- modutils/modutils-24.c | 4 ++-- networking/hostname.c | 2 +- networking/ping.c | 2 +- networking/traceroute.c | 4 ++-- runit/chpst.c | 2 +- runit/runit_lib.h | 2 +- runit/runsv.c | 2 +- runit/runsvdir.c | 2 +- runit/sv.c | 2 +- runit/svlogd.c | 2 +- scripts/echo.c | 2 +- shell/ash.c | 2 +- shell/ash_test/printenv.c | 2 +- shell/math.c | 2 +- sysklogd/logger.c | 2 +- util-linux/cal.c | 2 +- util-linux/fdisk_osf.c | 2 +- 35 files changed, 42 insertions(+), 42 deletions(-) diff --git a/coreutils/date.c b/coreutils/date.c index 0fb9f1f00..2c6e1d4df 100644 --- a/coreutils/date.c +++ b/coreutils/date.c @@ -66,7 +66,7 @@ * date [OPTION]... [+FORMAT] * date [-u|--utc|--universal] [MMDDhhmm[[CC]YY][.ss]] * -d, --date=STRING - * display time described by STRING, not `now' + * display time described by STRING, not 'now' * -f, --file=DATEFILE * like --date once for each line of DATEFILE * -r, --reference=FILE diff --git a/coreutils/echo.c b/coreutils/echo.c index af33319a1..e45b90940 100644 --- a/coreutils/echo.c +++ b/coreutils/echo.c @@ -218,7 +218,7 @@ int echo_main(int argc UNUSED_PARAM, char **argv) * may be used to endorse or promote products derived from this software * without specific prior written permission. * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ''AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE diff --git a/coreutils/env.c b/coreutils/env.c index 8def9c2da..3242446f5 100644 --- a/coreutils/env.c +++ b/coreutils/env.c @@ -129,7 +129,7 @@ int env_main(int argc UNUSED_PARAM, char **argv) * may be used to endorse or promote products derived from this software * without specific prior written permission. * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ''AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE diff --git a/coreutils/nohup.c b/coreutils/nohup.c index 8e28f9029..df271c738 100644 --- a/coreutils/nohup.c +++ b/coreutils/nohup.c @@ -31,12 +31,12 @@ /* Compat info: nohup (GNU coreutils 6.8) does this: # nohup true -nohup: ignoring input and appending output to `nohup.out' +nohup: ignoring input and appending output to 'nohup.out' # nohup true 1>/dev/null nohup: ignoring input and redirecting stderr to stdout # nohup true 2>zz # cat zz -nohup: ignoring input and appending output to `nohup.out' +nohup: ignoring input and appending output to 'nohup.out' # nohup true 2>zz 1>/dev/null # cat zz nohup: ignoring input diff --git a/coreutils/od.c b/coreutils/od.c index e3a68435b..9a888dd5f 100644 --- a/coreutils/od.c +++ b/coreutils/od.c @@ -223,7 +223,7 @@ int od_main(int argc, char **argv) * may be used to endorse or promote products derived from this software * without specific prior written permission. * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ''AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE diff --git a/e2fsprogs/e2fs_lib.h b/e2fsprogs/e2fs_lib.h index f2ae56f43..ae28c353b 100644 --- a/e2fsprogs/e2fs_lib.h +++ b/e2fsprogs/e2fs_lib.h @@ -26,7 +26,7 @@ int fgetsetflags(const char *name, unsigned long *get_flags, unsigned long set_f #define fgetflags(name, flags) fgetsetflags(name, flags, 0) #define fsetflags(name, flags) fgetsetflags(name, NULL, flags) -/* Must be 1 for compatibility with `int long_format'. */ +/* Must be 1 for compatibility with 'int long_format'. */ #define PFOPT_LONG 1 /* Print file attributes on an ext2 file system */ void print_e2flags(FILE *f, unsigned long flags, unsigned options); diff --git a/editors/awk.c b/editors/awk.c index cc17ad438..372a255bd 100644 --- a/editors/awk.c +++ b/editors/awk.c @@ -230,7 +230,7 @@ typedef struct tsplitter_s { */ #define TC_LENGTH (1 << 20) #define TC_GETLINE (1 << 21) -#define TC_FUNCDECL (1 << 22) /* `function' `func' */ +#define TC_FUNCDECL (1 << 22) /* 'function' 'func' */ #define TC_BEGIN (1 << 23) #define TC_END (1 << 24) #define TC_EOF (1 << 25) diff --git a/findutils/find.c b/findutils/find.c index 69baf065d..5857a3f44 100644 --- a/findutils/find.c +++ b/findutils/find.c @@ -15,7 +15,7 @@ * # find file.txt -exec 'echo {}' '{} {}' ';' * find: echo file.txt: No such file or directory * # find file.txt -exec 'echo' '{} {}' '; ' - * find: missing argument to `-exec' + * find: missing argument to '-exec' * # find file.txt -exec 'echo {}' '{} {}' ';' junk * find: paths must precede expression * # find file.txt -exec 'echo {}' '{} {}' ';' junk ';' diff --git a/libbb/change_identity.c b/libbb/change_identity.c index d48d86326..431f72c8c 100644 --- a/libbb/change_identity.c +++ b/libbb/change_identity.c @@ -15,7 +15,7 @@ * may be used to endorse or promote products derived from this software * without specific prior written permission. * - * THIS SOFTWARE IS PROVIDED BY JULIE HAUGH AND CONTRIBUTORS ``AS IS'' AND + * THIS SOFTWARE IS PROVIDED BY JULIE HAUGH AND CONTRIBUTORS ''AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL JULIE HAUGH OR CONTRIBUTORS BE LIABLE diff --git a/libbb/correct_password.c b/libbb/correct_password.c index f4635a5bc..51928f68d 100644 --- a/libbb/correct_password.c +++ b/libbb/correct_password.c @@ -15,7 +15,7 @@ * may be used to endorse or promote products derived from this software * without specific prior written permission. * - * THIS SOFTWARE IS PROVIDED BY JULIE HAUGH AND CONTRIBUTORS ``AS IS'' AND + * THIS SOFTWARE IS PROVIDED BY JULIE HAUGH AND CONTRIBUTORS ''AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL JULIE HAUGH OR CONTRIBUTORS BE LIABLE diff --git a/libbb/dump.c b/libbb/dump.c index 211a1ed9e..e23b71294 100644 --- a/libbb/dump.c +++ b/libbb/dump.c @@ -828,7 +828,7 @@ void FAST_FUNC bb_dump_add(dumper_t* pub_dumper, const char *fmt) * may be used to endorse or promote products derived from this software * without specific prior written permission. * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ''AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE diff --git a/libbb/progress.c b/libbb/progress.c index 3c2f01667..64e6529ac 100644 --- a/libbb/progress.c +++ b/libbb/progress.c @@ -25,7 +25,7 @@ * may be used to endorse or promote products derived from this software * without specific prior written permission. * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ''AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE diff --git a/libbb/pw_encrypt_des.c b/libbb/pw_encrypt_des.c index c8e02ddff..19a9ab15b 100644 --- a/libbb/pw_encrypt_des.c +++ b/libbb/pw_encrypt_des.c @@ -24,7 +24,7 @@ * may be used to endorse or promote products derived from this software * without specific prior written permission. * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ''AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE diff --git a/libbb/run_shell.c b/libbb/run_shell.c index b6b9360e8..3bb58bb6f 100644 --- a/libbb/run_shell.c +++ b/libbb/run_shell.c @@ -15,7 +15,7 @@ * may be used to endorse or promote products derived from this software * without specific prior written permission. * - * THIS SOFTWARE IS PROVIDED BY JULIE HAUGH AND CONTRIBUTORS ``AS IS'' AND + * THIS SOFTWARE IS PROVIDED BY JULIE HAUGH AND CONTRIBUTORS ''AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL JULIE HAUGH OR CONTRIBUTORS BE LIABLE diff --git a/libbb/setup_environment.c b/libbb/setup_environment.c index 4258656fe..91b6d94db 100644 --- a/libbb/setup_environment.c +++ b/libbb/setup_environment.c @@ -15,7 +15,7 @@ * may be used to endorse or promote products derived from this software * without specific prior written permission. * - * THIS SOFTWARE IS PROVIDED BY JULIE HAUGH AND CONTRIBUTORS ``AS IS'' AND + * THIS SOFTWARE IS PROVIDED BY JULIE HAUGH AND CONTRIBUTORS ''AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL JULIE HAUGH OR CONTRIBUTORS BE LIABLE diff --git a/libpwdgrp/uidgid_get.c b/libpwdgrp/uidgid_get.c index 1199f23f9..283ac78fc 100644 --- a/libpwdgrp/uidgid_get.c +++ b/libpwdgrp/uidgid_get.c @@ -13,7 +13,7 @@ modification, are permitted provided that the following conditions are met: 3. The name of the author may not be used to endorse or promote products derived from this software without specific prior written permission. -THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED +THIS SOFTWARE IS PROVIDED BY THE AUTHOR ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, diff --git a/miscutils/adjtimex.c b/miscutils/adjtimex.c index 04ba5636f..0830734ee 100644 --- a/miscutils/adjtimex.c +++ b/miscutils/adjtimex.c @@ -1,6 +1,6 @@ /* vi: set sw=4 ts=4: */ /* - * adjtimex.c - read, and possibly modify, the Linux kernel `timex' variables. + * adjtimex.c - read, and possibly modify, the Linux kernel 'timex' variables. * * Originally written: October 1997 * Last hack: March 2001 diff --git a/miscutils/time.c b/miscutils/time.c index 60fc11f6e..0ecdac1a6 100644 --- a/miscutils/time.c +++ b/miscutils/time.c @@ -127,13 +127,13 @@ static unsigned long ptok(const unsigned pagesize, const unsigned long pages) /* summarize: Report on the system use of a command. - Print the FMT argument except that `%' sequences - have special meaning, and `\n' and `\t' are translated into - newline and tab, respectively, and `\\' is translated into `\'. + Print the FMT argument except that '%' sequences + have special meaning, and '\n' and '\t' are translated into + newline and tab, respectively, and '\\' is translated into '\'. - The character following a `%' can be: + The character following a '%' can be: (* means the tcsh time builtin also recognizes it) - % == a literal `%' + % == a literal '%' C == command name and arguments * D == average unshared data size in K (ru_idrss+ru_isrss) * E == elapsed real (wall clock) time in [hour:]min:sec diff --git a/modutils/modutils-24.c b/modutils/modutils-24.c index 9ce91351d..1a30dd87c 100644 --- a/modutils/modutils-24.c +++ b/modutils/modutils-24.c @@ -2269,8 +2269,8 @@ static int add_symbols_from(struct obj_file *f, #ifdef SYMBOL_PREFIX /* Prepend SYMBOL_PREFIX to the symbol's name (the - kernel exports `C names', but module object files - reference `linker names'). */ + kernel exports 'C names', but module object files + reference 'linker names'). */ size_t extra = sizeof SYMBOL_PREFIX; size_t name_size = strlen(name) + extra; if (name_size > name_alloced_size) { diff --git a/networking/hostname.c b/networking/hostname.c index 4b305d2b6..7d7c60d18 100644 --- a/networking/hostname.c +++ b/networking/hostname.c @@ -114,7 +114,7 @@ static void do_sethostname(char *s, int isfile) * { bbox: not supported } * -F, --file filename * Read the host name from the specified file. Comments (lines - * starting with a `#') are ignored. + * starting with a '#') are ignored. */ int hostname_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; int hostname_main(int argc UNUSED_PARAM, char **argv) diff --git a/networking/ping.c b/networking/ping.c index 506e7b11b..2e8bef023 100644 --- a/networking/ping.c +++ b/networking/ping.c @@ -953,7 +953,7 @@ int ping6_main(int argc UNUSED_PARAM, char **argv) * may be used to endorse or promote products derived from this software * without specific prior written permission. * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ''AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE diff --git a/networking/traceroute.c b/networking/traceroute.c index a958a2c6c..d9c62f7f9 100644 --- a/networking/traceroute.c +++ b/networking/traceroute.c @@ -12,12 +12,12 @@ * this paragraph in its entirety in the documentation or other materials * provided with the distribution, and (3) all advertising materials mentioning * features or use of this software display the following acknowledgement: - * ``This product includes software developed by the University of California, + * ''This product includes software developed by the University of California, * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of * the University nor the names of its contributors may be used to endorse * or promote products derived from this software without specific prior * written permission. - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED + * THIS SOFTWARE IS PROVIDED ''AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. */ diff --git a/runit/chpst.c b/runit/chpst.c index 3a2f9e616..ccc96539d 100644 --- a/runit/chpst.c +++ b/runit/chpst.c @@ -13,7 +13,7 @@ modification, are permitted provided that the following conditions are met: 3. The name of the author may not be used to endorse or promote products derived from this software without specific prior written permission. -THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED +THIS SOFTWARE IS PROVIDED BY THE AUTHOR ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, diff --git a/runit/runit_lib.h b/runit/runit_lib.h index c36ea4ca5..c54561616 100644 --- a/runit/runit_lib.h +++ b/runit/runit_lib.h @@ -13,7 +13,7 @@ modification, are permitted provided that the following conditions are met: 3. The name of the author may not be used to endorse or promote products derived from this software without specific prior written permission. -THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED +THIS SOFTWARE IS PROVIDED BY THE AUTHOR ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, diff --git a/runit/runsv.c b/runit/runsv.c index ad7d82cb8..a67280b4b 100644 --- a/runit/runsv.c +++ b/runit/runsv.c @@ -13,7 +13,7 @@ modification, are permitted provided that the following conditions are met: 3. The name of the author may not be used to endorse or promote products derived from this software without specific prior written permission. -THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED +THIS SOFTWARE IS PROVIDED BY THE AUTHOR ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, diff --git a/runit/runsvdir.c b/runit/runsvdir.c index b4f5c303b..abba2e8e4 100644 --- a/runit/runsvdir.c +++ b/runit/runsvdir.c @@ -13,7 +13,7 @@ modification, are permitted provided that the following conditions are met: 3. The name of the author may not be used to endorse or promote products derived from this software without specific prior written permission. -THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED +THIS SOFTWARE IS PROVIDED BY THE AUTHOR ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, diff --git a/runit/sv.c b/runit/sv.c index 2d5b466bf..3dd02550a 100644 --- a/runit/sv.c +++ b/runit/sv.c @@ -13,7 +13,7 @@ modification, are permitted provided that the following conditions are met: 3. The name of the author may not be used to endorse or promote products derived from this software without specific prior written permission. -THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED +THIS SOFTWARE IS PROVIDED BY THE AUTHOR ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, diff --git a/runit/svlogd.c b/runit/svlogd.c index 8dbf67106..831873d86 100644 --- a/runit/svlogd.c +++ b/runit/svlogd.c @@ -13,7 +13,7 @@ modification, are permitted provided that the following conditions are met: 3. The name of the author may not be used to endorse or promote products derived from this software without specific prior written permission. -THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED +THIS SOFTWARE IS PROVIDED BY THE AUTHOR ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, diff --git a/scripts/echo.c b/scripts/echo.c index cb207ae05..8c6b409d3 100644 --- a/scripts/echo.c +++ b/scripts/echo.c @@ -214,7 +214,7 @@ int main(int argc, char **argv) * may be used to endorse or promote products derived from this software * without specific prior written permission. * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ''AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE diff --git a/shell/ash.c b/shell/ash.c index 1deae7c2f..78baa9aac 100644 --- a/shell/ash.c +++ b/shell/ash.c @@ -13877,7 +13877,7 @@ int ash_main(int argc UNUSED_PARAM, char **argv) * may be used to endorse or promote products derived from this software * without specific prior written permission. * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ''AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE diff --git a/shell/ash_test/printenv.c b/shell/ash_test/printenv.c index c0c5e197c..c86308d3b 100644 --- a/shell/ash_test/printenv.c +++ b/shell/ash_test/printenv.c @@ -56,7 +56,7 @@ main (argc, argv) if (**argv == **envp && strncmp (*envp, *argv, len) == 0) { eval = *envp + len; - /* If the environment variable doesn't have an `=', ignore it. */ + /* If the environment variable doesn't have an '=', ignore it. */ if (*eval == '=') { puts (eval + 1); diff --git a/shell/math.c b/shell/math.c index 006221b6a..f01f24362 100644 --- a/shell/math.c +++ b/shell/math.c @@ -743,7 +743,7 @@ arith(arith_state_t *math_state, const char *expr) * may be used to endorse or promote products derived from this software * without specific prior written permission. * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ''AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE diff --git a/sysklogd/logger.c b/sysklogd/logger.c index 6769a8175..359ac3acf 100644 --- a/sysklogd/logger.c +++ b/sysklogd/logger.c @@ -167,7 +167,7 @@ int logger_main(int argc UNUSED_PARAM, char **argv) * may be used to endorse or promote products derived from this software * without specific prior written permission. * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ''AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE diff --git a/util-linux/cal.c b/util-linux/cal.c index 091fdbd2b..10df0ae8b 100644 --- a/util-linux/cal.c +++ b/util-linux/cal.c @@ -376,7 +376,7 @@ static char *build_row(char *p, unsigned *dp) * may be used to endorse or promote products derived from this software * without specific prior written permission. * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ''AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE diff --git a/util-linux/fdisk_osf.c b/util-linux/fdisk_osf.c index 89f1f323c..1141b7801 100644 --- a/util-linux/fdisk_osf.c +++ b/util-linux/fdisk_osf.c @@ -18,7 +18,7 @@ * may be used to endorse or promote products derived from this software * without specific prior written permission. * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ''AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE -- cgit v1.2.3-55-g6feb From 7c40ddd9500907925041131374cb43eb87ef5494 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Wed, 2 Aug 2017 16:37:39 +0200 Subject: NOFORK fixes "rm -i FILE" and "yes" can now be interrupted by ^C in hush. This also now works: $ usleep 19999999 ^C $ echo $? 130 function old new delta run_pipe 1668 1711 +43 pseudo_exec_argv 312 321 +9 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 2/0 up/down: 52/0) Total: 52 bytes Signed-off-by: Denys Vlasenko --- coreutils/rm.c | 5 +++-- coreutils/seq.c | 5 +++-- coreutils/usleep.c | 7 +++++++ coreutils/yes.c | 3 ++- docs/nofork_noexec.txt | 3 +++ shell/hush.c | 31 ++++++++++++++++++++++++++++++- 6 files changed, 48 insertions(+), 6 deletions(-) diff --git a/coreutils/rm.c b/coreutils/rm.c index f91c94570..5e4acab8c 100644 --- a/coreutils/rm.c +++ b/coreutils/rm.c @@ -16,7 +16,8 @@ //config: help //config: rm is used to remove files or directories. -//applet:IF_RM(APPLET_NOFORK(rm, rm, BB_DIR_BIN, BB_SUID_DROP, rm)) +//applet:IF_RM(APPLET_NOEXEC(rm, rm, BB_DIR_BIN, BB_SUID_DROP, rm)) +/* was NOFORK, but then "rm -i FILE" can't be ^C'ed if run by hush */ //kbuild:lib-$(CONFIG_RM) += rm.o @@ -36,7 +37,7 @@ #include "libbb.h" -/* This is a NOFORK applet. Be very careful! */ +/* This is a NOEXEC applet. Be very careful! */ int rm_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; int rm_main(int argc UNUSED_PARAM, char **argv) diff --git a/coreutils/seq.c b/coreutils/seq.c index f36dbb4ec..c26ff06b9 100644 --- a/coreutils/seq.c +++ b/coreutils/seq.c @@ -12,7 +12,8 @@ //config: help //config: print a sequence of numbers -//applet:IF_SEQ(APPLET_NOFORK(seq, seq, BB_DIR_USR_BIN, BB_SUID_DROP, seq)) +//applet:IF_SEQ(APPLET_NOEXEC(seq, seq, BB_DIR_USR_BIN, BB_SUID_DROP, seq)) +/* was NOFORK, but then "seq 1 999999999" can't be ^C'ed if run by hush */ //kbuild:lib-$(CONFIG_SEQ) += seq.o @@ -26,7 +27,7 @@ #include "libbb.h" -/* This is a NOFORK applet. Be very careful! */ +/* This is a NOEXEC applet. Be very careful! */ int seq_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; int seq_main(int argc, char **argv) diff --git a/coreutils/usleep.c b/coreutils/usleep.c index 7c25aada1..684ab781b 100644 --- a/coreutils/usleep.c +++ b/coreutils/usleep.c @@ -38,6 +38,13 @@ int usleep_main(int argc UNUSED_PARAM, char **argv) bb_show_usage(); } + /* Safe wrt NOFORK? (noforks are not allowed to run for + * a long time). Try "usleep 99999999" + ^C + "echo $?" + * in hush with FEATURE_SH_NOFORK=y. + * At least on uclibc, usleep() thanslates to nanosleep() + * which returns early on any signal (even caught one), + * and uclibc does not loop back on EINTR. + */ usleep(xatou(argv[1])); return EXIT_SUCCESS; diff --git a/coreutils/yes.c b/coreutils/yes.c index ea35d146c..c244bfe10 100644 --- a/coreutils/yes.c +++ b/coreutils/yes.c @@ -17,7 +17,8 @@ //config: yes is used to repeatedly output a specific string, or //config: the default string 'y'. -//applet:IF_YES(APPLET_NOFORK(yes, yes, BB_DIR_USR_BIN, BB_SUID_DROP, yes)) +//applet:IF_YES(APPLET_NOEXEC(yes, yes, BB_DIR_USR_BIN, BB_SUID_DROP, yes)) +/* was NOFORK, but then yes can't be ^C'ed if run by hush */ //kbuild:lib-$(CONFIG_YES) += yes.o diff --git a/docs/nofork_noexec.txt b/docs/nofork_noexec.txt index a24dd9c27..0ad4e6e60 100644 --- a/docs/nofork_noexec.txt +++ b/docs/nofork_noexec.txt @@ -52,6 +52,9 @@ xargs, find, shells do it (grep for "spawn_and_wait" and This poses much more serious limitations on what applet can do: * all NOEXEC limitations apply. +* do not run for a long time or wait for user input: + hush shell only handles signals (like ^C) after you return + from APPLET_main(). * do not ever exit() or exec(). - xfuncs are okay. They are using special trick to return to the caller applet instead of dying when they detect "x" condition. diff --git a/shell/hush.c b/shell/hush.c index 9f946d82f..cfefb7324 100644 --- a/shell/hush.c +++ b/shell/hush.c @@ -7363,6 +7363,8 @@ static NOINLINE void pseudo_exec_argv(nommu_save_t *nommu_save, */ close_saved_fds_and_FILE_fds(); //FIXME: should also close saved redir fds + /* Without this, "rm -i FILE" can't be ^C'ed: */ + switch_off_special_sigs(G.special_sig_mask); debug_printf_exec("running applet '%s'\n", argv[0]); run_applet_no_and_exit(a, argv[0], argv); } @@ -8045,6 +8047,24 @@ static NOINLINE int run_pipe(struct pipe *pi) add_vars(old_vars); /* clean_up_and_ret0: */ restore_redirects(squirrel); + /* + * Try "usleep 99999999" + ^C + "echo $?" + * with FEATURE_SH_NOFORK=y. + */ + if (!funcp) { + /* It was builtin or nofork. + * if this would be a real fork/execed program, + * it should have died if a fatal sig was received. + * But OTOH, there was no separate process, + * the sig was sent to _shell_, not to non-existing + * child. + * Let's just handle ^C only, this one is obvious: + * we aren't ok with exitcode 0 when ^C was pressed + * during builtin/nofork. + */ + if (sigismember(&G.pending_set, SIGINT)) + rcode = 128 + SIGINT; + } clean_up_and_ret1: free(argv_expanded); IF_HAS_KEYWORDS(if (pi->pi_inverted) rcode = !rcode;) @@ -8060,6 +8080,14 @@ static NOINLINE int run_pipe(struct pipe *pi) if (rcode == 0) { debug_printf_exec(": run_nofork_applet '%s' '%s'...\n", argv_expanded[0], argv_expanded[1]); + /* + * Note: signals (^C) can't interrupt here. + * We remember them and they will be acted upon + * after applet returns. + * This makes applets which can run for a long time + * and/or wait for user input ineligible for NOFORK: + * for example, "yes" or "rm" (rm -i waits for input). + */ rcode = run_nofork_applet(n, argv_expanded); } goto clean_up_and_ret; @@ -8491,7 +8519,7 @@ static int run_list(struct pipe *pi) G.last_bg_pid = pi->cmds[pi->num_cmds - 1].pid; G.last_bg_pid_exitcode = 0; debug_printf_exec(": cmd&: exitcode EXIT_SUCCESS\n"); -/* Check pi->pi_inverted? "! sleep 1 & echo $?": bash says 1. dash and ash says 0 */ +/* Check pi->pi_inverted? "! sleep 1 & echo $?": bash says 1. dash and ash say 0 */ rcode = EXIT_SUCCESS; goto check_traps; } else { @@ -10178,6 +10206,7 @@ static int wait_for_child_or_signal(struct pipe *waitfor_pipe, pid_t waitfor_pid /* So, did we get a signal? */ sig = check_and_run_traps(); if (sig /*&& sig != SIGCHLD - always true */) { + /* Do this for any (non-ignored) signal, not only for ^C */ ret = 128 + sig; break; } -- cgit v1.2.3-55-g6feb From dd4b446f76736c0a13a61a38d7d816b6e6b5fca2 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Wed, 2 Aug 2017 16:52:12 +0200 Subject: hush: make SIGINT handling visually less confusing $ echo $$ 18448 $ echo $? <=== NOTHING?? $ That empty line does not look right. After this patch: $ echo $$ 18448 $ echo $? ^C $ function old new delta fgetc_interactive 245 246 +1 Signed-off-by: Denys Vlasenko --- shell/hush.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/shell/hush.c b/shell/hush.c index cfefb7324..93ed0bc0b 100644 --- a/shell/hush.c +++ b/shell/hush.c @@ -2415,14 +2415,14 @@ static int get_user_input(struct in_str *i) /*timeout*/ -1 ); /* read_line_input intercepts ^C, "convert" it to SIGINT */ - if (r == 0) { - write(STDOUT_FILENO, "^C", 2); + if (r == 0) raise(SIGINT); - } check_and_run_traps(); if (r != 0 && !G.flag_SIGINT) break; /* ^C or SIGINT: repeat */ + /* bash prints ^C even on real SIGINT (non-kbd generated) */ + write(STDOUT_FILENO, "^C", 2); G.last_exitcode = 128 + SIGINT; } if (r < 0) { -- cgit v1.2.3-55-g6feb From 84ea60ed65f6ea6fd3b2170e44bbff5de410a78b Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Wed, 2 Aug 2017 17:27:28 +0200 Subject: line editing: make read_line_input() not take timeout param It's almost always -1. function old new delta read_line_input 3902 3912 +10 new_line_input_t 24 31 +7 pgetc 583 585 +2 save_command_ps_at_cur_history 80 78 -2 read_line 76 74 -2 fgetc_interactive 246 244 -2 addLines 84 82 -2 doCommands 2226 2222 -4 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 3/5 up/down: 19/-12) Total: 7 bytes Signed-off-by: Denys Vlasenko --- editors/ed.c | 6 +++--- include/libbb.h | 11 ++++++----- libbb/lineedit.c | 23 ++++++++++++++++------- shell/ash.c | 5 +++-- shell/hush.c | 3 +-- util-linux/fdisk.c | 2 +- 6 files changed, 30 insertions(+), 20 deletions(-) diff --git a/editors/ed.c b/editors/ed.c index 7f21ded92..05797692c 100644 --- a/editors/ed.c +++ b/editors/ed.c @@ -360,7 +360,7 @@ static void addLines(int num) * 0 on ctrl-C, * >0 length of input string, including terminating '\n' */ - len = read_line_input(NULL, "", buf, sizeof(buf), /*timeout*/ -1); + len = read_line_input(NULL, "", buf, sizeof(buf)); if (len <= 0) { /* Previously, ctrl-C was exiting to shell. * Now we exit to ed prompt. Is in important? */ @@ -789,7 +789,7 @@ static void doCommands(void) * 0 on ctrl-C, * >0 length of input string, including terminating '\n' */ - len = read_line_input(NULL, ": ", buf, sizeof(buf), /*timeout*/ -1); + len = read_line_input(NULL, ": ", buf, sizeof(buf)); if (len <= 0) return; while (len && isspace(buf[--len])) @@ -892,7 +892,7 @@ static void doCommands(void) } if (!dirty) return; - len = read_line_input(NULL, "Really quit? ", buf, 16, /*timeout*/ -1); + len = read_line_input(NULL, "Really quit? ", buf, 16); /* read error/EOF - no way to continue */ if (len < 0) return; diff --git a/include/libbb.h b/include/libbb.h index 9aba71949..46180c5aa 100644 --- a/include/libbb.h +++ b/include/libbb.h @@ -1639,9 +1639,9 @@ enum { * buffer[0] is used as a counter of buffered chars and must be 0 * on first call. * timeout: - * -2: do not poll for input; - * -1: poll(-1) (i.e. block); - * >=0: poll for TIMEOUT milliseconds, return -1/EAGAIN on timeout + * -2: do not poll(-1) for input - read() it, return on EAGAIN at once + * -1: poll(-1) (i.e. block even on NONBLOCKed fd) + * >=0: poll() for TIMEOUT milliseconds, return -1/EAGAIN on timeout */ int64_t read_key(int fd, char *buffer, int timeout) FAST_FUNC; void read_key_ungets(char *buffer, const char *str, unsigned len) FAST_FUNC; @@ -1657,6 +1657,7 @@ unsigned size_from_HISTFILESIZE(const char *hp) FAST_FUNC; # endif typedef struct line_input_t { int flags; + int timeout; const char *path_lookup; # if MAX_HISTORY int cnt_history; @@ -1692,7 +1693,7 @@ line_input_t *new_line_input_t(int flags) FAST_FUNC; * 0 on ctrl-C (the line entered is still returned in 'command'), * >0 length of input string, including terminating '\n' */ -int read_line_input(line_input_t *st, const char *prompt, char *command, int maxsize, int timeout) FAST_FUNC; +int read_line_input(line_input_t *st, const char *prompt, char *command, int maxsize) FAST_FUNC; void show_history(const line_input_t *st) FAST_FUNC; # if ENABLE_FEATURE_EDITING_SAVE_ON_EXIT void save_history(line_input_t *st); @@ -1700,7 +1701,7 @@ void save_history(line_input_t *st); #else #define MAX_HISTORY 0 int read_line_input(const char* prompt, char* command, int maxsize) FAST_FUNC; -#define read_line_input(state, prompt, command, maxsize, timeout) \ +#define read_line_input(state, prompt, command, maxsize) \ read_line_input(prompt, command, maxsize) #endif diff --git a/libbb/lineedit.c b/libbb/lineedit.c index e5721b063..0106093a1 100644 --- a/libbb/lineedit.c +++ b/libbb/lineedit.c @@ -1267,6 +1267,7 @@ line_input_t* FAST_FUNC new_line_input_t(int flags) { line_input_t *n = xzalloc(sizeof(*n)); n->flags = flags; + n->timeout = -1; #if MAX_HISTORY > 0 n->max_history = MAX_HISTORY; #endif @@ -2130,7 +2131,7 @@ enum { * Backspace deletes last matched char. * Control keys exit search and return to normal editing (at current history line). */ -static int32_t reverse_i_search(void) +static int32_t reverse_i_search(int timeout) { char match_buf[128]; /* for user input */ char read_key_buffer[KEYCODE_BUFFER_SIZE]; @@ -2152,8 +2153,8 @@ static int32_t reverse_i_search(void) int h; unsigned match_buf_len = strlen(match_buf); -//FIXME: correct timeout? - ic = lineedit_read_key(read_key_buffer, -1); +//FIXME: correct timeout? (i.e. count it down?) + ic = lineedit_read_key(read_key_buffer, timeout); switch (ic) { case CTRL('R'): /* searching for the next match */ @@ -2256,9 +2257,10 @@ static int32_t reverse_i_search(void) * (in both cases the cursor remains on the input line, '\n' is not printed) * >0 length of input string, including terminating '\n' */ -int FAST_FUNC read_line_input(line_input_t *st, const char *prompt, char *command, int maxsize, int timeout) +int FAST_FUNC read_line_input(line_input_t *st, const char *prompt, char *command, int maxsize) { int len; + int timeout; #if ENABLE_FEATURE_TAB_COMPLETION smallint lastWasTab = 0; #endif @@ -2297,8 +2299,15 @@ int FAST_FUNC read_line_input(line_input_t *st, const char *prompt, char *comman maxsize = MAX_LINELEN; S.maxsize = maxsize; - /* With zero flags, no other fields are ever used */ - state = st ? st : (line_input_t*) &const_int_0; + timeout = -1; + /* Make state->flags == 0 if st is NULL. + * With zeroed flags, no other fields are ever referenced. + */ + state = (line_input_t*) &const_int_0; + if (st) { + state = st; + timeout = st->timeout; + } #if MAX_HISTORY > 0 # if ENABLE_FEATURE_EDITING_SAVEHISTORY if (state->hist_file) @@ -2510,7 +2519,7 @@ int FAST_FUNC read_line_input(line_input_t *st, const char *prompt, char *comman } #if ENABLE_FEATURE_REVERSE_SEARCH case CTRL('R'): - ic = ic_raw = reverse_i_search(); + ic = ic_raw = reverse_i_search(timeout); goto again; #endif diff --git a/shell/ash.c b/shell/ash.c index 78baa9aac..b285e3d33 100644 --- a/shell/ash.c +++ b/shell/ash.c @@ -10185,8 +10185,8 @@ preadfd(void) if (!iflag || g_parsefile->pf_fd != STDIN_FILENO) nr = nonblock_immune_read(g_parsefile->pf_fd, buf, IBUFSIZ - 1); else { - int timeout = -1; # if ENABLE_ASH_IDLE_TIMEOUT + int timeout = -1; if (iflag) { const char *tmout_var = lookupvar("TMOUT"); if (tmout_var) { @@ -10195,12 +10195,13 @@ preadfd(void) timeout = -1; } } + line_input_state->timeout = timeout; # endif # if ENABLE_FEATURE_TAB_COMPLETION line_input_state->path_lookup = pathval(); # endif reinit_unicode_for_ash(); - nr = read_line_input(line_input_state, cmdedit_prompt, buf, IBUFSIZ, timeout); + nr = read_line_input(line_input_state, cmdedit_prompt, buf, IBUFSIZ); if (nr == 0) { /* ^C pressed, "convert" to SIGINT */ write(STDOUT_FILENO, "^C", 2); diff --git a/shell/hush.c b/shell/hush.c index 93ed0bc0b..6fa4e1630 100644 --- a/shell/hush.c +++ b/shell/hush.c @@ -2411,8 +2411,7 @@ static int get_user_input(struct in_str *i) /* buglet: SIGINT will not make new prompt to appear _at once_, * only after . (^C works immediately) */ r = read_line_input(G.line_input_state, prompt_str, - G.user_input_buf, CONFIG_FEATURE_EDITING_MAX_LEN-1, - /*timeout*/ -1 + G.user_input_buf, CONFIG_FEATURE_EDITING_MAX_LEN-1 ); /* read_line_input intercepts ^C, "convert" it to SIGINT */ if (r == 0) diff --git a/util-linux/fdisk.c b/util-linux/fdisk.c index e00f85864..4828c0a51 100644 --- a/util-linux/fdisk.c +++ b/util-linux/fdisk.c @@ -644,7 +644,7 @@ read_line(const char *prompt) { int sz; - sz = read_line_input(NULL, prompt, line_buffer, sizeof(line_buffer), /*timeout*/ -1); + sz = read_line_input(NULL, prompt, line_buffer, sizeof(line_buffer)); if (sz <= 0) exit(EXIT_SUCCESS); /* Ctrl-D or Ctrl-C */ -- cgit v1.2.3-55-g6feb From 39701204cfa0f261beb2dc056024634e4c3afd71 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Wed, 2 Aug 2017 19:44:05 +0200 Subject: hush: do not accept "if() { echo; }" function def function old new delta parse_stream 2634 2692 +58 msg_and_die_if_script - 21 +21 syntax_error_unexpected_ch 41 46 +5 syntax_error_at 14 18 +4 die_if_script 31 28 -3 setup_redirects 319 308 -11 ------------------------------------------------------------------------------ (add/remove: 1/0 grow/shrink: 3/2 up/down: 88/-14) Total: 74 bytes Signed-off-by: Denys Vlasenko --- .../ash-parsing/groups_and_keywords2.right | 3 ++ .../ash-parsing/groups_and_keywords2.tests | 9 ++++ shell/hush.c | 53 +++++++++++++++------- .../hush-parsing/groups_and_keywords2.right | 3 ++ .../hush-parsing/groups_and_keywords2.tests | 9 ++++ 5 files changed, 60 insertions(+), 17 deletions(-) create mode 100644 shell/ash_test/ash-parsing/groups_and_keywords2.right create mode 100755 shell/ash_test/ash-parsing/groups_and_keywords2.tests create mode 100644 shell/hush_test/hush-parsing/groups_and_keywords2.right create mode 100755 shell/hush_test/hush-parsing/groups_and_keywords2.tests diff --git a/shell/ash_test/ash-parsing/groups_and_keywords2.right b/shell/ash_test/ash-parsing/groups_and_keywords2.right new file mode 100644 index 000000000..3fcbeb662 --- /dev/null +++ b/shell/ash_test/ash-parsing/groups_and_keywords2.right @@ -0,0 +1,3 @@ +./groups_and_keywords2.tests: eval: line 1: syntax error: unexpected ")" +Fail:2 +./groups_and_keywords2.tests: line 8: syntax error: unexpected ")" diff --git a/shell/ash_test/ash-parsing/groups_and_keywords2.tests b/shell/ash_test/ash-parsing/groups_and_keywords2.tests new file mode 100755 index 000000000..ab33b909f --- /dev/null +++ b/shell/ash_test/ash-parsing/groups_and_keywords2.tests @@ -0,0 +1,9 @@ +# This is an error +(eval 'if() { echo; }') +echo Fail:$? +# ^^^^^^ bash prints 1, but interactively it sets $? = 2 +# we print 2 + +# This is an error, and it aborts in script +if() { echo; } +echo Not reached diff --git a/shell/hush.c b/shell/hush.c index 6fa4e1630..b04f793f1 100644 --- a/shell/hush.c +++ b/shell/hush.c @@ -1272,7 +1272,7 @@ static void xxfree(void *ptr) * HUSH_DEBUG >= 2 prints line number in this file where it was detected. */ #if HUSH_DEBUG < 2 -# define die_if_script(lineno, ...) die_if_script(__VA_ARGS__) +# define msg_and_die_if_script(lineno, ...) msg_and_die_if_script(__VA_ARGS__) # define syntax_error(lineno, msg) syntax_error(msg) # define syntax_error_at(lineno, msg) syntax_error_at(msg) # define syntax_error_unterm_ch(lineno, ch) syntax_error_unterm_ch(ch) @@ -1280,7 +1280,16 @@ static void xxfree(void *ptr) # define syntax_error_unexpected_ch(lineno, ch) syntax_error_unexpected_ch(ch) #endif -static void die_if_script(unsigned lineno, const char *fmt, ...) +static void die_if_script(void) +{ + if (!G_interactive_fd) { + if (G.last_exitcode) /* sometines it's 2, not 1 (bash compat) */ + xfunc_error_retval = G.last_exitcode; + xfunc_die(); + } +} + +static void msg_and_die_if_script(unsigned lineno, const char *fmt, ...) { va_list p; @@ -1290,8 +1299,7 @@ static void die_if_script(unsigned lineno, const char *fmt, ...) va_start(p, fmt); bb_verror_msg(fmt, p, NULL); va_end(p); - if (!G_interactive_fd) - xfunc_die(); + die_if_script(); } static void syntax_error(unsigned lineno UNUSED_PARAM, const char *msg) @@ -1300,16 +1308,20 @@ static void syntax_error(unsigned lineno UNUSED_PARAM, const char *msg) bb_error_msg("syntax error: %s", msg); else bb_error_msg("syntax error"); + die_if_script(); } static void syntax_error_at(unsigned lineno UNUSED_PARAM, const char *msg) { bb_error_msg("syntax error at '%s'", msg); + die_if_script(); } static void syntax_error_unterm_str(unsigned lineno UNUSED_PARAM, const char *s) { bb_error_msg("syntax error: unterminated %s", s); +//? source4.tests fails: in bash, echo ${^} in script does not terminate the script +// die_if_script(); } static void syntax_error_unterm_ch(unsigned lineno, char ch) @@ -1327,17 +1339,18 @@ static void syntax_error_unexpected_ch(unsigned lineno UNUSED_PARAM, int ch) bb_error_msg("hush.c:%u", lineno); #endif bb_error_msg("syntax error: unexpected %s", ch == EOF ? "EOF" : msg); + die_if_script(); } #if HUSH_DEBUG < 2 -# undef die_if_script +# undef msg_and_die_if_script # undef syntax_error # undef syntax_error_at # undef syntax_error_unterm_ch # undef syntax_error_unterm_str # undef syntax_error_unexpected_ch #else -# define die_if_script(...) die_if_script(__LINE__, __VA_ARGS__) +# define msg_and_die_if_script(...) msg_and_die_if_script(__LINE__, __VA_ARGS__) # define syntax_error(msg) syntax_error(__LINE__, msg) # define syntax_error_at(msg) syntax_error_at(__LINE__, msg) # define syntax_error_unterm_ch(ch) syntax_error_unterm_ch(__LINE__, ch) @@ -1800,7 +1813,7 @@ static void restore_ttypgrp_and__exit(void) * echo END_OF_SCRIPT * lseeks fd in input FILE object from EOF to "e" in "echo END_OF_SCRIPT". * This makes "echo END_OF_SCRIPT" executed twice. - * Similar problems can be seen with die_if_script() -> xfunc_die() + * Similar problems can be seen with msg_and_die_if_script() -> xfunc_die() * and in `cmd` handling. * If set as die_func(), this makes xfunc_die() exit via _exit(), not exit(): */ @@ -3383,7 +3396,7 @@ static int done_command(struct parse_context *ctx) #if 0 /* Instead we emit error message at run time */ if (ctx->pending_redirect) { /* For example, "cmd >" (no filename to redirect to) */ - die_if_script("syntax error: %s", "invalid redirect"); + syntax_error("invalid redirect"); ctx->pending_redirect = NULL; } #endif @@ -3949,7 +3962,7 @@ static int parse_redirect(struct parse_context *ctx, #if 0 /* Instead we emit error message at run time */ if (ctx->pending_redirect) { /* For example, "cmd > pending_redirect, so we know what to do at the @@ -5021,10 +5034,16 @@ static struct pipe *parse_stream(char **pstring, else o_free_unsafe(&ctx.as_string); #endif - debug_leave(); + if (ch != ';' && IS_NULL_PIPE(ctx.list_head)) { + /* Example: bare "{ }", "()" */ + G.last_exitcode = 2; /* bash compat */ + syntax_error_unexpected_ch(ch); + goto parse_error2; + } debug_printf_parse("parse_stream return %p: " "end_trigger char found\n", ctx.list_head); + debug_leave(); return ctx.list_head; } } @@ -5282,8 +5301,8 @@ static struct pipe *parse_stream(char **pstring, /* proper use of this character is caught by end_trigger: * if we see {, we call parse_group(..., end_trigger='}') * and it will match } earlier (not here). */ - syntax_error_unexpected_ch(ch); G.last_exitcode = 2; + syntax_error_unexpected_ch(ch); goto parse_error2; default: if (HUSH_DEBUG) @@ -5513,7 +5532,7 @@ static arith_t expand_and_evaluate_arith(const char *arg, const char **errmsg_p) if (errmsg_p) *errmsg_p = math_state.errmsg; if (math_state.errmsg) - die_if_script(math_state.errmsg); + msg_and_die_if_script(math_state.errmsg); return res; } #endif @@ -5780,7 +5799,7 @@ static NOINLINE const char *expand_one_var(char **to_be_freed_pp, char *arg, cha /* in bash, len=-n means strlen()-n */ len = (arith_t)strlen(val) - beg + len; if (len < 0) /* bash compat */ - die_if_script("%s: substring expression < 0", var); + msg_and_die_if_script("%s: substring expression < 0", var); } if (len <= 0 || !val || beg >= strlen(val)) { arith_err: @@ -5794,7 +5813,7 @@ static NOINLINE const char *expand_one_var(char **to_be_freed_pp, char *arg, cha } debug_printf_varexp("val:'%s'\n", val); #else /* not (HUSH_SUBSTR_EXPANSION && FEATURE_SH_MATH) */ - die_if_script("malformed ${%s:...}", var); + msg_and_die_if_script("malformed ${%s:...}", var); val = NULL; #endif } else { /* one of "-=+?" */ @@ -5831,7 +5850,7 @@ static NOINLINE const char *expand_one_var(char **to_be_freed_pp, char *arg, cha exp_word = to_be_freed; if (exp_op == '?') { /* mimic bash message */ - die_if_script("%s: %s", + msg_and_die_if_script("%s: %s", var, exp_word[0] ? exp_word @@ -5848,7 +5867,7 @@ static NOINLINE const char *expand_one_var(char **to_be_freed_pp, char *arg, cha /* ${var=[word]} or ${var:=[word]} */ if (isdigit(var[0]) || var[0] == '#') { /* mimic bash message */ - die_if_script("$%s: cannot assign in this way", var); + msg_and_die_if_script("$%s: cannot assign in this way", var); val = NULL; } else { char *new_var = xasprintf("%s=%s", var, val); @@ -6862,7 +6881,7 @@ static int setup_redirects(struct command *prog, struct squirrel **sqp) * "cmd >" (no filename) * "cmd > rd_type].mode; diff --git a/shell/hush_test/hush-parsing/groups_and_keywords2.right b/shell/hush_test/hush-parsing/groups_and_keywords2.right new file mode 100644 index 000000000..ae74a5db9 --- /dev/null +++ b/shell/hush_test/hush-parsing/groups_and_keywords2.right @@ -0,0 +1,3 @@ +hush: syntax error: unexpected ) +Fail:2 +hush: syntax error: unexpected ) diff --git a/shell/hush_test/hush-parsing/groups_and_keywords2.tests b/shell/hush_test/hush-parsing/groups_and_keywords2.tests new file mode 100755 index 000000000..ab33b909f --- /dev/null +++ b/shell/hush_test/hush-parsing/groups_and_keywords2.tests @@ -0,0 +1,9 @@ +# This is an error +(eval 'if() { echo; }') +echo Fail:$? +# ^^^^^^ bash prints 1, but interactively it sets $? = 2 +# we print 2 + +# This is an error, and it aborts in script +if() { echo; } +echo Not reached -- cgit v1.2.3-55-g6feb From 819b47aa357c33bf84919495795b36f8c1faa3ac Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Thu, 3 Aug 2017 03:29:32 +0200 Subject: new NOFORKs: clear, nproc, tty, uname, arch, unlink, which Signed-off-by: Denys Vlasenko --- NOFORK_NOEXEC.lst | 404 ++++++++++++++++++++++++++++++++++++++++++++++++++ console-tools/clear.c | 2 +- coreutils/nproc.c | 2 +- coreutils/tty.c | 2 +- coreutils/uname.c | 6 +- coreutils/unlink.c | 2 +- debianutils/which.c | 4 +- 7 files changed, 414 insertions(+), 8 deletions(-) create mode 100644 NOFORK_NOEXEC.lst diff --git a/NOFORK_NOEXEC.lst b/NOFORK_NOEXEC.lst new file mode 100644 index 000000000..02eba46e8 --- /dev/null +++ b/NOFORK_NOEXEC.lst @@ -0,0 +1,404 @@ +Why an applet can't be NOFORK or NOEXEC? + +Why can't be NOFORK: +daemon: runs indefinitely +interactive: may wait for user input, ^C has to work +spawner: "tool PROG ARGS" which changes program's environment - must fork +changes state: e.g. environment, signal handlers +runner: sometimes may run for long time, and/or works with network: + ^C has to work (cat BIGFILE, chmod -R, ftpget, nc) + +"runners" can become eligible after hush is taught ^C to interrupt NOFORKs! + +Why can't be NOEXEC: +suid: runs under different uid - must fork+exec + +Why shouldn't be NOFORK/NOEXEC: +complex: no immediately obvious reason why NOFORK wouldn't work, + but does some non-obvoius operations (example: fuser, lsof, losetup). + for NOFORK, nested xmallocs (typical in complex code) is a problem. +rare: not used often enough to bother optimizing (example: poweroff) + +[ - NOFORK +[[ - NOFORK +acpid - daemon +add-shell +addgroup +adduser +adjtimex +ar - runner +arch - NOFORK +arp +arping - runner +ash - interactive +awk - noexec, runner +base64 - runner +basename - NOFORK +beep +blkdiscard +blkid +blockdev +bootchartd - daemon +brctl +bunzip2 - runner +busybox +bzcat - runner +bzip2 - runner +cal +cat - runner +chat +chattr - runner +chgrp - noexec, runner +chmod - noexec, runner +chown - noexec, runner +chpasswd - runner (list of "user:password"s from stdin) +chpst - spawner +chroot - spawner +chrt - spawner +chvt +cksum - noexec, runner +clear - NOFORK +cmp - runner +comm - runner +conspy - interactive +cp - noexec, runner +cpio - runner +crond - daemon +crontab +cryptpw +cttyhack - spawner +cut - noexec, runner +date +dc - runner (eats stdin if no params) +dd - noexec, runner +deallocvt +delgroup +deluser +depmod +devmem +df +dhcprelay - daemon +diff - runner +dirname - NOFORK +dmesg +dnsd - daemon +dnsdomainname +dos2unix - noexec, runner +dpkg - runner +du +dumpkmap +dumpleases +echo - NOFORK +ed - interactive +egrep - runner +eject +env - noexec, changes state (env) +envdir - spawner +envuidgid - spawner +expand - runner +expr +factor - runner (eats stdin if no params) +fakeidentd - daemon +false - NOFORK +fatattr +fbset +fbsplash - runner, interactive +fdflush +fdformat - runner +fdisk - interactive +fgconsole +fgrep - runner +find - noexec, runner +findfs - suid +flash_eraseall +flash_lock +flash_unlock +flashcp +flock +fold - noexec, runner +free +freeramdisk +fsck - interactive +fsck.minix +fsfreeze +fstrim +fsync - NOFORK +ftpd - daemon +ftpget - runner +ftpput - runner +fuser - complex +getopt +getty - interactive +grep - runner +groups - noexec +gunzip - runner +gzip - runner +halt - rare +hd - noexec, runner +hdparm - complex, rare +head - noexec, runner +hexdump - noexec, runner +hostid - NOFORK +hostname +httpd - daemon +hush - interactive +hwclock +i2cdetect +i2cdump +i2cget +i2cset +id - noexec +ifconfig +ifenslave +ifplugd - daemon +inetd - daemon +init - daemon +inotifyd - daemon +insmod +install - runner +ionice - spawner +iostat - runner +ip +ipaddr +ipcalc +ipcrm +ipcs +iplink +ipneigh +iproute +iprule +iptunnel +kbd_mode +kill +killall +killall5 +klogd - daemon +last +less - interactive +link - NOFORK +linux32 - spawner +linux64 - spawner +linuxrc - daemon +ln - noexec +loadfont +loadkmap +logger - runner +login - suid, interactive +logname - NOFORK +losetup - complex +lpd - daemon +lpq - runner +lpr - runner +ls - noexec, runner +lsattr +lsmod +lsof - complex +lspci +lsscsi +lsusb +lzcat - runner +lzma - runner +lzop - runner +lzopcat - runner +makedevs +makemime - runner +man - spawner, interactive +md5sum - noexec, runner +mdev - daemon +mesg +microcom - interactive, complex +mkdir - NOFORK +mkdosfs +mke2fs +mkfifo - noexec +mkfs.ext2 +mkfs.minix +mkfs.vfat +mknod - noexec +mkpasswd +mkswap +mktemp +modinfo +modprobe +more - interactive +mount - suid +mountpoint +mpstat +mt +mv +nameif +nbd-client +nc - runner +netstat +nice - spawner +nl - runner +nmeter - runner +nohup - spawner +nproc - NOFORK +ntpd - daemon +od - runner +openvt - spawner +partprobe +passwd - suid +paste - noexec, runner +patch +pgrep +pidof +ping - suid, runner +ping6 - suid, runner +pipe_progress +pivot_root +pkill +pmap +popmaildir - runner +poweroff - rare +powertop - interactive +printenv - NOFORK +printf - NOFORK +ps +pscan +pstree +pwd - NOFORK +pwdx +raidautorun +rdate +rdev +readlink +readprofile +realpath +reboot - rare +reformime - runner +remove-shell +renice +reset - spawner (execs "stty") +resize +rev - runner +rm - noexec, rm -i interactive +rmdir - NOFORK +rmmod +route +rpm - runner +rpm2cpio - runner +rtcwake - complex, rare +run-parts +runlevel +runsv - daemon +runsvdir - daemon +rx - runner +script +scriptreplay +sed - runner +sendmail - runner +seq - noexec, runner +setarch - spawner +setconsole +setfont +setkeycodes +setlogcons +setpriv - spawner +setserial +setsid - spawner +setuidgid +sh - interactive +sha1sum - noexec, runner +sha256sum - noexec, runner +sha3sum - noexec, runner +sha512sum - noexec, runner +showkey - interactive +shred - runner +shuf - noexec, runner +slattach +sleep - runner +smemcap - runner +softlimit - spawner +sort - noexec, runner +split - runner +ssl_client - network +start-stop-daemon +stat +strings - runner +stty +su - suid, spawner +sulogin - spawner +sum - runner +sv +svc +svlogd - daemon +swapoff - rare +swapon - rare +switch_root - spawner, rare, change state +sync - NOFORK +sysctl +syslogd - daemon +tac - noexec, runner +tail - runner +tar - runner +taskset - spawner +tcpsvd - daemon +tee - runner +telnet - interactive +telnetd - daemon +test - NOFORK +tftp - runner +tftpd - daemon +time - spawner, change state (signals) +timeout - spawner, change state (signals) +top - interactive +touch - NOFORK +tr - runner +traceroute - suid, runner +traceroute6 - suid, runner +true - NOFORK +truncate - NOFORK +tty - NOFORK +ttysize +tunctl +tune2fs +ubiattach +ubidetach +ubimkvol +ubirename +ubirmvol +ubirsvol +ubiupdatevol +udhcpc - daemon +udhcpd - daemon +udpsvd - daemon +uevent - daemon +umount +uname - NOFORK +uncompress - runner +unexpand - runner +uniq - runner +unix2dos - noexec, runner +unlink - NOFORK +unlzma - runner +unlzop - runner +unxz - runner +unzip - runner +uptime +users +usleep - NOFORK +uudecode - runner +uuencode - runner +vconfig +vi - interactive +vlock - suid +volname - runner +w +wall - suid +watch - runner +watchdog - daemon +wc - runner +wget - runner +which - NOFORK +who +whoami - NOFORK +whois +xargs - noexec, spawner +xxd - noexec, runner +xz - runner +xzcat - runner +yes - noexec, runner +zcat - runner +zcip - daemon diff --git a/console-tools/clear.c b/console-tools/clear.c index 13eec498b..3cc16257b 100644 --- a/console-tools/clear.c +++ b/console-tools/clear.c @@ -12,7 +12,7 @@ //config: help //config: This program clears the terminal screen. -//applet:IF_CLEAR(APPLET(clear, BB_DIR_USR_BIN, BB_SUID_DROP)) +//applet:IF_CLEAR(APPLET_NOFORK(clear, clear, BB_DIR_USR_BIN, BB_SUID_DROP, clear)) //kbuild:lib-$(CONFIG_CLEAR) += clear.o diff --git a/coreutils/nproc.c b/coreutils/nproc.c index 68a831865..0ae55e70a 100644 --- a/coreutils/nproc.c +++ b/coreutils/nproc.c @@ -9,7 +9,7 @@ //config: help //config: Print number of CPUs -//applet:IF_NPROC(APPLET(nproc, BB_DIR_USR_BIN, BB_SUID_DROP)) +//applet:IF_NPROC(APPLET_NOFORK(nproc, nproc, BB_DIR_USR_BIN, BB_SUID_DROP, nproc)) //kbuild:lib-$(CONFIG_NPROC) += nproc.o diff --git a/coreutils/tty.c b/coreutils/tty.c index 331941a01..18ad7c566 100644 --- a/coreutils/tty.c +++ b/coreutils/tty.c @@ -13,7 +13,7 @@ //config: tty is used to print the name of the current terminal to //config: standard output. -//applet:IF_TTY(APPLET(tty, BB_DIR_USR_BIN, BB_SUID_DROP)) +//applet:IF_TTY(APPLET_NOFORK(tty, tty, BB_DIR_USR_BIN, BB_SUID_DROP, tty)) //kbuild:lib-$(CONFIG_TTY) += tty.o diff --git a/coreutils/uname.c b/coreutils/uname.c index aad58cab0..d6e447e33 100644 --- a/coreutils/uname.c +++ b/coreutils/uname.c @@ -63,9 +63,9 @@ //config: help //config: Same as uname -m. -//applet:IF_UNAME(APPLET(uname, BB_DIR_BIN, BB_SUID_DROP)) -// APPLET_ODDNAME:name main location suid_type help -//applet:IF_BB_ARCH(APPLET_ODDNAME(arch, uname, BB_DIR_BIN, BB_SUID_DROP, arch)) +// APPLET_NOFORK:name main location suid_type help +//applet:IF_UNAME(APPLET_NOFORK( uname, uname, BB_DIR_BIN, BB_SUID_DROP, uname)) +//applet:IF_BB_ARCH(APPLET_NOFORK(arch, uname, BB_DIR_BIN, BB_SUID_DROP, arch)) //kbuild:lib-$(CONFIG_UNAME) += uname.o //kbuild:lib-$(CONFIG_BB_ARCH) += uname.o diff --git a/coreutils/unlink.c b/coreutils/unlink.c index 3322d5b47..e32a9743c 100644 --- a/coreutils/unlink.c +++ b/coreutils/unlink.c @@ -11,7 +11,7 @@ //config: help //config: unlink deletes a file by calling unlink() -//applet:IF_UNLINK(APPLET(unlink, BB_DIR_USR_BIN, BB_SUID_DROP)) +//applet:IF_UNLINK(APPLET_NOFORK(unlink, unlink, BB_DIR_USR_BIN, BB_SUID_DROP, unlink)) //kbuild:lib-$(CONFIG_UNLINK) += unlink.o diff --git a/debianutils/which.c b/debianutils/which.c index 3197ddac1..b31d61871 100644 --- a/debianutils/which.c +++ b/debianutils/which.c @@ -12,7 +12,7 @@ //config: which is used to find programs in your PATH and //config: print out their pathnames. -//applet:IF_WHICH(APPLET(which, BB_DIR_USR_BIN, BB_SUID_DROP)) +//applet:IF_WHICH(APPLET_NOFORK(which, which, BB_DIR_USR_BIN, BB_SUID_DROP, which)) //kbuild:lib-$(CONFIG_WHICH) += which.o @@ -56,6 +56,8 @@ int which_main(int argc UNUSED_PARAM, char **argv) char *p; path = tmp = xstrdup(env_path); +//NOFORK FIXME: nested xmallocs (one is inside find_executable()) +//can leak memory on failure while ((p = find_executable(*argv, &tmp)) != NULL) { missing = 0; puts(p); -- cgit v1.2.3-55-g6feb From 663ae52676eae3b0fdc6bb968ff6497279a034a4 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Thu, 3 Aug 2017 03:46:14 +0200 Subject: config: FEDORA_COMPAT option (so far only tweaks uname) Signed-off-by: Denys Vlasenko --- Config.in | 13 +++++++++++++ coreutils/uname.c | 2 +- 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/Config.in b/Config.in index acd3cb883..1bc214e44 100644 --- a/Config.in +++ b/Config.in @@ -37,6 +37,19 @@ config EXTRA_COMPAT some GNU extensions in libc. You probably only need this option if you plan to run busybox on desktop. +config FEDORA_COMPAT + bool "Building for Fedora distribution" + default n + help + This option makes some tools behave like they do on Fedora. + + At the time of this writing (2017-08) this only affects uname: + normally, uname -p (processor) and uname -i (platform) + are shown as "unknown", but with this option uname -p + shows the same string as uname -m (machine type), + and so does uname -i unless machine type is i486/i586/i686 - + then uname -i shows "i386". + config INCLUDE_SUSv2 bool "Enable obsolete features removed before SUSv3" default y diff --git a/coreutils/uname.c b/coreutils/uname.c index d6e447e33..be9a3f90d 100644 --- a/coreutils/uname.c +++ b/coreutils/uname.c @@ -183,7 +183,7 @@ int uname_main(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) strcpy(uname_info.processor, unknown_str); strcpy(uname_info.platform, unknown_str); strcpy(uname_info.os, CONFIG_UNAME_OSNAME); -# if 0 +# if ENABLE_FEDORA_COMPAT /* Fedora does something like this */ strcpy(uname_info.processor, uname_info.name.machine); strcpy(uname_info.platform, uname_info.name.machine); -- cgit v1.2.3-55-g6feb From 39194f030918b87eeb3e11e94cfa05f575fb47b4 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Thu, 3 Aug 2017 19:00:01 +0200 Subject: new NOFORKs: pwdx,kill[all5],ttysize,realpath,readlink NOEXECs: date,resize function old new delta run_nofork_applet 258 280 +22 readlink_main 112 123 +11 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 2/0 up/down: 33/0) Total: 33 bytes Signed-off-by: Denys Vlasenko --- NOFORK_NOEXEC.lst | 140 +++++++++++++++++++++++---------------------- console-tools/resize.c | 2 +- coreutils/date.c | 21 ++++--- coreutils/readlink.c | 7 +-- coreutils/realpath.c | 3 +- docs/nofork_noexec.txt | 2 +- libbb/bb_pwd.c | 3 +- libbb/vfork_daemon_rexec.c | 6 +- miscutils/ttysize.c | 2 +- procps/kill.c | 10 ++-- procps/pwdx.c | 3 +- 11 files changed, 106 insertions(+), 93 deletions(-) diff --git a/NOFORK_NOEXEC.lst b/NOFORK_NOEXEC.lst index 02eba46e8..7073611a4 100644 --- a/NOFORK_NOEXEC.lst +++ b/NOFORK_NOEXEC.lst @@ -1,11 +1,10 @@ Why an applet can't be NOFORK or NOEXEC? Why can't be NOFORK: -daemon: runs indefinitely interactive: may wait for user input, ^C has to work spawner: "tool PROG ARGS" which changes program's environment - must fork changes state: e.g. environment, signal handlers -runner: sometimes may run for long time, and/or works with network: +runner: sometimes may run for long(ish) time, and/or works with network: ^C has to work (cat BIGFILE, chmod -R, ftpget, nc) "runners" can become eligible after hush is taught ^C to interrupt NOFORKs! @@ -15,9 +14,12 @@ suid: runs under different uid - must fork+exec Why shouldn't be NOFORK/NOEXEC: complex: no immediately obvious reason why NOFORK wouldn't work, - but does some non-obvoius operations (example: fuser, lsof, losetup). - for NOFORK, nested xmallocs (typical in complex code) is a problem. + but does some non-obvoius operations (example: fuser, lsof, losetup); + nested xmallocs (typical in complex code) is a problem for NOFORK rare: not used often enough to bother optimizing (example: poweroff) +longterm: often runs for a long time (many seconds), execing would make + memory footprint smaller +daemon: runs indefinitely [ - NOFORK [[ - NOFORK @@ -31,7 +33,7 @@ arch - NOFORK arp arping - runner ash - interactive -awk - noexec, runner +awk - noexec. runner base64 - runner basename - NOFORK beep @@ -44,63 +46,63 @@ bunzip2 - runner busybox bzcat - runner bzip2 - runner -cal +cal - runner: cal -n9999 cat - runner chat chattr - runner -chgrp - noexec, runner -chmod - noexec, runner -chown - noexec, runner +chgrp - noexec. runner +chmod - noexec. runner +chown - noexec. runner chpasswd - runner (list of "user:password"s from stdin) chpst - spawner chroot - spawner chrt - spawner chvt -cksum - noexec, runner +cksum - noexec. runner clear - NOFORK cmp - runner comm - runner conspy - interactive -cp - noexec, runner +cp - noexec. runner cpio - runner crond - daemon crontab cryptpw cttyhack - spawner -cut - noexec, runner -date +cut - noexec. runner +date - noexec. nofork candidate(needs to stop messing up env, free xasprintf result, not use xfuncs after xasprintf) dc - runner (eats stdin if no params) -dd - noexec, runner +dd - noexec. runner deallocvt delgroup deluser depmod -devmem -df +devmem - runner, complex (access to device memory may hang) +df - complex (nested allocs) dhcprelay - daemon diff - runner dirname - NOFORK -dmesg +dmesg - runner dnsd - daemon -dnsdomainname -dos2unix - noexec, runner +dnsdomainname - DNS resolution may trigger, need ^C +dos2unix - noexec. runner dpkg - runner -du +du - runner dumpkmap dumpleases echo - NOFORK ed - interactive egrep - runner eject -env - noexec, changes state (env) +env - noexec. changes state (env) envdir - spawner envuidgid - spawner expand - runner -expr +expr - complex (nested allocs) factor - runner (eats stdin if no params) fakeidentd - daemon false - NOFORK -fatattr +fatattr - complex (xopen+xioctl can leak fd) fbset fbsplash - runner, interactive fdflush @@ -108,15 +110,15 @@ fdformat - runner fdisk - interactive fgconsole fgrep - runner -find - noexec, runner +find - noexec. runner findfs - suid flash_eraseall flash_lock flash_unlock flashcp flock -fold - noexec, runner -free +fold - noexec. runner +free - nofork candidate(struct globals, needs to close /proc/meminfo fd) freeramdisk fsck - interactive fsck.minix @@ -134,12 +136,12 @@ groups - noexec gunzip - runner gzip - runner halt - rare -hd - noexec, runner +hd - noexec. runner hdparm - complex, rare -head - noexec, runner -hexdump - noexec, runner +head - noexec. runner +hexdump - noexec. runner hostid - NOFORK -hostname +hostname - DNS resolution may trigger, need ^C httpd - daemon hush - interactive hwclock @@ -169,11 +171,11 @@ iproute iprule iptunnel kbd_mode -kill -killall -killall5 +kill - NOFORK +killall - NOFORK +killall5 - NOFORK klogd - daemon -last +last - runner (I've got 1300 lines of output when tried it) less - interactive link - NOFORK linux32 - spawner @@ -189,7 +191,7 @@ losetup - complex lpd - daemon lpq - runner lpr - runner -ls - noexec, runner +ls - noexec. runner lsattr lsmod lsof - complex @@ -203,7 +205,7 @@ lzopcat - runner makedevs makemime - runner man - spawner, interactive -md5sum - noexec, runner +md5sum - noexec. runner mdev - daemon mesg microcom - interactive, complex @@ -225,11 +227,11 @@ mount - suid mountpoint mpstat mt -mv +mv - runner (can be noexec?) nameif nbd-client nc - runner -netstat +netstat - runner with -c nice - spawner nl - runner nmeter - runner @@ -240,40 +242,40 @@ od - runner openvt - spawner partprobe passwd - suid -paste - noexec, runner +paste - noexec. runner patch -pgrep -pidof +pgrep - nofork candidate(xregcomp, procps_scan - are they ok?) +pidof - nofork candidate(uses find_pid_by_name, is that ok?) ping - suid, runner ping6 - suid, runner pipe_progress pivot_root -pkill +pkill - nofork candidate(xregcomp, procps_scan - are they ok?) pmap popmaildir - runner poweroff - rare -powertop - interactive +powertop - interactive, longterm printenv - NOFORK printf - NOFORK ps pscan pstree pwd - NOFORK -pwdx +pwdx - NOFORK raidautorun rdate rdev -readlink +readlink - NOFORK readprofile -realpath +realpath - NOFORK reboot - rare reformime - runner remove-shell -renice +renice - nofork candidate(uses getpwnam, is that ok?) reset - spawner (execs "stty") -resize +resize - noexec. changes state (signal handlers) rev - runner -rm - noexec, rm -i interactive +rm - noexec. rm -i interactive rmdir - NOFORK rmmod route @@ -289,7 +291,7 @@ script scriptreplay sed - runner sendmail - runner -seq - noexec, runner +seq - noexec. runner setarch - spawner setconsole setfont @@ -300,22 +302,22 @@ setserial setsid - spawner setuidgid sh - interactive -sha1sum - noexec, runner -sha256sum - noexec, runner -sha3sum - noexec, runner -sha512sum - noexec, runner +sha1sum - noexec. runner +sha256sum - noexec. runner +sha3sum - noexec. runner +sha512sum - noexec. runner showkey - interactive shred - runner -shuf - noexec, runner +shuf - noexec. runner slattach sleep - runner smemcap - runner softlimit - spawner -sort - noexec, runner +sort - noexec. runner split - runner ssl_client - network start-stop-daemon -stat +stat - nofork candidate(needs fewer allocs) strings - runner stty su - suid, spawner @@ -326,11 +328,11 @@ svc svlogd - daemon swapoff - rare swapon - rare -switch_root - spawner, rare, change state +switch_root - spawner, rare, changes state sync - NOFORK sysctl syslogd - daemon -tac - noexec, runner +tac - noexec. runner tail - runner tar - runner taskset - spawner @@ -341,9 +343,9 @@ telnetd - daemon test - NOFORK tftp - runner tftpd - daemon -time - spawner, change state (signals) -timeout - spawner, change state (signals) -top - interactive +time - spawner, changes state (signals) +timeout - spawner, changes state (signals) +top - interactive, longterm touch - NOFORK tr - runner traceroute - suid, runner @@ -351,7 +353,7 @@ traceroute6 - suid, runner true - NOFORK truncate - NOFORK tty - NOFORK -ttysize +ttysize - NOFORK tunctl tune2fs ubiattach @@ -370,14 +372,14 @@ uname - NOFORK uncompress - runner unexpand - runner uniq - runner -unix2dos - noexec, runner +unix2dos - noexec. runner unlink - NOFORK unlzma - runner unlzop - runner unxz - runner unzip - runner -uptime -users +uptime - nofork candidate(is getutxent ok?) +users - nofork candidate(is getutxent ok?) usleep - NOFORK uudecode - runner uuencode - runner @@ -395,10 +397,10 @@ which - NOFORK who whoami - NOFORK whois -xargs - noexec, spawner -xxd - noexec, runner +xargs - noexec. spawner +xxd - noexec. runner xz - runner xzcat - runner -yes - noexec, runner +yes - noexec. runner zcat - runner zcip - daemon diff --git a/console-tools/resize.c b/console-tools/resize.c index 62928a01e..97866673a 100644 --- a/console-tools/resize.c +++ b/console-tools/resize.c @@ -23,7 +23,7 @@ //config: E.g.: //config: COLUMNS=80;LINES=44;export COLUMNS LINES; -//applet:IF_RESIZE(APPLET(resize, BB_DIR_USR_BIN, BB_SUID_DROP)) +//applet:IF_RESIZE(APPLET_NOEXEC(resize, resize, BB_DIR_USR_BIN, BB_SUID_DROP, resize)) //kbuild:lib-$(CONFIG_RESIZE) += resize.o diff --git a/coreutils/date.c b/coreutils/date.c index 2c6e1d4df..89b281646 100644 --- a/coreutils/date.c +++ b/coreutils/date.c @@ -58,7 +58,7 @@ //config: the same format. With it on, 'date DATE' additionally supports //config: MMDDhhmm[[YY]YY][.ss] format. -//applet:IF_DATE(APPLET(date, BB_DIR_BIN, BB_SUID_DROP)) +//applet:IF_DATE(APPLET_NOEXEC(date, date, BB_DIR_BIN, BB_SUID_DROP, date)) //kbuild:lib-$(CONFIG_DATE) += date.o @@ -152,12 +152,6 @@ enum { OPT_HINT = (1 << 6) * ENABLE_FEATURE_DATE_ISOFMT, /* D */ }; -static void maybe_set_utc(int opt) -{ - if (opt & OPT_UTC) - putenv((char*)"TZ=UTC0"); -} - #if ENABLE_LONG_OPTS static const char date_longopts[] ALIGN1 = "rfc-822\0" No_argument "R" @@ -170,6 +164,19 @@ static const char date_longopts[] ALIGN1 = ; #endif +/* We are a NOEXEC applet. + * Obstacles to NOFORK: + * - we change env + * - xasprintf result not freed + * - after xasprintf we use other xfuncs + */ + +static void maybe_set_utc(int opt) +{ + if (opt & OPT_UTC) + putenv((char*)"TZ=UTC0"); +} + int date_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; int date_main(int argc UNUSED_PARAM, char **argv) { diff --git a/coreutils/readlink.c b/coreutils/readlink.c index 9690290e3..7f8d6b239 100644 --- a/coreutils/readlink.c +++ b/coreutils/readlink.c @@ -20,7 +20,7 @@ //config: help //config: Enable the readlink option (-f). -//applet:IF_READLINK(APPLET(readlink, BB_DIR_USR_BIN, BB_SUID_DROP)) +//applet:IF_READLINK(APPLET_NOFORK(readlink, readlink, BB_DIR_USR_BIN, BB_SUID_DROP, readlink)) //kbuild:lib-$(CONFIG_READLINK) += readlink.o @@ -85,6 +85,7 @@ int readlink_main(int argc UNUSED_PARAM, char **argv) if (!(opt & 4)) /* not -v */ logmode = LOGMODE_NONE; + /* NOFORK: only one alloc is allowed; must free */ if (opt & 1) { /* -f */ buf = xmalloc_realpath(fname); } else { @@ -94,9 +95,7 @@ int readlink_main(int argc UNUSED_PARAM, char **argv) if (!buf) return EXIT_FAILURE; printf((opt & 2) ? "%s" : "%s\n", buf); - - if (ENABLE_FEATURE_CLEAN_UP) - free(buf); + free(buf); fflush_stdout_and_exit(EXIT_SUCCESS); } diff --git a/coreutils/realpath.c b/coreutils/realpath.c index 6a61c3dc8..f9c630135 100644 --- a/coreutils/realpath.c +++ b/coreutils/realpath.c @@ -13,7 +13,7 @@ //config: Return the canonicalized absolute pathname. //config: This isn't provided by GNU shellutils, but where else does it belong. -//applet:IF_REALPATH(APPLET(realpath, BB_DIR_USR_BIN, BB_SUID_DROP)) +//applet:IF_REALPATH(APPLET_NOFORK(realpath, realpath, BB_DIR_USR_BIN, BB_SUID_DROP, realpath)) //kbuild:lib-$(CONFIG_REALPATH) += realpath.o @@ -36,6 +36,7 @@ int realpath_main(int argc UNUSED_PARAM, char **argv) } do { + /* NOFORK: only one alloc is allowed; must free */ char *resolved_path = xmalloc_realpath(*argv); if (resolved_path != NULL) { puts(resolved_path); diff --git a/docs/nofork_noexec.txt b/docs/nofork_noexec.txt index 0ad4e6e60..cfb02145a 100644 --- a/docs/nofork_noexec.txt +++ b/docs/nofork_noexec.txt @@ -98,7 +98,7 @@ It itself calls run_nofork_applet(), if argv[0] turned out to be a name of a NOFORK applet. run_nofork_applet() saves/inits/restores option parsing, xfunc_error_retval, -applet_name. Thus, for example, caller does not need to worry about +logmode, applet_name. Thus, for example, caller does not need to worry about option_mask32 getting trashed. diff --git a/libbb/bb_pwd.c b/libbb/bb_pwd.c index 4829b723a..dca0a150b 100644 --- a/libbb/bb_pwd.c +++ b/libbb/bb_pwd.c @@ -31,9 +31,9 @@ struct group* FAST_FUNC xgetgrnam(const char *name) return gr; } - struct passwd* FAST_FUNC xgetpwuid(uid_t uid) { + /* Note: used in nofork applets (whoami), be careful not to leak anything */ struct passwd *pw = getpwuid(uid); if (!pw) bb_error_msg_and_die("unknown uid %u", (unsigned)uid); @@ -50,6 +50,7 @@ struct group* FAST_FUNC xgetgrgid(gid_t gid) char* FAST_FUNC xuid2uname(uid_t uid) { + /* Note: used in nofork applets (whoami), be careful not to leak anything */ struct passwd *pw = xgetpwuid(uid); return pw->pw_name; } diff --git a/libbb/vfork_daemon_rexec.c b/libbb/vfork_daemon_rexec.c index 576534ee5..487ecb0e4 100644 --- a/libbb/vfork_daemon_rexec.c +++ b/libbb/vfork_daemon_rexec.c @@ -92,6 +92,7 @@ struct nofork_save_area { void (*die_func)(void); const char *applet_name; uint32_t option_mask32; + smallint logmode; uint8_t xfunc_error_retval; }; static void save_nofork_data(struct nofork_save_area *save) @@ -100,6 +101,7 @@ static void save_nofork_data(struct nofork_save_area *save) save->die_func = die_func; save->applet_name = applet_name; save->option_mask32 = option_mask32; + save->logmode = logmode; save->xfunc_error_retval = xfunc_error_retval; } static void restore_nofork_data(struct nofork_save_area *save) @@ -108,6 +110,7 @@ static void restore_nofork_data(struct nofork_save_area *save) die_func = save->die_func; applet_name = save->applet_name; option_mask32 = save->option_mask32; + logmode = save->logmode; xfunc_error_retval = save->xfunc_error_retval; } @@ -118,8 +121,8 @@ int FAST_FUNC run_nofork_applet(int applet_no, char **argv) save_nofork_data(&old); + logmode = LOGMODE_STDIO; xfunc_error_retval = EXIT_FAILURE; - /* In case getopt() or getopt32() was already called: * reset the libc getopt() function, which keeps internal state. */ @@ -146,7 +149,6 @@ int FAST_FUNC run_nofork_applet(int applet_no, char **argv) /* Restoring some globals */ restore_nofork_data(&old); - /* Other globals can be simply reset to defaults */ GETOPT_RESET(); diff --git a/miscutils/ttysize.c b/miscutils/ttysize.c index 7f6a84308..2c2d4ec33 100644 --- a/miscutils/ttysize.c +++ b/miscutils/ttysize.c @@ -18,7 +18,7 @@ //config: error, but returns default 80x24. //config: Usage in shell scripts: width=`ttysize w`. -//applet:IF_TTYSIZE(APPLET(ttysize, BB_DIR_USR_BIN, BB_SUID_DROP)) +//applet:IF_TTYSIZE(APPLET_NOFORK(ttysize, ttysize, BB_DIR_USR_BIN, BB_SUID_DROP, ttysize)) //kbuild:lib-$(CONFIG_TTYSIZE) += ttysize.o diff --git a/procps/kill.c b/procps/kill.c index 09beefb2d..0ddae2f70 100644 --- a/procps/kill.c +++ b/procps/kill.c @@ -32,10 +32,10 @@ //config: in its own session, so it won't kill the shell that is running //config: the script it was called from. -//applet:IF_KILL(APPLET(kill, BB_DIR_BIN, BB_SUID_DROP)) -// APPLET_ODDNAME:name main location suid_type help -//applet:IF_KILLALL( APPLET_ODDNAME(killall, kill, BB_DIR_USR_BIN, BB_SUID_DROP, killall)) -//applet:IF_KILLALL5(APPLET_ODDNAME(killall5, kill, BB_DIR_USR_SBIN, BB_SUID_DROP, killall5)) +//applet:IF_KILL( APPLET_NOFORK(kill, kill, BB_DIR_BIN, BB_SUID_DROP, kill)) +// APPLET_NOFORK:name main location suid_type help +//applet:IF_KILLALL( APPLET_NOFORK(killall, kill, BB_DIR_USR_BIN, BB_SUID_DROP, killall)) +//applet:IF_KILLALL5(APPLET_NOFORK(killall5, kill, BB_DIR_USR_SBIN, BB_SUID_DROP, killall5)) //kbuild:lib-$(CONFIG_KILL) += kill.o //kbuild:lib-$(CONFIG_KILLALL) += kill.o @@ -87,7 +87,7 @@ * + we can't use xfunc here * + we can't use applet_name * + we can't use bb_show_usage - * (Above doesn't apply for killall[5] cases) + * (doesn't apply for killall[5], still should be careful b/c NOFORK) * * kill %n gets translated into kill ' -' by shell (note space!) * This is needed to avoid collision with kill -9 ... syntax diff --git a/procps/pwdx.c b/procps/pwdx.c index dac238950..84802bbcd 100644 --- a/procps/pwdx.c +++ b/procps/pwdx.c @@ -14,7 +14,7 @@ //config: help //config: Report current working directory of a process -//applet:IF_PWDX(APPLET(pwdx, BB_DIR_USR_BIN, BB_SUID_DROP)) +//applet:IF_PWDX(APPLET_NOFORK(pwdx, pwdx, BB_DIR_USR_BIN, BB_SUID_DROP, pwdx)) //kbuild:lib-$(CONFIG_PWDX) += pwdx.o @@ -50,6 +50,7 @@ int pwdx_main(int argc UNUSED_PARAM, char **argv) sprintf(buf, "/proc/%u/cwd", pid); + /* NOFORK: only one alloc is allowed; must free */ s = xmalloc_readlink(buf); // "pwdx /proc/1" says "/proc/1: DIR", not "1: DIR" printf("%s: %s\n", *argv, s ? s : strerror(errno == ENOENT ? ESRCH : errno)); -- cgit v1.2.3-55-g6feb From 72d725d7cc6d5cd8ad6c69f7efb3b7046931395b Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Thu, 3 Aug 2017 19:30:21 +0200 Subject: getopt: make it NOEXEC Signed-off-by: Denys Vlasenko --- NOFORK_NOEXEC.lst | 26 +++++++++++++------------- util-linux/getopt.c | 2 +- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/NOFORK_NOEXEC.lst b/NOFORK_NOEXEC.lst index 7073611a4..9fcef7823 100644 --- a/NOFORK_NOEXEC.lst +++ b/NOFORK_NOEXEC.lst @@ -129,7 +129,7 @@ ftpd - daemon ftpget - runner ftpput - runner fuser - complex -getopt +getopt - noexec. complex (many allocs) getty - interactive grep - runner groups - noexec @@ -160,16 +160,16 @@ insmod install - runner ionice - spawner iostat - runner -ip -ipaddr -ipcalc -ipcrm -ipcs -iplink -ipneigh -iproute -iprule -iptunnel +ip - noexec candidate +ipaddr - noexec candidate +ipcalc - noexec candidate +ipcrm - noexec candidate +ipcs - noexec candidate +iplink - noexec candidate +ipneigh - noexec candidate +iproute - noexec candidate +iprule - noexec candidate +iptunnel - noexec candidate kbd_mode kill - NOFORK killall - NOFORK @@ -257,8 +257,8 @@ poweroff - rare powertop - interactive, longterm printenv - NOFORK printf - NOFORK -ps -pscan +ps - noexec candidate +pscan - longterm pstree pwd - NOFORK pwdx - NOFORK diff --git a/util-linux/getopt.c b/util-linux/getopt.c index cf1bc592f..5fe0da7cd 100644 --- a/util-linux/getopt.c +++ b/util-linux/getopt.c @@ -47,7 +47,7 @@ //config: help //config: Enable support for long options (option -l). -//applet:IF_GETOPT(APPLET(getopt, BB_DIR_BIN, BB_SUID_DROP)) +//applet:IF_GETOPT(APPLET_NOEXEC(getopt, getopt, BB_DIR_BIN, BB_SUID_DROP, getopt)) //kbuild:lib-$(CONFIG_GETOPT) += getopt.o -- cgit v1.2.3-55-g6feb From 19c9f31af17f2c34e93c9c322b5c546ffbcda6ad Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Thu, 3 Aug 2017 19:52:47 +0200 Subject: nofork: fix a bug uncovered by hush testsuite (forgotten fflush) function old new delta run_nofork_applet 280 287 +7 Signed-off-by: Denys Vlasenko --- libbb/vfork_daemon_rexec.c | 2 ++ shell/hush_test/run-all | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/libbb/vfork_daemon_rexec.c b/libbb/vfork_daemon_rexec.c index 487ecb0e4..98512bb00 100644 --- a/libbb/vfork_daemon_rexec.c +++ b/libbb/vfork_daemon_rexec.c @@ -143,6 +143,8 @@ int FAST_FUNC run_nofork_applet(int applet_no, char **argv) applet_name = tmp_argv[0]; /* Finally we can call NOFORK applet's main() */ rc = applet_main[applet_no](argc, tmp_argv); + /* Important for shells: `which CMD` was failing */ + fflush_all(); } else { /* xfunc died in NOFORK applet */ } diff --git a/shell/hush_test/run-all b/shell/hush_test/run-all index 1dd0edc39..3fbc7c531 100755 --- a/shell/hush_test/run-all +++ b/shell/hush_test/run-all @@ -80,7 +80,7 @@ do_test() case $? in 0) echo " ok";; 77) echo " skip (feature disabled)";; - *) echo " fail"; tret=1;; + *) echo " fail ($?)"; tret=1;; esac done exit ${tret} -- cgit v1.2.3-55-g6feb From cfd392bea9f52539baae9be4833075e464075958 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Thu, 3 Aug 2017 19:56:29 +0200 Subject: ash: add a fixme comment at run_nofork_applet Signed-off-by: Denys Vlasenko --- shell/ash.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/shell/ash.c b/shell/ash.c index b285e3d33..8c9f4adc6 100644 --- a/shell/ash.c +++ b/shell/ash.c @@ -9918,11 +9918,13 @@ evalcommand(union node *cmd, int flags) if (applet_no >= 0 && APPLET_IS_NOFORK(applet_no)) { listsetvar(varlist.list, VEXPORT|VSTACK); /* run _main() */ +//FIXME: do we need INT_OFF / INT_ON here? +//wouldn't open files and allocations leak on ^C otherwise? status = run_nofork_applet(applet_no, argv); break; } #endif - /* Can we avoid forking off? For example, very last command + /* Can we avoid forking? For example, very last command * in a script or a subshell does not need forking, * we can just exec it. */ -- cgit v1.2.3-55-g6feb From 4dc86699b57ff35c287ca396d562ec206776694a Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Fri, 4 Aug 2017 02:01:45 +0200 Subject: microcom: require exactly one non-option Signed-off-by: Denys Vlasenko --- miscutils/microcom.c | 1 + 1 file changed, 1 insertion(+) diff --git a/miscutils/microcom.c b/miscutils/microcom.c index 14b9f3baf..f382edebb 100644 --- a/miscutils/microcom.c +++ b/miscutils/microcom.c @@ -74,6 +74,7 @@ int microcom_main(int argc UNUSED_PARAM, char **argv) unsigned opts; // fetch options + opt_complementary = "=1"; opts = getopt32(argv, "Xs:+d:+t:+", &speed, &delay, &timeout); // argc -= optind; argv += optind; -- cgit v1.2.3-55-g6feb From 3346b4afc5c81d53eae4e7fc7e12ebd6fa573a4e Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Fri, 4 Aug 2017 02:56:39 +0200 Subject: modutils: make them NOEXEC except depmod Signed-off-by: Denys Vlasenko --- NOFORK_NOEXEC.lst | 10 +++++----- modutils/insmod.c | 2 +- modutils/lsmod.c | 2 +- modutils/modinfo.c | 2 +- modutils/modprobe-small.c | 15 +++++++++------ modutils/modprobe.c | 2 +- modutils/rmmod.c | 2 +- 7 files changed, 19 insertions(+), 16 deletions(-) diff --git a/NOFORK_NOEXEC.lst b/NOFORK_NOEXEC.lst index 9fcef7823..12ae1cd55 100644 --- a/NOFORK_NOEXEC.lst +++ b/NOFORK_NOEXEC.lst @@ -156,7 +156,7 @@ ifplugd - daemon inetd - daemon init - daemon inotifyd - daemon -insmod +insmod - noexec install - runner ionice - spawner iostat - runner @@ -193,7 +193,7 @@ lpq - runner lpr - runner ls - noexec. runner lsattr -lsmod +lsmod - noexec lsof - complex lspci lsscsi @@ -220,8 +220,8 @@ mknod - noexec mkpasswd mkswap mktemp -modinfo -modprobe +modinfo - noexec +modprobe - noexec more - interactive mount - suid mountpoint @@ -277,7 +277,7 @@ resize - noexec. changes state (signal handlers) rev - runner rm - noexec. rm -i interactive rmdir - NOFORK -rmmod +rmmod - noexec route rpm - runner rpm2cpio - runner diff --git a/modutils/insmod.c b/modutils/insmod.c index b8ede8a81..4dc0b6608 100644 --- a/modutils/insmod.c +++ b/modutils/insmod.c @@ -13,7 +13,7 @@ //config: help //config: insmod is used to load specified modules in the running kernel. -//applet:IF_INSMOD(IF_NOT_MODPROBE_SMALL(APPLET(insmod, BB_DIR_SBIN, BB_SUID_DROP))) +//applet:IF_INSMOD(IF_NOT_MODPROBE_SMALL(APPLET_NOEXEC(insmod, insmod, BB_DIR_SBIN, BB_SUID_DROP, insmod))) //kbuild:ifneq ($(CONFIG_MODPROBE_SMALL),y) //kbuild:lib-$(CONFIG_INSMOD) += insmod.o modutils.o diff --git a/modutils/lsmod.c b/modutils/lsmod.c index 4bf8f8481..84860cd79 100644 --- a/modutils/lsmod.c +++ b/modutils/lsmod.c @@ -23,7 +23,7 @@ //config: the format of module-init-tools for Linux kernel 2.6. //config: Increases size somewhat. -//applet:IF_LSMOD(IF_NOT_MODPROBE_SMALL(APPLET(lsmod, BB_DIR_SBIN, BB_SUID_DROP))) +//applet:IF_LSMOD(IF_NOT_MODPROBE_SMALL(APPLET_NOEXEC(lsmod, lsmod, BB_DIR_SBIN, BB_SUID_DROP, lsmod))) //kbuild:ifneq ($(CONFIG_MODPROBE_SMALL),y) //kbuild:lib-$(CONFIG_LSMOD) += lsmod.o modutils.o diff --git a/modutils/modinfo.c b/modutils/modinfo.c index 371c93991..0f1d3ee47 100644 --- a/modutils/modinfo.c +++ b/modutils/modinfo.c @@ -12,7 +12,7 @@ //config: help //config: Show information about a Linux Kernel module -//applet:IF_MODINFO(APPLET(modinfo, BB_DIR_SBIN, BB_SUID_DROP)) +//applet:IF_MODINFO(APPLET_NOEXEC(modinfo, modinfo, BB_DIR_SBIN, BB_SUID_DROP, modinfo)) //kbuild:lib-$(CONFIG_MODINFO) += modinfo.o modutils.o diff --git a/modutils/modprobe-small.c b/modutils/modprobe-small.c index 053a7df89..cd4f554f3 100644 --- a/modutils/modprobe-small.c +++ b/modutils/modprobe-small.c @@ -11,12 +11,15 @@ /* modprobe-small configs are defined in Config.src to ensure better * "make config" order */ -//applet:IF_LSMOD( IF_MODPROBE_SMALL(APPLET(lsmod, BB_DIR_SBIN, BB_SUID_DROP))) -//applet:IF_MODPROBE(IF_MODPROBE_SMALL(APPLET(modprobe, BB_DIR_SBIN, BB_SUID_DROP))) -// APPLET_ODDNAME:name main location suid_type help -//applet:IF_DEPMOD(IF_MODPROBE_SMALL(APPLET_ODDNAME(depmod, modprobe, BB_DIR_SBIN, BB_SUID_DROP, depmod))) -//applet:IF_INSMOD(IF_MODPROBE_SMALL(APPLET_ODDNAME(insmod, modprobe, BB_DIR_SBIN, BB_SUID_DROP, insmod))) -//applet:IF_RMMOD( IF_MODPROBE_SMALL(APPLET_ODDNAME(rmmod, modprobe, BB_DIR_SBIN, BB_SUID_DROP, rmmod))) +//applet:IF_LSMOD( IF_MODPROBE_SMALL(APPLET_NOEXEC( lsmod, lsmod, BB_DIR_SBIN, BB_SUID_DROP, lsmod ))) +//applet:IF_MODPROBE(IF_MODPROBE_SMALL(APPLET_NOEXEC( modprobe, modprobe, BB_DIR_SBIN, BB_SUID_DROP, modprobe))) +// APPLET_ODDNAME:name main location suid_type help +//applet:IF_DEPMOD( IF_MODPROBE_SMALL(APPLET_ODDNAME(depmod, modprobe, BB_DIR_SBIN, BB_SUID_DROP, depmod ))) +//applet:IF_INSMOD( IF_MODPROBE_SMALL(APPLET_NOEXEC( insmod, modprobe, BB_DIR_SBIN, BB_SUID_DROP, insmod ))) +//applet:IF_RMMOD( IF_MODPROBE_SMALL(APPLET_NOEXEC( rmmod, modprobe, BB_DIR_SBIN, BB_SUID_DROP, rmmod ))) +/* noexec speeds up boot with many modules loaded (need SH_STANDALONE=y) */ +/* I measured about ~5 times faster insmod */ +/* depmod is not noexec, it runs longer and benefits from memory trimming via exec */ //kbuild:lib-$(CONFIG_MODPROBE_SMALL) += modprobe-small.o diff --git a/modutils/modprobe.c b/modutils/modprobe.c index 1a7db09f2..e899935c4 100644 --- a/modutils/modprobe.c +++ b/modutils/modprobe.c @@ -26,7 +26,7 @@ //config: hardware autodetection scripts to load modules like evdev, frame //config: buffer drivers etc. -//applet:IF_MODPROBE(IF_NOT_MODPROBE_SMALL(APPLET(modprobe, BB_DIR_SBIN, BB_SUID_DROP))) +//applet:IF_MODPROBE(IF_NOT_MODPROBE_SMALL(APPLET_NOEXEC(modprobe, modprobe, BB_DIR_SBIN, BB_SUID_DROP, modprobe))) //kbuild:ifneq ($(CONFIG_MODPROBE_SMALL),y) //kbuild:lib-$(CONFIG_MODPROBE) += modprobe.o modutils.o diff --git a/modutils/rmmod.c b/modutils/rmmod.c index d60e49413..df50e58af 100644 --- a/modutils/rmmod.c +++ b/modutils/rmmod.c @@ -14,7 +14,7 @@ //config: help //config: rmmod is used to unload specified modules from the kernel. -//applet:IF_RMMOD(IF_NOT_MODPROBE_SMALL(APPLET(rmmod, BB_DIR_SBIN, BB_SUID_DROP))) +//applet:IF_RMMOD(IF_NOT_MODPROBE_SMALL(APPLET_NOEXEC(rmmod, rmmod, BB_DIR_SBIN, BB_SUID_DROP, rmmod))) //kbuild:ifneq ($(CONFIG_MODPROBE_SMALL),y) //kbuild:lib-$(CONFIG_RMMOD) += rmmod.o modutils.o -- cgit v1.2.3-55-g6feb From 49e6bf2db92d896a71d08eb364069ba50fa82781 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Fri, 4 Aug 2017 14:28:16 +0200 Subject: sheel: improve comments on signal handling Signed-off-by: Denys Vlasenko --- NOFORK_NOEXEC.lst | 4 +++- docs/nofork_noexec.txt | 24 +++++++++++++++++++----- shell/ash.c | 27 ++++++++++++++++----------- shell/hush.c | 7 +++++++ 4 files changed, 45 insertions(+), 17 deletions(-) diff --git a/NOFORK_NOEXEC.lst b/NOFORK_NOEXEC.lst index 12ae1cd55..14019bf7d 100644 --- a/NOFORK_NOEXEC.lst +++ b/NOFORK_NOEXEC.lst @@ -4,10 +4,12 @@ Why can't be NOFORK: interactive: may wait for user input, ^C has to work spawner: "tool PROG ARGS" which changes program's environment - must fork changes state: e.g. environment, signal handlers +alloc+xfunc: xmalloc, then xfunc - leaks memory if xfunc dies +open+xfunc: opens fd, then calls xfunc - fd is leaked if xfunc dies runner: sometimes may run for long(ish) time, and/or works with network: ^C has to work (cat BIGFILE, chmod -R, ftpget, nc) -"runners" can become eligible after hush is taught ^C to interrupt NOFORKs! +"runners" can become eligible after shell is taught ^C to interrupt NOFORKs! Why can't be NOEXEC: suid: runs under different uid - must fork+exec diff --git a/docs/nofork_noexec.txt b/docs/nofork_noexec.txt index cfb02145a..b45a4be89 100644 --- a/docs/nofork_noexec.txt +++ b/docs/nofork_noexec.txt @@ -64,15 +64,27 @@ This poses much more serious limitations on what applet can do: * do not use shared global data, or save/restore shared global data (e.g. bb_common_bufsiz1) prior to returning. - getopt32() is ok to use. You do not need to save/restore option_mask32, - it is already done by core code. + xfunc_error_retval, and logmode - it is already done by core code. * if you allocate memory, you can use xmalloc() only on the very first allocation. All other allocations should use malloc[_or_warn](). After first allocation, you cannot use any xfuncs. Otherwise, failing xfunc will return to caller applet without freeing malloced data! -* All allocated data, opened files, signal handlers, termios settings, - O_NONBLOCK flags etc should be freed/closed/restored prior to return. -* ... +* the same applies to other resources, such as open fds: no xfuncs after + acquiring them! +* All allocated data, opened files, signal handlers, termios settings + etc should be freed/closed/restored prior to return. + +Currently, ash shell signal handling is implemented in a way that signals +have non-SA_RESTARTed handlers. This means that system calls can +return EINTR. An example of such problem is "yes" applet: +it is implemented so that it has a writing loop, this loop is exited on +any write error, and in the case of user pressing ^C the error was EINTR. +The problem is, the error causes stdout FILE* object to get into error +state, needing clearerr() - or else subsequent shell output will also +not work. ("yes" has been downgraded to NOEXEC, since hush signal handling +does not have this problem - which makes "yes" to not exit on ^C (bug). +But stray EINTRs can be seen in any NOFORK under ash, until ash is fixed). NOFORK applets give the most of speed advantage, but are trickiest to implement. In order to minimize amount of bugs and maintenance, @@ -82,6 +94,8 @@ frequently executed from shell/find/xargs, particularly in shell script loops. Applets which mess with signal handlers, termios etc are probably not worth the effort. +Applets which must be interruptible by ^C in shells can not be NOFORKs. + Any NOFORK applet is also a NOEXEC applet. @@ -94,7 +108,7 @@ API to call NOFORK applets is two functions: First one is directly used by shells if FEATURE_SH_NOFORK=y. Second one is used by many applets, but main users are xargs and find. -It itself calls run_nofork_applet(), if argv[0] turned out to be a name +It itself calls run_nofork_applet(), if argv[0] is a name of a NOFORK applet. run_nofork_applet() saves/inits/restores option parsing, xfunc_error_retval, diff --git a/shell/ash.c b/shell/ash.c index 8c9f4adc6..ca9926b54 100644 --- a/shell/ash.c +++ b/shell/ash.c @@ -3536,9 +3536,12 @@ setsignal(int signo) #endif } } -//TODO: if !rootshell, we reset SIGQUIT to DFL, -//whereas we have to restore it to what shell got on entry -//from the parent. See comment above + /* if !rootshell, we reset SIGQUIT to DFL, + * whereas we have to restore it to what shell got on entry. + * This is handled by the fact that if signal was IGNored on entry, + * then cur_act is S_HARD_IGN and we never change its sigaction + * (see code below). + */ if (signo == SIGCHLD) new_act = S_CATCH; @@ -3566,6 +3569,8 @@ setsignal(int signo) if (cur_act == S_HARD_IGN || cur_act == new_act) return; + *t = new_act; + act.sa_handler = SIG_DFL; switch (new_act) { case S_CATCH: @@ -3575,16 +3580,13 @@ setsignal(int signo) act.sa_handler = SIG_IGN; break; } - /* flags and mask matter only if !DFL and !IGN, but we do it * for all cases for more deterministic behavior: */ - act.sa_flags = 0; + act.sa_flags = 0; //TODO: why not SA_RESTART? sigfillset(&act.sa_mask); sigaction_set(signo, &act); - - *t = new_act; } /* mode flags for set_curjob */ @@ -13429,7 +13431,9 @@ readcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) INT_ON; if ((uintptr_t)r == 1 && errno == EINTR) { - /* to get SIGCHLD: sleep 1 & read x; echo $x */ + /* To get SIGCHLD: sleep 1 & read x; echo $x + * Correct behavior is to not exit "read" + */ if (pending_sig == 0) goto again; } @@ -13544,13 +13548,14 @@ exitshell(void) /* NOTREACHED */ } -static void +/* Don't inline: conserve stack of caller from having our locals too */ +static NOINLINE void init(void) { /* we will never free this */ basepf.next_to_pgetc = basepf.buf = ckmalloc(IBUFSIZ); - sigmode[SIGCHLD - 1] = S_DFL; + sigmode[SIGCHLD - 1] = S_DFL; /* ensure we install handler even if it is SIG_IGNed */ setsignal(SIGCHLD); /* bash re-enables SIGHUP which is SIG_IGNed on entry. @@ -13561,7 +13566,6 @@ init(void) { char **envp; const char *p; - struct stat st1, st2; initvar(); for (envp = environ; envp && *envp; envp++) { @@ -13587,6 +13591,7 @@ init(void) #endif p = lookupvar("PWD"); if (p) { + struct stat st1, st2; if (p[0] != '/' || stat(p, &st1) || stat(".", &st2) || st1.st_dev != st2.st_dev || st1.st_ino != st2.st_ino ) { diff --git a/shell/hush.c b/shell/hush.c index b04f793f1..bb80f422c 100644 --- a/shell/hush.c +++ b/shell/hush.c @@ -1979,6 +1979,9 @@ static int check_and_run_traps(void) break; #if ENABLE_HUSH_JOB case SIGHUP: { +//TODO: why are we doing this? ash and dash don't do this, +//they have no handler for SIGHUP at all, +//they rely on kernel to send SIGHUP+SIGCONT to orphaned process groups struct pipe *job; debug_printf_exec("%s: sig:%d default SIGHUP handler\n", __func__, sig); /* bash is observed to signal whole process groups, @@ -8646,6 +8649,10 @@ static void install_sighandlers(unsigned mask) */ if (sig == SIGCHLD) continue; + /* bash re-enables SIGHUP which is SIG_IGNed on entry. + * Try: "trap '' HUP; bash; echo RET" and type "kill -HUP $$" + */ + //if (sig == SIGHUP) continue; - TODO? if (old_handler == SIG_IGN) { /* oops... restore back to IGN, and record this fact */ install_sighandler(sig, old_handler); -- cgit v1.2.3-55-g6feb From d329e34c96e0429602fe39489586cd61f97a2877 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Fri, 4 Aug 2017 14:50:03 +0200 Subject: ash: INT_OFF/INT_ON around run_nofork_applet() function old new delta evalcommand 1441 1447 +6 Signed-off-by: Denys Vlasenko --- shell/ash.c | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/shell/ash.c b/shell/ash.c index ca9926b54..2afa5e83d 100644 --- a/shell/ash.c +++ b/shell/ash.c @@ -9919,10 +9919,26 @@ evalcommand(union node *cmd, int flags) int applet_no = (- cmdentry.u.index - 2); if (applet_no >= 0 && APPLET_IS_NOFORK(applet_no)) { listsetvar(varlist.list, VEXPORT|VSTACK); - /* run _main() */ -//FIXME: do we need INT_OFF / INT_ON here? -//wouldn't open files and allocations leak on ^C otherwise? + /* + * Run _main(). + * Signals (^C) can't interrupt here. + * Otherwise we can mangle stdio or malloc internal state. + * This makes applets which can run for a long time + * and/or wait for user input ineligible for NOFORK: + * for example, "yes" or "rm" (rm -i waits for input). + */ + INT_OFF; status = run_nofork_applet(applet_no, argv); + /* + * Try enabling NOFORK for "yes" applet. + * ^C _will_ stop it (write returns EINTR), + * but this causes stdout FILE to be stuck + * and needing clearerr(). What if other applets + * also can get EINTRs? Do we need to switch + * our signals to SA_RESTART? + */ + /*clearerr(stdout);*/ + INT_ON; break; } #endif -- cgit v1.2.3-55-g6feb From 7344755823df5510b089cc5db30f8c1cdebdc5a2 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Fri, 4 Aug 2017 12:16:46 +0200 Subject: ash: remove no-longer-used variable As of 035486c75 (ash: significant overhaul of redirect saving logic, 2017-07-31), the sv_pos variable is no longer used (just assigned to, with no further effect). Let's just remove it. Signed-off-by: Johannes Schindelin Signed-off-by: Denys Vlasenko --- shell/ash.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/shell/ash.c b/shell/ash.c index 2afa5e83d..2ad86c187 100644 --- a/shell/ash.c +++ b/shell/ash.c @@ -5546,12 +5546,10 @@ static void redirect(union node *redir, int flags) { struct redirtab *sv; - int sv_pos; if (!redir) return; - sv_pos = 0; sv = NULL; INT_OFF; if (flags & REDIR_PUSH) -- cgit v1.2.3-55-g6feb From f8cdc7a2bcd0a9d067f5ca7da8ce7bc9c98cf34e Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Fri, 4 Aug 2017 15:24:49 +0200 Subject: ash: BASH_XTRACEFD bashism Based on patch by Johannes Schindelin function old new delta evalcommand 1447 1500 +53 Signed-off-by: Denys Vlasenko --- shell/ash.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/shell/ash.c b/shell/ash.c index 2ad86c187..e80425f5e 100644 --- a/shell/ash.c +++ b/shell/ash.c @@ -188,6 +188,7 @@ #define BASH_PIPEFAIL ENABLE_ASH_BASH_COMPAT #define BASH_HOSTNAME_VAR ENABLE_ASH_BASH_COMPAT #define BASH_SHLVL_VAR ENABLE_ASH_BASH_COMPAT +#define BASH_XTRACEFD ENABLE_ASH_BASH_COMPAT #if defined(__ANDROID_API__) && __ANDROID_API__ <= 24 /* Bionic at least up to version 24 has no glob() */ @@ -9792,6 +9793,15 @@ evalcommand(union node *cmd, int flags) expredir(cmd->ncmd.redirect); redir_stop = pushredir(cmd->ncmd.redirect); preverrout_fd = 2; + if (BASH_XTRACEFD && xflag) { + /* NB: bash closes fd == $BASH_XTRACEFD when it is changed. + * we do not emulate this. We only use its value. + */ + const char *xtracefd = lookupvar("BASH_XTRACEFD"); + if (xtracefd && is_number(xtracefd)) + preverrout_fd = atoi(xtracefd); + + } status = redirectsafe(cmd->ncmd.redirect, REDIR_PUSH | REDIR_SAVEFD2); path = vpath.var_text; -- cgit v1.2.3-55-g6feb From 7f9d62d7f5b67b6b1cc7e0b94826ba2a6e193586 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Fri, 4 Aug 2017 16:01:39 +0200 Subject: tweak NOFORK_NOEXEC.lst Signed-off-by: Denys Vlasenko --- NOFORK_NOEXEC.lst | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/NOFORK_NOEXEC.lst b/NOFORK_NOEXEC.lst index 14019bf7d..74922ff52 100644 --- a/NOFORK_NOEXEC.lst +++ b/NOFORK_NOEXEC.lst @@ -2,26 +2,28 @@ Why an applet can't be NOFORK or NOEXEC? Why can't be NOFORK: interactive: may wait for user input, ^C has to work -spawner: "tool PROG ARGS" which changes program's environment - must fork +spawner: "tool PROG ARGS" which changes program state and execs - must fork changes state: e.g. environment, signal handlers alloc+xfunc: xmalloc, then xfunc - leaks memory if xfunc dies open+xfunc: opens fd, then calls xfunc - fd is leaked if xfunc dies +leaks: does not free allocated memory or opened fds runner: sometimes may run for long(ish) time, and/or works with network: ^C has to work (cat BIGFILE, chmod -R, ftpget, nc) -"runners" can become eligible after shell is taught ^C to interrupt NOFORKs! +"runners" can become eligible after shell is taught ^C to interrupt NOFORKs, +need to be inspected that they do not fall into alloc+xfunc, open+xfunc +categories. Why can't be NOEXEC: suid: runs under different uid - must fork+exec Why shouldn't be NOFORK/NOEXEC: -complex: no immediately obvious reason why NOFORK wouldn't work, - but does some non-obvoius operations (example: fuser, lsof, losetup); - nested xmallocs (typical in complex code) is a problem for NOFORK -rare: not used often enough to bother optimizing (example: poweroff) +rare: not started often enough to bother optimizing (example: poweroff) +daemon: runs indefinitely; these are also always fit "rare" category longterm: often runs for a long time (many seconds), execing would make memory footprint smaller -daemon: runs indefinitely +complex: no immediately obvious reason why NOFORK wouldn't work, + but does some non-obvoius operations (example: fuser, lsof, losetup) [ - NOFORK [[ - NOFORK @@ -59,7 +61,7 @@ chpasswd - runner (list of "user:password"s from stdin) chpst - spawner chroot - spawner chrt - spawner -chvt +chvt - leaks: get_console_fd_or_die() may open a new fd, or return one of stdio fds. Also, "rare" category. Can be noexec. cksum - noexec. runner clear - NOFORK cmp - runner @@ -69,7 +71,7 @@ cp - noexec. runner cpio - runner crond - daemon crontab -cryptpw +cryptpw - changes state: with --password-fd=N, moves N to stdin. Also, "rare" category. Can be noexec. cttyhack - spawner cut - noexec. runner date - noexec. nofork candidate(needs to stop messing up env, free xasprintf result, not use xfuncs after xasprintf) -- cgit v1.2.3-55-g6feb From 727948e585cb133c32c8d42570e5524c58190307 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Fri, 4 Aug 2017 16:23:42 +0200 Subject: getopt32: factor out code to treat all args as options Working towards making getopt32() xmalloc-free function old new delta make_all_argv_opts - 58 +58 top_main 914 912 -2 getopt32 1517 1458 -59 ------------------------------------------------------------------------------ (add/remove: 2/0 grow/shrink: 0/2 up/down: 58/-61) Total: -3 bytes Signed-off-by: Denys Vlasenko --- include/libbb.h | 4 +++- libbb/Kbuild.src | 1 - libbb/getopt32.c | 31 ++++++------------------------- libbb/getopt_allopts.c | 27 +++++++++++++++++++++++++++ procps/ps.c | 5 +++-- procps/top.c | 5 ++--- 6 files changed, 41 insertions(+), 32 deletions(-) create mode 100644 libbb/getopt_allopts.c diff --git a/include/libbb.h b/include/libbb.h index 46180c5aa..bb27c59a1 100644 --- a/include/libbb.h +++ b/include/libbb.h @@ -1183,7 +1183,9 @@ extern const char *opt_complementary; extern const char *applet_long_options; #endif extern uint32_t option_mask32; -extern uint32_t getopt32(char **argv, const char *applet_opts, ...) FAST_FUNC; +uint32_t getopt32(char **argv, const char *applet_opts, ...) FAST_FUNC; +/* For top, ps. Some argv[i] are replaced by malloced "-opt" strings */ +void make_all_argv_opts(char **argv) FAST_FUNC; /* BSD-derived getopt() functions require that optind be set to 1 in * order to reset getopt() state. This used to be generally accepted * way of resetting getopt(). However, glibc's getopt() diff --git a/libbb/Kbuild.src b/libbb/Kbuild.src index 458973f17..73201a6bd 100644 --- a/libbb/Kbuild.src +++ b/libbb/Kbuild.src @@ -40,7 +40,6 @@ lib-y += full_write.o lib-y += get_console.o lib-y += get_last_path_component.o lib-y += get_line_from_file.o -lib-y += getopt32.o lib-y += getpty.o lib-y += get_volsize.o lib-y += herror_msg.o diff --git a/libbb/getopt32.c b/libbb/getopt32.c index 80f4cc060..129840cea 100644 --- a/libbb/getopt32.c +++ b/libbb/getopt32.c @@ -6,12 +6,13 @@ * * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ - #if ENABLE_LONG_OPTS || ENABLE_FEATURE_GETOPT_LONG # include #endif #include "libbb.h" +//kbuild:lib-y += getopt32.o + /* Documentation uint32_t @@ -170,21 +171,6 @@ const char *opt_complementary Special characters: - "-" A group consisting of just a dash 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. - Example: - - opt_complementary = "-:w-x:x-w"; // "-w-x:x-w" would also work, - getopt32(argv, "wx"); // but is less readable - - This makes it possible to use options without a dash (./program w x) - as well as with a dash (./program -x). - - NB: getopt32() will leak a small amount of memory if you use - this option! Do not use it if there is a possibility of recursive - getopt32() calls. - "--" 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 @@ -373,8 +359,7 @@ getopt32(char **argv, const char *applet_opts, ...) int max_arg = -1; #define SHOW_USAGE_IF_ERROR 1 -#define ALL_ARGV_IS_OPTS 2 -#define FIRST_ARGV_IS_OPT 4 +#define FIRST_ARGV_IS_OPT 2 int spec_flgs = 0; @@ -486,8 +471,7 @@ getopt32(char **argv, const char *applet_opts, ...) if (c == '-') { spec_flgs |= FIRST_ARGV_IS_OPT; s++; - } else - spec_flgs |= ALL_ARGV_IS_OPTS; + } } else { min_arg = c - '0'; s++; @@ -551,9 +535,9 @@ getopt32(char **argv, const char *applet_opts, ...) opt_complementary = NULL; va_end(p); - if (spec_flgs & (FIRST_ARGV_IS_OPT | ALL_ARGV_IS_OPTS)) { + if (spec_flgs & FIRST_ARGV_IS_OPT) { pargv = argv + 1; - while (*pargv) { + if (*pargv) { if (pargv[0][0] != '-' && pargv[0][0] != '\0') { /* Can't use alloca: opts with params will * return pointers to stack! @@ -563,9 +547,6 @@ getopt32(char **argv, const char *applet_opts, ...) strcpy(pp + 1, *pargv); *pargv = pp; } - if (!(spec_flgs & ALL_ARGV_IS_OPTS)) - break; - pargv++; } } diff --git a/libbb/getopt_allopts.c b/libbb/getopt_allopts.c new file mode 100644 index 000000000..a67d2b70e --- /dev/null +++ b/libbb/getopt_allopts.c @@ -0,0 +1,27 @@ +/* vi: set sw=4 ts=4: */ +/* + * Copyright (C) 2017 Denys Vlasenko + * + * Licensed under GPLv2 or later, see file LICENSE in this source tree. + */ +#include "libbb.h" + +//kbuild:lib-y += getopt_allopts.o + +void FAST_FUNC make_all_argv_opts(char **argv) +{ + /* Note: we skip argv[0] */ + while (*++argv) { + char *p; + + if (argv[0][0] == '-') + continue; + /* Neither top nor ps care if "" arg turns into "-" */ + /*if (argv[0][0] == '\0') + continue;*/ + p = xmalloc(strlen(*argv) + 2); + *p = '-'; + strcpy(p + 1, *argv); + *argv = p; + } +} diff --git a/procps/ps.c b/procps/ps.c index eb1946d27..081479b33 100644 --- a/procps/ps.c +++ b/procps/ps.c @@ -715,7 +715,8 @@ int ps_main(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) # if ENABLE_FEATURE_PS_WIDE /* -w is a bit complicated */ int w_count = 0; - opt_complementary = "-:ww"; + make_all_argv_opts(argv); + opt_complementary = "ww"; opts = getopt32(argv, IF_SELINUX("Z")IF_FEATURE_SHOW_THREADS("T")IF_FEATURE_PS_LONG("l") "w", &w_count); /* if w is given once, GNU ps sets the width to 132, @@ -731,7 +732,7 @@ int ps_main(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) } # else /* -w is not supported, only -Z and/or -T */ - opt_complementary = "-"; + make_all_argv_opts(argv); opts = getopt32(argv, IF_SELINUX("Z")IF_FEATURE_SHOW_THREADS("T")IF_FEATURE_PS_LONG("l")); # endif diff --git a/procps/top.c b/procps/top.c index 015d1ab74..1bc432fc9 100644 --- a/procps/top.c +++ b/procps/top.c @@ -1110,15 +1110,14 @@ int top_main(int argc UNUSED_PARAM, char **argv) #endif /* all args are options; -n NUM */ - opt_complementary = "-"; /* options can be specified w/o dash */ + make_all_argv_opts(argv); /* options can be specified w/o dash */ col = getopt32(argv, "d:n:b"IF_FEATURE_TOPMEM("m"), &str_interval, &str_iterations); #if ENABLE_FEATURE_TOPMEM if (col & OPT_m) /* -m (busybox specific) */ scan_mask = TOPMEM_MASK; #endif if (col & OPT_d) { - /* work around for "-d 1" -> "-d -1" done by getopt32 - * (opt_complementary == "-" does this) */ + /* work around for "-d 1" -> "-d -1" done by make_all_argv_opts() */ if (str_interval[0] == '-') str_interval++; /* Need to limit it to not overflow poll timeout */ -- cgit v1.2.3-55-g6feb From dd5a40246b91bd5d3d165998e6ac3cc4f7083f63 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Fri, 4 Aug 2017 16:46:17 +0200 Subject: getopt32: move support for "always treat first arg as option" to users (tar/ar) Now getopt() never leaks (and never performs) any xmalloc's. function old new delta ar_main 522 556 +34 tar_main 986 1014 +28 getopt32 1458 1350 -108 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 2/1 up/down: 62/-108) Total: -46 bytes Signed-off-by: Denys Vlasenko --- archival/ar.c | 6 ++++-- archival/tar.c | 4 +++- libbb/getopt32.c | 36 +++--------------------------------- 3 files changed, 10 insertions(+), 36 deletions(-) diff --git a/archival/ar.c b/archival/ar.c index 2886d155b..46c10aad4 100644 --- a/archival/ar.c +++ b/archival/ar.c @@ -240,10 +240,12 @@ int ar_main(int argc UNUSED_PARAM, char **argv) archive_handle = init_handle(); - /* --: prepend '-' to the first argument if required */ + /* prepend '-' to the first argument if required */ + if (argv[1] && argv[1][0] != '-' && argv[1][0] != '\0') + argv[1] = xasprintf("-%s", argv[1]); /* -1: at least one param is reqd */ /* one of p,t,x[,r] is required */ - opt_complementary = "--:-1:p:t:x"IF_FEATURE_AR_CREATE(":r"); + opt_complementary = "-1:p:t:x"IF_FEATURE_AR_CREATE(":r"); opt = getopt32(argv, "voc""ptx"IF_FEATURE_AR_CREATE("r")); argv += optind; diff --git a/archival/tar.c b/archival/tar.c index 280ded4e1..f62b33005 100644 --- a/archival/tar.c +++ b/archival/tar.c @@ -966,7 +966,9 @@ int tar_main(int argc UNUSED_PARAM, char **argv) tar_handle->ah_flags |= ARCHIVE_DONT_RESTORE_PERM; /* Prepend '-' to the first argument if required */ - opt_complementary = "--:" // first arg is options + if (argv[1] && argv[1][0] != '-' && argv[1][0] != '\0') + argv[1] = xasprintf("-%s", argv[1]); + opt_complementary = "tt:vv:" // count -t,-v #if ENABLE_FEATURE_TAR_LONG_OPTIONS && ENABLE_FEATURE_TAR_FROM "\xff::" // --exclude=PATTERN is a list diff --git a/libbb/getopt32.c b/libbb/getopt32.c index 129840cea..513415894 100644 --- a/libbb/getopt32.c +++ b/libbb/getopt32.c @@ -171,16 +171,6 @@ const char *opt_complementary Special characters: - "--" 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 - - NB: getopt32() will leak a small amount of memory if you use - this option! Do not use it if there is a possibility of recursive - getopt32() calls. - "-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 @@ -337,6 +327,8 @@ const char *applet_long_options; uint32_t option_mask32; +/* Please keep getopt32 free from xmalloc */ + uint32_t FAST_FUNC getopt32(char **argv, const char *applet_opts, ...) { @@ -354,12 +346,10 @@ getopt32(char **argv, const char *applet_opts, ...) struct option *long_options = (struct option *) &bb_null_long_options; #endif unsigned trigger; - char **pargv; int min_arg = 0; int max_arg = -1; #define SHOW_USAGE_IF_ERROR 1 -#define FIRST_ARGV_IS_OPT 2 int spec_flgs = 0; @@ -467,12 +457,7 @@ getopt32(char **argv, const char *applet_opts, ...) continue; } if (*s == '-') { - if (c < '0' || c > '9') { - if (c == '-') { - spec_flgs |= FIRST_ARGV_IS_OPT; - s++; - } - } else { + if (c >= '0' && c <= '9') { min_arg = c - '0'; s++; } @@ -535,21 +520,6 @@ getopt32(char **argv, const char *applet_opts, ...) opt_complementary = NULL; va_end(p); - if (spec_flgs & FIRST_ARGV_IS_OPT) { - pargv = argv + 1; - if (*pargv) { - if (pargv[0][0] != '-' && pargv[0][0] != '\0') { - /* Can't use alloca: opts with params will - * return pointers to stack! - * NB: we leak these allocations... */ - char *pp = xmalloc(strlen(*pargv) + 2); - *pp = '-'; - strcpy(pp + 1, *pargv); - *pargv = pp; - } - } - } - /* In case getopt32 was already called: * reset the libc getopt() function, which keeps internal state. * run_nofork_applet() does this, but we might end up here -- cgit v1.2.3-55-g6feb From 74c05f5b2cfde7a561e55437eb499f96864179a3 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Fri, 4 Aug 2017 17:36:16 +0200 Subject: chat: trim help text Noticed while auditing nofork/noexec status function old new delta packed_usage 31777 31747 -30 Signed-off-by: Denys Vlasenko --- NOFORK_NOEXEC.lst | 93 ++++++++++++++++++++++++++---------------------- miscutils/chat.c | 4 +-- util-linux/freeramdisk.c | 8 +++-- 3 files changed, 58 insertions(+), 47 deletions(-) diff --git a/NOFORK_NOEXEC.lst b/NOFORK_NOEXEC.lst index 74922ff52..9741f21ea 100644 --- a/NOFORK_NOEXEC.lst +++ b/NOFORK_NOEXEC.lst @@ -11,8 +11,8 @@ runner: sometimes may run for long(ish) time, and/or works with network: ^C has to work (cat BIGFILE, chmod -R, ftpget, nc) "runners" can become eligible after shell is taught ^C to interrupt NOFORKs, -need to be inspected that they do not fall into alloc+xfunc, open+xfunc -categories. +need to be inspected that they do not fall into alloc+xfunc, open+xfunc, +leak categories. Why can't be NOEXEC: suid: runs under different uid - must fork+exec @@ -23,7 +23,15 @@ daemon: runs indefinitely; these are also always fit "rare" category longterm: often runs for a long time (many seconds), execing would make memory footprint smaller complex: no immediately obvious reason why NOFORK wouldn't work, - but does some non-obvoius operations (example: fuser, lsof, losetup) + but does some non-obvoius operations (example: fuser, lsof, losetup); + detailed audit often turns out that it's a leaker + +Interesting example of "interactive" applet which is nevertheless can be +(and is) NOEXEC is "rm". Yes, "rm -i" is interactive - but it's not that typical +for users to keep it waiting for many minutes, whereas running "rm" in shell +is very typical, and speeding up this common use via NOEXEC is useful. +IOW: rm is "interactive", but not "longterm". + [ - NOFORK [[ - NOFORK @@ -34,9 +42,9 @@ adduser adjtimex ar - runner arch - NOFORK -arp +arp - complex, rare arping - runner -ash - interactive +ash - interactive, longterm awk - noexec. runner base64 - runner basename - NOFORK @@ -52,7 +60,7 @@ bzcat - runner bzip2 - runner cal - runner: cal -n9999 cat - runner -chat +chat - needs ^C to work chattr - runner chgrp - noexec. runner chmod - noexec. runner @@ -77,10 +85,10 @@ cut - noexec. runner date - noexec. nofork candidate(needs to stop messing up env, free xasprintf result, not use xfuncs after xasprintf) dc - runner (eats stdin if no params) dd - noexec. runner -deallocvt +deallocvt - leaks: get_console_fd_or_die() may open a new fd, or return one of stdio fds. Also, "rare" category. Can be noexec. delgroup deluser -depmod +depmod - complex, rare devmem - runner, complex (access to device memory may hang) df - complex (nested allocs) dhcprelay - daemon @@ -88,16 +96,16 @@ diff - runner dirname - NOFORK dmesg - runner dnsd - daemon -dnsdomainname - DNS resolution may trigger, need ^C +dnsdomainname - needs ^C (may talk to DNS servers, which may be down) dos2unix - noexec. runner dpkg - runner du - runner -dumpkmap +dumpkmap - leaks: get_console_fd_or_die() may open a new fd, or return one of stdio fds. Also, "rare" category. Can be noexec. dumpleases echo - NOFORK -ed - interactive -egrep - runner -eject +ed - interactive, longterm +egrep - longterm runner ("CMD | egrep ..." may run indefinitely, better to exec to conserve memory) +eject - leaks: open+ioctl_or_perror_and_die, changes state (moves fds) env - noexec. changes state (env) envdir - spawner envuidgid - spawner @@ -107,24 +115,24 @@ factor - runner (eats stdin if no params) fakeidentd - daemon false - NOFORK fatattr - complex (xopen+xioctl can leak fd) -fbset -fbsplash - runner, interactive -fdflush -fdformat - runner -fdisk - interactive -fgconsole -fgrep - runner +fbset - leaks: open+xfunc, complex, rare +fbsplash - runner, longterm +fdflush - leaks: open+ioctl_or_perror_and_die, needs ^C (floppy may be unresponsive), rare +fdformat - needs ^C (floppy may be unresponsive), longterm, rare +fdisk - interactive, longterm +fgconsole - leaks: get_console_fd_or_die() may open a new fd, or return one of stdio fds. Also, "rare" category. Can be noexec. +fgrep - longterm runner ("CMD | fgrep ..." may run indefinitely, better to exec to conserve memory) find - noexec. runner findfs - suid flash_eraseall flash_lock flash_unlock flashcp -flock +flock - spawner, changes state (file locks) fold - noexec. runner free - nofork candidate(struct globals, needs to close /proc/meminfo fd) -freeramdisk -fsck - interactive +freeramdisk - leaks: open+ioctl_or_perror_and_die +fsck - interactive, longterm fsck.minix fsfreeze fstrim @@ -134,8 +142,8 @@ ftpget - runner ftpput - runner fuser - complex getopt - noexec. complex (many allocs) -getty - interactive -grep - runner +getty - interactive, longterm +grep - longterm runner ("CMD | grep ..." may run indefinitely, better to exec to conserve memory) groups - noexec gunzip - runner gzip - runner @@ -147,7 +155,7 @@ hexdump - noexec. runner hostid - NOFORK hostname - DNS resolution may trigger, need ^C httpd - daemon -hush - interactive +hush - interactive, longterm hwclock i2cdetect i2cdump @@ -180,39 +188,39 @@ killall - NOFORK killall5 - NOFORK klogd - daemon last - runner (I've got 1300 lines of output when tried it) -less - interactive +less - interactive, longterm link - NOFORK linux32 - spawner linux64 - spawner linuxrc - daemon ln - noexec loadfont -loadkmap +loadkmap - leaks: get_console_fd_or_die() may open a new fd, or return one of stdio fds. Also, "rare" category. Can be noexec. logger - runner -login - suid, interactive +login - suid, interactive, longterm logname - NOFORK losetup - complex lpd - daemon lpq - runner lpr - runner ls - noexec. runner -lsattr +lsattr - runner. noexec candidate (ls is, why not this one?) lsmod - noexec lsof - complex -lspci -lsscsi -lsusb +lspci - noexec candidate, too rare to bother for nofork +lsscsi - noexec candidate, too rare to bother for nofork +lsusb - noexec candidate, too rare to bother for nofork lzcat - runner lzma - runner lzop - runner lzopcat - runner makedevs makemime - runner -man - spawner, interactive +man - spawner, interactive, longterm md5sum - noexec. runner mdev - daemon mesg -microcom - interactive, complex +microcom - interactive, longterm mkdir - NOFORK mkdosfs mke2fs @@ -223,10 +231,10 @@ mkfs.vfat mknod - noexec mkpasswd mkswap -mktemp +mktemp - leaks: xstrdup+concat_path_file modinfo - noexec modprobe - noexec -more - interactive +more - interactive, longterm mount - suid mountpoint mpstat @@ -305,12 +313,11 @@ setpriv - spawner setserial setsid - spawner setuidgid -sh - interactive sha1sum - noexec. runner sha256sum - noexec. runner sha3sum - noexec. runner sha512sum - noexec. runner -showkey - interactive +showkey - interactive, longterm shred - runner shuf - noexec. runner slattach @@ -342,7 +349,7 @@ tar - runner taskset - spawner tcpsvd - daemon tee - runner -telnet - interactive +telnet - interactive, longterm telnetd - daemon test - NOFORK tftp - runner @@ -359,7 +366,7 @@ truncate - NOFORK tty - NOFORK ttysize - NOFORK tunctl -tune2fs +tune2fs - leaks: open+xfunc ubiattach ubidetach ubimkvol @@ -387,8 +394,8 @@ users - nofork candidate(is getutxent ok?) usleep - NOFORK uudecode - runner uuencode - runner -vconfig -vi - interactive +vconfig - leaks: xsocket+ioctl_or_perror_and_die +vi - interactive, longterm vlock - suid volname - runner w diff --git a/miscutils/chat.c b/miscutils/chat.c index 216a899a0..1446a040c 100644 --- a/miscutils/chat.c +++ b/miscutils/chat.c @@ -82,8 +82,8 @@ //usage: "EXPECT [SEND [EXPECT [SEND...]]]" //usage:#define chat_full_usage "\n\n" //usage: "Useful for interacting with a modem connected to stdin/stdout.\n" -//usage: "A script consists of one or more \"expect-send\" pairs of strings,\n" -//usage: "each pair is a pair of arguments. Example:\n" +//usage: "A script consists of \"expect-send\" argument pairs.\n" +//usage: "Example:\n" //usage: "chat '' ATZ OK ATD123456 CONNECT '' ogin: pppuser word: ppppass '~'" #include "libbb.h" diff --git a/util-linux/freeramdisk.c b/util-linux/freeramdisk.c index 55187cb40..a73578404 100644 --- a/util-linux/freeramdisk.c +++ b/util-linux/freeramdisk.c @@ -67,8 +67,12 @@ int freeramdisk_main(int argc UNUSED_PARAM, char **argv) fd = xopen(single_argv(argv), O_RDWR); // Act like freeramdisk, fdflush, or both depending on configuration. - ioctl_or_perror_and_die(fd, (ENABLE_FREERAMDISK && applet_name[1] == 'r') - || !ENABLE_FDFLUSH ? BLKFLSBUF : FDFLUSH, NULL, "%s", argv[1]); + ioctl_or_perror_and_die(fd, + ((ENABLE_FREERAMDISK && applet_name[1] == 'r') || !ENABLE_FDFLUSH) + ? BLKFLSBUF + : FDFLUSH, + NULL, "%s", argv[1] + ); if (ENABLE_FEATURE_CLEAN_UP) close(fd); -- cgit v1.2.3-55-g6feb From 6bec24c4f5a2c853c10fd59a56d0d197b5e5fd64 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Fri, 4 Aug 2017 17:39:05 +0200 Subject: mktemp: make it NOEXEC Signed-off-by: Denys Vlasenko --- NOFORK_NOEXEC.lst | 2 +- coreutils/mktemp.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/NOFORK_NOEXEC.lst b/NOFORK_NOEXEC.lst index 9741f21ea..90c802b2a 100644 --- a/NOFORK_NOEXEC.lst +++ b/NOFORK_NOEXEC.lst @@ -231,7 +231,7 @@ mkfs.vfat mknod - noexec mkpasswd mkswap -mktemp - leaks: xstrdup+concat_path_file +mktemp - noexec. leaks: xstrdup+concat_path_file modinfo - noexec modprobe - noexec more - interactive, longterm diff --git a/coreutils/mktemp.c b/coreutils/mktemp.c index bfef0b4a6..944eb0e06 100644 --- a/coreutils/mktemp.c +++ b/coreutils/mktemp.c @@ -36,7 +36,7 @@ //config: help //config: mktemp is used to create unique temporary files -//applet:IF_MKTEMP(APPLET(mktemp, BB_DIR_BIN, BB_SUID_DROP)) +//applet:IF_MKTEMP(APPLET_NOEXEC(mktemp, mktemp, BB_DIR_BIN, BB_SUID_DROP, mktemp)) //kbuild:lib-$(CONFIG_MKTEMP) += mktemp.o -- cgit v1.2.3-55-g6feb From 83d7785e413bbfc4c639c855a6e47f64bdc5da9a Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Fri, 4 Aug 2017 17:59:46 +0200 Subject: runlevel: make it NOEXEC Signed-off-by: Denys Vlasenko --- NOFORK_NOEXEC.lst | 38 +++++++++++++++++++------------------- miscutils/runlevel.c | 2 +- 2 files changed, 20 insertions(+), 20 deletions(-) diff --git a/NOFORK_NOEXEC.lst b/NOFORK_NOEXEC.lst index 90c802b2a..d6959e363 100644 --- a/NOFORK_NOEXEC.lst +++ b/NOFORK_NOEXEC.lst @@ -66,21 +66,21 @@ chgrp - noexec. runner chmod - noexec. runner chown - noexec. runner chpasswd - runner (list of "user:password"s from stdin) -chpst - spawner -chroot - spawner -chrt - spawner +chpst - noexec candidate, spawner +chroot - noexec candidate, spawner +chrt - noexec candidate, spawner chvt - leaks: get_console_fd_or_die() may open a new fd, or return one of stdio fds. Also, "rare" category. Can be noexec. cksum - noexec. runner clear - NOFORK cmp - runner comm - runner -conspy - interactive +conspy - interactive, longterm cp - noexec. runner cpio - runner crond - daemon crontab cryptpw - changes state: with --password-fd=N, moves N to stdin. Also, "rare" category. Can be noexec. -cttyhack - spawner +cttyhack - noexec candidate, spawner cut - noexec. runner date - noexec. nofork candidate(needs to stop messing up env, free xasprintf result, not use xfuncs after xasprintf) dc - runner (eats stdin if no params) @@ -90,7 +90,7 @@ delgroup deluser depmod - complex, rare devmem - runner, complex (access to device memory may hang) -df - complex (nested allocs) +df - leaks: nested allocs dhcprelay - daemon diff - runner dirname - NOFORK @@ -106,15 +106,15 @@ echo - NOFORK ed - interactive, longterm egrep - longterm runner ("CMD | egrep ..." may run indefinitely, better to exec to conserve memory) eject - leaks: open+ioctl_or_perror_and_die, changes state (moves fds) -env - noexec. changes state (env) -envdir - spawner -envuidgid - spawner +env - noexec. spawner, changes state (env) +envdir - noexec candidate, spawner +envuidgid - noexec candidate, spawner expand - runner -expr - complex (nested allocs) +expr - leaks: nested allocs factor - runner (eats stdin if no params) fakeidentd - daemon false - NOFORK -fatattr - complex (xopen+xioctl can leak fd) +fatattr - leaks: open+xioctl, complex fbset - leaks: open+xfunc, complex, rare fbsplash - runner, longterm fdflush - leaks: open+ioctl_or_perror_and_die, needs ^C (floppy may be unresponsive), rare @@ -134,14 +134,14 @@ free - nofork candidate(struct globals, needs to close /proc/meminfo fd) freeramdisk - leaks: open+ioctl_or_perror_and_die fsck - interactive, longterm fsck.minix -fsfreeze -fstrim +fsfreeze - noexec candidate (it's very simple), leaks: open+xioctl +fstrim - noexec candidate (it's very simple), leaks: open+xioctl fsync - NOFORK ftpd - daemon ftpget - runner ftpput - runner fuser - complex -getopt - noexec. complex (many allocs) +getopt - noexec. leaks: many allocs getty - interactive, longterm grep - longterm runner ("CMD | grep ..." may run indefinitely, better to exec to conserve memory) groups - noexec @@ -156,7 +156,7 @@ hostid - NOFORK hostname - DNS resolution may trigger, need ^C httpd - daemon hush - interactive, longterm -hwclock +hwclock - talks to hardware (xioctl(RTC_RD_TIME)) - needs ^C i2cdetect i2cdump i2cget @@ -293,9 +293,9 @@ rmmod - noexec route rpm - runner rpm2cpio - runner -rtcwake - complex, rare +rtcwake - puts system to sleep, optimizing this for speed is pointless run-parts -runlevel +runlevel - noexec. can be nofork if "endutxent()" is called unconditionally, but too rare to bother? runsv - daemon runsvdir - daemon rx - runner @@ -400,10 +400,10 @@ vlock - suid volname - runner w wall - suid -watch - runner +watch - longterm watchdog - daemon wc - runner -wget - runner +wget - longterm which - NOFORK who whoami - NOFORK diff --git a/miscutils/runlevel.c b/miscutils/runlevel.c index 6b4742255..0b2098564 100644 --- a/miscutils/runlevel.c +++ b/miscutils/runlevel.c @@ -21,7 +21,7 @@ //config: This applet uses utmp but does not rely on busybox supporing //config: utmp on purpose. It is used by e.g. emdebian via /etc/init.d/rc. -//applet:IF_RUNLEVEL(APPLET(runlevel, BB_DIR_SBIN, BB_SUID_DROP)) +//applet:IF_RUNLEVEL(APPLET_NOEXEC(runlevel, runlevel, BB_DIR_SBIN, BB_SUID_DROP, runlevel)) //kbuild:lib-$(CONFIG_RUNLEVEL) += runlevel.o -- cgit v1.2.3-55-g6feb From 947b2391c07f8a11f7bd4658f77cd03172fc221a Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Fri, 4 Aug 2017 18:36:55 +0200 Subject: pmap: tweak help text, show usage if no params are given Noticed while auditing nofork/noexec status function old new delta pmap_main 70 80 +10 packed_usage 31747 31744 -3 Signed-off-by: Denys Vlasenko --- NOFORK_NOEXEC.lst | 60 +++++++++++++++++++++++++++---------------------------- procps/pmap.c | 3 ++- 2 files changed, 32 insertions(+), 31 deletions(-) diff --git a/NOFORK_NOEXEC.lst b/NOFORK_NOEXEC.lst index d6959e363..730f2cc3c 100644 --- a/NOFORK_NOEXEC.lst +++ b/NOFORK_NOEXEC.lst @@ -135,7 +135,7 @@ freeramdisk - leaks: open+ioctl_or_perror_and_die fsck - interactive, longterm fsck.minix fsfreeze - noexec candidate (it's very simple), leaks: open+xioctl -fstrim - noexec candidate (it's very simple), leaks: open+xioctl +fstrim - noexec candidate (it's very simple), leaks: open+xioctl, find_block_device -> readdir+xstrdup fsync - NOFORK ftpd - daemon ftpget - runner @@ -153,7 +153,7 @@ hdparm - complex, rare head - noexec. runner hexdump - noexec. runner hostid - NOFORK -hostname - DNS resolution may trigger, need ^C +hostname - needs ^C (may talk to DNS servers, which may be down) httpd - daemon hush - interactive, longterm hwclock - talks to hardware (xioctl(RTC_RD_TIME)) - needs ^C @@ -222,40 +222,40 @@ mdev - daemon mesg microcom - interactive, longterm mkdir - NOFORK -mkdosfs -mke2fs +mkdosfs - needs ^C +mke2fs - needs ^C mkfifo - noexec -mkfs.ext2 -mkfs.minix -mkfs.vfat +mkfs.ext2 - needs ^C +mkfs.minix - needs ^C +mkfs.vfat - needs ^C mknod - noexec -mkpasswd -mkswap +mkpasswd - changes state: with --password-fd=N, moves N to stdin. Also, "rare" category. Can be noexec. +mkswap - needs ^C mktemp - noexec. leaks: xstrdup+concat_path_file modinfo - noexec modprobe - noexec more - interactive, longterm mount - suid -mountpoint -mpstat -mt +mountpoint - noexec candidate, leaks: option -n "print dev name": find_block_device -> readdir+xstrdup +mpstat - noexec candidate (it's a measuring tool, putting less load by itself is good), complex +mt - rare mv - runner (can be noexec?) nameif nbd-client nc - runner netstat - runner with -c -nice - spawner +nice - noexec candidate, spawner nl - runner -nmeter - runner -nohup - spawner +nmeter - longterm +nohup - noexec candidate (maybe free concat_path_file result?), spawner nproc - NOFORK ntpd - daemon od - runner openvt - spawner -partprobe +partprobe - noexec candidate (simple), leaks: open+ioctl_or_perror_and_die(BLKRRPART) passwd - suid paste - noexec. runner -patch +patch - needs ^C pgrep - nofork candidate(xregcomp, procps_scan - are they ok?) pidof - nofork candidate(uses find_pid_by_name, is that ok?) ping - suid, runner @@ -263,7 +263,7 @@ ping6 - suid, runner pipe_progress pivot_root pkill - nofork candidate(xregcomp, procps_scan - are they ok?) -pmap +pmap - noexec candidate, leaks: open+xstrdup popmaildir - runner poweroff - rare powertop - interactive, longterm @@ -275,8 +275,8 @@ pstree pwd - NOFORK pwdx - NOFORK raidautorun -rdate -rdev +rdate - needs ^C (may talk to DNS servers, which may be down) +rdev - leaks: find_block_device -> readdir+xstrdup readlink - NOFORK readprofile realpath - NOFORK @@ -284,16 +284,16 @@ reboot - rare reformime - runner remove-shell renice - nofork candidate(uses getpwnam, is that ok?) -reset - spawner (execs "stty") +reset - noexec candidate, spawner (execs "stty") resize - noexec. changes state (signal handlers) rev - runner rm - noexec. rm -i interactive rmdir - NOFORK rmmod - noexec -route +route - needs ^C (may talk to DNS servers, which may be down) rpm - runner rpm2cpio - runner -rtcwake - puts system to sleep, optimizing this for speed is pointless +rtcwake - longterm: puts system to sleep, optimizing this for speed is pointless run-parts runlevel - noexec. can be nofork if "endutxent()" is called unconditionally, but too rare to bother? runsv - daemon @@ -321,27 +321,27 @@ showkey - interactive, longterm shred - runner shuf - noexec. runner slattach -sleep - runner +sleep - runner, longterm smemcap - runner -softlimit - spawner +softlimit - noexec candidate, spawner sort - noexec. runner split - runner -ssl_client - network +ssl_client - longterm start-stop-daemon stat - nofork candidate(needs fewer allocs) strings - runner -stty +stty - noexec/nofork candidate. has no allocs or opens except xmove_fd(xopen("-F DEVICE"),STDIN). tcsetattr(STDIN) is not a problem: it would work the same across processes sharing this fd su - suid, spawner sulogin - spawner sum - runner -sv -svc +sv - noexec candidate, needs ^C (uses usleep(420000)) +svc - noexec candidate, needs ^C (uses usleep(420000)) svlogd - daemon swapoff - rare swapon - rare switch_root - spawner, rare, changes state sync - NOFORK -sysctl +sysctl - noexec candidate, leaks: xstrdup+xmalloc_read syslogd - daemon tac - noexec. runner tail - runner diff --git a/procps/pmap.c b/procps/pmap.c index c8f728897..3dc733974 100644 --- a/procps/pmap.c +++ b/procps/pmap.c @@ -18,7 +18,7 @@ //kbuild:lib-$(CONFIG_PMAP) += pmap.o //usage:#define pmap_trivial_usage -//usage: "[-xq] PID" +//usage: "[-xq] PID..." //usage:#define pmap_full_usage "\n\n" //usage: "Display process memory usage" //usage: "\n" @@ -96,6 +96,7 @@ int pmap_main(int argc UNUSED_PARAM, char **argv) unsigned opts; int ret; + opt_complementary = "-1"; /* min one arg */ opts = getopt32(argv, "xq"); argv += optind; -- cgit v1.2.3-55-g6feb From 6514785f95878911b3ec88e2367234df74c14cd4 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Fri, 4 Aug 2017 19:16:01 +0200 Subject: mesg: make in NOFORK Signed-off-by: Denys Vlasenko --- NOFORK_NOEXEC.lst | 48 ++++++++++++++++++++++++------------------------ util-linux/mesg.c | 9 +++++++-- 2 files changed, 31 insertions(+), 26 deletions(-) diff --git a/NOFORK_NOEXEC.lst b/NOFORK_NOEXEC.lst index 730f2cc3c..ccd8f0c96 100644 --- a/NOFORK_NOEXEC.lst +++ b/NOFORK_NOEXEC.lst @@ -51,7 +51,7 @@ basename - NOFORK beep blkdiscard blkid -blockdev +blockdev - noexec candidate (rather simple), leaks fd bootchartd - daemon brctl bunzip2 - runner @@ -69,7 +69,7 @@ chpasswd - runner (list of "user:password"s from stdin) chpst - noexec candidate, spawner chroot - noexec candidate, spawner chrt - noexec candidate, spawner -chvt - leaks: get_console_fd_or_die() may open a new fd, or return one of stdio fds. Also, "rare" category. Can be noexec. +chvt - leaks: get_console_fd_or_die() may open a new fd, or return one of stdio fds. Also, "rare" category. noexec candidate. cksum - noexec. runner clear - NOFORK cmp - runner @@ -78,14 +78,14 @@ conspy - interactive, longterm cp - noexec. runner cpio - runner crond - daemon -crontab -cryptpw - changes state: with --password-fd=N, moves N to stdin. Also, "rare" category. Can be noexec. +crontab 0 leaks: open+xasprintf +cryptpw - changes state: with --password-fd=N, moves N to stdin. Also, "rare" category. noexec candidate. cttyhack - noexec candidate, spawner cut - noexec. runner date - noexec. nofork candidate(needs to stop messing up env, free xasprintf result, not use xfuncs after xasprintf) dc - runner (eats stdin if no params) dd - noexec. runner -deallocvt - leaks: get_console_fd_or_die() may open a new fd, or return one of stdio fds. Also, "rare" category. Can be noexec. +deallocvt - leaks: get_console_fd_or_die() may open a new fd, or return one of stdio fds. Also, "rare" category. noexec candidate. delgroup deluser depmod - complex, rare @@ -100,8 +100,8 @@ dnsdomainname - needs ^C (may talk to DNS servers, which may be down) dos2unix - noexec. runner dpkg - runner du - runner -dumpkmap - leaks: get_console_fd_or_die() may open a new fd, or return one of stdio fds. Also, "rare" category. Can be noexec. -dumpleases +dumpkmap - leaks: get_console_fd_or_die() may open a new fd, or return one of stdio fds. Also, "rare" category. noexec candidate. +dumpleases - leaks: open+xread echo - NOFORK ed - interactive, longterm egrep - longterm runner ("CMD | egrep ..." may run indefinitely, better to exec to conserve memory) @@ -120,7 +120,7 @@ fbsplash - runner, longterm fdflush - leaks: open+ioctl_or_perror_and_die, needs ^C (floppy may be unresponsive), rare fdformat - needs ^C (floppy may be unresponsive), longterm, rare fdisk - interactive, longterm -fgconsole - leaks: get_console_fd_or_die() may open a new fd, or return one of stdio fds. Also, "rare" category. Can be noexec. +fgconsole - leaks: get_console_fd_or_die() may open a new fd, or return one of stdio fds. Also, "rare" category. noexec candidate. fgrep - longterm runner ("CMD | fgrep ..." may run indefinitely, better to exec to conserve memory) find - noexec. runner findfs - suid @@ -133,7 +133,7 @@ fold - noexec. runner free - nofork candidate(struct globals, needs to close /proc/meminfo fd) freeramdisk - leaks: open+ioctl_or_perror_and_die fsck - interactive, longterm -fsck.minix +fsck.minix - needs ^C fsfreeze - noexec candidate (it's very simple), leaks: open+xioctl fstrim - noexec candidate (it's very simple), leaks: open+xioctl, find_block_device -> readdir+xstrdup fsync - NOFORK @@ -162,8 +162,8 @@ i2cdump i2cget i2cset id - noexec -ifconfig -ifenslave +ifconfig - leaks: xsocket+ioctl_or_perror_and_die +ifenslave - leaks: xsocket+bb_perror_msg_and_die ifplugd - daemon inetd - daemon init - daemon @@ -182,7 +182,7 @@ ipneigh - noexec candidate iproute - noexec candidate iprule - noexec candidate iptunnel - noexec candidate -kbd_mode +kbd_mode - leaks: xopen_nonblocking+xioctl kill - NOFORK killall - NOFORK killall5 - NOFORK @@ -194,8 +194,8 @@ linux32 - spawner linux64 - spawner linuxrc - daemon ln - noexec -loadfont -loadkmap - leaks: get_console_fd_or_die() may open a new fd, or return one of stdio fds. Also, "rare" category. Can be noexec. +loadfont - leaks: config_open+bb_error_msg_and_die("map format") +loadkmap - leaks: get_console_fd_or_die() may open a new fd, or return one of stdio fds. Also, "rare" category. noexec candidate. logger - runner login - suid, interactive, longterm logname - NOFORK @@ -219,7 +219,7 @@ makemime - runner man - spawner, interactive, longterm md5sum - noexec. runner mdev - daemon -mesg +mesg - NOFORK microcom - interactive, longterm mkdir - NOFORK mkdosfs - needs ^C @@ -229,7 +229,7 @@ mkfs.ext2 - needs ^C mkfs.minix - needs ^C mkfs.vfat - needs ^C mknod - noexec -mkpasswd - changes state: with --password-fd=N, moves N to stdin. Also, "rare" category. Can be noexec. +mkpasswd - changes state: with --password-fd=N, moves N to stdin. Also, "rare" category. noexec candidate. mkswap - needs ^C mktemp - noexec. leaks: xstrdup+concat_path_file modinfo - noexec @@ -239,8 +239,8 @@ mount - suid mountpoint - noexec candidate, leaks: option -n "print dev name": find_block_device -> readdir+xstrdup mpstat - noexec candidate (it's a measuring tool, putting less load by itself is good), complex mt - rare -mv - runner (can be noexec?) -nameif +mv - noexec candidate, runner +nameif - leaks: config_open2+ioctl_or_perror_and_die nbd-client nc - runner netstat - runner with -c @@ -260,8 +260,8 @@ pgrep - nofork candidate(xregcomp, procps_scan - are they ok?) pidof - nofork candidate(uses find_pid_by_name, is that ok?) ping - suid, runner ping6 - suid, runner -pipe_progress -pivot_root +pipe_progress - longterm +pivot_root - nofork candidate? the code is trivial pkill - nofork candidate(xregcomp, procps_scan - are they ok?) pmap - noexec candidate, leaks: open+xstrdup popmaildir - runner @@ -378,7 +378,7 @@ udhcpc - daemon udhcpd - daemon udpsvd - daemon uevent - daemon -umount +umount - noexec candidate, leaks: nested xmalloc uname - NOFORK uncompress - runner unexpand - runner @@ -398,16 +398,16 @@ vconfig - leaks: xsocket+ioctl_or_perror_and_die vi - interactive, longterm vlock - suid volname - runner -w +w - nofork candidate(is getutxent ok?) wall - suid watch - longterm watchdog - daemon wc - runner wget - longterm which - NOFORK -who +who - nofork candidate(is getutxent ok?) whoami - NOFORK -whois +whois - needs ^C xargs - noexec. spawner xxd - noexec. runner xz - runner diff --git a/util-linux/mesg.c b/util-linux/mesg.c index c4371eb24..91c05317e 100644 --- a/util-linux/mesg.c +++ b/util-linux/mesg.c @@ -26,7 +26,7 @@ //config: If you set this option to N, "mesg y" will enable writing //config: by anybody at all. This is not recommended. -//applet:IF_MESG(APPLET(mesg, BB_DIR_USR_BIN, BB_SUID_DROP)) +//applet:IF_MESG(APPLET_NOFORK(mesg, mesg, BB_DIR_USR_BIN, BB_SUID_DROP, mesg)) //kbuild:lib-$(CONFIG_MESG) += mesg.o @@ -60,10 +60,15 @@ int mesg_main(int argc UNUSED_PARAM, char **argv) bb_show_usage(); } + /* We are a NOFORK applet. + * (Not that it's very useful, but code is trivially NOFORK-safe). + * Play nice. Do not leak anything. + */ + if (!isatty(STDIN_FILENO)) bb_error_msg_and_die("not a tty"); - xfstat(STDIN_FILENO, &sb, "stderr"); + xfstat(STDIN_FILENO, &sb, "stdin"); if (c == 0) { puts((sb.st_mode & (S_IWGRP|S_IWOTH)) ? "is y" : "is n"); return EXIT_SUCCESS; -- cgit v1.2.3-55-g6feb From 5c527dc57e74c1b60c910dc1a3f3ec9683fca43d Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Fri, 4 Aug 2017 19:55:01 +0200 Subject: make 17 state-changing execing applets (ex: "nice PROG ARGS") noexec The applets with " [opts] PROG ARGS" API very quickly exec another program, noexec is okay for them: chpst/envdir/envuidgid/softlimit/setuidgid chroot chrt ionice nice nohup setarch/linux32/linux64 taskset cttyhack "reset" and "sulogin" applets don't have this form, but also exec another program at once, thus made noexec too. Signed-off-by: Denys Vlasenko --- NOFORK_NOEXEC.lst | 46 +++++++++++++++++++++++----------------------- console-tools/reset.c | 2 +- coreutils/chroot.c | 3 ++- coreutils/nice.c | 2 +- coreutils/nohup.c | 2 +- loginutils/sulogin.c | 4 ++-- runit/chpst.c | 12 ++++++------ shell/cttyhack.c | 2 +- util-linux/chrt.c | 2 +- util-linux/ionice.c | 2 +- util-linux/setarch.c | 8 ++++---- util-linux/taskset.c | 2 +- 12 files changed, 44 insertions(+), 43 deletions(-) diff --git a/NOFORK_NOEXEC.lst b/NOFORK_NOEXEC.lst index ccd8f0c96..5ec9ae3fe 100644 --- a/NOFORK_NOEXEC.lst +++ b/NOFORK_NOEXEC.lst @@ -20,7 +20,7 @@ suid: runs under different uid - must fork+exec Why shouldn't be NOFORK/NOEXEC: rare: not started often enough to bother optimizing (example: poweroff) daemon: runs indefinitely; these are also always fit "rare" category -longterm: often runs for a long time (many seconds), execing would make +longterm: often runs for a long time (many seconds), execing makes memory footprint smaller complex: no immediately obvious reason why NOFORK wouldn't work, but does some non-obvoius operations (example: fuser, lsof, losetup); @@ -66,9 +66,9 @@ chgrp - noexec. runner chmod - noexec. runner chown - noexec. runner chpasswd - runner (list of "user:password"s from stdin) -chpst - noexec candidate, spawner -chroot - noexec candidate, spawner -chrt - noexec candidate, spawner +chpst - noexec. spawner +chroot - noexec. spawner +chrt - noexec. spawner chvt - leaks: get_console_fd_or_die() may open a new fd, or return one of stdio fds. Also, "rare" category. noexec candidate. cksum - noexec. runner clear - NOFORK @@ -80,7 +80,7 @@ cpio - runner crond - daemon crontab 0 leaks: open+xasprintf cryptpw - changes state: with --password-fd=N, moves N to stdin. Also, "rare" category. noexec candidate. -cttyhack - noexec candidate, spawner +cttyhack - noexec. spawner cut - noexec. runner date - noexec. nofork candidate(needs to stop messing up env, free xasprintf result, not use xfuncs after xasprintf) dc - runner (eats stdin if no params) @@ -107,8 +107,8 @@ ed - interactive, longterm egrep - longterm runner ("CMD | egrep ..." may run indefinitely, better to exec to conserve memory) eject - leaks: open+ioctl_or_perror_and_die, changes state (moves fds) env - noexec. spawner, changes state (env) -envdir - noexec candidate, spawner -envuidgid - noexec candidate, spawner +envdir - noexec. spawner +envuidgid - noexec. spawner expand - runner expr - leaks: nested allocs factor - runner (eats stdin if no params) @@ -128,7 +128,7 @@ flash_eraseall flash_lock flash_unlock flashcp -flock - spawner, changes state (file locks) +flock - spawner, changes state (file locks), let's play safe and not be noexec fold - noexec. runner free - nofork candidate(struct globals, needs to close /proc/meminfo fd) freeramdisk - leaks: open+ioctl_or_perror_and_die @@ -170,7 +170,7 @@ init - daemon inotifyd - daemon insmod - noexec install - runner -ionice - spawner +ionice - noexec. spawner iostat - runner ip - noexec candidate ipaddr - noexec candidate @@ -190,8 +190,8 @@ klogd - daemon last - runner (I've got 1300 lines of output when tried it) less - interactive, longterm link - NOFORK -linux32 - spawner -linux64 - spawner +linux32 - noexec. spawner +linux64 - noexec. spawner linuxrc - daemon ln - noexec loadfont - leaks: config_open+bb_error_msg_and_die("map format") @@ -247,11 +247,11 @@ netstat - runner with -c nice - noexec candidate, spawner nl - runner nmeter - longterm -nohup - noexec candidate (maybe free concat_path_file result?), spawner +nohup - noexec. spawner nproc - NOFORK ntpd - daemon od - runner -openvt - spawner +openvt - longterm: spawns a child and waits for it partprobe - noexec candidate (simple), leaks: open+ioctl_or_perror_and_die(BLKRRPART) passwd - suid paste - noexec. runner @@ -304,15 +304,15 @@ scriptreplay sed - runner sendmail - runner seq - noexec. runner -setarch - spawner +setarch - noexec. spawner setconsole setfont setkeycodes setlogcons -setpriv - spawner +setpriv - spawner, changes state, let's play safe and not be noexec setserial -setsid - spawner -setuidgid +setsid - spawner, uses fork_or_rexec() [not audted to work in noexec], let's play safe and not be noexec +setuidgid - noexec. spawner sha1sum - noexec. runner sha256sum - noexec. runner sha3sum - noexec. runner @@ -323,7 +323,7 @@ shuf - noexec. runner slattach sleep - runner, longterm smemcap - runner -softlimit - noexec candidate, spawner +softlimit - noexec. spawner sort - noexec. runner split - runner ssl_client - longterm @@ -332,21 +332,21 @@ stat - nofork candidate(needs fewer allocs) strings - runner stty - noexec/nofork candidate. has no allocs or opens except xmove_fd(xopen("-F DEVICE"),STDIN). tcsetattr(STDIN) is not a problem: it would work the same across processes sharing this fd su - suid, spawner -sulogin - spawner +sulogin - noexec. spawner sum - runner sv - noexec candidate, needs ^C (uses usleep(420000)) svc - noexec candidate, needs ^C (uses usleep(420000)) svlogd - daemon swapoff - rare swapon - rare -switch_root - spawner, rare, changes state +switch_root - spawner, rare, changes state (oh yes), execing may be important to free binary's inode sync - NOFORK sysctl - noexec candidate, leaks: xstrdup+xmalloc_read syslogd - daemon tac - noexec. runner tail - runner tar - runner -taskset - spawner +taskset - noexec. spawner tcpsvd - daemon tee - runner telnet - interactive, longterm @@ -354,8 +354,8 @@ telnetd - daemon test - NOFORK tftp - runner tftpd - daemon -time - spawner, changes state (signals) -timeout - spawner, changes state (signals) +time - spawner, longterm, changes state (signals) +timeout - spawner, longterm, changes state (signals) top - interactive, longterm touch - NOFORK tr - runner diff --git a/console-tools/reset.c b/console-tools/reset.c index 04e5b0ca1..f2b900ddb 100644 --- a/console-tools/reset.c +++ b/console-tools/reset.c @@ -16,7 +16,7 @@ //config: This program is used to reset the terminal screen, if it //config: gets messed up. -//applet:IF_RESET(APPLET(reset, BB_DIR_USR_BIN, BB_SUID_DROP)) +//applet:IF_RESET(APPLET_NOEXEC(reset, reset, BB_DIR_USR_BIN, BB_SUID_DROP, reset)) //kbuild:lib-$(CONFIG_RESET) += reset.o diff --git a/coreutils/chroot.c b/coreutils/chroot.c index 5645d72df..78751df84 100644 --- a/coreutils/chroot.c +++ b/coreutils/chroot.c @@ -13,7 +13,7 @@ //config: chroot is used to change the root directory and run a command. //config: The default command is '/bin/sh'. -//applet:IF_CHROOT(APPLET(chroot, BB_DIR_USR_SBIN, BB_SUID_DROP)) +//applet:IF_CHROOT(APPLET_NOEXEC(chroot, chroot, BB_DIR_USR_SBIN, BB_SUID_DROP, chroot)) //kbuild:lib-$(CONFIG_CHROOT) += chroot.o @@ -40,6 +40,7 @@ int chroot_main(int argc UNUSED_PARAM, char **argv) ++argv; if (!*argv) bb_show_usage(); + xchroot(*argv); ++argv; diff --git a/coreutils/nice.c b/coreutils/nice.c index 0bf055299..d6818cf00 100644 --- a/coreutils/nice.c +++ b/coreutils/nice.c @@ -12,7 +12,7 @@ //config: help //config: nice runs a program with modified scheduling priority. -//applet:IF_NICE(APPLET(nice, BB_DIR_BIN, BB_SUID_DROP)) +//applet:IF_NICE(APPLET_NOEXEC(nice, nice, BB_DIR_BIN, BB_SUID_DROP, nice)) //kbuild:lib-$(CONFIG_NICE) += nice.o diff --git a/coreutils/nohup.c b/coreutils/nohup.c index df271c738..8a70ec4df 100644 --- a/coreutils/nohup.c +++ b/coreutils/nohup.c @@ -15,7 +15,7 @@ //config: help //config: run a command immune to hangups, with output to a non-tty. -//applet:IF_NOHUP(APPLET(nohup, BB_DIR_USR_BIN, BB_SUID_DROP)) +//applet:IF_NOHUP(APPLET_NOEXEC(nohup, nohup, BB_DIR_USR_BIN, BB_SUID_DROP, nohup)) //kbuild:lib-$(CONFIG_NOHUP) += nohup.o diff --git a/loginutils/sulogin.c b/loginutils/sulogin.c index d5a463cac..27ea5dff0 100644 --- a/loginutils/sulogin.c +++ b/loginutils/sulogin.c @@ -12,7 +12,7 @@ //config: sulogin is invoked when the system goes into single user //config: mode (this is done through an entry in inittab). -//applet:IF_SULOGIN(APPLET(sulogin, BB_DIR_SBIN, BB_SUID_DROP)) +//applet:IF_SULOGIN(APPLET_NOEXEC(sulogin, sulogin, BB_DIR_SBIN, BB_SUID_DROP, sulogin)) //kbuild:lib-$(CONFIG_SULOGIN) += sulogin.o @@ -34,7 +34,7 @@ int sulogin_main(int argc UNUSED_PARAM, char **argv) /* Note: sulogin is not a suid app. It is meant to be run by init * for single user / emergency mode. init starts it as root. - * Normal users (potentially malisious ones) can only run it under + * Normal users (potentially malicious ones) can only run it under * their UID, therefore no paranoia here is warranted: * $LD_LIBRARY_PATH in env, TTY = /dev/sda * are no more dangerous here than in e.g. cp applet. diff --git a/runit/chpst.c b/runit/chpst.c index ccc96539d..c061a91ea 100644 --- a/runit/chpst.c +++ b/runit/chpst.c @@ -59,12 +59,12 @@ ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. //config: help //config: Sets soft resource limits as specified by options -//applet:IF_CHPST(APPLET(chpst, BB_DIR_USR_BIN, BB_SUID_DROP)) -// APPLET_ODDNAME:name main location suid_type help -//applet:IF_ENVDIR( APPLET_ODDNAME(envdir, chpst, BB_DIR_USR_BIN, BB_SUID_DROP, envdir)) -//applet:IF_ENVUIDGID(APPLET_ODDNAME(envuidgid, chpst, BB_DIR_USR_BIN, BB_SUID_DROP, envuidgid)) -//applet:IF_SETUIDGID(APPLET_ODDNAME(setuidgid, chpst, BB_DIR_USR_BIN, BB_SUID_DROP, setuidgid)) -//applet:IF_SOFTLIMIT(APPLET_ODDNAME(softlimit, chpst, BB_DIR_USR_BIN, BB_SUID_DROP, softlimit)) +//applet:IF_CHPST( APPLET_NOEXEC(chpst, chpst, BB_DIR_USR_BIN, BB_SUID_DROP, chpst)) +// APPLET_NOEXEC:name main location suid_type help +//applet:IF_ENVDIR( APPLET_NOEXEC(envdir, chpst, BB_DIR_USR_BIN, BB_SUID_DROP, envdir)) +//applet:IF_ENVUIDGID(APPLET_NOEXEC(envuidgid, chpst, BB_DIR_USR_BIN, BB_SUID_DROP, envuidgid)) +//applet:IF_SETUIDGID(APPLET_NOEXEC(setuidgid, chpst, BB_DIR_USR_BIN, BB_SUID_DROP, setuidgid)) +//applet:IF_SOFTLIMIT(APPLET_NOEXEC(softlimit, chpst, BB_DIR_USR_BIN, BB_SUID_DROP, softlimit)) //kbuild:lib-$(CONFIG_CHPST) += chpst.o //kbuild:lib-$(CONFIG_ENVDIR) += chpst.o diff --git a/shell/cttyhack.c b/shell/cttyhack.c index 9004b4763..849fe9e48 100644 --- a/shell/cttyhack.c +++ b/shell/cttyhack.c @@ -6,7 +6,7 @@ */ #include "libbb.h" -//applet:IF_CTTYHACK(APPLET(cttyhack, BB_DIR_BIN, BB_SUID_DROP)) +//applet:IF_CTTYHACK(APPLET_NOEXEC(cttyhack, cttyhack, BB_DIR_BIN, BB_SUID_DROP, cttyhack)) //kbuild:lib-$(CONFIG_CTTYHACK) += cttyhack.o diff --git a/util-linux/chrt.c b/util-linux/chrt.c index 4bc8b6cfa..52523df02 100644 --- a/util-linux/chrt.c +++ b/util-linux/chrt.c @@ -12,7 +12,7 @@ //config: manipulate real-time attributes of a process. //config: This requires sched_{g,s}etparam support in your libc. -//applet:IF_CHRT(APPLET(chrt, BB_DIR_USR_BIN, BB_SUID_DROP)) +//applet:IF_CHRT(APPLET_NOEXEC(chrt, chrt, BB_DIR_USR_BIN, BB_SUID_DROP, chrt)) //kbuild:lib-$(CONFIG_CHRT) += chrt.o diff --git a/util-linux/ionice.c b/util-linux/ionice.c index c7b7f0373..5b9664d25 100644 --- a/util-linux/ionice.c +++ b/util-linux/ionice.c @@ -14,7 +14,7 @@ //config: Set/set program io scheduling class and priority //config: Requires kernel >= 2.6.13 -//applet:IF_IONICE(APPLET(ionice, BB_DIR_BIN, BB_SUID_DROP)) +//applet:IF_IONICE(APPLET_NOEXEC(ionice, ionice, BB_DIR_BIN, BB_SUID_DROP, ionice)) //kbuild:lib-$(CONFIG_IONICE) += ionice.o diff --git a/util-linux/setarch.c b/util-linux/setarch.c index d4b568832..520865318 100644 --- a/util-linux/setarch.c +++ b/util-linux/setarch.c @@ -30,10 +30,10 @@ //config: help //config: Alias to "setarch linux64". -//applet:IF_SETARCH(APPLET(setarch, BB_DIR_BIN, BB_SUID_DROP)) -// APPLET_ODDNAME:name main location suid_type help -//applet:IF_LINUX32(APPLET_ODDNAME(linux32, setarch, BB_DIR_BIN, BB_SUID_DROP, linux32)) -//applet:IF_LINUX64(APPLET_ODDNAME(linux64, setarch, BB_DIR_BIN, BB_SUID_DROP, linux64)) +//applet:IF_SETARCH(APPLET_NOEXEC(setarch, setarch, BB_DIR_BIN, BB_SUID_DROP, setarch)) +// APPLET_NOEXEC:name main location suid_type help +//applet:IF_LINUX32(APPLET_NOEXEC(linux32, setarch, BB_DIR_BIN, BB_SUID_DROP, linux32)) +//applet:IF_LINUX64(APPLET_NOEXEC(linux64, setarch, BB_DIR_BIN, BB_SUID_DROP, linux64)) //kbuild:lib-$(CONFIG_SETARCH) += setarch.o //kbuild:lib-$(CONFIG_LINUX32) += setarch.o diff --git a/util-linux/taskset.c b/util-linux/taskset.c index 9957b1a71..89dea176e 100644 --- a/util-linux/taskset.c +++ b/util-linux/taskset.c @@ -22,7 +22,7 @@ //config: affinity parameter 0xHHHHHHHHHHHHHHHHHHHH can be arbitrarily long //config: in this case. Otherwise, it is limited to sizeof(long). -//applet:IF_TASKSET(APPLET(taskset, BB_DIR_USR_BIN, BB_SUID_DROP)) +//applet:IF_TASKSET(APPLET_NOEXEC(taskset, taskset, BB_DIR_USR_BIN, BB_SUID_DROP, taskset)) //kbuild:lib-$(CONFIG_TASKSET) += taskset.o //usage:#define taskset_trivial_usage -- cgit v1.2.3-55-g6feb From 692eeb81a4c54d7d8bf0d2e370c12762b2a16ff7 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Fri, 4 Aug 2017 20:07:19 +0200 Subject: stty: make in NOEXEC Signed-off-by: Denys Vlasenko --- NOFORK_NOEXEC.lst | 6 +++--- coreutils/stty.c | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/NOFORK_NOEXEC.lst b/NOFORK_NOEXEC.lst index 5ec9ae3fe..ad49cd809 100644 --- a/NOFORK_NOEXEC.lst +++ b/NOFORK_NOEXEC.lst @@ -244,7 +244,7 @@ nameif - leaks: config_open2+ioctl_or_perror_and_die nbd-client nc - runner netstat - runner with -c -nice - noexec candidate, spawner +nice - noexec. spawner nl - runner nmeter - longterm nohup - noexec. spawner @@ -284,7 +284,7 @@ reboot - rare reformime - runner remove-shell renice - nofork candidate(uses getpwnam, is that ok?) -reset - noexec candidate, spawner (execs "stty") +reset - noexec. spawner (execs "stty") resize - noexec. changes state (signal handlers) rev - runner rm - noexec. rm -i interactive @@ -330,7 +330,7 @@ ssl_client - longterm start-stop-daemon stat - nofork candidate(needs fewer allocs) strings - runner -stty - noexec/nofork candidate. has no allocs or opens except xmove_fd(xopen("-F DEVICE"),STDIN). tcsetattr(STDIN) is not a problem: it would work the same across processes sharing this fd +stty - noexec. nofork candidate: has no allocs or opens except xmove_fd(xopen("-F DEVICE"),STDIN). tcsetattr(STDIN) is not a problem: it would work the same across processes sharing this fd su - suid, spawner sulogin - noexec. spawner sum - runner diff --git a/coreutils/stty.c b/coreutils/stty.c index f987fbbcf..d09f0e453 100644 --- a/coreutils/stty.c +++ b/coreutils/stty.c @@ -25,7 +25,7 @@ //config: help //config: stty is used to change and print terminal line settings. -//applet:IF_STTY(APPLET(stty, BB_DIR_BIN, BB_SUID_DROP)) +//applet:IF_STTY(APPLET_NOEXEC(stty, stty, BB_DIR_BIN, BB_SUID_DROP, stty)) //kbuild:lib-$(CONFIG_STTY) += stty.o -- cgit v1.2.3-55-g6feb From b182e9ad6011909fdb76358431d23d195febaf54 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Fri, 4 Aug 2017 23:04:17 +0200 Subject: libbb: use _exit, not exit, in bb_daemonize_or_rexec() By the time we reach exit in parent, child already exited or execed. We should not re-run libc cleanup code. While at it, introduce bb_daemon_helper() and add a few comments. Signed-off-by: Denys Vlasenko --- console-tools/openvt.c | 4 ++-- debianutils/start_stop_daemon.c | 13 +++++++------ include/libbb.h | 1 + libbb/vfork_daemon_rexec.c | 10 ++++++++-- loginutils/login.c | 4 ++-- printutils/lpd.c | 5 ++--- 6 files changed, 22 insertions(+), 15 deletions(-) diff --git a/console-tools/openvt.c b/console-tools/openvt.c index f3db28367..423122fe9 100644 --- a/console-tools/openvt.c +++ b/console-tools/openvt.c @@ -99,7 +99,7 @@ static int find_free_vtno(void) /*xfunc_error_retval = 3; - do we need compat? */ if (ioctl(fd, VT_OPENQRY, &vtno) != 0 || vtno <= 0) bb_perror_msg_and_die("can't find open VT"); -// Not really needed, grep for DAEMON_ONLY_SANITIZE +// Not really needed, grep for DAEMON_CLOSE_EXTRA_FDS // if (fd > 2) // close(fd); return vtno; @@ -155,7 +155,7 @@ int openvt_main(int argc UNUSED_PARAM, char **argv) /* Grab new VT */ sprintf(vtname, VC_FORMAT, vtno); /* (Try to) clean up stray open fds above fd 2 */ - bb_daemonize_or_rexec(DAEMON_CLOSE_EXTRA_FDS | DAEMON_ONLY_SANITIZE, NULL); + bb_daemon_helper(DAEMON_CLOSE_EXTRA_FDS); close(STDIN_FILENO); /*setsid(); - BAD IDEA: after we exit, child is SIGHUPed... */ xopen(vtname, O_RDWR); diff --git a/debianutils/start_stop_daemon.c b/debianutils/start_stop_daemon.c index 9d60b2c7f..07c104baa 100644 --- a/debianutils/start_stop_daemon.c +++ b/debianutils/start_stop_daemon.c @@ -516,6 +516,11 @@ int start_stop_daemon_main(int argc UNUSED_PARAM, char **argv) /* DAEMON_DEVNULL_STDIO is superfluous - * it's always done by bb_daemonize() */ #else + /* Daemons usually call bb_daemonize_or_rexec(), but SSD can do + * without: SSD is not itself a daemon, it _execs_ a daemon. + * The usual NOMMU problem of "child can't run indefinitely, + * it must exec" does not bite us: we exec anyway. + */ pid_t pid = xvfork(); if (pid != 0) { /* parent */ @@ -525,12 +530,8 @@ int start_stop_daemon_main(int argc UNUSED_PARAM, char **argv) } /* Child */ setsid(); /* detach from controlling tty */ - /* Redirect stdio to /dev/null, close extra FDs. - * We do not actually daemonize because of DAEMON_ONLY_SANITIZE */ - bb_daemonize_or_rexec(DAEMON_DEVNULL_STDIO - + DAEMON_CLOSE_EXTRA_FDS - + DAEMON_ONLY_SANITIZE, - NULL /* argv, unused */ ); + /* Redirect stdio to /dev/null, close extra FDs */ + bb_daemon_helper(DAEMON_DEVNULL_STDIO + DAEMON_CLOSE_EXTRA_FDS); #endif } if (opt & OPT_MAKEPID) { diff --git a/include/libbb.h b/include/libbb.h index bb27c59a1..6a2a2d640 100644 --- a/include/libbb.h +++ b/include/libbb.h @@ -1169,6 +1169,7 @@ enum { #endif void bb_daemonize_or_rexec(int flags, char **argv) FAST_FUNC; void bb_sanitize_stdio(void) FAST_FUNC; +#define bb_daemon_helper(arg) bb_daemonize_or_rexec((arg) | DAEMON_ONLY_SANITIZE, NULL) /* Clear dangerous stuff, set PATH. Return 1 if was run by different user. */ int sanitize_env_if_suid(void) FAST_FUNC; diff --git a/libbb/vfork_daemon_rexec.c b/libbb/vfork_daemon_rexec.c index 98512bb00..f84e678b5 100644 --- a/libbb/vfork_daemon_rexec.c +++ b/libbb/vfork_daemon_rexec.c @@ -209,6 +209,9 @@ pid_t FAST_FUNC fork_or_rexec(char **argv) /* Maybe we are already re-execed and come here again? */ if (re_execed) return 0; + + /* fflush_all(); ? - so far all callers had no buffered output to flush */ + pid = xvfork(); if (pid) /* parent */ return pid; @@ -245,8 +248,11 @@ void FAST_FUNC bb_daemonize_or_rexec(int flags, char **argv) fd = dup(fd); /* have 0,1,2 open at least to /dev/null */ if (!(flags & DAEMON_ONLY_SANITIZE)) { + + /* fflush_all(); - add it in fork_or_rexec() if necessary */ + if (fork_or_rexec(argv)) - exit(EXIT_SUCCESS); /* parent */ + _exit(EXIT_SUCCESS); /* parent */ /* if daemonizing, detach from stdio & ctty */ setsid(); dup2(fd, 0); @@ -258,7 +264,7 @@ void FAST_FUNC bb_daemonize_or_rexec(int flags, char **argv) * Prevent this: stop being a session leader. */ if (fork_or_rexec(argv)) - exit(EXIT_SUCCESS); /* parent */ + _exit(EXIT_SUCCESS); /* parent */ } } while (fd > 2) { diff --git a/loginutils/login.c b/loginutils/login.c index 381468d81..fcdb9592c 100644 --- a/loginutils/login.c +++ b/loginutils/login.c @@ -350,8 +350,8 @@ int login_main(int argc UNUSED_PARAM, char **argv) /* Mandatory paranoia for suid applet: * ensure that fd# 0,1,2 are opened (at least to /dev/null) * and any extra open fd's are closed. - * (The name of the function is misleading. Not daemonizing here.) */ - bb_daemonize_or_rexec(DAEMON_ONLY_SANITIZE | DAEMON_CLOSE_EXTRA_FDS, NULL); + */ + bb_daemon_helper(DAEMON_CLOSE_EXTRA_FDS); username[0] = '\0'; opt = getopt32(argv, "f:h:p", &opt_user, &opt_host); diff --git a/printutils/lpd.c b/printutils/lpd.c index 3fdba5d2b..662d3a224 100644 --- a/printutils/lpd.c +++ b/printutils/lpd.c @@ -198,9 +198,8 @@ int lpd_main(int argc UNUSED_PARAM, char *argv[]) q = p; // next line } // helper should not talk over network. - // this call reopens stdio fds to "/dev/null" - // (no daemonization is done) - bb_daemonize_or_rexec(DAEMON_DEVNULL_STDIO | DAEMON_ONLY_SANITIZE, NULL); + // this call reopens stdio fds to "/dev/null". + bb_daemon_helper(DAEMON_DEVNULL_STDIO); BB_EXECVP_or_die(argv); } -- cgit v1.2.3-55-g6feb From 9f59849daab488b5a46926a2979e8b957021e844 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Sat, 5 Aug 2017 01:29:12 +0200 Subject: blockdev, fsfreeze, fstrim, mountpoint: make NOEXEC Signed-off-by: Denys Vlasenko --- NOFORK_NOEXEC.lst | 8 ++++---- util-linux/blockdev.c | 2 +- util-linux/fsfreeze.c | 2 +- util-linux/fstrim.c | 2 +- util-linux/mountpoint.c | 2 +- 5 files changed, 8 insertions(+), 8 deletions(-) diff --git a/NOFORK_NOEXEC.lst b/NOFORK_NOEXEC.lst index ad49cd809..b2f410177 100644 --- a/NOFORK_NOEXEC.lst +++ b/NOFORK_NOEXEC.lst @@ -51,7 +51,7 @@ basename - NOFORK beep blkdiscard blkid -blockdev - noexec candidate (rather simple), leaks fd +blockdev - noexec. leaks fd bootchartd - daemon brctl bunzip2 - runner @@ -134,8 +134,8 @@ free - nofork candidate(struct globals, needs to close /proc/meminfo fd) freeramdisk - leaks: open+ioctl_or_perror_and_die fsck - interactive, longterm fsck.minix - needs ^C -fsfreeze - noexec candidate (it's very simple), leaks: open+xioctl -fstrim - noexec candidate (it's very simple), leaks: open+xioctl, find_block_device -> readdir+xstrdup +fsfreeze - noexec. leaks: open+xioctl +fstrim - noexec. leaks: open+xioctl, find_block_device -> readdir+xstrdup fsync - NOFORK ftpd - daemon ftpget - runner @@ -236,7 +236,7 @@ modinfo - noexec modprobe - noexec more - interactive, longterm mount - suid -mountpoint - noexec candidate, leaks: option -n "print dev name": find_block_device -> readdir+xstrdup +mountpoint - noexec. leaks: option -n "print dev name": find_block_device -> readdir+xstrdup mpstat - noexec candidate (it's a measuring tool, putting less load by itself is good), complex mt - rare mv - noexec candidate, runner diff --git a/util-linux/blockdev.c b/util-linux/blockdev.c index 9e1fef206..e53ade995 100644 --- a/util-linux/blockdev.c +++ b/util-linux/blockdev.c @@ -11,7 +11,7 @@ //config: help //config: Performs some ioctls with block devices. -//applet:IF_BLOCKDEV(APPLET(blockdev, BB_DIR_SBIN, BB_SUID_DROP)) +//applet:IF_BLOCKDEV(APPLET_NOEXEC(blockdev, blockdev, BB_DIR_SBIN, BB_SUID_DROP, blockdev)) //kbuild:lib-$(CONFIG_BLOCKDEV) += blockdev.o diff --git a/util-linux/fsfreeze.c b/util-linux/fsfreeze.c index 5c10c8044..c1f31569f 100644 --- a/util-linux/fsfreeze.c +++ b/util-linux/fsfreeze.c @@ -13,7 +13,7 @@ //config: help //config: Halt new accesses and flush writes on a mounted filesystem. -//applet:IF_FSFREEZE(APPLET(fsfreeze, BB_DIR_USR_SBIN, BB_SUID_DROP)) +//applet:IF_FSFREEZE(APPLET_NOEXEC(fsfreeze, fsfreeze, BB_DIR_USR_SBIN, BB_SUID_DROP, fsfreeze)) //kbuild:lib-$(CONFIG_FSFREEZE) += fsfreeze.o diff --git a/util-linux/fstrim.c b/util-linux/fstrim.c index 6d0d61d92..49b3ceb72 100644 --- a/util-linux/fstrim.c +++ b/util-linux/fstrim.c @@ -15,7 +15,7 @@ //config: help //config: Discard unused blocks on a mounted filesystem. -//applet:IF_FSTRIM(APPLET(fstrim, BB_DIR_SBIN, BB_SUID_DROP)) +//applet:IF_FSTRIM(APPLET_NOEXEC(fstrim, fstrim, BB_DIR_SBIN, BB_SUID_DROP, fstrim)) //kbuild:lib-$(CONFIG_FSTRIM) += fstrim.o diff --git a/util-linux/mountpoint.c b/util-linux/mountpoint.c index b7f048196..50772533f 100644 --- a/util-linux/mountpoint.c +++ b/util-linux/mountpoint.c @@ -14,7 +14,7 @@ //config: help //config: mountpoint checks if the directory is a mountpoint. -//applet:IF_MOUNTPOINT(APPLET(mountpoint, BB_DIR_BIN, BB_SUID_DROP)) +//applet:IF_MOUNTPOINT(APPLET_NOEXEC(mountpoint, mountpoint, BB_DIR_BIN, BB_SUID_DROP, mountpoint)) //kbuild:lib-$(CONFIG_MOUNTPOINT) += mountpoint.o -- cgit v1.2.3-55-g6feb From 754e9f96defd7be48dfdc9ffe820c3fb7f35ff9e Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Sat, 5 Aug 2017 01:38:55 +0200 Subject: svc: fix a case where with more than option, getopt() state is not reset Signed-off-by: Denys Vlasenko --- runit/sv.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/runit/sv.c b/runit/sv.c index 3dd02550a..3267c7e4c 100644 --- a/runit/sv.c +++ b/runit/sv.c @@ -718,15 +718,16 @@ int svc_main(int argc UNUSED_PARAM, char **argv) argv[1] = command; command[1] = '\0'; - /* getopt32() was already called: - * reset the libc getopt() function, which keeps internal state. - */ - GETOPT_RESET(); - do { if (opts & 1) { int r; + command[0] = *optstring; + + /* getopt() was already called by getopt32(): + * reset the libc getopt() function's internal state. + */ + GETOPT_RESET(); r = sv(argv); if (r) return 1; -- cgit v1.2.3-55-g6feb From a453ca576fba45849784322681a4515bdab9ceab Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Sat, 5 Aug 2017 01:42:08 +0200 Subject: sv, svc: make them NOEXEC Signed-off-by: Denys Vlasenko --- NOFORK_NOEXEC.lst | 4 ++-- runit/sv.c | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/NOFORK_NOEXEC.lst b/NOFORK_NOEXEC.lst index b2f410177..f6cc548d2 100644 --- a/NOFORK_NOEXEC.lst +++ b/NOFORK_NOEXEC.lst @@ -334,8 +334,8 @@ stty - noexec. nofork candidate: has no allocs or opens except xmove_fd(xopen("- su - suid, spawner sulogin - noexec. spawner sum - runner -sv - noexec candidate, needs ^C (uses usleep(420000)) -svc - noexec candidate, needs ^C (uses usleep(420000)) +sv - noexec. needs ^C (uses usleep(420000)) +svc - noexec. needs ^C (uses usleep(420000)) svlogd - daemon swapoff - rare swapon - rare diff --git a/runit/sv.c b/runit/sv.c index 3267c7e4c..0817ab472 100644 --- a/runit/sv.c +++ b/runit/sv.c @@ -175,8 +175,8 @@ Exit Codes //config: svc controls the state of services monitored by the runsv supervisor. //config: It is comaptible with daemontools command with the same name. -//applet:IF_SV(APPLET(sv, BB_DIR_USR_BIN, BB_SUID_DROP)) -//applet:IF_SVC(APPLET(svc, BB_DIR_USR_BIN, BB_SUID_DROP)) +//applet:IF_SV( APPLET_NOEXEC(sv, sv, BB_DIR_USR_BIN, BB_SUID_DROP, sv )) +//applet:IF_SVC(APPLET_NOEXEC(svc, svc, BB_DIR_USR_BIN, BB_SUID_DROP, svc)) //kbuild:lib-$(CONFIG_SV) += sv.o //kbuild:lib-$(CONFIG_SVC) += sv.o -- cgit v1.2.3-55-g6feb From 9c49d6e11b54bd0695240119f5f28672173f6300 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Sat, 5 Aug 2017 01:46:39 +0200 Subject: partprobe: make it NOEXEC Signed-off-by: Denys Vlasenko --- NOFORK_NOEXEC.lst | 2 +- miscutils/partprobe.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/NOFORK_NOEXEC.lst b/NOFORK_NOEXEC.lst index f6cc548d2..0e1fb1f55 100644 --- a/NOFORK_NOEXEC.lst +++ b/NOFORK_NOEXEC.lst @@ -252,7 +252,7 @@ nproc - NOFORK ntpd - daemon od - runner openvt - longterm: spawns a child and waits for it -partprobe - noexec candidate (simple), leaks: open+ioctl_or_perror_and_die(BLKRRPART) +partprobe - noexec. leaks: open+ioctl_or_perror_and_die(BLKRRPART) passwd - suid paste - noexec. runner patch - needs ^C diff --git a/miscutils/partprobe.c b/miscutils/partprobe.c index 2c12a7d20..d1ae27348 100644 --- a/miscutils/partprobe.c +++ b/miscutils/partprobe.c @@ -11,7 +11,7 @@ //config: help //config: Ask kernel to rescan partition table. -//applet:IF_PARTPROBE(APPLET(partprobe, BB_DIR_USR_SBIN, BB_SUID_DROP)) +//applet:IF_PARTPROBE(APPLET_NOEXEC(partprobe, partprobe, BB_DIR_USR_SBIN, BB_SUID_DROP, partprobe)) //kbuild:lib-$(CONFIG_PARTPROBE) += partprobe.o -- cgit v1.2.3-55-g6feb From fdb92359e47eee8ccd57092928cedccb28ce2f11 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Sat, 5 Aug 2017 01:51:12 +0200 Subject: pivot_root: make it NOFORK Signed-off-by: Denys Vlasenko --- NOFORK_NOEXEC.lst | 2 +- util-linux/pivot_root.c | 6 ++++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/NOFORK_NOEXEC.lst b/NOFORK_NOEXEC.lst index 0e1fb1f55..2fc280596 100644 --- a/NOFORK_NOEXEC.lst +++ b/NOFORK_NOEXEC.lst @@ -261,7 +261,7 @@ pidof - nofork candidate(uses find_pid_by_name, is that ok?) ping - suid, runner ping6 - suid, runner pipe_progress - longterm -pivot_root - nofork candidate? the code is trivial +pivot_root - NOFORK pkill - nofork candidate(xregcomp, procps_scan - are they ok?) pmap - noexec candidate, leaks: open+xstrdup popmaildir - runner diff --git a/util-linux/pivot_root.c b/util-linux/pivot_root.c index 331038057..d6a26b912 100644 --- a/util-linux/pivot_root.c +++ b/util-linux/pivot_root.c @@ -21,7 +21,7 @@ //config: Note: This is for initrd in linux 2.4. Under initramfs (introduced //config: in linux 2.6) use switch_root instead. -//applet:IF_PIVOT_ROOT(APPLET(pivot_root, BB_DIR_SBIN, BB_SUID_DROP)) +//applet:IF_PIVOT_ROOT(APPLET_NOFORK(pivot_root, pivot_root, BB_DIR_SBIN, BB_SUID_DROP, pivot_root)) //kbuild:lib-$(CONFIG_PIVOT_ROOT) += pivot_root.o @@ -33,7 +33,7 @@ #include "libbb.h" -extern int pivot_root(const char * new_root,const char * put_old); +extern int pivot_root(const char *new_root, const char *put_old); int pivot_root_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; int pivot_root_main(int argc, char **argv) @@ -41,6 +41,8 @@ int pivot_root_main(int argc, char **argv) if (argc != 3) bb_show_usage(); + /* NOFORK applet. Hardly matters wrt performance, but code is trivial */ + if (pivot_root(argv[1], argv[2]) < 0) { /* prints "pivot_root: " */ bb_perror_nomsg_and_die(); -- cgit v1.2.3-55-g6feb From ff53bee72300ba97c645404a64c7091991ffa110 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Sat, 5 Aug 2017 02:02:31 +0200 Subject: chvt, deallocvt, dumpkmap, fgconsole, loadkmap: make them NOEXEC Signed-off-by: Denys Vlasenko --- NOFORK_NOEXEC.lst | 10 +++++----- console-tools/chvt.c | 2 +- console-tools/deallocvt.c | 2 +- console-tools/dumpkmap.c | 2 +- console-tools/fgconsole.c | 2 +- console-tools/loadkmap.c | 2 +- 6 files changed, 10 insertions(+), 10 deletions(-) diff --git a/NOFORK_NOEXEC.lst b/NOFORK_NOEXEC.lst index 2fc280596..1d23ad962 100644 --- a/NOFORK_NOEXEC.lst +++ b/NOFORK_NOEXEC.lst @@ -69,7 +69,7 @@ chpasswd - runner (list of "user:password"s from stdin) chpst - noexec. spawner chroot - noexec. spawner chrt - noexec. spawner -chvt - leaks: get_console_fd_or_die() may open a new fd, or return one of stdio fds. Also, "rare" category. noexec candidate. +chvt - noexec. leaks: get_console_fd_or_die() may open a new fd, or return one of stdio fds cksum - noexec. runner clear - NOFORK cmp - runner @@ -85,7 +85,7 @@ cut - noexec. runner date - noexec. nofork candidate(needs to stop messing up env, free xasprintf result, not use xfuncs after xasprintf) dc - runner (eats stdin if no params) dd - noexec. runner -deallocvt - leaks: get_console_fd_or_die() may open a new fd, or return one of stdio fds. Also, "rare" category. noexec candidate. +deallocvt - noexec. leaks: get_console_fd_or_die() may open a new fd, or return one of stdio fds delgroup deluser depmod - complex, rare @@ -100,7 +100,7 @@ dnsdomainname - needs ^C (may talk to DNS servers, which may be down) dos2unix - noexec. runner dpkg - runner du - runner -dumpkmap - leaks: get_console_fd_or_die() may open a new fd, or return one of stdio fds. Also, "rare" category. noexec candidate. +dumpkmap - noexec. leaks: get_console_fd_or_die() may open a new fd, or return one of stdio fds dumpleases - leaks: open+xread echo - NOFORK ed - interactive, longterm @@ -120,7 +120,7 @@ fbsplash - runner, longterm fdflush - leaks: open+ioctl_or_perror_and_die, needs ^C (floppy may be unresponsive), rare fdformat - needs ^C (floppy may be unresponsive), longterm, rare fdisk - interactive, longterm -fgconsole - leaks: get_console_fd_or_die() may open a new fd, or return one of stdio fds. Also, "rare" category. noexec candidate. +fgconsole - noexec. leaks: get_console_fd_or_die() may open a new fd, or return one of stdio fds fgrep - longterm runner ("CMD | fgrep ..." may run indefinitely, better to exec to conserve memory) find - noexec. runner findfs - suid @@ -195,7 +195,7 @@ linux64 - noexec. spawner linuxrc - daemon ln - noexec loadfont - leaks: config_open+bb_error_msg_and_die("map format") -loadkmap - leaks: get_console_fd_or_die() may open a new fd, or return one of stdio fds. Also, "rare" category. noexec candidate. +loadkmap - noexec. leaks: get_console_fd_or_die() may open a new fd, or return one of stdio fds logger - runner login - suid, interactive, longterm logname - NOFORK diff --git a/console-tools/chvt.c b/console-tools/chvt.c index d8152de6b..75380a90b 100644 --- a/console-tools/chvt.c +++ b/console-tools/chvt.c @@ -14,7 +14,7 @@ //config: This program is used to change to another terminal. //config: Example: chvt 4 (change to terminal /dev/tty4) -//applet:IF_CHVT(APPLET(chvt, BB_DIR_USR_BIN, BB_SUID_DROP)) +//applet:IF_CHVT(APPLET_NOEXEC(chvt, chvt, BB_DIR_USR_BIN, BB_SUID_DROP, chvt)) //kbuild:lib-$(CONFIG_CHVT) += chvt.o diff --git a/console-tools/deallocvt.c b/console-tools/deallocvt.c index 6ffb1471e..05731fb78 100644 --- a/console-tools/deallocvt.c +++ b/console-tools/deallocvt.c @@ -14,7 +14,7 @@ //config: help //config: This program deallocates unused virtual consoles. -//applet:IF_DEALLOCVT(APPLET(deallocvt, BB_DIR_USR_BIN, BB_SUID_DROP)) +//applet:IF_DEALLOCVT(APPLET_NOEXEC(deallocvt, deallocvt, BB_DIR_USR_BIN, BB_SUID_DROP, deallocvt)) //kbuild:lib-$(CONFIG_DEALLOCVT) += deallocvt.o diff --git a/console-tools/dumpkmap.c b/console-tools/dumpkmap.c index d4e2cf281..5ffb0cddb 100644 --- a/console-tools/dumpkmap.c +++ b/console-tools/dumpkmap.c @@ -15,7 +15,7 @@ //config: This program dumps the kernel's keyboard translation table to //config: stdout, in binary format. You can then use loadkmap to load it. -//applet:IF_DUMPKMAP(APPLET(dumpkmap, BB_DIR_BIN, BB_SUID_DROP)) +//applet:IF_DUMPKMAP(APPLET_NOEXEC(dumpkmap, dumpkmap, BB_DIR_BIN, BB_SUID_DROP, dumpkmap)) //kbuild:lib-$(CONFIG_DUMPKMAP) += dumpkmap.o diff --git a/console-tools/fgconsole.c b/console-tools/fgconsole.c index 64311f6ea..a353becd5 100644 --- a/console-tools/fgconsole.c +++ b/console-tools/fgconsole.c @@ -13,7 +13,7 @@ //config: help //config: This program prints active (foreground) console number. -//applet:IF_FGCONSOLE(APPLET(fgconsole, BB_DIR_USR_BIN, BB_SUID_DROP)) +//applet:IF_FGCONSOLE(APPLET_NOEXEC(fgconsole, fgconsole, BB_DIR_USR_BIN, BB_SUID_DROP, fgconsole)) //kbuild:lib-$(CONFIG_FGCONSOLE) += fgconsole.o diff --git a/console-tools/loadkmap.c b/console-tools/loadkmap.c index 839dc2083..404aba1fb 100644 --- a/console-tools/loadkmap.c +++ b/console-tools/loadkmap.c @@ -14,7 +14,7 @@ //config: This program loads a keyboard translation table from //config: standard input. -//applet:IF_LOADKMAP(APPLET(loadkmap, BB_DIR_SBIN, BB_SUID_DROP)) +//applet:IF_LOADKMAP(APPLET_NOEXEC(loadkmap, loadkmap, BB_DIR_SBIN, BB_SUID_DROP, loadkmap)) //kbuild:lib-$(CONFIG_LOADKMAP) += loadkmap.o -- cgit v1.2.3-55-g6feb From feb79e8742eb3cef211804dadcc7f3ddfd154c72 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Sat, 5 Aug 2017 02:08:23 +0200 Subject: cryptpw, mkpasswd: make them NOEXEC Signed-off-by: Denys Vlasenko --- NOFORK_NOEXEC.lst | 4 ++-- loginutils/cryptpw.c | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/NOFORK_NOEXEC.lst b/NOFORK_NOEXEC.lst index 1d23ad962..1bb571b9c 100644 --- a/NOFORK_NOEXEC.lst +++ b/NOFORK_NOEXEC.lst @@ -79,7 +79,7 @@ cp - noexec. runner cpio - runner crond - daemon crontab 0 leaks: open+xasprintf -cryptpw - changes state: with --password-fd=N, moves N to stdin. Also, "rare" category. noexec candidate. +cryptpw - noexec. changes state: with --password-fd=N, moves N to stdin cttyhack - noexec. spawner cut - noexec. runner date - noexec. nofork candidate(needs to stop messing up env, free xasprintf result, not use xfuncs after xasprintf) @@ -229,7 +229,7 @@ mkfs.ext2 - needs ^C mkfs.minix - needs ^C mkfs.vfat - needs ^C mknod - noexec -mkpasswd - changes state: with --password-fd=N, moves N to stdin. Also, "rare" category. noexec candidate. +mkpasswd - noexec. changes state: with --password-fd=N, moves N to stdin mkswap - needs ^C mktemp - noexec. leaks: xstrdup+concat_path_file modinfo - noexec diff --git a/loginutils/cryptpw.c b/loginutils/cryptpw.c index f8906c59a..136c619bb 100644 --- a/loginutils/cryptpw.c +++ b/loginutils/cryptpw.c @@ -24,9 +24,9 @@ //config: using the given salt. Debian has this utility under mkpasswd //config: name. Busybox provides mkpasswd as an alias for cryptpw. -//applet:IF_CRYPTPW(APPLET(cryptpw, BB_DIR_USR_BIN, BB_SUID_DROP)) -// APPLET_ODDNAME:name main location suid_type help -//applet:IF_MKPASSWD(APPLET_ODDNAME(mkpasswd, cryptpw, BB_DIR_USR_BIN, BB_SUID_DROP, cryptpw)) +//applet:IF_CRYPTPW( APPLET_NOEXEC(cryptpw, cryptpw, BB_DIR_USR_BIN, BB_SUID_DROP, cryptpw)) +// APPLET_NOEXEC:name main location suid_type help +//applet:IF_MKPASSWD(APPLET_NOEXEC(mkpasswd, cryptpw, BB_DIR_USR_BIN, BB_SUID_DROP, cryptpw)) //kbuild:lib-$(CONFIG_CRYPTPW) += cryptpw.o //kbuild:lib-$(CONFIG_MKPASSWD) += cryptpw.o -- cgit v1.2.3-55-g6feb From 9cf89cdf84fb20154088145980b676d2b28fc55d Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Sat, 5 Aug 2017 13:45:22 +0200 Subject: sysctl: fix file parsing, do not require -w for VAR=VAL function old new delta sysctl_act_on_setting - 451 +451 sysctl_main 222 282 +60 packed_usage 31744 31793 +49 config_read 604 639 +35 sysctl_act_recursive 612 163 -449 ------------------------------------------------------------------------------ (add/remove: 1/0 grow/shrink: 3/1 up/down: 595/-449) Total: 146 bytes Signed-off-by: Denys Vlasenko --- libbb/parse_config.c | 10 +++++----- procps/sysctl.c | 51 +++++++++++++++++++++++++++++++++------------------ testsuite/mdev.tests | 4 ++-- testsuite/parse.tests | 44 +++++++++++++++++++++++++++++++++++++------- 4 files changed, 77 insertions(+), 32 deletions(-) diff --git a/libbb/parse_config.c b/libbb/parse_config.c index 307ae2cd2..da7482c6d 100644 --- a/libbb/parse_config.c +++ b/libbb/parse_config.c @@ -201,10 +201,10 @@ int FAST_FUNC config_read(parser_t *parser, char **tokens, unsigned flags, const /* Combine remaining arguments? */ if ((t != (ntokens-1)) || !(flags & PARSE_GREEDY)) { /* Vanilla token, find next delimiter */ - line += strcspn(line, delims[0] ? delims : delims + 1); + line += strcspn(line, (delims[0] && (flags & PARSE_EOL_COMMENTS)) ? delims : delims + 1); } else { /* Combining, find comment char if any */ - line = strchrnul(line, PARSE_EOL_COMMENTS ? delims[0] : '\0'); + line = strchrnul(line, (flags & PARSE_EOL_COMMENTS) ? delims[0] : '\0'); /* Trim any extra delimiters from the end */ if (flags & PARSE_TRIM) { @@ -214,10 +214,10 @@ int FAST_FUNC config_read(parser_t *parser, char **tokens, unsigned flags, const } /* Token not terminated? */ - if (*line == delims[0]) - *line = '\0'; + if ((flags & PARSE_EOL_COMMENTS) && *line == delims[0]) + *line = '\0'; /* ends with comment char: this line is done */ else if (*line != '\0') - *line++ = '\0'; + *line++ = '\0'; /* token is done, continue parsing line */ #if 0 /* unused so far */ if (flags & PARSE_ESCAPE) { diff --git a/procps/sysctl.c b/procps/sysctl.c index b17f5e896..619f4f1e4 100644 --- a/procps/sysctl.c +++ b/procps/sysctl.c @@ -21,17 +21,17 @@ //kbuild:lib-$(CONFIG_BB_SYSCTL) += sysctl.o //usage:#define sysctl_trivial_usage -//usage: "[OPTIONS] [KEY[=VALUE]]..." +//usage: "-p [-enq] [FILE...] / [-enqaw] [KEY[=VALUE]]..." //usage:#define sysctl_full_usage "\n\n" //usage: "Show/set kernel parameters\n" +//usage: "\n -p Set values from FILEs (default /etc/sysctl.conf)" //usage: "\n -e Don't warn about unknown keys" //usage: "\n -n Don't show key names" +//usage: "\n -q Quiet" //usage: "\n -a Show all values" /* Same as -a, no need to show it */ /* //usage: "\n -A Show all values in table form" */ //usage: "\n -w Set values" -//usage: "\n -p FILE Set values from FILE (default /etc/sysctl.conf)" -//usage: "\n -q Set values silently" //usage: //usage:#define sysctl_example_usage //usage: "sysctl [-n] [-e] variable...\n" @@ -48,7 +48,7 @@ enum { FLAG_TABLE_FORMAT = 1 << 2, /* not implemented */ FLAG_SHOW_ALL = 1 << 3, FLAG_PRELOAD_FILE = 1 << 4, -/* TODO: procps 3.2.8 seems to not require -w for KEY=VAL to work: */ + /* NB: procps 3.2.8 does not require -w for KEY=VAL to work, it only rejects non-KEY=VAL form */ FLAG_WRITE = 1 << 5, FLAG_QUIET = 1 << 6, }; @@ -104,6 +104,7 @@ static int sysctl_act_on_setting(char *setting) int fd, retval = EXIT_SUCCESS; char *cptr, *outname; char *value = value; /* for compiler */ + bool writing = (option_mask32 & FLAG_WRITE); outname = xstrdup(setting); @@ -114,8 +115,10 @@ static int sysctl_act_on_setting(char *setting) cptr++; } - if (option_mask32 & FLAG_WRITE) { - cptr = strchr(setting, '='); + cptr = strchr(setting, '='); + if (cptr) + writing = 1; + if (writing) { if (cptr == NULL) { bb_error_msg("error: '%s' must be of the form name=value", outname); @@ -147,7 +150,7 @@ static int sysctl_act_on_setting(char *setting) break; default: bb_perror_msg("error %sing key '%s'", - option_mask32 & FLAG_WRITE ? + writing ? "sett" : "read", outname); break; @@ -156,7 +159,7 @@ static int sysctl_act_on_setting(char *setting) goto end; } - if (option_mask32 & FLAG_WRITE) { + if (writing) { //TODO: procps 3.2.7 writes "value\n", note trailing "\n" xwrite_str(fd, value); close(fd); @@ -238,22 +241,27 @@ static int sysctl_handle_preload_file(const char *filename) { char *token[2]; parser_t *parser; + int parse_flags; parser = config_open(filename); /* Must do it _after_ config_open(): */ xchdir("/proc/sys"); - /* xchroot("/proc/sys") - if you are paranoid */ //TODO: ';' is comment char too -//TODO: comment may be only at line start. "var=1 #abc" - "1 #abc" is the value -// (but _whitespace_ from ends should be trimmed first (and we do it right)) -//TODO: "var==1" is mishandled (must use "=1" as a value, but uses "1") -// can it be fixed by removing PARSE_COLLAPSE bit? - while (config_read(parser, token, 2, 2, "# \t=", PARSE_NORMAL)) { +//TODO: #comment is also comment, not strictly 1st char only + parse_flags = 0; + parse_flags &= ~PARSE_COLLAPSE; // NO (var==val is not var=val) - treat consecutive delimiters as one + parse_flags &= ~PARSE_TRIM; // NO - trim leading and trailing delimiters + parse_flags |= PARSE_GREEDY; // YES - last token takes entire remainder of the line + parse_flags &= ~PARSE_MIN_DIE; // NO - die if < min tokens found + parse_flags &= ~PARSE_EOL_COMMENTS; // NO (only first char) - comments are recognized even if not first char + while (config_read(parser, token, 2, 2, "#=", parse_flags)) { char *tp; + trim(token[0]); + trim(token[1]); sysctl_dots_to_slashes(token[0]); tp = xasprintf("%s=%s", token[0], token[1]); - sysctl_act_recursive(tp); + sysctl_act_on_setting(tp); free(tp); } if (ENABLE_FEATURE_CLEAN_UP) @@ -273,12 +281,19 @@ int sysctl_main(int argc UNUSED_PARAM, char **argv) option_mask32 = opt; if (opt & FLAG_PRELOAD_FILE) { + int cur_dir_fd; option_mask32 |= FLAG_WRITE; - /* xchdir("/proc/sys") is inside */ - return sysctl_handle_preload_file(*argv ? *argv : "/etc/sysctl.conf"); + if (!*argv) + *--argv = (char*)"/etc/sysctl.conf"; + cur_dir_fd = xopen(".", O_RDONLY | O_DIRECTORY); + do { + /* xchdir("/proc/sys") is inside */ + sysctl_handle_preload_file(*argv); + xfchdir(cur_dir_fd); /* files can be relative, must restore cwd */ + } while (*++argv); + return 0; /* procps-ng 3.3.10 does not flag parse errors */ } xchdir("/proc/sys"); - /* xchroot("/proc/sys") - if you are paranoid */ if (opt & (FLAG_TABLE_FORMAT | FLAG_SHOW_ALL)) { return sysctl_act_recursive("."); } diff --git a/testsuite/mdev.tests b/testsuite/mdev.tests index 8515aff31..8e53ec564 100755 --- a/testsuite/mdev.tests +++ b/testsuite/mdev.tests @@ -168,7 +168,7 @@ SKIP= # continuing to use directory structure from prev test rm -rf mdev.testdir/dev/* echo "sda 0:0 644 @echo @echo TEST" >mdev.testdir/etc/mdev.conf -optional STATIC FEATURE_MDEV_CONF FEATURE_MDEV_EXEC FEATURE_LS_RECURSIVE FEATURE_LS_TIMESTAMPS FEATURE_LS_USERNAME FEATURE_SH_IS_ASH ASH_ECHO +optional STATIC FEATURE_MDEV_CONF FEATURE_MDEV_EXEC FEATURE_LS_RECURSIVE FEATURE_LS_TIMESTAMPS FEATURE_LS_USERNAME SH_IS_ASH ASH_ECHO testing "mdev command" \ "env - PATH=$PATH ACTION=add DEVPATH=/block/sda chroot mdev.testdir /mdev 2>&1; ls -lnR mdev.testdir/dev | $FILTER_LS" \ @@ -183,7 +183,7 @@ SKIP= # continuing to use directory structure from prev test rm -rf mdev.testdir/dev/* echo "sda 0:0 644 =block/ @echo @echo TEST:\$MDEV" >mdev.testdir/etc/mdev.conf -optional STATIC FEATURE_MDEV_CONF FEATURE_MDEV_RENAME FEATURE_MDEV_EXEC FEATURE_LS_RECURSIVE FEATURE_LS_TIMESTAMPS FEATURE_LS_USERNAME FEATURE_SH_IS_ASH +optional STATIC FEATURE_MDEV_CONF FEATURE_MDEV_RENAME FEATURE_MDEV_EXEC FEATURE_LS_RECURSIVE FEATURE_LS_TIMESTAMPS FEATURE_LS_USERNAME SH_IS_ASH testing "mdev move and command" \ "env - PATH=$PATH ACTION=add DEVPATH=/block/sda chroot mdev.testdir /mdev 2>&1; ls -lnR mdev.testdir/dev | $FILTER_LS2" \ diff --git a/testsuite/parse.tests b/testsuite/parse.tests index 904e1a17a..2cbed6f31 100755 --- a/testsuite/parse.tests +++ b/testsuite/parse.tests @@ -5,13 +5,13 @@ . ./testing.sh -COLLAPSE=$(( 0x00010000)) -TRIM=$(( 0x00020000)) -GREEDY=$(( 0x00040000)) -MIN_DIE=$(( 0x00100000)) -KEEP_COPY=$((0x00200000)) -ESCAPE=$(( 0x00400000)) -NORMAL=$(( COLLAPSE | TRIM | GREEDY)) +COLLAPSE=$(( 0x00010000)) +TRIM=$(( 0x00020000)) +GREEDY=$(( 0x00040000)) +MIN_DIE=$(( 0x00100000)) +KEEP_COPY=$(( 0x00200000)) +EOL_COMMENTS=$((0x00400000)) +NORMAL=$(( COLLAPSE | TRIM | GREEDY | EOL_COMMENTS)) # testing "description" "command" "result" "infile" "stdin" @@ -27,6 +27,34 @@ testing "parse notrim" \ "-" \ " sda 0:0 644 @echo @echo TEST \n" +testing "parse comments" \ + "parse -n 4 -m 3 -f $((NORMAL - EOL_COMMENTS)) -" \ + "[sda][0:0][644][@echo @echo TEST #this is not eaten]\n" \ + "-" \ + "\ +# sda 0:0 644 @echo @echo TEST - this gets eaten + sda 0:0 644 @echo @echo TEST #this is not eaten +" + +testing "parse bad comment" \ + "parse -n 2 -m 2 -d '#=' -f $((GREEDY)) - 2>&1" \ + "\ +[var][val] +parse: bad line 3: 1 tokens found, 2 needed +[ #this][ok] +[ #this][=ok] +[ #this][=ok=ok=ok=] +" \ + "-" \ + "\ +# this gets eaten +var=val + #this causes error msg + #this=ok + #this==ok + #this==ok=ok=ok= +" + FILE=__parse cat >$FILE <$FILE.res < Date: Sat, 5 Aug 2017 17:50:35 +0200 Subject: libbb: make trim() return pointer to terminating NUL function old new delta trim 80 90 +10 angle_address 56 50 -6 sysctl_main 282 273 -9 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 1/3 up/down: +10/-15) Total: -5 bytes Signed-off-by: Denys Vlasenko --- include/libbb.h | 2 +- libbb/trim.c | 12 ++++++++++-- mailutils/sendmail.c | 5 ++--- miscutils/lsscsi.c | 3 +-- procps/sysctl.c | 12 ++++++++---- 5 files changed, 22 insertions(+), 12 deletions(-) diff --git a/include/libbb.h b/include/libbb.h index 6a2a2d640..6077f64c9 100644 --- a/include/libbb.h +++ b/include/libbb.h @@ -347,7 +347,7 @@ unsigned long long monotonic_ms(void) FAST_FUNC; unsigned monotonic_sec(void) FAST_FUNC; extern void chomp(char *s) FAST_FUNC; -extern void trim(char *s) FAST_FUNC; +extern char *trim(char *s) FAST_FUNC; extern char *skip_whitespace(const char *) FAST_FUNC; extern char *skip_non_whitespace(const char *) FAST_FUNC; extern char *skip_dev_pfx(const char *tty_name) FAST_FUNC; diff --git a/libbb/trim.c b/libbb/trim.c index 16cb4fbb0..e47fec74e 100644 --- a/libbb/trim.c +++ b/libbb/trim.c @@ -10,9 +10,10 @@ #include "libbb.h" -void FAST_FUNC trim(char *s) +char* FAST_FUNC trim(char *s) { size_t len = strlen(s); + size_t old = len; /* trim trailing whitespace */ while (len && isspace(s[len-1])) @@ -26,5 +27,12 @@ void FAST_FUNC trim(char *s) memmove(s, nws, len); } } - s[len] = '\0'; + + s += len; + /* If it was a "const char*" which does not need trimming, + * avoid superfluous store */ + if (old != len) + *s = '\0'; + + return s; } diff --git a/mailutils/sendmail.c b/mailutils/sendmail.c index 346de2712..65895f0ec 100644 --- a/mailutils/sendmail.c +++ b/mailutils/sendmail.c @@ -166,9 +166,8 @@ static char *angle_address(char *str) { char *s, *e; - trim(str); - e = last_char_is(str, '>'); - if (e) { + e = trim(str); + if (e != str && e[-1] == '>') { s = strrchr(str, '<'); if (s) { *e = '\0'; diff --git a/miscutils/lsscsi.c b/miscutils/lsscsi.c index b69ff1eef..c86630e31 100644 --- a/miscutils/lsscsi.c +++ b/miscutils/lsscsi.c @@ -37,9 +37,8 @@ static char *get_line(const char *filename, char *buf, unsigned *bufsize_p) if (sz < 0) sz = 0; buf[sz] = '\0'; - trim(buf); - sz = strlen(buf) + 1; + sz = (trim(buf) - buf) + 1; bufsize -= sz; buf += sz; buf[0] = '\0'; diff --git a/procps/sysctl.c b/procps/sysctl.c index 619f4f1e4..ef1a1b99f 100644 --- a/procps/sysctl.c +++ b/procps/sysctl.c @@ -257,12 +257,16 @@ static int sysctl_handle_preload_file(const char *filename) parse_flags &= ~PARSE_EOL_COMMENTS; // NO (only first char) - comments are recognized even if not first char while (config_read(parser, token, 2, 2, "#=", parse_flags)) { char *tp; - trim(token[0]); + trim(token[1]); + tp = trim(token[0]); sysctl_dots_to_slashes(token[0]); - tp = xasprintf("%s=%s", token[0], token[1]); - sysctl_act_on_setting(tp); - free(tp); + /* ^^^converted in-place. tp still points to NUL */ + /* now, add "=TOKEN1" */ + *tp++ = '='; + overlapping_strcpy(tp, token[1]); + + sysctl_act_on_setting(token[0]); } if (ENABLE_FEATURE_CLEAN_UP) config_close(parser); -- cgit v1.2.3-55-g6feb From 50db1f29bf96c2ae4dbb96763793a9592d99cf02 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Sat, 5 Aug 2017 18:20:34 +0200 Subject: sysctl: recognize ";comment" and "#comment" lines function old new delta config_read 639 699 +60 Signed-off-by: Denys Vlasenko --- include/libbb.h | 5 +++++ libbb/parse_config.c | 12 ++++++++++-- procps/sysctl.c | 7 ++++--- 3 files changed, 19 insertions(+), 5 deletions(-) diff --git a/include/libbb.h b/include/libbb.h index 6077f64c9..51e8f27a5 100644 --- a/include/libbb.h +++ b/include/libbb.h @@ -1403,6 +1403,11 @@ enum { // keep a copy of current line PARSE_KEEP_COPY = 0x00200000 * ENABLE_FEATURE_CROND_D, PARSE_EOL_COMMENTS = 0x00400000, // comments are recognized even if they aren't the first char + PARSE_ALT_COMMENTS = 0x00800000, // delim[0] and delim[1] are two different allowed comment chars + // (so far, delim[0] will only work as comment char for full-line comment) + // (IOW: it works as if PARSE_EOL_COMMENTS is not set. sysctl applet is okay with this) + PARSE_WS_COMMENTS = 0x01000000, // comments are recognized even if there is whitespace before + // ("line start>#comment" is also comment, not only "line start>#comment") // NORMAL is: // * remove leading and trailing delimiters and collapse // multiple delimiters into one diff --git a/libbb/parse_config.c b/libbb/parse_config.c index da7482c6d..eaf69d97f 100644 --- a/libbb/parse_config.c +++ b/libbb/parse_config.c @@ -161,13 +161,18 @@ mintokens > 0 make config_read() print error message if less than mintokens #undef config_read int FAST_FUNC config_read(parser_t *parser, char **tokens, unsigned flags, const char *delims) { - char *line; + char *line, *p; int ntokens, mintokens; int t; + char alt_comment_ch; if (!parser) return 0; + alt_comment_ch = '\0'; + if (flags & PARSE_ALT_COMMENTS) + alt_comment_ch = *delims++; + ntokens = (uint8_t)flags; mintokens = (uint8_t)(flags >> 8); @@ -184,7 +189,10 @@ int FAST_FUNC config_read(parser_t *parser, char **tokens, unsigned flags, const if (flags & PARSE_TRIM) line += strspn(line, delims + 1); - if (line[0] == '\0' || line[0] == delims[0]) + p = line; + if (flags & PARSE_WS_COMMENTS) + p = skip_whitespace(p); + if (p[0] == '\0' || p[0] == delims[0] || p[0] == alt_comment_ch) goto again; if (flags & PARSE_KEEP_COPY) { diff --git a/procps/sysctl.c b/procps/sysctl.c index ef1a1b99f..a42a91247 100644 --- a/procps/sysctl.c +++ b/procps/sysctl.c @@ -247,15 +247,16 @@ static int sysctl_handle_preload_file(const char *filename) /* Must do it _after_ config_open(): */ xchdir("/proc/sys"); -//TODO: ';' is comment char too -//TODO: #comment is also comment, not strictly 1st char only parse_flags = 0; parse_flags &= ~PARSE_COLLAPSE; // NO (var==val is not var=val) - treat consecutive delimiters as one parse_flags &= ~PARSE_TRIM; // NO - trim leading and trailing delimiters parse_flags |= PARSE_GREEDY; // YES - last token takes entire remainder of the line parse_flags &= ~PARSE_MIN_DIE; // NO - die if < min tokens found parse_flags &= ~PARSE_EOL_COMMENTS; // NO (only first char) - comments are recognized even if not first char - while (config_read(parser, token, 2, 2, "#=", parse_flags)) { + parse_flags |= PARSE_ALT_COMMENTS;// YES - two comment chars: ';' and '#' + /* #comment is also comment, not strictly 1st char only */ + parse_flags |= PARSE_WS_COMMENTS; // YES - comments are recognized even if there is whitespace before + while (config_read(parser, token, 2, 2, ";#=", parse_flags)) { char *tp; trim(token[1]); -- cgit v1.2.3-55-g6feb From caf26b36f3c11f6b5c8f8ab2bf829d14e4e6980e Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Sat, 5 Aug 2017 18:23:10 +0200 Subject: sysctl: make it NOEXEC Signed-off-by: Denys Vlasenko --- NOFORK_NOEXEC.lst | 2 +- procps/sysctl.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/NOFORK_NOEXEC.lst b/NOFORK_NOEXEC.lst index 1bb571b9c..78d06f3f5 100644 --- a/NOFORK_NOEXEC.lst +++ b/NOFORK_NOEXEC.lst @@ -341,7 +341,7 @@ swapoff - rare swapon - rare switch_root - spawner, rare, changes state (oh yes), execing may be important to free binary's inode sync - NOFORK -sysctl - noexec candidate, leaks: xstrdup+xmalloc_read +sysctl - noexec. leaks: xstrdup+xmalloc_read syslogd - daemon tac - noexec. runner tail - runner diff --git a/procps/sysctl.c b/procps/sysctl.c index a42a91247..827e09cce 100644 --- a/procps/sysctl.c +++ b/procps/sysctl.c @@ -16,7 +16,7 @@ //config: help //config: Configure kernel parameters at runtime. -//applet:IF_BB_SYSCTL(APPLET(sysctl, BB_DIR_SBIN, BB_SUID_DROP)) +//applet:IF_BB_SYSCTL(APPLET_NOEXEC(sysctl, sysctl, BB_DIR_SBIN, BB_SUID_DROP, sysctl)) //kbuild:lib-$(CONFIG_BB_SYSCTL) += sysctl.o -- cgit v1.2.3-55-g6feb From d3147cd5c38d9f232a9e279562129157e871d1ee Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Sat, 5 Aug 2017 20:33:48 +0200 Subject: chattr: fix option parsing to accept more cryptic option combos function old new delta chattr_main 286 289 +3 packed_usage 31793 31761 -32 Signed-off-by: Denys Vlasenko --- e2fsprogs/chattr.c | 86 ++++++++++++++++++++++++++++++++---------------------- 1 file changed, 51 insertions(+), 35 deletions(-) diff --git a/e2fsprogs/chattr.c b/e2fsprogs/chattr.c index 72327d728..bb870a990 100644 --- a/e2fsprogs/chattr.c +++ b/e2fsprogs/chattr.c @@ -20,9 +20,12 @@ //kbuild:lib-$(CONFIG_CHATTR) += chattr.o e2fs_lib.o //usage:#define chattr_trivial_usage -//usage: "[-R] [-+=AacDdijsStTu] [-v VERSION] [FILE]..." +//usage: "[-R] [-v VERSION] [-+=AacDdijsStTu] FILE..." //usage:#define chattr_full_usage "\n\n" //usage: "Change ext2 file attributes\n" +//usage: "\n -R Recurse" +//usage: "\n -v VER Set version/generation number" +//-V, -f accepted but ignored //usage: "\nModifiers:" //usage: "\n -,+,= Remove/add/set attributes" //usage: "\nAttributes:" @@ -37,8 +40,6 @@ //usage: "\n S Write synchronously" //usage: "\n t Disable tail-merging of partial blocks with other files" //usage: "\n u Allow file to be undeleted" -//usage: "\n -R Recurse" -//usage: "\n -v VER Set version/generation number" #include "libbb.h" #include "e2fs_lib.h" @@ -52,7 +53,7 @@ struct globals { unsigned long version; unsigned long af; unsigned long rf; - smallint flags; + int flags; smallint recursive; }; @@ -64,10 +65,11 @@ static unsigned long get_flag(char c) bb_show_usage(); } -static int decode_arg(const char *arg, struct globals *gp) +static char** decode_arg(char **argv, struct globals *gp) { unsigned long *fl; - char opt = *arg++; + const char *arg = *argv; + char opt = *arg; fl = &gp->af; if (opt == '-') { @@ -75,15 +77,43 @@ static int decode_arg(const char *arg, struct globals *gp) fl = &gp->rf; } else if (opt == '+') { gp->flags |= OPT_ADD; - } else if (opt == '=') { + } else { /* if (opt == '=') */ gp->flags |= OPT_SET; - } else - return 0; + } - while (*arg) - *fl |= get_flag(*arg++); + while (*++arg) { + if (opt == '-') { +//e2fsprogs-1.43.1 accepts: +// "-RRR", "-RRRv VER" and even "-ARRRva VER" and "-vvv V1 V2 V3" +// but not "-vVER". +// IOW: options are parsed as part of "remove attrs" strings, +// if "v" is seen, next argv[] is VER, even if more opts/attrs follow in this argv[]! + if (*arg == 'R') { + gp->recursive = 1; + continue; + } + if (*arg == 'V') { + /*"verbose and print program version" (nop for now) */; + continue; + } + if (*arg == 'f') { + /*"suppress most error messages" (nop) */; + continue; + } + if (*arg == 'v') { + if (!*++argv) + bb_show_usage(); + gp->version = xatoul(*argv); + gp->flags |= OPT_SET_VER; + continue; + } +//TODO: "-p PROJECT_NUM" ? + /* not a known option, try as an attribute */ + } + *fl |= get_flag(*arg); + } - return 1; + return argv; } static void change_attributes(const char *name, struct globals *gp); @@ -133,7 +163,7 @@ static void change_attributes(const char *name, struct globals *gp) fsflags &= ~gp->rf; /*if (gp->flags & OPT_ADD) - not needed, af is zero otherwise */ fsflags |= gp->af; - /* What is this? And why it's not done for SET case? */ +// What is this? And why it's not done for SET case? if (!S_ISDIR(st.st_mode)) fsflags &= ~EXT2_DIRSYNC_FL; } @@ -149,36 +179,22 @@ int chattr_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; int chattr_main(int argc UNUSED_PARAM, char **argv) { struct globals g; - char *arg; memset(&g, 0, sizeof(g)); /* parse the args */ - while ((arg = *++argv)) { - /* take care of -R and -v */ - if (arg[0] == '-' - && (arg[1] == 'R' || arg[1] == 'v') - && !arg[2] - ) { - if (arg[1] == 'R') { - g.recursive = 1; - continue; - } - /* arg[1] == 'v' */ - if (!*++argv) - bb_show_usage(); - g.version = xatoul(*argv); - g.flags |= OPT_SET_VER; - continue; - } - - if (!decode_arg(arg, &g)) + for (;;) { + char *arg = *++argv; + if (!arg) + bb_show_usage(); + if (arg[0] != '-' && arg[0] != '+' && arg[0] != '=') break; + + argv = decode_arg(argv, &g); } + /* note: on loop exit, remaining argv[] is never empty */ /* run sanity checks on all the arguments given us */ - if (!*argv) - bb_show_usage(); if ((g.flags & OPT_SET) && (g.flags & (OPT_ADD|OPT_REM))) bb_error_msg_and_die("= is incompatible with - and +"); if (g.rf & g.af) -- cgit v1.2.3-55-g6feb From 99125c04950a7ba2ac90dc21c3d924fe9dd95651 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Sat, 5 Aug 2017 20:38:04 +0200 Subject: chattr,lsattr,tune2fs: make them NOEXEC Signed-off-by: Denys Vlasenko --- NOFORK_NOEXEC.lst | 6 +++--- e2fsprogs/chattr.c | 2 +- e2fsprogs/lsattr.c | 3 ++- e2fsprogs/tune2fs.c | 2 +- 4 files changed, 7 insertions(+), 6 deletions(-) diff --git a/NOFORK_NOEXEC.lst b/NOFORK_NOEXEC.lst index 78d06f3f5..0b6528d94 100644 --- a/NOFORK_NOEXEC.lst +++ b/NOFORK_NOEXEC.lst @@ -61,7 +61,7 @@ bzip2 - runner cal - runner: cal -n9999 cat - runner chat - needs ^C to work -chattr - runner +chattr - noexec. runner chgrp - noexec. runner chmod - noexec. runner chown - noexec. runner @@ -204,7 +204,7 @@ lpd - daemon lpq - runner lpr - runner ls - noexec. runner -lsattr - runner. noexec candidate (ls is, why not this one?) +lsattr - noexec. runner lsmod - noexec lsof - complex lspci - noexec candidate, too rare to bother for nofork @@ -366,7 +366,7 @@ truncate - NOFORK tty - NOFORK ttysize - NOFORK tunctl -tune2fs - leaks: open+xfunc +tune2fs - noexec. leaks: open+xfunc ubiattach ubidetach ubimkvol diff --git a/e2fsprogs/chattr.c b/e2fsprogs/chattr.c index bb870a990..76a5253b6 100644 --- a/e2fsprogs/chattr.c +++ b/e2fsprogs/chattr.c @@ -15,7 +15,7 @@ //config: help //config: chattr changes the file attributes on a second extended file system. -//applet:IF_CHATTR(APPLET(chattr, BB_DIR_BIN, BB_SUID_DROP)) +//applet:IF_CHATTR(APPLET_NOEXEC(chattr, chattr, BB_DIR_BIN, BB_SUID_DROP, chattr)) //kbuild:lib-$(CONFIG_CHATTR) += chattr.o e2fs_lib.o diff --git a/e2fsprogs/lsattr.c b/e2fsprogs/lsattr.c index 756d26832..56c1187c1 100644 --- a/e2fsprogs/lsattr.c +++ b/e2fsprogs/lsattr.c @@ -16,7 +16,8 @@ //config: help //config: lsattr lists the file attributes on a second extended file system. -//applet:IF_LSATTR(APPLET(lsattr, BB_DIR_BIN, BB_SUID_DROP)) +//applet:IF_LSATTR(APPLET_NOEXEC(lsattr, lsattr, BB_DIR_BIN, BB_SUID_DROP, lsattr)) +/* ls is NOEXEC, so we should be too! ;) */ //kbuild:lib-$(CONFIG_LSATTR) += lsattr.o e2fs_lib.o diff --git a/e2fsprogs/tune2fs.c b/e2fsprogs/tune2fs.c index 95411db5f..9f14b26ec 100644 --- a/e2fsprogs/tune2fs.c +++ b/e2fsprogs/tune2fs.c @@ -13,7 +13,7 @@ //config: tune2fs allows the system administrator to adjust various tunable //config: filesystem parameters on Linux ext2/ext3 filesystems. -//applet:IF_TUNE2FS(APPLET(tune2fs, BB_DIR_SBIN, BB_SUID_DROP)) +//applet:IF_TUNE2FS(APPLET_NOEXEC(tune2fs, tune2fs, BB_DIR_SBIN, BB_SUID_DROP, tune2fs)) //TODO alias to "tune2fs -L LABEL": //applet:IF_E2LABEL(APPLET_ODDNAME(e2label, tune2fs, BB_DIR_SBIN, BB_SUID_DROP, e2label)) -- cgit v1.2.3-55-g6feb From 00c1811d87ea9019c2beda0d182150792c6bb053 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Sat, 5 Aug 2017 22:25:00 +0200 Subject: pstree: make it NOEXEC While at it, documet why ps can't be NOEXEC. Signed-off-by: Denys Vlasenko --- NOFORK_NOEXEC.lst | 4 ++-- procps/ps.c | 24 +++++++++++++----------- procps/pstree.c | 3 +-- 3 files changed, 16 insertions(+), 15 deletions(-) diff --git a/NOFORK_NOEXEC.lst b/NOFORK_NOEXEC.lst index 0b6528d94..fbba3adb3 100644 --- a/NOFORK_NOEXEC.lst +++ b/NOFORK_NOEXEC.lst @@ -269,9 +269,9 @@ poweroff - rare powertop - interactive, longterm printenv - NOFORK printf - NOFORK -ps - noexec candidate +ps - looks for AT_CLKTCK elf aux vector, therefore can't be noexec pscan - longterm -pstree +pstree - noexec pwd - NOFORK pwdx - NOFORK raidautorun diff --git a/procps/ps.c b/procps/ps.c index 081479b33..afd981313 100644 --- a/procps/ps.c +++ b/procps/ps.c @@ -15,7 +15,7 @@ //config: ps gives a snapshot of the current processes. //config: //config:config FEATURE_PS_WIDE -//config: bool "Enable wide output option (-w)" +//config: bool "Enable wide output (-w)" //config: default y //config: depends on PS && !DESKTOP //config: help @@ -24,7 +24,7 @@ //config: than once, the length is unlimited. //config: //config:config FEATURE_PS_LONG -//config: bool "Enable long output option (-l)" +//config: bool "Enable long output (-l)" //config: default y //config: depends on PS && !DESKTOP //config: help @@ -32,11 +32,16 @@ //config: Adds fields PPID, RSS, START, TIME & TTY //config: //config:config FEATURE_PS_TIME -//config: bool "Support -o time and -o etime output specifiers" +//config: bool "Enable -o time and -o etime specifiers" //config: default y //config: depends on PS && DESKTOP //config: select PLATFORM_LINUX //config: +//config:config FEATURE_PS_ADDITIONAL_COLUMNS +//config: bool "Enable -o rgroup, -o ruser, -o nice specifiers" +//config: default y +//config: depends on PS && DESKTOP +//config: //config:config FEATURE_PS_UNUSUAL_SYSTEMS //config: bool "Support Linux prior to 2.4.0 and non-ELF systems" //config: default n @@ -44,13 +49,9 @@ //config: help //config: Include support for measuring HZ on old kernels and non-ELF systems //config: (if you are on Linux 2.4.0+ and use ELF, you don't need this) -//config: -//config:config FEATURE_PS_ADDITIONAL_COLUMNS -//config: bool "Support -o rgroup, -o ruser, -o nice specifiers" -//config: default y -//config: depends on PS && DESKTOP //applet:IF_PS(APPLET(ps, BB_DIR_BIN, BB_SUID_DROP)) +/* can't be NOEXEC: uses ELF aux vector. To have it, we must be a normal, execed process */ //kbuild:lib-$(CONFIG_PS) += ps.o @@ -202,6 +203,7 @@ struct globals { #if ENABLE_FEATURE_PS_TIME /* for ELF executables, notes are pushed before environment and args */ +/* try "LD_SHOW_AUXV=1 /bin/true" */ static uintptr_t find_elf_note(uintptr_t findme) { uintptr_t *ep = (uintptr_t *) environ; @@ -217,7 +219,7 @@ static uintptr_t find_elf_note(uintptr_t findme) return -1; } -#if ENABLE_FEATURE_PS_UNUSUAL_SYSTEMS +# if ENABLE_FEATURE_PS_UNUSUAL_SYSTEMS static unsigned get_HZ_by_waiting(void) { struct timeval tv1, tv2; @@ -260,13 +262,13 @@ static unsigned get_HZ_by_waiting(void) return r; } -#else +# else static inline unsigned get_HZ_by_waiting(void) { /* Better method? */ return 100; } -#endif +# endif static unsigned get_kernel_HZ(void) { diff --git a/procps/pstree.c b/procps/pstree.c index 212cda23c..824907997 100644 --- a/procps/pstree.c +++ b/procps/pstree.c @@ -9,14 +9,13 @@ * * Licensed under GPLv2, see file LICENSE in this source tree. */ - //config:config PSTREE //config: bool "pstree (9.4 kb)" //config: default y //config: help //config: Display a tree of processes. -//applet:IF_PSTREE(APPLET(pstree, BB_DIR_USR_BIN, BB_SUID_DROP)) +//applet:IF_PSTREE(APPLET_NOEXEC(pstree, pstree, BB_DIR_USR_BIN, BB_SUID_DROP, pstree)) //kbuild:lib-$(CONFIG_PSTREE) += pstree.o -- cgit v1.2.3-55-g6feb From 83a6c8d58b3209a1238d24b50c6b717a7c67d1b4 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Sat, 5 Aug 2017 23:21:02 +0200 Subject: umount: make it NOEXEC Signed-off-by: Denys Vlasenko --- NOFORK_NOEXEC.lst | 2 +- util-linux/umount.c | 13 ++++++++++++- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/NOFORK_NOEXEC.lst b/NOFORK_NOEXEC.lst index fbba3adb3..8b35df289 100644 --- a/NOFORK_NOEXEC.lst +++ b/NOFORK_NOEXEC.lst @@ -378,7 +378,7 @@ udhcpc - daemon udhcpd - daemon udpsvd - daemon uevent - daemon -umount - noexec candidate, leaks: nested xmalloc +umount - noexec. leaks: nested xmalloc uname - NOFORK uncompress - runner unexpand - runner diff --git a/util-linux/umount.c b/util-linux/umount.c index 122c0f579..33667b13c 100644 --- a/util-linux/umount.c +++ b/util-linux/umount.c @@ -24,7 +24,18 @@ //config: help //config: Support -a option to unmount all currently mounted filesystems. -//applet:IF_UMOUNT(APPLET(umount, BB_DIR_BIN, BB_SUID_DROP)) +//applet:IF_UMOUNT(APPLET_NOEXEC(umount, umount, BB_DIR_BIN, BB_SUID_DROP, umount)) +/* + * On one hand, in some weird situations you'd want umount + * to not do anything surprising, to behave as a usual fork+execed executable. + * + * OTOH, there can be situations where execing would not succeed, or even hang + * (say, if executable is on a filesystem which is in trouble and accesses to it + * block in kernel). + * In this case, you might be actually happy if your standalone bbox shell + * does not fork+exec, but only forks and calls umount_main() which it already has! + * Let's go with NOEXEC. + */ //kbuild:lib-$(CONFIG_UMOUNT) += umount.o -- cgit v1.2.3-55-g6feb From 3239ab89c9b401096966f6af373b0aa18bce9284 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Sat, 5 Aug 2017 23:28:19 +0200 Subject: lspci,lsscsi,lsusb: make them NOEXEC Signed-off-by: Denys Vlasenko --- NOFORK_NOEXEC.lst | 6 +++--- miscutils/lsscsi.c | 2 +- util-linux/lspci.c | 2 +- util-linux/lsusb.c | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/NOFORK_NOEXEC.lst b/NOFORK_NOEXEC.lst index 8b35df289..c605302d9 100644 --- a/NOFORK_NOEXEC.lst +++ b/NOFORK_NOEXEC.lst @@ -207,9 +207,9 @@ ls - noexec. runner lsattr - noexec. runner lsmod - noexec lsof - complex -lspci - noexec candidate, too rare to bother for nofork -lsscsi - noexec candidate, too rare to bother for nofork -lsusb - noexec candidate, too rare to bother for nofork +lspci - noexec. too rare to bother for nofork +lsscsi - noexec. too rare to bother for nofork +lsusb - noexec. too rare to bother for nofork lzcat - runner lzma - runner lzop - runner diff --git a/miscutils/lsscsi.c b/miscutils/lsscsi.c index c86630e31..d7cd51056 100644 --- a/miscutils/lsscsi.c +++ b/miscutils/lsscsi.c @@ -16,7 +16,7 @@ //config: //config: This version uses sysfs (/sys/bus/scsi/devices) only. -//applet:IF_LSSCSI(APPLET(lsscsi, BB_DIR_USR_BIN, BB_SUID_DROP)) +//applet:IF_LSSCSI(APPLET_NOEXEC(lsscsi, lsscsi, BB_DIR_USR_BIN, BB_SUID_DROP, lsscsi)) //kbuild:lib-$(CONFIG_LSSCSI) += lsscsi.o diff --git a/util-linux/lspci.c b/util-linux/lspci.c index 3877deb67..0000fbfda 100644 --- a/util-linux/lspci.c +++ b/util-linux/lspci.c @@ -16,7 +16,7 @@ //config: //config: This version uses sysfs (/sys/bus/pci/devices) only. -//applet:IF_LSPCI(APPLET(lspci, BB_DIR_USR_BIN, BB_SUID_DROP)) +//applet:IF_LSPCI(APPLET_NOEXEC(lspci, lspci, BB_DIR_USR_BIN, BB_SUID_DROP, lspci)) //kbuild:lib-$(CONFIG_LSPCI) += lspci.o diff --git a/util-linux/lsusb.c b/util-linux/lsusb.c index cabf047cf..33639413a 100644 --- a/util-linux/lsusb.c +++ b/util-linux/lsusb.c @@ -16,7 +16,7 @@ //config: //config: This version uses sysfs (/sys/bus/usb/devices) only. -//applet:IF_LSUSB(APPLET(lsusb, BB_DIR_USR_BIN, BB_SUID_DROP)) +//applet:IF_LSUSB(APPLET_NOEXEC(lsusb, lsusb, BB_DIR_USR_BIN, BB_SUID_DROP, lsusb)) //kbuild:lib-$(CONFIG_LSUSB) += lsusb.o -- cgit v1.2.3-55-g6feb From 6517bbc76c5e79273f72b951362125241552935d Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Sun, 6 Aug 2017 11:58:46 +0200 Subject: kbd_mode: show "off" mode too function old new delta kbd_mode_main 156 166 +10 Signed-off-by: Denys Vlasenko --- console-tools/kbd_mode.c | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/console-tools/kbd_mode.c b/console-tools/kbd_mode.c index d81c56e92..da31af28d 100644 --- a/console-tools/kbd_mode.c +++ b/console-tools/kbd_mode.c @@ -24,7 +24,7 @@ //usage:#define kbd_mode_full_usage "\n\n" //usage: "Report or set the keyboard mode\n" //usage: "\n -a Default (ASCII)" -//usage: "\n -k Medium-raw (keyboard)" +//usage: "\n -k Medium-raw (keycode)" //usage: "\n -s Raw (scancode)" //usage: "\n -u Unicode (utf-8)" //usage: "\n -C TTY Affect TTY instead of /dev/tty" @@ -43,6 +43,10 @@ int kbd_mode_main(int argc UNUSED_PARAM, char **argv) }; int fd; unsigned opt; +//TODO? kbd-2.0.3 without -C tries in sequence: +//fd#0, /dev/tty, /dev/tty0. +//Also, it checks KDGKBTYPE before doing KDGKBMODE +//maybe we can use get_console_fd_or_die()? const char *tty_name = CURRENT_TTY; opt = getopt32(argv, "sakuC:", &tty_name); @@ -62,9 +66,19 @@ int kbd_mode_main(int argc UNUSED_PARAM, char **argv) mode = "mediumraw (keycode)"; else if (m == K_UNICODE) mode = "Unicode (UTF-8)"; + else if (m == 4 /*K_OFF*/) /* kbd-2.0.3 does not show this mode, says "unknown" */ + mode = "off"; printf("The keyboard is in %s mode\n", mode); } else { - /* here we depend on specific bits assigned to options (*) */ + /* here we depend on specific bits assigned to options (*) + * KDSKBMODE constants have these values: + * #define K_RAW 0x00 + * #define K_XLATE 0x01 + * #define K_MEDIUMRAW 0x02 + * #define K_UNICODE 0x03 + * #define K_OFF 0x04 + * (looks like "-ak" together would cause the same effect as -u) + */ opt = opt & UNICODE ? 3 : opt >> 1; /* double cast prevents warnings about widening conversion */ xioctl(fd, KDSKBMODE, (void*)(ptrdiff_t)opt); -- cgit v1.2.3-55-g6feb From 32b60cc0db90e517399ca9fa73a8ac1140db810d Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Sun, 6 Aug 2017 12:17:46 +0200 Subject: kbd_mode: try harder to find console device if -C TTY is not given Was (under X): $ ./busybox_old kbd_mode kbd_mode: ioctl 0x4b44 failed: Inappropriate ioctl for device Now: $ ./busybox kbd_mode The keyboard is in off mode function old new delta kbd_mode_main 166 174 +8 packed_usage 31782 31764 -18 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 1/1 up/down: 8/-18) Total: -10 bytes text data bss dec hex filename 915757 485 6880 923122 e15f2 busybox_old 915747 485 6880 923112 e15e8 busybox_unstripped Signed-off-by: Denys Vlasenko --- console-tools/kbd_mode.c | 22 ++++++++++++++-------- libbb/get_console.c | 1 - 2 files changed, 14 insertions(+), 9 deletions(-) diff --git a/console-tools/kbd_mode.c b/console-tools/kbd_mode.c index da31af28d..b0b594614 100644 --- a/console-tools/kbd_mode.c +++ b/console-tools/kbd_mode.c @@ -22,7 +22,7 @@ //usage:#define kbd_mode_trivial_usage //usage: "[-a|k|s|u] [-C TTY]" //usage:#define kbd_mode_full_usage "\n\n" -//usage: "Report or set the keyboard mode\n" +//usage: "Report or set VT console keyboard mode\n" //usage: "\n -a Default (ASCII)" //usage: "\n -k Medium-raw (keycode)" //usage: "\n -s Raw (scancode)" @@ -43,15 +43,20 @@ int kbd_mode_main(int argc UNUSED_PARAM, char **argv) }; int fd; unsigned opt; -//TODO? kbd-2.0.3 without -C tries in sequence: -//fd#0, /dev/tty, /dev/tty0. -//Also, it checks KDGKBTYPE before doing KDGKBMODE -//maybe we can use get_console_fd_or_die()? - const char *tty_name = CURRENT_TTY; + const char *tty_name; opt = getopt32(argv, "sakuC:", &tty_name); - fd = xopen_nonblocking(tty_name); - opt &= 0xf; /* clear -C bit, see (*) */ + if (opt & 0x10) { + opt &= 0xf; /* clear -C bit, see (*) */ + fd = xopen_nonblocking(tty_name); + } else { + /* kbd-2.0.3 tries in sequence: + * fd#0, /dev/tty, /dev/tty0. + * get_console_fd_or_die: /dev/console, /dev/tty0, /dev/tty. + * kbd-2.0.3 checks KDGKBTYPE, get_console_fd_or_die checks too. + */ + fd = get_console_fd_or_die(); + } if (!opt) { /* print current setting */ const char *mode = "unknown"; @@ -79,6 +84,7 @@ int kbd_mode_main(int argc UNUSED_PARAM, char **argv) * #define K_OFF 0x04 * (looks like "-ak" together would cause the same effect as -u) */ + opt &= 0xf; /* clear -C bit */ opt = opt & UNICODE ? 3 : opt >> 1; /* double cast prevents warnings about widening conversion */ xioctl(fd, KDSKBMODE, (void*)(ptrdiff_t)opt); diff --git a/libbb/get_console.c b/libbb/get_console.c index 9b6407bd0..96b339ca7 100644 --- a/libbb/get_console.c +++ b/libbb/get_console.c @@ -64,7 +64,6 @@ int FAST_FUNC get_console_fd_or_die(void) } bb_error_msg_and_die("can't open console"); - /*return fd; - total failure */ } /* From */ -- cgit v1.2.3-55-g6feb From ae17ba0924c9c0020a6455020e7841a12bd738d4 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Sun, 6 Aug 2017 12:23:04 +0200 Subject: kbd_more: make it NOEXEC, remove redundant opt clearing Signed-off-by: Denys Vlasenko --- console-tools/kbd_mode.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/console-tools/kbd_mode.c b/console-tools/kbd_mode.c index b0b594614..f16449dcd 100644 --- a/console-tools/kbd_mode.c +++ b/console-tools/kbd_mode.c @@ -15,7 +15,7 @@ //config: help //config: This program reports and sets keyboard mode. -//applet:IF_KBD_MODE(APPLET(kbd_mode, BB_DIR_BIN, BB_SUID_DROP)) +//applet:IF_KBD_MODE(APPLET_NOEXEC(kbd_mode, kbd_mode, BB_DIR_BIN, BB_SUID_DROP, kbd_mode)) //kbuild:lib-$(CONFIG_KBD_MODE) += kbd_mode.o @@ -27,7 +27,7 @@ //usage: "\n -k Medium-raw (keycode)" //usage: "\n -s Raw (scancode)" //usage: "\n -u Unicode (utf-8)" -//usage: "\n -C TTY Affect TTY instead of /dev/tty" +//usage: "\n -C TTY Affect TTY" #include "libbb.h" #include @@ -84,7 +84,6 @@ int kbd_mode_main(int argc UNUSED_PARAM, char **argv) * #define K_OFF 0x04 * (looks like "-ak" together would cause the same effect as -u) */ - opt &= 0xf; /* clear -C bit */ opt = opt & UNICODE ? 3 : opt >> 1; /* double cast prevents warnings about widening conversion */ xioctl(fd, KDSKBMODE, (void*)(ptrdiff_t)opt); -- cgit v1.2.3-55-g6feb From 9a58cc0f7fbdf967c159588e0de5f3a8dfd87db5 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Sun, 6 Aug 2017 12:28:00 +0200 Subject: tunctl: make it NOEXEC Signed-off-by: Denys Vlasenko --- NOFORK_NOEXEC.lst | 4 ++-- networking/tunctl.c | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/NOFORK_NOEXEC.lst b/NOFORK_NOEXEC.lst index c605302d9..45b178ca8 100644 --- a/NOFORK_NOEXEC.lst +++ b/NOFORK_NOEXEC.lst @@ -182,7 +182,7 @@ ipneigh - noexec candidate iproute - noexec candidate iprule - noexec candidate iptunnel - noexec candidate -kbd_mode - leaks: xopen_nonblocking+xioctl +kbd_mode - noexec. leaks: xopen_nonblocking+xioctl kill - NOFORK killall - NOFORK killall5 - NOFORK @@ -365,7 +365,7 @@ true - NOFORK truncate - NOFORK tty - NOFORK ttysize - NOFORK -tunctl +tunctl - noexec tune2fs - noexec. leaks: open+xfunc ubiattach ubidetach diff --git a/networking/tunctl.c b/networking/tunctl.c index 0a26ff7fb..4c3220025 100644 --- a/networking/tunctl.c +++ b/networking/tunctl.c @@ -24,7 +24,7 @@ //config: Allow to specify owner and group of newly created interface. //config: 340 bytes of pure bloat. Say no here. -//applet:IF_TUNCTL(APPLET(tunctl, BB_DIR_SBIN, BB_SUID_DROP)) +//applet:IF_TUNCTL(APPLET_NOEXEC(tunctl, tunctl, BB_DIR_SBIN, BB_SUID_DROP, tunctl)) //kbuild:lib-$(CONFIG_TUNCTL) += tunctl.o -- cgit v1.2.3-55-g6feb From fbecca1bed1b6daf10341304af2156baabc7af57 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Sun, 6 Aug 2017 14:03:27 +0200 Subject: Tweak outdated documentation and comments Signed-off-by: Denys Vlasenko --- docs/new-applet-HOWTO.txt | 15 +++++++------- docs/nofork_noexec.txt | 53 ++++++++++++++++++++++++----------------------- networking/arping.c | 4 ++-- 3 files changed, 37 insertions(+), 35 deletions(-) diff --git a/docs/new-applet-HOWTO.txt b/docs/new-applet-HOWTO.txt index 078e77bce..619d47fb8 100644 --- a/docs/new-applet-HOWTO.txt +++ b/docs/new-applet-HOWTO.txt @@ -147,17 +147,17 @@ Placement / Directory Find the appropriate directory for your new applet. -Add the kbuild snippet to the .c file: - -//kbuild:lib-$(CONFIG_MU) += mu.o - Add the config snippet to the .c file: //config:config MU //config: bool "MU" //config: default y //config: help -//config: Returns an indeterminate value. +//config: Returns an indeterminate value. + +Add the kbuild snippet to the .c file: + +//kbuild:lib-$(CONFIG_MU) += mu.o Usage String(s) @@ -168,8 +168,9 @@ This should look like the following: //usage:#define mu_trivial_usage //usage: "[-abcde] FILE..." -//usage:#define mu_full_usage -//usage: "Returns an indeterminate value\n" +//usage:#define mu_full_usage "\n\n" +//usage: "Returns an indeterminate value" +//usage: "\n" //usage: "\n -a First function" //usage: "\n -b Second function" //usage: ... diff --git a/docs/nofork_noexec.txt b/docs/nofork_noexec.txt index b45a4be89..9d210a1c9 100644 --- a/docs/nofork_noexec.txt +++ b/docs/nofork_noexec.txt @@ -10,13 +10,8 @@ of reimplemented Unix commands, and we can do the same trick for speeding up busybox shells, and more. NOEXEC and NOFORK applets are exactly those applets which are eligible for these tricks. -Applet will be subject to NOFORK/NOEXEC tricks if it is marked as such -in applets.h. FEATURE_PREFER_APPLETS is a config option which -globally enables usage of NOFORK/NOEXEC tricks. -If it is enabled, FEATURE_SH_STANDALONE can be enabled too, -and then shells will use NOFORK/NOEXEC tricks for ordinary commands. -NB: shell builtins use these tricks regardless of FEATURE_SH_STANDALONE -or FEATURE_PREFER_APPLETS. +Applet will be subject to NOFORK/NOEXEC tricks only if it is marked +as such in applets.src.h or in their inline "//applet:" directives. In C, if you want to call a program and wait for it, use spawn_and_wait(argv), BB_EXECVP(prog,argv) or BB_EXECLP(prog,argv0,...). @@ -24,6 +19,31 @@ They check whether program name is an applet name and optionally do NOFORK/NOEXEC thing depending on configuration. + Relevant CONFIG options + +FEATURE_PREFER_APPLETS + Globally enables NOFORK/NOEXEC tricks for such programs as xargs + and find: + BB_EXECVP(cmd, argv) will try to exec /proc/self/exe + if command's name matches some applet name; + spawn_and_wait(argv) will do NOFORK/NOEXEC tricks + +//TODO: the above two things probably should have separate options? + +FEATURE_SH_STANDALONE + shells will try to exec /proc/self/exe if command's name matches + some applet name; shells will do NOEXEC trick on NOEXEC applets + +//TODO: split (same as for PREFER_APPLETS) + +FEATURE_SH_NOFORK + shells will do NOFORK trick on NOFORK applets + +NB: shell builtins use these tricks regardless of FEATURE_SH_STANDALONE, +FEATURE_PREFER_APPLETS or FEATURE_SH_NOFORK. In effect, builtins +are "always NOFORK". + + NOEXEC NOEXEC applet should work correctly if another applet forks and then @@ -121,22 +141,3 @@ option_mask32 getting trashed. It's the same trusty spawn_and_wait(argv). If FEATURE_PREFER_APPLETS=y, it does NOEXEC trick. It resets xfunc_error_retval = 1 and logmode = LOGMODE_STDIO in the child. - - - Relevant CONFIG options - -FEATURE_PREFER_APPLETS - BB_EXECVP(cmd, argv) will try to exec /proc/self/exe - if command's name matches some applet name; - spawn_and_wait(argv) will do NOFORK/NOEXEC tricks - -//TODO: the above two things probably should have separate options? - -FEATURE_SH_STANDALONE - shells will try to exec /proc/self/exe if command's name matches - some applet name; shells will do NOEXEC trick on NOEXEC applets - -//TODO: split (same as for PREFER_APPLETS) - -FEATURE_SH_NOFORK - shells will do NOFORK trick on NOFORK applets diff --git a/networking/arping.c b/networking/arping.c index 71672957e..3fd54a287 100644 --- a/networking/arping.c +++ b/networking/arping.c @@ -295,8 +295,8 @@ int arping_main(int argc UNUSED_PARAM, char **argv) sock_fd = xsocket(AF_PACKET, SOCK_DGRAM, 0); - // Drop suid root privileges - // Need to remove SUID_NEVER from applets.h for this to work + // If you ever change BB_SUID_DROP to BB_SUID_REQUIRE, + // drop suid root privileges here: //xsetuid(getuid()); { -- cgit v1.2.3-55-g6feb From a759b22c29fed7d6c77efe0c3e27772371d0889b Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Sun, 6 Aug 2017 14:15:24 +0200 Subject: nameif: make it NOEXEC Signed-off-by: Denys Vlasenko --- NOFORK_NOEXEC.lst | 4 ++-- networking/nameif.c | 2 +- procps/mpstat.c | 1 + 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/NOFORK_NOEXEC.lst b/NOFORK_NOEXEC.lst index 45b178ca8..9b33afc32 100644 --- a/NOFORK_NOEXEC.lst +++ b/NOFORK_NOEXEC.lst @@ -237,10 +237,10 @@ modprobe - noexec more - interactive, longterm mount - suid mountpoint - noexec. leaks: option -n "print dev name": find_block_device -> readdir+xstrdup -mpstat - noexec candidate (it's a measuring tool, putting less load by itself is good), complex +mpstat - longterm: "mpstat 1" runs indefinitely mt - rare mv - noexec candidate, runner -nameif - leaks: config_open2+ioctl_or_perror_and_die +nameif - noexec. openlog(), leaks: config_open2+ioctl_or_perror_and_die nbd-client nc - runner netstat - runner with -c diff --git a/networking/nameif.c b/networking/nameif.c index 31ee98a39..1f2695495 100644 --- a/networking/nameif.c +++ b/networking/nameif.c @@ -40,7 +40,7 @@ //config: new_interface_name mac=00:80:C8:38:91:B5 //config: new_interface_name 00:80:C8:38:91:B5 -//applet:IF_NAMEIF(APPLET(nameif, BB_DIR_SBIN, BB_SUID_DROP)) +//applet:IF_NAMEIF(APPLET_NOEXEC(nameif, nameif, BB_DIR_SBIN, BB_SUID_DROP, nameif)) //kbuild:lib-$(CONFIG_NAMEIF) += nameif.o diff --git a/procps/mpstat.c b/procps/mpstat.c index 1eabd8e38..acaff4dc0 100644 --- a/procps/mpstat.c +++ b/procps/mpstat.c @@ -8,6 +8,7 @@ */ //applet:IF_MPSTAT(APPLET(mpstat, BB_DIR_BIN, BB_SUID_DROP)) +/* shouldn't be noexec: "mpstat INTERVAL" runs indefinitely */ //kbuild:lib-$(CONFIG_MPSTAT) += mpstat.o -- cgit v1.2.3-55-g6feb From 2262746e2b798361a9c293e02f76cb4f06b7b100 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Sun, 6 Aug 2017 17:14:09 +0200 Subject: slattach: code shrink, better --help text function old new delta tcsetattr_serial_or_warn - 34 +34 static.int_N_SLIP - 4 +4 restore_state_and_exit 123 117 -6 packed_usage 31774 31747 -27 set_termios_state_or_warn 42 - -42 slattach_main 673 624 -49 ------------------------------------------------------------------------------ (add/remove: 2/1 grow/shrink: 0/3 up/down: 38/-124) Total: -86 bytes Signed-off-by: Denys Vlasenko --- NOFORK_NOEXEC.lst | 6 +- libbb/xfuncs.c | 2 +- networking/slattach.c | 167 +++++++++++++++++++------------------------------- 3 files changed, 68 insertions(+), 107 deletions(-) diff --git a/NOFORK_NOEXEC.lst b/NOFORK_NOEXEC.lst index 9b33afc32..3bd82aa60 100644 --- a/NOFORK_NOEXEC.lst +++ b/NOFORK_NOEXEC.lst @@ -78,7 +78,7 @@ conspy - interactive, longterm cp - noexec. runner cpio - runner crond - daemon -crontab 0 leaks: open+xasprintf +crontab - longterm (runs $EDITOR), leaks: open+xasprintf cryptpw - noexec. changes state: with --password-fd=N, moves N to stdin cttyhack - noexec. spawner cut - noexec. runner @@ -311,7 +311,7 @@ setkeycodes setlogcons setpriv - spawner, changes state, let's play safe and not be noexec setserial -setsid - spawner, uses fork_or_rexec() [not audted to work in noexec], let's play safe and not be noexec +setsid - spawner, uses fork_or_rexec() [not audited to work in noexec], let's play safe and not be noexec setuidgid - noexec. spawner sha1sum - noexec. runner sha256sum - noexec. runner @@ -320,7 +320,7 @@ sha512sum - noexec. runner showkey - interactive, longterm shred - runner shuf - noexec. runner -slattach +slattach - longterm (may sleep forever), uses bb_common_bufsiz1 sleep - runner, longterm smemcap - runner softlimit - noexec. spawner diff --git a/libbb/xfuncs.c b/libbb/xfuncs.c index 98d3531d6..1b3a1667b 100644 --- a/libbb/xfuncs.c +++ b/libbb/xfuncs.c @@ -313,7 +313,7 @@ int FAST_FUNC tcsetattr_stdin_TCSANOW(const struct termios *tp) int FAST_FUNC set_termios_to_raw(int fd, struct termios *oldterm, int flags) { -//TODO: lineedit, microcom and less might be adapted to use this too: +//TODO: lineedit, microcom, slattach, less might be adapted to use this too: // grep for "tcsetattr" struct termios newterm; diff --git a/networking/slattach.c b/networking/slattach.c index 71b5bf427..d4659a314 100644 --- a/networking/slattach.c +++ b/networking/slattach.c @@ -17,23 +17,23 @@ //config: default y //config: select PLATFORM_LINUX //config: help -//config: slattach is a small utility to attach network interfaces to serial -//config: lines. +//config: slattach configures serial line as SLIP network interface. //applet:IF_SLATTACH(APPLET(slattach, BB_DIR_SBIN, BB_SUID_DROP)) +/* shouldn't be NOEXEC: may sleep indefinitely */ //kbuild:lib-$(CONFIG_SLATTACH) += slattach.o //usage:#define slattach_trivial_usage -//usage: "[-cehmLF] [-s SPEED] [-p PROTOCOL] DEVICE" +//usage: "[-ehmLF] [-c SCRIPT] [-s BAUD] [-p PROTOCOL] SERIAL_DEVICE" //usage:#define slattach_full_usage "\n\n" -//usage: "Attach network interface(s) to serial line(s)\n" -//usage: "\n -p PROT Set protocol (slip, cslip, slip6, clisp6 or adaptive)" -//usage: "\n -s SPD Set line speed" -//usage: "\n -e Exit after initializing device" -//usage: "\n -h Exit when the carrier is lost" -//usage: "\n -c PROG Run PROG when the line is hung up" -//usage: "\n -m Do NOT initialize the line in raw 8 bits mode" +//usage: "Configure serial line as SLIP network interface\n" +//usage: "\n -p PROT Protocol: slip, cslip (default), slip6, clisp6, adaptive" +//usage: "\n -s BAUD Line speed" +//usage: "\n -e Exit after initialization" +//usage: "\n -h Exit if carrier is lost (else never exits)" +//usage: "\n -c PROG Run PROG on carrier loss" +//usage: "\n -m Do NOT set raw 8bit mode" //usage: "\n -L Enable 3-wire operation" //usage: "\n -F Disable RTS/CTS flow control" @@ -42,103 +42,53 @@ #include "libiproute/utils.h" /* invarg_1_to_2() */ struct globals { - int handle; int saved_disc; struct termios saved_state; } FIX_ALIASING; #define G (*(struct globals*)bb_common_bufsiz1) -#define handle (G.handle ) -#define saved_disc (G.saved_disc ) -#define saved_state (G.saved_state ) #define INIT_G() do { setup_common_bufsiz(); } while (0) +#define serial_fd 3 -/* - * Save tty state and line discipline - * - * It is fine here to bail out on errors, since we haven modified anything yet - */ -static void save_state(void) -{ - /* Save line status */ - if (tcgetattr(handle, &saved_state) < 0) - bb_perror_msg_and_die("get state"); - - /* Save line discipline */ - xioctl(handle, TIOCGETD, &saved_disc); -} - -static int set_termios_state_or_warn(struct termios *state) +static int tcsetattr_serial_or_warn(struct termios *state) { int ret; - ret = tcsetattr(handle, TCSANOW, state); - if (ret < 0) { - bb_perror_msg("set state"); + ret = tcsetattr(serial_fd, TCSANOW, state); + if (ret != 0) { + bb_perror_msg("tcsetattr"); return 1; /* used as exitcode */ } - return 0; + return ret; /* 0 */ } -/* - * Restore state and line discipline for ALL managed ttys - * - * Restoring ALL managed ttys is the only way to have a single - * hangup delay. - * - * Go on after errors: we want to restore as many controlled ttys - * as possible. - */ static void restore_state_and_exit(int exitcode) NORETURN; static void restore_state_and_exit(int exitcode) { struct termios state; /* Restore line discipline */ - if (ioctl_or_warn(handle, TIOCSETD, &saved_disc) < 0) { + if (ioctl_or_warn(serial_fd, TIOCSETD, &G.saved_disc)) { exitcode = 1; } /* Hangup */ - memcpy(&state, &saved_state, sizeof(state)); + memcpy(&state, &G.saved_state, sizeof(state)); cfsetispeed(&state, B0); cfsetospeed(&state, B0); - if (set_termios_state_or_warn(&state)) - exitcode = 1; + exitcode |= tcsetattr_serial_or_warn(&state); sleep(1); /* Restore line status */ - if (set_termios_state_or_warn(&saved_state)) + if (tcsetattr_serial_or_warn(&G.saved_state)) exit(EXIT_FAILURE); + if (ENABLE_FEATURE_CLEAN_UP) - close(handle); + close(serial_fd); exit(exitcode); } -/* - * Set tty state, line discipline and encapsulation - */ -static void set_state(struct termios *state, int encap) -{ - int disc; - - /* Set line status */ - if (set_termios_state_or_warn(state)) - goto bad; - /* Set line discliple (N_SLIP always) */ - disc = N_SLIP; - if (ioctl_or_warn(handle, TIOCSETD, &disc) < 0) { - goto bad; - } - - /* Set encapsulation (SLIP, CSLIP, etc) */ - if (ioctl_or_warn(handle, SIOCSIFENCAP, &encap) < 0) { - bad: - restore_state_and_exit(EXIT_FAILURE); - } -} - static void sig_handler(int signo UNUSED_PARAM) { restore_state_and_exit(EXIT_SUCCESS); @@ -155,13 +105,14 @@ int slattach_main(int argc UNUSED_PARAM, char **argv) "cslip6\0" /* 3 */ "adaptive\0" /* 8 */ ; + static const int int_N_SLIP = N_SLIP; - int i, encap, opt; + int encap, opt, fd; struct termios state; const char *proto = "cslip"; const char *extcmd; /* Command to execute after hangup */ const char *baud_str; - int baud_code = -1; /* Line baud rate (system code) */ + int baud_code = baud_code; /* for compiler */ enum { OPT_p_proto = 1 << 0, @@ -177,15 +128,12 @@ int slattach_main(int argc UNUSED_PARAM, char **argv) INIT_G(); /* Parse command line options */ + opt_complementary = "=1"; opt = getopt32(argv, "p:s:c:ehmLF", &proto, &baud_str, &extcmd); /*argc -= optind;*/ argv += optind; - if (!*argv) - bb_show_usage(); - encap = index_in_strings(proto_names, proto); - if (encap < 0) invarg_1_to_2(proto, "protocol"); if (encap > 3) @@ -198,6 +146,22 @@ int slattach_main(int argc UNUSED_PARAM, char **argv) invarg_1_to_2(baud_str, "baud rate"); } + /* Open tty */ + fd = open(*argv, O_RDWR | O_NDELAY); + if (fd < 0) { + char *buf = concat_path_file("/dev", *argv); + fd = xopen(buf, O_RDWR | O_NDELAY); + /* maybe if (ENABLE_FEATURE_CLEAN_UP) ?? */ + free(buf); + } + xmove_fd(fd, serial_fd); + + /* Save current tty state */ + if (tcgetattr(serial_fd, &G.saved_state) != 0) + bb_perror_msg_and_die("tcgetattr"); + /* Save line discipline */ + xioctl(serial_fd, TIOCGETD, &G.saved_disc); + /* Trap signals in order to restore tty states upon exit */ if (!(opt & OPT_e_quit)) { bb_signals(0 @@ -208,43 +172,37 @@ int slattach_main(int argc UNUSED_PARAM, char **argv) , sig_handler); } - /* Open tty */ - handle = open(*argv, O_RDWR | O_NDELAY); - if (handle < 0) { - char *buf = concat_path_file("/dev", *argv); - handle = xopen(buf, O_RDWR | O_NDELAY); - /* maybe if (ENABLE_FEATURE_CLEAN_UP) ?? */ - free(buf); - } - - /* Save current tty state */ - save_state(); - /* Configure tty */ - memcpy(&state, &saved_state, sizeof(state)); + memcpy(&state, &G.saved_state, sizeof(state)); if (!(opt & OPT_m_nonraw)) { /* raw not suppressed */ memset(&state.c_cc, 0, sizeof(state.c_cc)); state.c_cc[VMIN] = 1; state.c_iflag = IGNBRK | IGNPAR; - state.c_oflag = 0; - state.c_lflag = 0; + /*state.c_oflag = 0;*/ + /*state.c_lflag = 0;*/ state.c_cflag = CS8 | HUPCL | CREAD | ((opt & OPT_L_local) ? CLOCAL : 0) | ((opt & OPT_F_noflow) ? 0 : CRTSCTS); - cfsetispeed(&state, cfgetispeed(&saved_state)); - cfsetospeed(&state, cfgetospeed(&saved_state)); + cfsetispeed(&state, cfgetispeed(&G.saved_state)); + cfsetospeed(&state, cfgetospeed(&G.saved_state)); } - if (opt & OPT_s_baud) { cfsetispeed(&state, baud_code); cfsetospeed(&state, baud_code); } - - set_state(&state, encap); + /* Set line status */ + if (tcsetattr_serial_or_warn(&state)) + goto bad; + /* Set line disclipline (N_SLIP always) */ + if (ioctl_or_warn(serial_fd, TIOCSETD, (void*)&int_N_SLIP)) + goto bad; + /* Set encapsulation (SLIP, CSLIP, etc) */ + if (ioctl_or_warn(serial_fd, SIOCSIFENCAP, &encap)) + goto bad; /* Exit now if option -e was passed */ if (opt & OPT_e_quit) - return 0; + return EXIT_SUCCESS; /* If we're not requested to watch, just keep descriptor open * until we are killed */ @@ -254,17 +212,20 @@ int slattach_main(int argc UNUSED_PARAM, char **argv) /* Watch line for hangup */ while (1) { - if (ioctl(handle, TIOCMGET, &i) < 0 || !(i & TIOCM_CAR)) - goto no_carrier; + int modem_stat; + if (ioctl(serial_fd, TIOCMGET, &modem_stat)) + break; + if (!(modem_stat & TIOCM_CAR)) + break; sleep(15); } - no_carrier: - /* Execute command on hangup */ if (opt & OPT_c_extcmd) system(extcmd); /* Restore states and exit */ restore_state_and_exit(EXIT_SUCCESS); + bad: + restore_state_and_exit(EXIT_FAILURE); } -- cgit v1.2.3-55-g6feb From 08e66a81495274dbe8a16f264761ccdf921b6564 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Sun, 6 Aug 2017 17:59:37 +0200 Subject: setserial: code shrink, better --help text function old new delta packed_usage 31747 31749 +2 setserial_main 1152 1132 -20 Signed-off-by: Denys Vlasenko --- miscutils/setserial.c | 91 ++++++++++++++++++++++++++------------------------- 1 file changed, 46 insertions(+), 45 deletions(-) diff --git a/miscutils/setserial.c b/miscutils/setserial.c index 28a1bef18..a4d59f898 100644 --- a/miscutils/setserial.c +++ b/miscutils/setserial.c @@ -210,35 +210,35 @@ struct serial_struct { #endif //usage:#define setserial_trivial_usage -//usage: "[-gabGvzV] DEVICE [PARAMETER [ARG]]..." +//usage: "[-abGvz] { DEVICE [PARAMETER [ARG]]... | -g DEVICE... }" //usage:#define setserial_full_usage "\n\n" -//usage: "Request or set Linux serial port information\n" -//usage: "\n" -//usage: " -g Interpret parameters as list of devices for reporting\n" -//usage: " -a Print all available information\n" -//usage: " -b Print summary information\n" -//usage: " -G Print in form which can be fed back\n" -//usage: " to setserial as command line parameters\n" -//usage: " -z Zero out serial flags before setting\n" -//usage: " -v Verbose\n" -//usage: "\n" -//usage: "Parameters: (* = takes an argument, ^ = can be turned off by preceding ^)\n" -//usage: " *port, *irq, *divisor, *uart, *baud_base, *close_delay, *closing_wait,\n" -//usage: " ^fourport, ^auto_irq, ^skip_test, ^sak, ^session_lockout, ^pgrp_lockout,\n" -//usage: " ^callout_nohup, ^split_termios, ^hup_notify, ^low_latency, autoconfig,\n" -//usage: " spd_normal, spd_hi, spd_vhi, spd_shi, spd_warp, spd_cust\n" -//usage: "\n" -//usage: "UART types:\n" -//usage: " unknown, 8250, 16450, 16550, 16550A, Cirrus, 16650, 16650V2, 16750,\n" -//usage: " 16950, 16954, 16654, 16850, RSA, NS16550A, XSCALE, RM9000, OCTEON, AR7,\n" -//usage: " U6_16550A" - +//usage: "Print or set serial port parameters" +//usage: "\n" +//usage: "\n"" -a Print all" +//usage: "\n"" -b Print summary" +//usage: "\n"" -G Print as setserial PARAMETERs" +//usage: "\n"" -v Verbose" +//usage: "\n"" -z Zero out serial flags before setting" +//usage: "\n"" -g All args are device names" +//usage: "\n" +//usage: "\n""PARAMETERs: (* = takes ARG, ^ = can be turned off by preceding ^)" +//usage: "\n"" *port, *irq, *divisor, *uart, *baud_base, *close_delay, *closing_wait," +//usage: "\n"" ^fourport, ^auto_irq, ^skip_test, ^sak, ^session_lockout, ^pgrp_lockout," +//usage: "\n"" ^callout_nohup, ^split_termios, ^hup_notify, ^low_latency, autoconfig," +//usage: "\n"" spd_normal, spd_hi, spd_vhi, spd_shi, spd_warp, spd_cust" +//usage: "\n""ARG for uart:" +//usage: "\n"" unknown, 8250, 16450, 16550, 16550A, Cirrus, 16650, 16650V2, 16750," +//usage: "\n"" 16950, 16954, 16654, 16850, RSA, NS16550A, XSCALE, RM9000, OCTEON, AR7," +//usage: "\n"" U6_16550A" + +// option string is "bGavzgq". "q" is accepted but ignored. #define OPT_PRINT_SUMMARY (1 << 0) #define OPT_PRINT_FEDBACK (1 << 1) #define OPT_PRINT_ALL (1 << 2) #define OPT_VERBOSE (1 << 3) #define OPT_ZERO (1 << 4) -#define OPT_GET (1 << 5) +#define OPT_LIST_OF_DEVS (1 << 5) +/*#define OPT_QUIET (1 << 6)*/ #define OPT_MODE_MASK \ (OPT_PRINT_ALL | OPT_PRINT_SUMMARY | OPT_PRINT_FEDBACK) @@ -362,7 +362,7 @@ static bool cmd_is_flag(int cmd) return (cmd >= CMD_FLAG_FIRST && cmd <= CMD_FLAG_LAST); } -static bool cmd_need_arg(int cmd) +static bool cmd_needs_arg(int cmd) { return (cmd >= CMD_PORT && cmd <= CMD_WAIT); } @@ -652,11 +652,9 @@ static int find_cmd(const char *cmd) static void serial_set(char **arg, int opts) { struct serial_struct serinfo; - int cmd; - const char *word; int fd; - fd = serial_open(*arg++, /*quiet:*/ false); + fd = serial_open(*arg, /*quiet:*/ false); if (fd < 0) exit(201); @@ -665,17 +663,20 @@ static void serial_set(char **arg, int opts) if (opts & OPT_ZERO) serinfo.flags = 0; - while (*arg) { + while (*++arg) { + const char *word; int invert; + int cmd; - word = *arg++; - invert = (*word == '^'); + word = *arg; + invert = (word[0] == '^'); word += invert; cmd = find_cmd(word); - if (*arg == NULL && cmd_need_arg(cmd)) - bb_error_msg_and_die(bb_msg_requires_arg, word); + if (cmd_needs_arg(cmd)) + if (*++arg == NULL) + bb_error_msg_and_die(bb_msg_requires_arg, word); if (invert && !cmd_is_flag(cmd)) bb_error_msg_and_die("can't invert %s", word); @@ -705,25 +706,25 @@ static void serial_set(char **arg, int opts) serinfo.flags |= setbits[cmd]; break; case CMD_PORT: - serinfo.port = get_numeric(*arg++); + serinfo.port = get_numeric(*arg); break; case CMD_IRQ: - serinfo.irq = get_numeric(*arg++); + serinfo.irq = get_numeric(*arg); break; case CMD_DIVISOR: - serinfo.custom_divisor = get_numeric(*arg++); + serinfo.custom_divisor = get_numeric(*arg); break; case CMD_UART: - serinfo.type = get_uart(*arg++); + serinfo.type = get_uart(*arg); break; case CMD_BASE: - serinfo.baud_base = get_numeric(*arg++); + serinfo.baud_base = get_numeric(*arg); break; case CMD_DELAY: - serinfo.close_delay = get_numeric(*arg++); + serinfo.close_delay = get_numeric(*arg); break; case CMD_WAIT: - serinfo.closing_wait = get_wait(*arg++); + serinfo.closing_wait = get_wait(*arg); break; case CMD_AUTOCONFIG: serial_ctl(fd, CTL_SET | CTL_CONFIG | CTL_GET, &serinfo); @@ -742,21 +743,21 @@ int setserial_main(int argc UNUSED_PARAM, char **argv) int opts; opt_complementary = "-1:b-aG:G-ab:a-bG"; - opts = getopt32(argv, "bGavzg"); + opts = getopt32(argv, "bGavzgq"); argv += optind; if (!argv[1]) /* one arg only? */ - opts |= OPT_GET; + opts |= OPT_LIST_OF_DEVS; - if (!(opts & OPT_GET)) { + if (!(opts & OPT_LIST_OF_DEVS)) { serial_set(argv, opts); argv[1] = NULL; } - if (opts & (OPT_VERBOSE | OPT_GET)) { + if (opts & (OPT_VERBOSE | OPT_LIST_OF_DEVS)) { do { - serial_get(*argv++, opts & OPT_MODE_MASK); - } while (*argv); + serial_get(*argv, opts & OPT_MODE_MASK); + } while (*++argv); } return EXIT_SUCCESS; -- cgit v1.2.3-55-g6feb From 97b738d359c0398942d0dc4301415a2fe814eace Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Sun, 6 Aug 2017 18:06:46 +0200 Subject: setserial: make it NOEXEC Signed-off-by: Denys Vlasenko --- NOFORK_NOEXEC.lst | 2 +- miscutils/setserial.c | 7 ++++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/NOFORK_NOEXEC.lst b/NOFORK_NOEXEC.lst index 3bd82aa60..30690af61 100644 --- a/NOFORK_NOEXEC.lst +++ b/NOFORK_NOEXEC.lst @@ -310,7 +310,7 @@ setfont setkeycodes setlogcons setpriv - spawner, changes state, let's play safe and not be noexec -setserial +setserial - noexec setsid - spawner, uses fork_or_rexec() [not audited to work in noexec], let's play safe and not be noexec setuidgid - noexec. spawner sha1sum - noexec. runner diff --git a/miscutils/setserial.c b/miscutils/setserial.c index a4d59f898..2000de7b1 100644 --- a/miscutils/setserial.c +++ b/miscutils/setserial.c @@ -15,7 +15,7 @@ //config: help //config: Retrieve or set Linux serial port. -//applet:IF_SETSERIAL(APPLET(setserial, BB_DIR_BIN, BB_SUID_DROP)) +//applet:IF_SETSERIAL(APPLET_NOEXEC(setserial, setserial, BB_DIR_BIN, BB_SUID_DROP, setserial)) //kbuild:lib-$(CONFIG_SETSERIAL) += setserial.o @@ -746,14 +746,15 @@ int setserial_main(int argc UNUSED_PARAM, char **argv) opts = getopt32(argv, "bGavzgq"); argv += optind; - if (!argv[1]) /* one arg only? */ - opts |= OPT_LIST_OF_DEVS; + if (!argv[1]) /* one arg only? (nothing to change?) */ + opts |= OPT_LIST_OF_DEVS; /* force display */ if (!(opts & OPT_LIST_OF_DEVS)) { serial_set(argv, opts); argv[1] = NULL; } + /* -v effect: "after setting params, do not be silent, show them" */ if (opts & (OPT_VERBOSE | OPT_LIST_OF_DEVS)) { do { serial_get(*argv, opts & OPT_MODE_MASK); -- cgit v1.2.3-55-g6feb From 341ce0a31eb2bdc352ef61df1954983c5235c818 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Sun, 6 Aug 2017 18:17:58 +0200 Subject: setlogcons: make it NOEXEC, better --help text Signed-off-by: Denys Vlasenko --- NOFORK_NOEXEC.lst | 2 +- console-tools/setlogcons.c | 20 ++++++++++++++++---- 2 files changed, 17 insertions(+), 5 deletions(-) diff --git a/NOFORK_NOEXEC.lst b/NOFORK_NOEXEC.lst index 30690af61..8145e2597 100644 --- a/NOFORK_NOEXEC.lst +++ b/NOFORK_NOEXEC.lst @@ -308,7 +308,7 @@ setarch - noexec. spawner setconsole setfont setkeycodes -setlogcons +setlogcons - noexec setpriv - spawner, changes state, let's play safe and not be noexec setserial - noexec setsid - spawner, uses fork_or_rexec() [not audited to work in noexec], let's play safe and not be noexec diff --git a/console-tools/setlogcons.c b/console-tools/setlogcons.c index 1b5814eee..6778a4d2b 100644 --- a/console-tools/setlogcons.c +++ b/console-tools/setlogcons.c @@ -15,14 +15,26 @@ //config: help //config: This program redirects the output console of kernel messages. -//applet:IF_SETLOGCONS(APPLET(setlogcons, BB_DIR_USR_SBIN, BB_SUID_DROP)) +//applet:IF_SETLOGCONS(APPLET_NOEXEC(setlogcons, setlogcons, BB_DIR_USR_SBIN, BB_SUID_DROP, setlogcons)) //kbuild:lib-$(CONFIG_SETLOGCONS) += setlogcons.o //usage:#define setlogcons_trivial_usage //usage: "[N]" //usage:#define setlogcons_full_usage "\n\n" -//usage: "Redirect the kernel output to console N. Default:0 (current console)" +//usage: "Pin kernel output to VT console N. Default:0 (do not pin)" + +// Comment from kernel source: +/* ... + * By default, the kernel messages are always printed on the current virtual + * console. However, the user may modify that default with the + * TIOCL_SETKMSGREDIRECT ioctl call. + * + * This function sets the kernel message console to be @new. It returns the old + * virtual console number. The virtual terminal number 0 (both as parameter and + * return value) means no redirection (i.e. always printed on the currently + * active console). + */ #include "libbb.h" @@ -33,8 +45,8 @@ int setlogcons_main(int argc UNUSED_PARAM, char **argv) char fn; char subarg; } arg = { - 11, /* redirect kernel messages */ - 0 /* to specified console (current as default) */ + 11, /* redirect kernel messages (TIOCL_SETKMSGREDIRECT) */ + 0 }; if (argv[1]) -- cgit v1.2.3-55-g6feb From b83db4ddae4c88b8837cd721c0f74e83bf956a5e Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Sun, 6 Aug 2017 18:29:25 +0200 Subject: setkeycodes: make it NOEXEC, better --help text Signed-off-by: Denys Vlasenko --- NOFORK_NOEXEC.lst | 2 +- console-tools/setkeycodes.c | 15 ++++++++------- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/NOFORK_NOEXEC.lst b/NOFORK_NOEXEC.lst index 8145e2597..58b3e9c54 100644 --- a/NOFORK_NOEXEC.lst +++ b/NOFORK_NOEXEC.lst @@ -307,7 +307,7 @@ seq - noexec. runner setarch - noexec. spawner setconsole setfont -setkeycodes +setkeycodes - noexec setlogcons - noexec setpriv - spawner, changes state, let's play safe and not be noexec setserial - noexec diff --git a/console-tools/setkeycodes.c b/console-tools/setkeycodes.c index 543fbe3e0..1363ac9d1 100644 --- a/console-tools/setkeycodes.c +++ b/console-tools/setkeycodes.c @@ -16,17 +16,16 @@ //config: This program loads entries into the kernel's scancode-to-keycode //config: map, allowing unusual keyboards to generate usable keycodes. -//applet:IF_SETKEYCODES(APPLET(setkeycodes, BB_DIR_USR_BIN, BB_SUID_DROP)) +//applet:IF_SETKEYCODES(APPLET_NOEXEC(setkeycodes, setkeycodes, BB_DIR_USR_BIN, BB_SUID_DROP, setkeycodes)) //kbuild:lib-$(CONFIG_SETKEYCODES) += setkeycodes.o //usage:#define setkeycodes_trivial_usage -//usage: "SCANCODE KEYCODE..." +//usage: "{ SCANCODE KEYCODE }..." //usage:#define setkeycodes_full_usage "\n\n" -//usage: "Set entries into the kernel's scancode-to-keycode map,\n" +//usage: "Modify kernel's scancode-to-keycode map,\n" //usage: "allowing unusual keyboards to generate usable keycodes.\n\n" -//usage: "SCANCODE may be either xx or e0xx (hexadecimal),\n" -//usage: "and KEYCODE is given in decimal." +//usage: "SCANCODE is either xx or e0xx (hexadecimal), KEYCODE is decimal." //usage: //usage:#define setkeycodes_example_usage //usage: "$ setkeycodes e030 127\n" @@ -45,7 +44,6 @@ int setkeycodes_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; int setkeycodes_main(int argc, char **argv) { int fd; - struct kbkeycode a; if (!(argc & 1) /* if even */ || argc < 2) { bb_show_usage(); @@ -54,7 +52,10 @@ int setkeycodes_main(int argc, char **argv) fd = get_console_fd_or_die(); while (argv[1]) { - int sc = xstrtoul_range(argv[1], 16, 0, 0xe07f); + struct kbkeycode a; + int sc; + + sc = xstrtoul_range(argv[1], 16, 0, 0xe07f); if (sc >= 0xe000) { sc -= 0xe000; sc += 0x0080; -- cgit v1.2.3-55-g6feb From ab2338110094fe371f44657b17e6980afd37c535 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Sun, 6 Aug 2017 18:54:16 +0200 Subject: setconsole: since SUSE version has no -r, nuke our --reset longopt Why we even bother inventing incompatible longopts?! function old new delta packed_usage 31734 31738 +4 static.setconsole_longopts 9 - -9 setconsole_main 94 84 -10 ------------------------------------------------------------------------------ (add/remove: 0/1 grow/shrink: 1/1 up/down: 4/-19) Total: -15 bytes Signed-off-by: Denys Vlasenko --- console-tools/setconsole.c | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/console-tools/setconsole.c b/console-tools/setconsole.c index ad0f756ca..fa5269ebb 100644 --- a/console-tools/setconsole.c +++ b/console-tools/setconsole.c @@ -25,11 +25,15 @@ //kbuild:lib-$(CONFIG_SETCONSOLE) += setconsole.o //usage:#define setconsole_trivial_usage -//usage: "[-r" IF_FEATURE_SETCONSOLE_LONG_OPTIONS("|--reset") "] [DEVICE]" +//usage: "[-r] [DEVICE]" //usage:#define setconsole_full_usage "\n\n" //usage: "Redirect system console output to DEVICE (default: /dev/tty)\n" //usage: "\n -r Reset output to /dev/console" +/* It was a bbox-specific invention, but SUSE does have a similar utility. + * SUSE has no -r option, though. + */ + #include "libbb.h" int setconsole_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; @@ -38,12 +42,6 @@ int setconsole_main(int argc UNUSED_PARAM, char **argv) const char *device = CURRENT_TTY; bool reset; -#if ENABLE_FEATURE_SETCONSOLE_LONG_OPTIONS - static const char setconsole_longopts[] ALIGN1 = - "reset\0" No_argument "r" - ; - applet_long_options = setconsole_longopts; -#endif /* at most one non-option argument */ opt_complementary = "?1"; reset = getopt32(argv, "r"); -- cgit v1.2.3-55-g6feb From 5cb907fffc25ce26d7388b485e64261f7ee42450 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Sun, 6 Aug 2017 18:56:25 +0200 Subject: setconsole: make it NOEXEC BTW, I failed to make it do what it meant to do. ioctl appears to succeed, but kernel's output is not coming to the specified console (tried on VT consoles too). OTOH, setlogcons does work... Signed-off-by: Denys Vlasenko --- NOFORK_NOEXEC.lst | 2 +- console-tools/setconsole.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/NOFORK_NOEXEC.lst b/NOFORK_NOEXEC.lst index 58b3e9c54..ec3b2a67e 100644 --- a/NOFORK_NOEXEC.lst +++ b/NOFORK_NOEXEC.lst @@ -305,7 +305,7 @@ sed - runner sendmail - runner seq - noexec. runner setarch - noexec. spawner -setconsole +setconsole - noexec setfont setkeycodes - noexec setlogcons - noexec diff --git a/console-tools/setconsole.c b/console-tools/setconsole.c index fa5269ebb..9a8ca3821 100644 --- a/console-tools/setconsole.c +++ b/console-tools/setconsole.c @@ -20,7 +20,7 @@ //config: default y //config: depends on SETCONSOLE && LONG_OPTS -//applet:IF_SETCONSOLE(APPLET(setconsole, BB_DIR_SBIN, BB_SUID_DROP)) +//applet:IF_SETCONSOLE(APPLET_NOEXEC(setconsole, setconsole, BB_DIR_SBIN, BB_SUID_DROP, setconsole)) //kbuild:lib-$(CONFIG_SETCONSOLE) += setconsole.o -- cgit v1.2.3-55-g6feb From 1b280e46520420dad1ed1e985d11b7b2bea493e4 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Sun, 6 Aug 2017 19:05:45 +0200 Subject: loadfont,setfont: make them NOEXEC Signed-off-by: Denys Vlasenko --- NOFORK_NOEXEC.lst | 4 ++-- console-tools/loadfont.c | 54 ++++++++++++++++++++++-------------------------- 2 files changed, 27 insertions(+), 31 deletions(-) diff --git a/NOFORK_NOEXEC.lst b/NOFORK_NOEXEC.lst index ec3b2a67e..3a30af0e2 100644 --- a/NOFORK_NOEXEC.lst +++ b/NOFORK_NOEXEC.lst @@ -194,7 +194,7 @@ linux32 - noexec. spawner linux64 - noexec. spawner linuxrc - daemon ln - noexec -loadfont - leaks: config_open+bb_error_msg_and_die("map format") +loadfont - noexec. leaks: config_open+bb_error_msg_and_die("map format") loadkmap - noexec. leaks: get_console_fd_or_die() may open a new fd, or return one of stdio fds logger - runner login - suid, interactive, longterm @@ -306,7 +306,7 @@ sendmail - runner seq - noexec. runner setarch - noexec. spawner setconsole - noexec -setfont +setfont - noexec. leaks a lot of stuff setkeycodes - noexec setlogcons - noexec setpriv - spawner, changes state, let's play safe and not be noexec diff --git a/console-tools/loadfont.c b/console-tools/loadfont.c index 6dc8fa831..623d98175 100644 --- a/console-tools/loadfont.c +++ b/console-tools/loadfont.c @@ -51,31 +51,12 @@ //config: default y //config: depends on LOADFONT || SETFONT -//applet:IF_LOADFONT(APPLET(loadfont, BB_DIR_USR_SBIN, BB_SUID_DROP)) -//applet:IF_SETFONT(APPLET(setfont, BB_DIR_USR_SBIN, BB_SUID_DROP)) +//applet:IF_LOADFONT(APPLET_NOEXEC(loadfont, loadfont, BB_DIR_USR_SBIN, BB_SUID_DROP, loadfont)) +//applet:IF_SETFONT(APPLET_NOEXEC(setfont, setfont, BB_DIR_USR_SBIN, BB_SUID_DROP, setfont)) //kbuild:lib-$(CONFIG_LOADFONT) += loadfont.o //kbuild:lib-$(CONFIG_SETFONT) += loadfont.o -//usage:#define loadfont_trivial_usage -//usage: "< font" -//usage:#define loadfont_full_usage "\n\n" -//usage: "Load a console font from stdin" -/* //usage: "\n -C TTY Affect TTY instead of /dev/tty" */ -//usage: -//usage:#define loadfont_example_usage -//usage: "$ loadfont < /etc/i18n/fontname\n" -//usage: -//usage:#define setfont_trivial_usage -//usage: "FONT [-m MAPFILE] [-C TTY]" -//usage:#define setfont_full_usage "\n\n" -//usage: "Load a console font\n" -//usage: "\n -m MAPFILE Load console screen map" -//usage: "\n -C TTY Affect TTY instead of /dev/tty" -//usage: -//usage:#define setfont_example_usage -//usage: "$ setfont -m koi8-r /etc/i18n/fontname\n" - #include "libbb.h" #include @@ -352,6 +333,14 @@ static void do_load(int fd, unsigned char *buffer, size_t len) #if ENABLE_LOADFONT +//usage:#define loadfont_trivial_usage +//usage: "< font" +//usage:#define loadfont_full_usage "\n\n" +//usage: "Load a console font from stdin" +/* //usage: "\n -C TTY Affect TTY instead of /dev/tty" */ +//usage: +//usage:#define loadfont_example_usage +//usage: "$ loadfont < /etc/i18n/fontname\n" int loadfont_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; int loadfont_main(int argc UNUSED_PARAM, char **argv) { @@ -380,11 +369,9 @@ int loadfont_main(int argc UNUSED_PARAM, char **argv) } #endif -#if ENABLE_SETFONT - -/* -kbd-1.12: +#if ENABLE_SETFONT +/* kbd-1.12: setfont [-O font+umap.orig] [-o font.orig] [-om cmap.orig] [-ou umap.orig] [-N] [font.new ...] [-m cmap] [-u umap] [-C console] [-hNN] [-v] [-V] @@ -414,8 +401,17 @@ setfont [-O font+umap.orig] [-o font.orig] [-om cmap.orig] -v Verbose -V Version */ +//usage:#define setfont_trivial_usage +//usage: "FONT [-m MAPFILE] [-C TTY]" +//usage:#define setfont_full_usage "\n\n" +//usage: "Load a console font\n" +//usage: "\n -m MAPFILE Load console screen map" +//usage: "\n -C TTY Affect TTY instead of /dev/tty" +//usage: +//usage:#define setfont_example_usage +//usage: "$ setfont -m koi8-r /etc/i18n/fontname\n" -#if ENABLE_FEATURE_SETFONT_TEXTUAL_MAP +# if ENABLE_FEATURE_SETFONT_TEXTUAL_MAP static int ctoi(char *s) { if (s[0] == '\'' && s[1] != '\0' && s[2] == '\'' && s[3] == '\0') @@ -429,7 +425,7 @@ static int ctoi(char *s) return -1; return xstrtoul(s, 0); } -#endif +# endif int setfont_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; int setfont_main(int argc UNUSED_PARAM, char **argv) @@ -480,7 +476,7 @@ int setfont_main(int argc UNUSED_PARAM, char **argv) if (len == 2*E_TABSZ) mode = PIO_UNISCRNMAP; } -#if ENABLE_FEATURE_SETFONT_TEXTUAL_MAP +# if ENABLE_FEATURE_SETFONT_TEXTUAL_MAP // assume textual Unicode console maps: // 0x00 U+0000 # NULL (NUL) // 0x01 U+0001 # START OF HEADING (SOH) @@ -527,7 +523,7 @@ int setfont_main(int argc UNUSED_PARAM, char **argv) } #undef unicodes } -#endif // ENABLE_FEATURE_SETFONT_TEXTUAL_MAP +# endif // ENABLE_FEATURE_SETFONT_TEXTUAL_MAP // do set screen map xioctl(fd, mode, map); -- cgit v1.2.3-55-g6feb From a894a4beddf9c132556b001925ea3e8e0881e273 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Sun, 6 Aug 2017 19:08:46 +0200 Subject: raidautorun: make it NOEXEC Signed-off-by: Denys Vlasenko --- NOFORK_NOEXEC.lst | 4 ++-- miscutils/raidautorun.c | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/NOFORK_NOEXEC.lst b/NOFORK_NOEXEC.lst index 3a30af0e2..99af24357 100644 --- a/NOFORK_NOEXEC.lst +++ b/NOFORK_NOEXEC.lst @@ -274,7 +274,7 @@ pscan - longterm pstree - noexec pwd - NOFORK pwdx - NOFORK -raidautorun +raidautorun - noexec. very simple. leaks: open+xioctl rdate - needs ^C (may talk to DNS servers, which may be down) rdev - leaks: find_block_device -> readdir+xstrdup readlink - NOFORK @@ -294,7 +294,7 @@ route - needs ^C (may talk to DNS servers, which may be down) rpm - runner rpm2cpio - runner rtcwake - longterm: puts system to sleep, optimizing this for speed is pointless -run-parts +run-parts - longterm runlevel - noexec. can be nofork if "endutxent()" is called unconditionally, but too rare to bother? runsv - daemon runsvdir - daemon diff --git a/miscutils/raidautorun.c b/miscutils/raidautorun.c index ecedf9ce2..caf6e0821 100644 --- a/miscutils/raidautorun.c +++ b/miscutils/raidautorun.c @@ -15,7 +15,7 @@ //config: raidautorun tells the kernel md driver to //config: search and start RAID arrays. -//applet:IF_RAIDAUTORUN(APPLET(raidautorun, BB_DIR_SBIN, BB_SUID_DROP)) +//applet:IF_RAIDAUTORUN(APPLET_NOEXEC(raidautorun, raidautorun, BB_DIR_SBIN, BB_SUID_DROP, raidautorun)) //kbuild:lib-$(CONFIG_RAIDAUTORUN) += raidautorun.o -- cgit v1.2.3-55-g6feb From c8e29317e97ee595a66314275c163a5ce55fcca9 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Sun, 6 Aug 2017 19:46:21 +0200 Subject: adjtimex: zero-fill whole structure, to be on the safe side function old new delta adjtimex_main 395 406 +11 Signed-off-by: Denys Vlasenko --- miscutils/adjtimex.c | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/miscutils/adjtimex.c b/miscutils/adjtimex.c index 0830734ee..a39c4f5cf 100644 --- a/miscutils/adjtimex.c +++ b/miscutils/adjtimex.c @@ -90,13 +90,14 @@ int adjtimex_main(int argc UNUSED_PARAM, char **argv) unsigned opt; char *opt_o, *opt_f, *opt_p, *opt_t; struct timex txc; - int i, ret; + int ret; const char *descript; + memset(&txc, 0, sizeof(txc)); + opt_complementary = "=0"; /* no valid non-option parameters */ opt = getopt32(argv, "qo:f:p:t:", &opt_o, &opt_f, &opt_p, &opt_t); - txc.modes = 0; //if (opt & 0x1) // -q if (opt & 0x2) { // -o txc.offset = xatol(opt_o); @@ -116,14 +117,13 @@ int adjtimex_main(int argc UNUSED_PARAM, char **argv) } ret = adjtimex(&txc); - - if (ret < 0) { + if (ret < 0) bb_perror_nomsg_and_die(); - } if (!(opt & OPT_quiet)) { const char *sep; const char *name; + int i; printf( " mode: %d\n" @@ -132,8 +132,9 @@ int adjtimex_main(int argc UNUSED_PARAM, char **argv) " maxerror: %ld\n" " esterror: %ld\n" " status: %d (", - txc.modes, txc.offset, txc.freq, txc.maxerror, - txc.esterror, txc.status); + txc.modes, txc.offset, txc.freq, txc.maxerror, + txc.esterror, txc.status + ); /* representative output of next code fragment: * "PLL | PPSTIME" @@ -159,9 +160,11 @@ int adjtimex_main(int argc UNUSED_PARAM, char **argv) " time.tv_sec: %ld\n" " time.tv_usec: %ld\n" " return value: %d (%s)\n", - txc.constant, - txc.precision, txc.tolerance, txc.tick, - (long)txc.time.tv_sec, (long)txc.time.tv_usec, ret, descript); + txc.constant, + txc.precision, txc.tolerance, txc.tick, + (long)txc.time.tv_sec, (long)txc.time.tv_usec, + ret, descript + ); } return 0; -- cgit v1.2.3-55-g6feb From ed7d118dd0cfda7be21dafae5eb34b0d419f62ec Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Sun, 6 Aug 2017 20:00:21 +0200 Subject: adjtimex: make it NOFORK Signed-off-by: Denys Vlasenko --- NOFORK_NOEXEC.lst | 2 +- miscutils/adjtimex.c | 7 ++++++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/NOFORK_NOEXEC.lst b/NOFORK_NOEXEC.lst index 99af24357..97b7d8b20 100644 --- a/NOFORK_NOEXEC.lst +++ b/NOFORK_NOEXEC.lst @@ -39,7 +39,7 @@ acpid - daemon add-shell addgroup adduser -adjtimex +adjtimex - NOFORK ar - runner arch - NOFORK arp - complex, rare diff --git a/miscutils/adjtimex.c b/miscutils/adjtimex.c index a39c4f5cf..ce6f8ccd8 100644 --- a/miscutils/adjtimex.c +++ b/miscutils/adjtimex.c @@ -18,7 +18,7 @@ //config: Adjtimex reads and optionally sets adjustment parameters for //config: the Linux clock adjustment algorithm. -//applet:IF_ADJTIMEX(APPLET(adjtimex, BB_DIR_SBIN, BB_SUID_DROP)) +//applet:IF_ADJTIMEX(APPLET_NOFORK(adjtimex, adjtimex, BB_DIR_SBIN, BB_SUID_DROP, adjtimex)) //kbuild:lib-$(CONFIG_ADJTIMEX) += adjtimex.o @@ -116,6 +116,11 @@ int adjtimex_main(int argc UNUSED_PARAM, char **argv) txc.modes |= ADJ_TICK; } + /* It's NOFORK applet because the code is very simple: + * just some printf. No opens, no allocs. + * If you need to make it more complex, feel free to downgrade to NOEXEC + */ + ret = adjtimex(&txc); if (ret < 0) bb_perror_nomsg_and_die(); -- cgit v1.2.3-55-g6feb From 0f14f41e72d48836a5287d00f05cea236b25be40 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Sun, 6 Aug 2017 20:06:19 +0200 Subject: ash: do not set a signal to SIG_DFL if it already is function old new delta setsignal 312 338 +26 Signed-off-by: Denys Vlasenko --- shell/ash.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/shell/ash.c b/shell/ash.c index e80425f5e..e8f3ed26b 100644 --- a/shell/ash.c +++ b/shell/ash.c @@ -366,7 +366,7 @@ struct globals_misc { #define S_DFL 1 /* default signal handling (SIG_DFL) */ #define S_CATCH 2 /* signal is caught */ #define S_IGN 3 /* signal is ignored (SIG_IGN) */ -#define S_HARD_IGN 4 /* signal is ignored permanently */ +#define S_HARD_IGN 4 /* signal is ignored permanently (it was SIG_IGN on entry to shell) */ /* indicates specified signal received */ uint8_t gotsig[NSIG - 1]; /* offset by 1: "signal" 0 is meaningless */ @@ -3566,6 +3566,12 @@ setsignal(int signo) cur_act = S_IGN; /* don't hard ignore these */ } } + if (act.sa_handler == SIG_DFL && new_act == S_DFL) { + /* installing SIG_DFL over SIG_DFL is a no-op */ + /* saves one sigaction call in each "sh -c SCRIPT" invocation */ + *t = S_DFL; + return; + } } if (cur_act == S_HARD_IGN || cur_act == new_act) return; -- cgit v1.2.3-55-g6feb From 86e07f6893cfe94a4a7c4aba4b643752808d4235 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Sun, 6 Aug 2017 20:14:02 +0200 Subject: brctl: make it NOEXEC Signed-off-by: Denys Vlasenko --- NOFORK_NOEXEC.lst | 2 +- networking/brctl.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/NOFORK_NOEXEC.lst b/NOFORK_NOEXEC.lst index 97b7d8b20..dc2828069 100644 --- a/NOFORK_NOEXEC.lst +++ b/NOFORK_NOEXEC.lst @@ -53,7 +53,7 @@ blkdiscard blkid blockdev - noexec. leaks fd bootchartd - daemon -brctl +brctl - noexec bunzip2 - runner busybox bzcat - runner diff --git a/networking/brctl.c b/networking/brctl.c index 690791e4c..5d5f0af30 100644 --- a/networking/brctl.c +++ b/networking/brctl.c @@ -39,7 +39,7 @@ //config: Add support for option which prints the current config: //config: show -//applet:IF_BRCTL(APPLET(brctl, BB_DIR_USR_SBIN, BB_SUID_DROP)) +//applet:IF_BRCTL(APPLET_NOEXEC(brctl, brctl, BB_DIR_USR_SBIN, BB_SUID_DROP, brctl)) //kbuild:lib-$(CONFIG_BRCTL) += brctl.o -- cgit v1.2.3-55-g6feb From bf18239e3d6305fc83e5177bd9a27c5114cc4c16 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Sun, 6 Aug 2017 20:16:28 +0200 Subject: blkid: make it NOEXEC, make FEATURE_BLKID_TYPE=y default Signed-off-by: Denys Vlasenko --- NOFORK_NOEXEC.lst | 2 +- util-linux/blkid.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/NOFORK_NOEXEC.lst b/NOFORK_NOEXEC.lst index dc2828069..9735e756a 100644 --- a/NOFORK_NOEXEC.lst +++ b/NOFORK_NOEXEC.lst @@ -50,7 +50,7 @@ base64 - runner basename - NOFORK beep blkdiscard -blkid +blkid - noexec blockdev - noexec. leaks fd bootchartd - daemon brctl - noexec diff --git a/util-linux/blkid.c b/util-linux/blkid.c index 0bd701aae..a56b69661 100644 --- a/util-linux/blkid.c +++ b/util-linux/blkid.c @@ -16,12 +16,12 @@ //config: //config:config FEATURE_BLKID_TYPE //config: bool "Print filesystem type" -//config: default n +//config: default y //config: depends on BLKID //config: help //config: Show TYPE="filesystem type" -//applet:IF_BLKID(APPLET(blkid, BB_DIR_SBIN, BB_SUID_DROP)) +//applet:IF_BLKID(APPLET_NOEXEC(blkid, blkid, BB_DIR_SBIN, BB_SUID_DROP, blkid)) //kbuild:lib-$(CONFIG_BLKID) += blkid.o -- cgit v1.2.3-55-g6feb From 277081e0a4e04b1c39b3eadf4422ef36fded4705 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Sun, 6 Aug 2017 20:20:47 +0200 Subject: blkdiscard: make it NOEXEC Signed-off-by: Denys Vlasenko --- NOFORK_NOEXEC.lst | 2 +- util-linux/blkdiscard.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/NOFORK_NOEXEC.lst b/NOFORK_NOEXEC.lst index 9735e756a..ab58df50d 100644 --- a/NOFORK_NOEXEC.lst +++ b/NOFORK_NOEXEC.lst @@ -49,7 +49,7 @@ awk - noexec. runner base64 - runner basename - NOFORK beep -blkdiscard +blkdiscard - noexec. leaks: open+xioctl blkid - noexec blockdev - noexec. leaks fd bootchartd - daemon diff --git a/util-linux/blkdiscard.c b/util-linux/blkdiscard.c index 8f6a4ab6c..048d39e83 100644 --- a/util-linux/blkdiscard.c +++ b/util-linux/blkdiscard.c @@ -11,8 +11,9 @@ //config: help //config: blkdiscard discards sectors on a given device. +//applet:IF_BLKDISCARD(APPLET_NOEXEC(blkdiscard, blkdiscard, BB_DIR_USR_BIN, BB_SUID_DROP, blkdiscard)) + //kbuild:lib-$(CONFIG_BLKDISCARD) += blkdiscard.o -//applet:IF_BLKDISCARD(APPLET(blkdiscard, BB_DIR_USR_BIN, BB_SUID_DROP)) //usage:#define blkdiscard_trivial_usage //usage: "[-o OFS] [-l LEN] [-s] DEVICE" @@ -44,7 +45,6 @@ int blkdiscard_main(int argc UNUSED_PARAM, char **argv) uint64_t offset; /* Leaving these two variables out does not */ uint64_t length; /* shrink code size and hampers readability. */ uint64_t range[2]; -// struct stat st; int fd; enum { -- cgit v1.2.3-55-g6feb From 035e71578e98744acba2394bb03686d08f60d956 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Sun, 6 Aug 2017 20:39:27 +0200 Subject: readprofile: do not close/free just before exiting function old new delta readprofile_main 1784 1762 -22 Signed-off-by: Denys Vlasenko --- NOFORK_NOEXEC.lst | 6 +++--- util-linux/readprofile.c | 6 ++++-- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/NOFORK_NOEXEC.lst b/NOFORK_NOEXEC.lst index ab58df50d..02e2ba956 100644 --- a/NOFORK_NOEXEC.lst +++ b/NOFORK_NOEXEC.lst @@ -48,7 +48,7 @@ ash - interactive, longterm awk - noexec. runner base64 - runner basename - NOFORK -beep +beep - longterm: beep -r 999999999 blkdiscard - noexec. leaks: open+xioctl blkid - noexec blockdev - noexec. leaks fd @@ -127,7 +127,7 @@ findfs - suid flash_eraseall flash_lock flash_unlock -flashcp +flashcp - needs ^C. flash writing may be slow, better to free memory memory by execing flock - spawner, changes state (file locks), let's play safe and not be noexec fold - noexec. runner free - nofork candidate(struct globals, needs to close /proc/meminfo fd) @@ -278,7 +278,7 @@ raidautorun - noexec. very simple. leaks: open+xioctl rdate - needs ^C (may talk to DNS servers, which may be down) rdev - leaks: find_block_device -> readdir+xstrdup readlink - NOFORK -readprofile +readprofile - reads /boot/System.map and /proc/profile, better to free more memory memory by execing? realpath - NOFORK reboot - rare reformime - runner diff --git a/util-linux/readprofile.c b/util-linux/readprofile.c index b045657d8..394ece1dd 100644 --- a/util-linux/readprofile.c +++ b/util-linux/readprofile.c @@ -266,8 +266,10 @@ int readprofile_main(int argc UNUSED_PARAM, char **argv) printf("%6u %-40s %8.4f\n", total, "total", total/(double)(fn_add-add0)); - fclose(map); - free(buf); + if (ENABLE_FEATURE_CLEAN_UP) { + fclose(map); + free(buf); + } return EXIT_SUCCESS; } -- cgit v1.2.3-55-g6feb From 184c738582eb190489dd2e9d120b1e036df65401 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Sun, 6 Aug 2017 20:55:56 +0200 Subject: stty: fix bb_common_bufsiz1 use in NOEXEC function old new delta stty_main 1211 1221 +10 do_display 379 370 -9 Signed-off-by: Denys Vlasenko --- NOFORK_NOEXEC.lst | 2 +- coreutils/stty.c | 10 ++++++---- debianutils/start_stop_daemon.c | 9 +++++---- 3 files changed, 12 insertions(+), 9 deletions(-) diff --git a/NOFORK_NOEXEC.lst b/NOFORK_NOEXEC.lst index 02e2ba956..fb76fcf63 100644 --- a/NOFORK_NOEXEC.lst +++ b/NOFORK_NOEXEC.lst @@ -327,7 +327,7 @@ softlimit - noexec. spawner sort - noexec. runner split - runner ssl_client - longterm -start-stop-daemon +start-stop-daemon - not noexec: uses bb_common_bufsiz1 stat - nofork candidate(needs fewer allocs) strings - runner stty - noexec. nofork candidate: has no allocs or opens except xmove_fd(xopen("-F DEVICE"),STDIN). tcsetattr(STDIN) is not a problem: it would work the same across processes sharing this fd diff --git a/coreutils/stty.c b/coreutils/stty.c index d09f0e453..2292fa5ee 100644 --- a/coreutils/stty.c +++ b/coreutils/stty.c @@ -782,12 +782,12 @@ struct globals { unsigned max_col; /* Current position, to know when to wrap */ unsigned current_col; - char buf[10]; } FIX_ALIASING; #define G (*(struct globals*)bb_common_bufsiz1) #define INIT_G() do { \ G.device_name = bb_msg_standard_input; \ G.max_col = 80; \ + G.current_col = 0; /* we are noexec, must clear */ \ } while (0) static void set_speed_or_die(enum speed_setting type, const char *arg, @@ -1018,6 +1018,8 @@ static void do_display(const struct termios *mode, int all) for (i = 0; i != CIDX_min; ++i) { char ch; + char buf10[10]; + /* If swtch is the same as susp, don't print both */ #if VSWTCH == VSUSP if (i == CIDX_swtch) @@ -1033,10 +1035,10 @@ static void do_display(const struct termios *mode, int all) #endif ch = mode->c_cc[control_info[i].offset]; if (ch == _POSIX_VDISABLE) - strcpy(G.buf, ""); + strcpy(buf10, ""); else - visible(ch, G.buf, 0); - wrapf("%s = %s;", nth_string(control_name, i), G.buf); + visible(ch, buf10, 0); + wrapf("%s = %s;", nth_string(control_name, i), buf10); } #if VEOF == VMIN if ((mode->c_lflag & ICANON) == 0) diff --git a/debianutils/start_stop_daemon.c b/debianutils/start_stop_daemon.c index 07c104baa..9effdc80b 100644 --- a/debianutils/start_stop_daemon.c +++ b/debianutils/start_stop_daemon.c @@ -79,6 +79,7 @@ Misc options: //config: -N|--nicelevel N //applet:IF_START_STOP_DAEMON(APPLET_ODDNAME(start-stop-daemon, start_stop_daemon, BB_DIR_SBIN, BB_SUID_DROP, start_stop_daemon)) +/* not NOEXEC: uses bb_common_bufsiz1 */ //kbuild:lib-$(CONFIG_START_STOP_DAEMON) += start_stop_daemon.o @@ -409,11 +410,11 @@ static const char start_stop_daemon_longopts[] ALIGN1 = "quiet\0" No_argument "q" "test\0" No_argument "t" "make-pidfile\0" No_argument "m" -#if ENABLE_FEATURE_START_STOP_DAEMON_FANCY +# if ENABLE_FEATURE_START_STOP_DAEMON_FANCY "oknodo\0" No_argument "o" "verbose\0" No_argument "v" "nicelevel\0" Required_argument "N" -#endif +# endif "startas\0" Required_argument "a" "name\0" Required_argument "n" "signal\0" Required_argument "s" @@ -421,9 +422,9 @@ static const char start_stop_daemon_longopts[] ALIGN1 = "chuid\0" Required_argument "c" "exec\0" Required_argument "x" "pidfile\0" Required_argument "p" -#if ENABLE_FEATURE_START_STOP_DAEMON_FANCY +# if ENABLE_FEATURE_START_STOP_DAEMON_FANCY "retry\0" Required_argument "R" -#endif +# endif ; #endif -- cgit v1.2.3-55-g6feb From b9be78070569e69960ba2b3c4098c3dc3316b9bd Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Sun, 6 Aug 2017 21:23:03 +0200 Subject: sv,svc: fix NOEXEC fallout function old new delta svc_main 145 162 +17 sv 1280 1297 +17 status 139 133 -6 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 2/1 up/down: 34/-6) Total: 28 bytes Signed-off-by: Denys Vlasenko --- console-tools/dumpkmap.c | 19 +++---------------- console-tools/resize.c | 2 ++ coreutils/cksum.c | 1 + coreutils/date.c | 1 + coreutils/stty.c | 1 + runit/sv.c | 10 ++++++++-- util-linux/umount.c | 2 ++ 7 files changed, 18 insertions(+), 18 deletions(-) diff --git a/console-tools/dumpkmap.c b/console-tools/dumpkmap.c index 5ffb0cddb..b803e579a 100644 --- a/console-tools/dumpkmap.c +++ b/console-tools/dumpkmap.c @@ -16,6 +16,7 @@ //config: stdout, in binary format. You can then use loadkmap to load it. //applet:IF_DUMPKMAP(APPLET_NOEXEC(dumpkmap, dumpkmap, BB_DIR_BIN, BB_SUID_DROP, dumpkmap)) +/* bb_common_bufsiz1 usage here is safe wrt NOEXEC: not expecting it to be zeroed. */ //kbuild:lib-$(CONFIG_DUMPKMAP) += dumpkmap.o @@ -47,8 +48,6 @@ int dumpkmap_main(int argc UNUSED_PARAM, char **argv) { struct kbentry ke; int i, j, fd; -#define flags bb_common_bufsiz1 - setup_common_bufsiz(); /* When user accidentally runs "dumpkmap FILE" * instead of "dumpkmap >FILE", we'd dump binary stuff to tty. @@ -60,19 +59,8 @@ int dumpkmap_main(int argc UNUSED_PARAM, char **argv) fd = get_console_fd_or_die(); -#if 0 - write(STDOUT_FILENO, "bkeymap", 7); - /* Here we want to set everything to 0 except for indexes: - * [0-2] [4-6] [8-10] [12] - */ - /*memset(flags, 0x00, MAX_NR_KEYMAPS); - already is */ - memset(flags, 0x01, 13); - flags[3] = flags[7] = flags[11] = 0; - /* dump flags */ - write(STDOUT_FILENO, flags, MAX_NR_KEYMAPS); -#define flags7 flags -#else - /* Same effect */ +#define flags bb_common_bufsiz1 + setup_common_bufsiz(); /* 0 1 2 3 4 5 6 7 8 9 a b c=12 */ memcpy(flags, "bkeymap\1\1\1\0\1\1\1\0\1\1\1\0\1", /* Can use sizeof, or sizeof-1. sizeof is even, using that */ @@ -80,7 +68,6 @@ int dumpkmap_main(int argc UNUSED_PARAM, char **argv) ); write(STDOUT_FILENO, flags, 7 + MAX_NR_KEYMAPS); #define flags7 (flags + 7) -#endif for (i = 0; i < 13; i++) { if (flags7[i]) { diff --git a/console-tools/resize.c b/console-tools/resize.c index 97866673a..8aa487c41 100644 --- a/console-tools/resize.c +++ b/console-tools/resize.c @@ -24,6 +24,7 @@ //config: COLUMNS=80;LINES=44;export COLUMNS LINES; //applet:IF_RESIZE(APPLET_NOEXEC(resize, resize, BB_DIR_USR_BIN, BB_SUID_DROP, resize)) +/* bb_common_bufsiz1 usage here is safe wrt NOEXEC: not expecting it to be zeroed. */ //kbuild:lib-$(CONFIG_RESIZE) += resize.o @@ -63,6 +64,7 @@ int resize_main(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) */ tcgetattr(STDERR_FILENO, old_termios_p); /* fiddle echo */ +//TODO: die if the above fails? memcpy(&new, old_termios_p, sizeof(new)); new.c_cflag |= (CLOCAL | CREAD); new.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG); diff --git a/coreutils/cksum.c b/coreutils/cksum.c index c0cf65d2a..059a33310 100644 --- a/coreutils/cksum.c +++ b/coreutils/cksum.c @@ -13,6 +13,7 @@ //config: cksum is used to calculate the CRC32 checksum of a file. //applet:IF_CKSUM(APPLET_NOEXEC(cksum, cksum, BB_DIR_USR_BIN, BB_SUID_DROP, cksum)) +/* bb_common_bufsiz1 usage here is safe wrt NOEXEC: not expecting it to be zeroed. */ //kbuild:lib-$(CONFIG_CKSUM) += cksum.o diff --git a/coreutils/date.c b/coreutils/date.c index 89b281646..5a4ad5fe5 100644 --- a/coreutils/date.c +++ b/coreutils/date.c @@ -59,6 +59,7 @@ //config: MMDDhhmm[[YY]YY][.ss] format. //applet:IF_DATE(APPLET_NOEXEC(date, date, BB_DIR_BIN, BB_SUID_DROP, date)) +/* bb_common_bufsiz1 usage here is safe wrt NOEXEC: not expecting it to be zeroed. */ //kbuild:lib-$(CONFIG_DATE) += date.o diff --git a/coreutils/stty.c b/coreutils/stty.c index 2292fa5ee..57e2cc30d 100644 --- a/coreutils/stty.c +++ b/coreutils/stty.c @@ -785,6 +785,7 @@ struct globals { } FIX_ALIASING; #define G (*(struct globals*)bb_common_bufsiz1) #define INIT_G() do { \ + setup_common_bufsiz(); \ G.device_name = bb_msg_standard_input; \ G.max_col = 80; \ G.current_col = 0; /* we are noexec, must clear */ \ diff --git a/runit/sv.c b/runit/sv.c index 0817ab472..630f1f37e 100644 --- a/runit/sv.c +++ b/runit/sv.c @@ -193,7 +193,7 @@ struct globals { /* "Bernstein" time format: unix + 0x400000000000000aULL */ uint64_t tstart, tnow; svstatus_t svstatus; - unsigned islog; + smallint islog; } FIX_ALIASING; #define G (*(struct globals*)bb_common_bufsiz1) #define acts (G.acts ) @@ -203,7 +203,13 @@ struct globals { #define tnow (G.tnow ) #define svstatus (G.svstatus ) #define islog (G.islog ) -#define INIT_G() do { setup_common_bufsiz(); } while (0) +#define INIT_G() do { \ + setup_common_bufsiz(); \ + /* need to zero out, we are NOEXEC */ \ + rc = EXIT_SUCCESS; \ + islog = 0; \ + /* other fields need not be zero */ \ +} while (0) #define str_equal(s,t) (strcmp((s), (t)) == 0) diff --git a/util-linux/umount.c b/util-linux/umount.c index 33667b13c..a6405dfcc 100644 --- a/util-linux/umount.c +++ b/util-linux/umount.c @@ -35,6 +35,8 @@ * In this case, you might be actually happy if your standalone bbox shell * does not fork+exec, but only forks and calls umount_main() which it already has! * Let's go with NOEXEC. + * + * bb_common_bufsiz1 usage here is safe wrt NOEXEC: not expecting it to be zeroed. */ //kbuild:lib-$(CONFIG_UMOUNT) += umount.o -- cgit v1.2.3-55-g6feb From 7389662dbf54463222d66e555368e0151098ab38 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Sun, 6 Aug 2017 21:29:51 +0200 Subject: svc: remove superfluout INIT_G() function old new delta sv 1297 1296 -1 svc_main 162 145 -17 Signed-off-by: Denys Vlasenko --- runit/sv.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/runit/sv.c b/runit/sv.c index 630f1f37e..477c1ac6e 100644 --- a/runit/sv.c +++ b/runit/sv.c @@ -205,10 +205,8 @@ struct globals { #define islog (G.islog ) #define INIT_G() do { \ setup_common_bufsiz(); \ - /* need to zero out, we are NOEXEC */ \ - rc = EXIT_SUCCESS; \ - islog = 0; \ - /* other fields need not be zero */ \ + /* need to zero out, svc calls sv() repeatedly */ \ + memset(&G, 0, sizeof(G)); \ } while (0) @@ -707,8 +705,6 @@ int svc_main(int argc UNUSED_PARAM, char **argv) const char *optstring; unsigned opts; - INIT_G(); - optstring = "udopchaitkx"; opts = getopt32(argv, optstring); argv += optind; -- cgit v1.2.3-55-g6feb From 9536ef7c9855172d25223242eba7b7692339e3d8 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Sun, 6 Aug 2017 21:47:07 +0200 Subject: makedevs: make it NOEXEC Signed-off-by: Denys Vlasenko --- NOFORK_NOEXEC.lst | 6 +++--- miscutils/makedevs.c | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/NOFORK_NOEXEC.lst b/NOFORK_NOEXEC.lst index fb76fcf63..63ec08643 100644 --- a/NOFORK_NOEXEC.lst +++ b/NOFORK_NOEXEC.lst @@ -127,7 +127,7 @@ findfs - suid flash_eraseall flash_lock flash_unlock -flashcp - needs ^C. flash writing may be slow, better to free memory memory by execing +flashcp - needs ^C. flash writing may be slow, better to free memory by execing flock - spawner, changes state (file locks), let's play safe and not be noexec fold - noexec. runner free - nofork candidate(struct globals, needs to close /proc/meminfo fd) @@ -214,7 +214,7 @@ lzcat - runner lzma - runner lzop - runner lzopcat - runner -makedevs +makedevs - noexec makemime - runner man - spawner, interactive, longterm md5sum - noexec. runner @@ -278,7 +278,7 @@ raidautorun - noexec. very simple. leaks: open+xioctl rdate - needs ^C (may talk to DNS servers, which may be down) rdev - leaks: find_block_device -> readdir+xstrdup readlink - NOFORK -readprofile - reads /boot/System.map and /proc/profile, better to free more memory memory by execing? +readprofile - reads /boot/System.map and /proc/profile, better to free more memory by execing? realpath - NOFORK reboot - rare reformime - runner diff --git a/miscutils/makedevs.c b/miscutils/makedevs.c index c2f86df01..c13ad1442 100644 --- a/miscutils/makedevs.c +++ b/miscutils/makedevs.c @@ -38,7 +38,7 @@ //config: //config:endchoice -//applet:IF_MAKEDEVS(APPLET(makedevs, BB_DIR_SBIN, BB_SUID_DROP)) +//applet:IF_MAKEDEVS(APPLET_NOEXEC(makedevs, makedevs, BB_DIR_SBIN, BB_SUID_DROP, makedevs)) //kbuild:lib-$(CONFIG_MAKEDEVS) += makedevs.o -- cgit v1.2.3-55-g6feb From bfc66d49806a4305014b12bbe078484b2da6f93f Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Sun, 6 Aug 2017 21:53:39 +0200 Subject: nbd-client: make it NOEXEC, stop using argc function old new delta nbdclient_main 484 492 +8 Signed-off-by: Denys Vlasenko --- NOFORK_NOEXEC.lst | 2 +- networking/nbd-client.c | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/NOFORK_NOEXEC.lst b/NOFORK_NOEXEC.lst index 63ec08643..9c8df23ab 100644 --- a/NOFORK_NOEXEC.lst +++ b/NOFORK_NOEXEC.lst @@ -241,7 +241,7 @@ mpstat - longterm: "mpstat 1" runs indefinitely mt - rare mv - noexec candidate, runner nameif - noexec. openlog(), leaks: config_open2+ioctl_or_perror_and_die -nbd-client +nbd-client - noexec nc - runner netstat - runner with -c nice - noexec. spawner diff --git a/networking/nbd-client.c b/networking/nbd-client.c index a5e25e6aa..cf1857231 100644 --- a/networking/nbd-client.c +++ b/networking/nbd-client.c @@ -7,7 +7,7 @@ #include #include -//applet:IF_NBDCLIENT(APPLET_ODDNAME(nbd-client, nbdclient, BB_DIR_USR_SBIN, BB_SUID_DROP, nbdclient)) +//applet:IF_NBDCLIENT(APPLET_NOEXEC(nbd-client, nbdclient, BB_DIR_USR_SBIN, BB_SUID_DROP, nbdclient)) //kbuild:lib-$(CONFIG_NBDCLIENT) += nbd-client.o @@ -43,7 +43,7 @@ //blocksizes other than 1024 without patches int nbdclient_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; -int nbdclient_main(int argc, char **argv) +int nbdclient_main(int argc UNUSED_PARAM, char **argv) { unsigned long timeout = 0; #if BB_MMU @@ -61,7 +61,7 @@ int nbdclient_main(int argc, char **argv) BUILD_BUG_ON(offsetof(struct nbd_header_t, data) != 8+8+8+4); // Parse command line stuff (just a stub now) - if (argc != 4) + if (!argv[1] || !argv[2] || !argv[3] || argv[4]) bb_show_usage(); #if !BB_MMU -- cgit v1.2.3-55-g6feb From 7b8372b81926ef6aa8d91945a95261bbb93d0b9e Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Mon, 7 Aug 2017 00:28:15 +0200 Subject: add/remove-shell,add/deluser,add/delgroup: make them NOEXEC Signed-off-by: Denys Vlasenko --- NOFORK_NOEXEC.lst | 12 ++++++------ loginutils/add-remove-shell.c | 7 ++++--- loginutils/addgroup.c | 2 +- loginutils/adduser.c | 2 +- loginutils/deluser.c | 5 +++-- 5 files changed, 15 insertions(+), 13 deletions(-) diff --git a/NOFORK_NOEXEC.lst b/NOFORK_NOEXEC.lst index 9c8df23ab..ac04f75da 100644 --- a/NOFORK_NOEXEC.lst +++ b/NOFORK_NOEXEC.lst @@ -36,9 +36,9 @@ IOW: rm is "interactive", but not "longterm". [ - NOFORK [[ - NOFORK acpid - daemon -add-shell -addgroup -adduser +add-shell - noexec. leaks: open+xfunc +addgroup - noexec. leaks +adduser - noexec. leaks adjtimex - NOFORK ar - runner arch - NOFORK @@ -86,8 +86,8 @@ date - noexec. nofork candidate(needs to stop messing up env, free xasprintf res dc - runner (eats stdin if no params) dd - noexec. runner deallocvt - noexec. leaks: get_console_fd_or_die() may open a new fd, or return one of stdio fds -delgroup -deluser +delgroup - noexec. leaks +deluser - noexec. leaks depmod - complex, rare devmem - runner, complex (access to device memory may hang) df - leaks: nested allocs @@ -282,7 +282,7 @@ readprofile - reads /boot/System.map and /proc/profile, better to free more memo realpath - NOFORK reboot - rare reformime - runner -remove-shell +remove-shell - noexec. leaks: open+xfunc renice - nofork candidate(uses getpwnam, is that ok?) reset - noexec. spawner (execs "stty") resize - noexec. changes state (signal handlers) diff --git a/loginutils/add-remove-shell.c b/loginutils/add-remove-shell.c index 750b44bd6..6d03de254 100644 --- a/loginutils/add-remove-shell.c +++ b/loginutils/add-remove-shell.c @@ -19,9 +19,9 @@ //config: help //config: Remove shells from /etc/shells. -// APPLET_ODDNAME:name main location suid_type help -//applet:IF_ADD_SHELL( APPLET_ODDNAME(add-shell , add_remove_shell, BB_DIR_USR_SBIN, BB_SUID_DROP, add_shell )) -//applet:IF_REMOVE_SHELL(APPLET_ODDNAME(remove-shell, add_remove_shell, BB_DIR_USR_SBIN, BB_SUID_DROP, remove_shell)) +// APPLET_NOEXEC:name main location suid_type help +//applet:IF_ADD_SHELL( APPLET_NOEXEC(add-shell , add_remove_shell, BB_DIR_USR_SBIN, BB_SUID_DROP, add_shell )) +//applet:IF_REMOVE_SHELL(APPLET_NOEXEC(remove-shell, add_remove_shell, BB_DIR_USR_SBIN, BB_SUID_DROP, remove_shell)) //kbuild:lib-$(CONFIG_ADD_SHELL) += add-remove-shell.o //kbuild:lib-$(CONFIG_REMOVE_SHELL) += add-remove-shell.o @@ -64,6 +64,7 @@ int add_remove_shell_main(int argc UNUSED_PARAM, char **argv) if (orig_fp) xfstat(fileno(orig_fp), &sb, orig_fn); + new_fn = xasprintf("%s.tmp", orig_fn); /* * O_TRUNC or O_EXCL? At the first glance, O_EXCL looks better, diff --git a/loginutils/addgroup.c b/loginutils/addgroup.c index b197fc149..30f7e72dc 100644 --- a/loginutils/addgroup.c +++ b/loginutils/addgroup.c @@ -29,7 +29,7 @@ //config: addgroup will add an existing user to an //config: existing group. -//applet:IF_ADDGROUP(APPLET(addgroup, BB_DIR_USR_SBIN, BB_SUID_DROP)) +//applet:IF_ADDGROUP(APPLET_NOEXEC(addgroup, addgroup, BB_DIR_USR_SBIN, BB_SUID_DROP, addgroup)) //kbuild:lib-$(CONFIG_ADDGROUP) += addgroup.o diff --git a/loginutils/adduser.c b/loginutils/adduser.c index ef18278ac..913dbaf83 100644 --- a/loginutils/adduser.c +++ b/loginutils/adduser.c @@ -53,7 +53,7 @@ //config: help //config: Last valid system uid or gid for adduser and addgroup -//applet:IF_ADDUSER(APPLET(adduser, BB_DIR_USR_SBIN, BB_SUID_DROP)) +//applet:IF_ADDUSER(APPLET_NOEXEC(adduser, adduser, BB_DIR_USR_SBIN, BB_SUID_DROP, adduser)) //kbuild:lib-$(CONFIG_ADDUSER) += adduser.o diff --git a/loginutils/deluser.c b/loginutils/deluser.c index 3b6bd952d..f5bc3c28a 100644 --- a/loginutils/deluser.c +++ b/loginutils/deluser.c @@ -28,8 +28,9 @@ //config: If called with two non-option arguments, deluser //config: or delgroup will remove an user from a specified group. -//applet:IF_DELUSER(APPLET(deluser, BB_DIR_USR_SBIN, BB_SUID_DROP)) -//applet:IF_DELGROUP(APPLET_ODDNAME(delgroup, deluser, BB_DIR_USR_SBIN, BB_SUID_DROP, delgroup)) +// APPLET_NOEXEC:name main location suid_type help +//applet:IF_DELUSER( APPLET_NOEXEC(deluser, deluser, BB_DIR_USR_SBIN, BB_SUID_DROP, deluser)) +//applet:IF_DELGROUP(APPLET_NOEXEC(delgroup, deluser, BB_DIR_USR_SBIN, BB_SUID_DROP, delgroup)) //kbuild:lib-$(CONFIG_DELUSER) += deluser.o //kbuild:lib-$(CONFIG_DELGROUP) += deluser.o -- cgit v1.2.3-55-g6feb From dd55d5d53c394edb65d392f77087049540568997 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Mon, 7 Aug 2017 01:53:17 +0200 Subject: script: make -t independent of scriptreplay Signed-off-by: Denys Vlasenko --- NOFORK_NOEXEC.lst | 4 ++-- util-linux/script.c | 22 +++++++++++++++------- util-linux/scriptreplay.c | 3 +-- 3 files changed, 18 insertions(+), 11 deletions(-) diff --git a/NOFORK_NOEXEC.lst b/NOFORK_NOEXEC.lst index ac04f75da..21f09728d 100644 --- a/NOFORK_NOEXEC.lst +++ b/NOFORK_NOEXEC.lst @@ -299,8 +299,8 @@ runlevel - noexec. can be nofork if "endutxent()" is called unconditionally, but runsv - daemon runsvdir - daemon rx - runner -script -scriptreplay +script - longterm: pumps script output from slave pty +scriptreplay - longterm: plays back "script" saved output, sleeping as necessary. sed - runner sendmail - runner seq - noexec. runner diff --git a/util-linux/script.c b/util-linux/script.c index 9eebb51a4..6e8094312 100644 --- a/util-linux/script.c +++ b/util-linux/script.c @@ -21,15 +21,23 @@ //kbuild:lib-$(CONFIG_SCRIPT) += script.o //usage:#define script_trivial_usage -//usage: "[-afq" IF_SCRIPTREPLAY("t") "] [-c PROG] [OUTFILE]" +//usage: "[-afqt] [-c PROG] [OUTFILE]" //usage:#define script_full_usage "\n\n" //usage: " -a Append output" //usage: "\n -c PROG Run PROG, not shell" //usage: "\n -f Flush output after each write" //usage: "\n -q Quiet" -//usage: IF_SCRIPTREPLAY( //usage: "\n -t Send timing to stderr" -//usage: ) + +//util-linux-2.28: +//-t[FILE] +//-e: return exit code of the child + +//FYI (reported as bbox bug #2749): +// > script -q -c 'echo -e -n "1\n2\n3\n"' /dev/null 123.txt +// > The output file on full-blown ubuntu system contains 6 bytes. +// > Output on Busybox system (arm-linux) contains extra '\r' byte in each line. +//however, in my test, "script" from util-linux-2.28 seems to also add '\r' bytes. #include "libbb.h" #include "common_bufsiz.h" @@ -64,14 +72,14 @@ int script_main(int argc UNUSED_PARAM, char **argv) "command\0" Required_argument "c" "flush\0" No_argument "f" "quiet\0" No_argument "q" - IF_SCRIPTREPLAY("timing\0" No_argument "t") + "timing\0" No_argument "t" ; applet_long_options = getopt_longopts; #endif opt_complementary = "?1"; /* max one arg */ - opt = getopt32(argv, "ac:fq" IF_SCRIPTREPLAY("t") , &shell_arg); + opt = getopt32(argv, "ac:fqt", &shell_arg); //argc -= optind; argv += optind; if (argv[0]) { @@ -120,7 +128,7 @@ int script_main(int argc UNUSED_PARAM, char **argv) /* parent */ struct pollfd pfd[2]; int outfd, count, loop; - double oldtime = ENABLE_SCRIPTREPLAY ? time(NULL) : 0; + double oldtime = time(NULL); smallint fd_count = 2; #define buf bb_common_bufsiz1 setup_common_bufsiz(); @@ -151,7 +159,7 @@ int script_main(int argc UNUSED_PARAM, char **argv) goto restore; } if (count > 0) { - if (ENABLE_SCRIPTREPLAY && (opt & OPT_t)) { + if (opt & OPT_t) { struct timeval tv; double newtime; diff --git a/util-linux/scriptreplay.c b/util-linux/scriptreplay.c index 7e9850103..e3083ab93 100644 --- a/util-linux/scriptreplay.c +++ b/util-linux/scriptreplay.c @@ -5,7 +5,6 @@ * pascal.bellard@ads-lu.com * * Licensed under GPLv2 or later, see file LICENSE in this source tree. - * */ //config:config SCRIPTREPLAY //config: bool "scriptreplay (2.6 kb)" @@ -19,7 +18,7 @@ //kbuild:lib-$(CONFIG_SCRIPTREPLAY) += scriptreplay.o //usage:#define scriptreplay_trivial_usage -//usage: "timingfile [typescript [divisor]]" +//usage: "TIMINGFILE [TYPESCRIPT [DIVISOR]]" //usage:#define scriptreplay_full_usage "\n\n" //usage: "Play back typescripts, using timing information" -- cgit v1.2.3-55-g6feb From 269b36a49a60a90ce59dd6209728ec97fd72077e Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Mon, 7 Aug 2017 02:12:36 +0200 Subject: script: make -t[FILE] compatible with util-linux function old new delta script_main 1056 1102 +46 packed_usage 31736 31765 +29 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 2/0 up/down: 75/0) Total: 75 bytes Signed-off-by: Denys Vlasenko --- editors/sed.c | 4 ++-- util-linux/script.c | 22 +++++++++++++++------- 2 files changed, 17 insertions(+), 9 deletions(-) diff --git a/editors/sed.c b/editors/sed.c index bec20040a..22580cf71 100644 --- a/editors/sed.c +++ b/editors/sed.c @@ -68,8 +68,8 @@ //applet:IF_SED(APPLET(sed, BB_DIR_BIN, BB_SUID_DROP)) //usage:#define sed_trivial_usage -//usage: "[-inrE] [-f FILE]... [-e CMD]... [FILE]...\n" -//usage: "or: sed [-inrE] CMD [FILE]..." +//usage: "[-i[SFX]] [-nrE] [-f FILE]... [-e CMD]... [FILE]...\n" +//usage: "or: sed [-i[SFX]] [-nrE] CMD [FILE]..." //usage:#define sed_full_usage "\n\n" //usage: " -e CMD Add CMD to sed commands to be executed" //usage: "\n -f FILE Add FILE contents to sed commands to be executed" diff --git a/util-linux/script.c b/util-linux/script.c index 6e8094312..62a241762 100644 --- a/util-linux/script.c +++ b/util-linux/script.c @@ -21,16 +21,17 @@ //kbuild:lib-$(CONFIG_SCRIPT) += script.o //usage:#define script_trivial_usage -//usage: "[-afqt] [-c PROG] [OUTFILE]" +//usage: "[-afq] [-t[FILE]] [-c PROG] [OUTFILE]" //usage:#define script_full_usage "\n\n" -//usage: " -a Append output" +//usage: "Default OUTFILE is 'typescript'" +//usage: "\n" +//usage: "\n -a Append output" //usage: "\n -c PROG Run PROG, not shell" //usage: "\n -f Flush output after each write" //usage: "\n -q Quiet" -//usage: "\n -t Send timing to stderr" +//usage: "\n -t[FILE] Send timing to stderr or FILE" //util-linux-2.28: -//-t[FILE] //-e: return exit code of the child //FYI (reported as bbox bug #2749): @@ -54,6 +55,8 @@ int script_main(int argc UNUSED_PARAM, char **argv) char pty_line[GETPTY_BUFSIZE]; struct termios tt, rtt; struct winsize win; + FILE *timing_fp; + const char *str_t = NULL; const char *fname = "typescript"; const char *shell; char shell_opt[] = "-i"; @@ -72,14 +75,14 @@ int script_main(int argc UNUSED_PARAM, char **argv) "command\0" Required_argument "c" "flush\0" No_argument "f" "quiet\0" No_argument "q" - "timing\0" No_argument "t" + "timing\0" Optional_argument "t" ; applet_long_options = getopt_longopts; #endif opt_complementary = "?1"; /* max one arg */ - opt = getopt32(argv, "ac:fqt", &shell_arg); + opt = getopt32(argv, "ac:fqt::", &shell_arg, &str_t); //argc -= optind; argv += optind; if (argv[0]) { @@ -95,6 +98,10 @@ int script_main(int argc UNUSED_PARAM, char **argv) if (!(opt & OPT_q)) { printf("Script started, file is %s\n", fname); } + timing_fp = stderr; + if (str_t) { + timing_fp = xfopen_for_write(str_t); + } shell = get_shell_name(); @@ -130,6 +137,7 @@ int script_main(int argc UNUSED_PARAM, char **argv) int outfd, count, loop; double oldtime = time(NULL); smallint fd_count = 2; + #define buf bb_common_bufsiz1 setup_common_bufsiz(); @@ -165,7 +173,7 @@ int script_main(int argc UNUSED_PARAM, char **argv) gettimeofday(&tv, NULL); newtime = tv.tv_sec + (double) tv.tv_usec / 1000000; - fprintf(stderr, "%f %u\n", newtime - oldtime, count); + fprintf(timing_fp, "%f %u\n", newtime - oldtime, count); oldtime = newtime; } full_write(STDOUT_FILENO, buf, count); -- cgit v1.2.3-55-g6feb From 4dea1edd08a45c5987448719e56ee61a20fb9210 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Mon, 7 Aug 2017 02:21:34 +0200 Subject: script: -f means "flush", not "fsync" function old new delta packed_usage 31765 31768 +3 script_main 1102 1082 -20 Signed-off-by: Denys Vlasenko --- util-linux/script.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/util-linux/script.c b/util-linux/script.c index 62a241762..89b439163 100644 --- a/util-linux/script.c +++ b/util-linux/script.c @@ -27,7 +27,8 @@ //usage: "\n" //usage: "\n -a Append output" //usage: "\n -c PROG Run PROG, not shell" -//usage: "\n -f Flush output after each write" +/* Accepted but has no effect (we never buffer output) */ +/*//usage: "\n -f Flush output after each write"*/ //usage: "\n -q Quiet" //usage: "\n -t[FILE] Send timing to stderr or FILE" @@ -178,9 +179,10 @@ int script_main(int argc UNUSED_PARAM, char **argv) } full_write(STDOUT_FILENO, buf, count); full_write(outfd, buf, count); - if (opt & OPT_f) { - fsync(outfd); - } + // If we'd be using (buffered) FILE i/o, we'd need this: + //if (opt & OPT_f) { + // fflush(outfd); + //} } } if (pfd[1].revents) { -- cgit v1.2.3-55-g6feb From 115e0a719950f8f716f73d5e36e9483df9dbbf1e Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Mon, 7 Aug 2017 02:55:33 +0200 Subject: ubi_tools: a bit smaller applet resolution code function old new delta ubi_tools_main 1241 1235 -6 Signed-off-by: Denys Vlasenko --- NOFORK_NOEXEC.lst | 1 - miscutils/ubi_tools.c | 21 +++++++++++++++------ 2 files changed, 15 insertions(+), 7 deletions(-) diff --git a/NOFORK_NOEXEC.lst b/NOFORK_NOEXEC.lst index 21f09728d..d54c206fe 100644 --- a/NOFORK_NOEXEC.lst +++ b/NOFORK_NOEXEC.lst @@ -55,7 +55,6 @@ blockdev - noexec. leaks fd bootchartd - daemon brctl - noexec bunzip2 - runner -busybox bzcat - runner bzip2 - runner cal - runner: cal -n9999 diff --git a/miscutils/ubi_tools.c b/miscutils/ubi_tools.c index c6ba22adf..d9b76b69c 100644 --- a/miscutils/ubi_tools.c +++ b/miscutils/ubi_tools.c @@ -67,12 +67,21 @@ #endif #include -#define do_attach (ENABLE_UBIATTACH && applet_name[3] == 'a') -#define do_detach (ENABLE_UBIDETACH && applet_name[3] == 'd') -#define do_mkvol (ENABLE_UBIMKVOL && applet_name[3] == 'm') -#define do_rmvol (ENABLE_UBIRMVOL && applet_name[4] == 'm') -#define do_rsvol (ENABLE_UBIRSVOL && applet_name[4] == 's') -#define do_update (ENABLE_UBIUPDATEVOL && applet_name[3] == 'u') +#define UBI_APPLET_CNT (0 \ + + ENABLE_UBIATTACH \ + + ENABLE_UBIDETACH \ + + ENABLE_UBIMKVOL \ + + ENABLE_UBIRMVOL \ + + ENABLE_UBIRSVOL \ + + ENABLE_UBIUPDATEVOL \ + ) + +#define do_attach (ENABLE_UBIATTACH && (UBI_APPLET_CNT == 1 || applet_name[4] == 't')) +#define do_detach (ENABLE_UBIDETACH && (UBI_APPLET_CNT == 1 || applet_name[4] == 'e')) +#define do_mkvol (ENABLE_UBIMKVOL && (UBI_APPLET_CNT == 1 || applet_name[4] == 'k')) +#define do_rmvol (ENABLE_UBIRMVOL && (UBI_APPLET_CNT == 1 || applet_name[4] == 'm')) +#define do_rsvol (ENABLE_UBIRSVOL && (UBI_APPLET_CNT == 1 || applet_name[4] == 's')) +#define do_update (ENABLE_UBIUPDATEVOL && (UBI_APPLET_CNT == 1 || applet_name[4] == 'p')) static unsigned get_num_from_file(const char *path, unsigned max, const char *errmsg) { -- cgit v1.2.3-55-g6feb From b34eb4a591fa4dbbc091524a1c1159e2743134c8 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Mon, 7 Aug 2017 03:24:29 +0200 Subject: ubiupdatevol: fix bug with -sSIZE: was ignoring IMAGE_FILE While at it, fix help text Signed-off-by: Denys Vlasenko --- miscutils/ubi_tools.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/miscutils/ubi_tools.c b/miscutils/ubi_tools.c index d9b76b69c..494718ccf 100644 --- a/miscutils/ubi_tools.c +++ b/miscutils/ubi_tools.c @@ -298,7 +298,7 @@ int ubi_tools_main(int argc UNUSED_PARAM, char **argv) } else //usage:#define ubiupdatevol_trivial_usage -//usage: "[-t | [-s SIZE] IMG_FILE] UBI_DEVICE" +//usage: "-t UBI_DEVICE | [-s SIZE] UBI_DEVICE IMG_FILE" //usage:#define ubiupdatevol_full_usage "\n\n" //usage: "Update UBI volume\n" //usage: "\n -t Truncate to zero size" @@ -313,7 +313,6 @@ int ubi_tools_main(int argc UNUSED_PARAM, char **argv) xioctl(fd, UBI_IOCVOLUP, &bytes64); } else { - struct stat st; unsigned ubinum, volnum; unsigned leb_size; ssize_t len; @@ -327,12 +326,15 @@ int ubi_tools_main(int argc UNUSED_PARAM, char **argv) sprintf(path_sys_class_ubi_ubi, "%u_%u/usable_eb_size", ubinum, volnum); leb_size = get_num_from_file(path, MAX_SANE_ERASEBLOCK, "Can't get usable eraseblock size from '%s'"); - if (!(opts & OPTION_s)) { + if (!(opts & OPTION_t)) { if (!*argv) bb_show_usage(); xmove_fd(xopen(*argv, O_RDONLY), STDIN_FILENO); - xfstat(STDIN_FILENO, &st, *argv); - size_bytes = st.st_size; + if (!(opts & OPTION_s)) { + struct stat st; + xfstat(STDIN_FILENO, &st, *argv); + size_bytes = st.st_size; + } } bytes64 = size_bytes; -- cgit v1.2.3-55-g6feb From 798b94518e61ced3f7be7766727705df4859878c Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Mon, 7 Aug 2017 16:00:25 +0200 Subject: ubi tools: ubiupdatevol supports "-" input and actually respects -s SIZE Decided to not make any flash applets NOEXEC. Minor robustifications here and there. Better error messages. Save on strings: function old new delta ubi_tools_main 1235 1288 +53 ubi_get_volid_by_name 125 133 +8 ubirename_main 198 204 +6 get_num_from_file 90 94 +4 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 4/0 up/down: 71/0) Total: 71 bytes text data bss dec hex filename 915696 485 6880 923061 e15b5 busybox_old 915670 485 6880 923035 e159b busybox_unstripped Signed-off-by: Denys Vlasenko --- NOFORK_NOEXEC.lst | 22 +++++++-------- libbb/ubi.c | 1 + miscutils/flash_eraseall.c | 1 + miscutils/flash_lock_unlock.c | 1 + miscutils/flashcp.c | 1 + miscutils/ubi_tools.c | 63 ++++++++++++++++++++++++++----------------- miscutils/ubirename.c | 6 ++++- 7 files changed, 59 insertions(+), 36 deletions(-) diff --git a/NOFORK_NOEXEC.lst b/NOFORK_NOEXEC.lst index d54c206fe..981a10192 100644 --- a/NOFORK_NOEXEC.lst +++ b/NOFORK_NOEXEC.lst @@ -123,10 +123,10 @@ fgconsole - noexec. leaks: get_console_fd_or_die() may open a new fd, or return fgrep - longterm runner ("CMD | fgrep ..." may run indefinitely, better to exec to conserve memory) find - noexec. runner findfs - suid -flash_eraseall -flash_lock -flash_unlock -flashcp - needs ^C. flash writing may be slow, better to free memory by execing +flash_eraseall - could be noexec, but I feel flash ops are risky (prone to hw/fw/sw bugs) +flash_lock - could be noexec, but I feel flash ops are risky (prone to hw/fw/sw bugs) +flash_unlock - could be noexec, but I feel flash ops are risky (prone to hw/fw/sw bugs) +flashcp - needs ^C. could be noexec, but I feel flash ops are risky (prone to hw/fw/sw bugs) flock - spawner, changes state (file locks), let's play safe and not be noexec fold - noexec. runner free - nofork candidate(struct globals, needs to close /proc/meminfo fd) @@ -366,13 +366,13 @@ tty - NOFORK ttysize - NOFORK tunctl - noexec tune2fs - noexec. leaks: open+xfunc -ubiattach -ubidetach -ubimkvol -ubirename -ubirmvol -ubirsvol -ubiupdatevol +ubiattach - could be noexec, but I feel flash ops are risky (prone to hw/fw/sw bugs) +ubidetach - could be noexec, but I feel flash ops are risky (prone to hw/fw/sw bugs) +ubimkvol - could be noexec, but I feel flash ops are risky (prone to hw/fw/sw bugs) +ubirename - could be noexec, but I feel flash ops are risky (prone to hw/fw/sw bugs) +ubirmvol - could be noexec, but I feel flash ops are risky (prone to hw/fw/sw bugs) +ubirsvol - could be noexec, but I feel flash ops are risky (prone to hw/fw/sw bugs) +ubiupdatevol - could be noexec, but I feel flash ops are risky (prone to hw/fw/sw bugs) udhcpc - daemon udhcpd - daemon udpsvd - daemon diff --git a/libbb/ubi.c b/libbb/ubi.c index 34595d797..a90016acf 100644 --- a/libbb/ubi.c +++ b/libbb/ubi.c @@ -35,6 +35,7 @@ int FAST_FUNC ubi_get_volid_by_name(unsigned ubi_devnum, const char *vol_name) if (open_read_close(fname, buf, sizeof(buf)) <= 0) continue; + buf[UBI_MAX_VOLUME_NAME] = '\0'; strchrnul(buf, '\n')[0] = '\0'; if (strcmp(vol_name, buf) == 0) return i; diff --git a/miscutils/flash_eraseall.c b/miscutils/flash_eraseall.c index af9ebea24..3ddd9dd99 100644 --- a/miscutils/flash_eraseall.c +++ b/miscutils/flash_eraseall.c @@ -17,6 +17,7 @@ //config: This utility is used to erase the whole MTD device. //applet:IF_FLASH_ERASEALL(APPLET(flash_eraseall, BB_DIR_USR_SBIN, BB_SUID_DROP)) +/* not NOEXEC: if flash operation stalls, use less memory in "hung" process */ //kbuild:lib-$(CONFIG_FLASH_ERASEALL) += flash_eraseall.o diff --git a/miscutils/flash_lock_unlock.c b/miscutils/flash_lock_unlock.c index 374eed5f6..6f2c049f4 100644 --- a/miscutils/flash_lock_unlock.c +++ b/miscutils/flash_lock_unlock.c @@ -20,6 +20,7 @@ // APPLET_ODDNAME:name main location suid_type help //applet:IF_FLASH_LOCK( APPLET_ODDNAME(flash_lock, flash_lock_unlock, BB_DIR_USR_SBIN, BB_SUID_DROP, flash_lock)) //applet:IF_FLASH_UNLOCK(APPLET_ODDNAME(flash_unlock, flash_lock_unlock, BB_DIR_USR_SBIN, BB_SUID_DROP, flash_unlock)) +/* not NOEXEC: if flash operation stalls, use less memory in "hung" process */ //kbuild:lib-$(CONFIG_FLASH_LOCK) += flash_lock_unlock.o //kbuild:lib-$(CONFIG_FLASH_UNLOCK) += flash_lock_unlock.o diff --git a/miscutils/flashcp.c b/miscutils/flashcp.c index d4ac62df4..c10b96ee8 100644 --- a/miscutils/flashcp.c +++ b/miscutils/flashcp.c @@ -14,6 +14,7 @@ //config: This utility is used to copy images into a MTD device. //applet:IF_FLASHCP(APPLET(flashcp, BB_DIR_USR_SBIN, BB_SUID_DROP)) +/* not NOEXEC: if flash operation stalls, use less memory in "hung" process */ //kbuild:lib-$(CONFIG_FLASHCP) += flashcp.o diff --git a/miscutils/ubi_tools.c b/miscutils/ubi_tools.c index 494718ccf..123551e94 100644 --- a/miscutils/ubi_tools.c +++ b/miscutils/ubi_tools.c @@ -52,6 +52,7 @@ //applet:IF_UBIRMVOL( APPLET_ODDNAME(ubirmvol, ubi_tools, BB_DIR_USR_SBIN, BB_SUID_DROP, ubirmvol)) //applet:IF_UBIRSVOL( APPLET_ODDNAME(ubirsvol, ubi_tools, BB_DIR_USR_SBIN, BB_SUID_DROP, ubirsvol)) //applet:IF_UBIUPDATEVOL(APPLET_ODDNAME(ubiupdatevol, ubi_tools, BB_DIR_USR_SBIN, BB_SUID_DROP, ubiupdatevol)) +/* not NOEXEC: if flash operation stalls, use less memory in "hung" process */ //kbuild:lib-$(CONFIG_UBIATTACH) += ubi_tools.o //kbuild:lib-$(CONFIG_UBIDETACH) += ubi_tools.o @@ -83,16 +84,16 @@ #define do_rsvol (ENABLE_UBIRSVOL && (UBI_APPLET_CNT == 1 || applet_name[4] == 's')) #define do_update (ENABLE_UBIUPDATEVOL && (UBI_APPLET_CNT == 1 || applet_name[4] == 'p')) -static unsigned get_num_from_file(const char *path, unsigned max, const char *errmsg) +static unsigned get_num_from_file(const char *path, unsigned max) { char buf[sizeof(long long)*3]; unsigned long long num; if (open_read_close(path, buf, sizeof(buf)) < 0) - bb_perror_msg_and_die(errmsg, path); + bb_perror_msg_and_die("can't open '%s'", path); /* It can be \n terminated, xatoull won't work well */ if (sscanf(buf, "%llu", &num) != 1 || num > max) - bb_error_msg_and_die(errmsg, path); + bb_error_msg_and_die("number in '%s' is malformed or too large", path); return num; } @@ -226,10 +227,10 @@ int ubi_tools_main(int argc UNUSED_PARAM, char **argv) p = path_sys_class_ubi_ubi + sprintf(path_sys_class_ubi_ubi, "%u/", num); strcpy(p, "avail_eraseblocks"); - leb_avail = get_num_from_file(path, UINT_MAX, "Can't get available eraseblocks from '%s'"); + leb_avail = get_num_from_file(path, UINT_MAX); strcpy(p, "eraseblock_size"); - leb_size = get_num_from_file(path, MAX_SANE_ERASEBLOCK, "Can't get eraseblock size from '%s'"); + leb_size = get_num_from_file(path, MAX_SANE_ERASEBLOCK); size_bytes = leb_avail * (unsigned long long)leb_size; //if (size_bytes <= 0) @@ -241,16 +242,19 @@ int ubi_tools_main(int argc UNUSED_PARAM, char **argv) if (!(opts & OPTION_N)) bb_error_msg_and_die("name not specified"); + /* the structure is memset(0) above */ mkvol_req.vol_id = vol_id; mkvol_req.vol_type = UBI_DYNAMIC_VOLUME; if ((opts & OPTION_t) && type[0] == 's') mkvol_req.vol_type = UBI_STATIC_VOLUME; mkvol_req.alignment = alignment; mkvol_req.bytes = size_bytes; /* signed int64_t */ - strncpy(mkvol_req.name, vol_name, UBI_MAX_VOLUME_NAME); - mkvol_req.name_len = strlen(vol_name); + /* strnlen avoids overflow of 16-bit field (paranoia) */ + mkvol_req.name_len = strnlen(vol_name, UBI_MAX_VOLUME_NAME+1); if (mkvol_req.name_len > UBI_MAX_VOLUME_NAME) bb_error_msg_and_die("volume name too long: '%s'", vol_name); + /* this is safe: .name[] is UBI_MAX_VOLUME_NAME+1 bytes */ + strcpy(mkvol_req.name, vol_name); xioctl(fd, UBI_IOCMKVOL, &mkvol_req); } else @@ -315,38 +319,49 @@ int ubi_tools_main(int argc UNUSED_PARAM, char **argv) else { unsigned ubinum, volnum; unsigned leb_size; - ssize_t len; - char *input_data; + char *buf; /* Assume that device is in normal format. */ /* Removes need for scanning sysfs tree as full libubi does. */ if (sscanf(ubi_ctrl, "/dev/ubi%u_%u", &ubinum, &volnum) != 2) - bb_error_msg_and_die("wrong format of UBI device name"); + bb_error_msg_and_die("UBI device name '%s' is not /dev/ubiN_M", ubi_ctrl); sprintf(path_sys_class_ubi_ubi, "%u_%u/usable_eb_size", ubinum, volnum); - leb_size = get_num_from_file(path, MAX_SANE_ERASEBLOCK, "Can't get usable eraseblock size from '%s'"); + leb_size = get_num_from_file(path, MAX_SANE_ERASEBLOCK); - if (!(opts & OPTION_t)) { - if (!*argv) - bb_show_usage(); + if (!*argv) + bb_show_usage(); + if (NOT_LONE_DASH(*argv)) /* mtd-utils supports "-" as stdin */ xmove_fd(xopen(*argv, O_RDONLY), STDIN_FILENO); - if (!(opts & OPTION_s)) { - struct stat st; - xfstat(STDIN_FILENO, &st, *argv); - size_bytes = st.st_size; - } + + if (!(opts & OPTION_s)) { + struct stat st; + xfstat(STDIN_FILENO, &st, *argv); + size_bytes = st.st_size; } bytes64 = size_bytes; /* this ioctl expects signed int64_t* parameter */ xioctl(fd, UBI_IOCVOLUP, &bytes64); - input_data = xmalloc(leb_size); - while ((len = full_read(STDIN_FILENO, input_data, leb_size)) > 0) { - xwrite(fd, input_data, len); + /* can't use bb_copyfd_exact_size(): copy in blocks of exactly leb_size */ + buf = xmalloc(leb_size); + while (size_bytes != 0) { + int len = full_read(STDIN_FILENO, buf, leb_size); + if (len <= 0) { + if (len < 0) + bb_perror_msg_and_die("read error from '%s'", *argv); + break; + } + if ((unsigned)len > size_bytes) { + /* for this case: "ubiupdatevol -s 1024000 $UBIDEV /dev/urandom" */ + len = size_bytes; + } + xwrite(fd, buf, len); + size_bytes -= len; } - if (len < 0) - bb_perror_msg_and_die("UBI volume update failed"); + if (ENABLE_FEATURE_CLEAN_UP) + free(buf); } } diff --git a/miscutils/ubirename.c b/miscutils/ubirename.c index 786c4b9fa..ecc8fe137 100644 --- a/miscutils/ubirename.c +++ b/miscutils/ubirename.c @@ -14,6 +14,7 @@ //config: Utility to rename UBI volumes //applet:IF_UBIRENAME(APPLET(ubirename, BB_DIR_USR_SBIN, BB_SUID_DROP)) +/* not NOEXEC: if flash operation stalls, use less memory in "hung" process */ //kbuild:lib-$(CONFIG_UBIRENAME) += ubirename.o @@ -80,9 +81,12 @@ int ubirename_main(int argc, char **argv) argv += 2; while (argv[0]) { rnvol->ents[n].vol_id = ubi_get_volid_by_name(ubi_devnum, argv[0]); - rnvol->ents[n].name_len = strlen(argv[1]); + + /* strnlen avoids overflow of 16-bit field (paranoia) */ + rnvol->ents[n].name_len = strnlen(argv[1], sizeof(rnvol->ents[n].name)); if (rnvol->ents[n].name_len >= sizeof(rnvol->ents[n].name)) bb_error_msg_and_die("new name '%s' is too long", argv[1]); + strcpy(rnvol->ents[n].name, argv[1]); n++; argv += 2; -- cgit v1.2.3-55-g6feb From 1a1203ff8909efc003bb6bf679a6afd6628dc179 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Mon, 7 Aug 2017 16:47:34 +0200 Subject: users,w,who,uptime,renice: make NOEXEC Signed-off-by: Denys Vlasenko --- NOFORK_NOEXEC.lst | 72 ++++++++++++++++++++++++++------------------------- coreutils/who.c | 8 +++--- miscutils/i2c_tools.c | 1 + procps/uptime.c | 2 +- util-linux/renice.c | 2 +- 5 files changed, 44 insertions(+), 41 deletions(-) diff --git a/NOFORK_NOEXEC.lst b/NOFORK_NOEXEC.lst index 981a10192..70f38d867 100644 --- a/NOFORK_NOEXEC.lst +++ b/NOFORK_NOEXEC.lst @@ -4,9 +4,9 @@ Why can't be NOFORK: interactive: may wait for user input, ^C has to work spawner: "tool PROG ARGS" which changes program state and execs - must fork changes state: e.g. environment, signal handlers -alloc+xfunc: xmalloc, then xfunc - leaks memory if xfunc dies -open+xfunc: opens fd, then calls xfunc - fd is leaked if xfunc dies leaks: does not free allocated memory or opened fds + alloc+xfunc: xmalloc, then xfunc - leaks memory if xfunc dies + open+xfunc: opens fd, then calls xfunc - fd is leaked if xfunc dies runner: sometimes may run for long(ish) time, and/or works with network: ^C has to work (cat BIGFILE, chmod -R, ftpget, nc) @@ -25,6 +25,8 @@ longterm: often runs for a long time (many seconds), execing makes complex: no immediately obvious reason why NOFORK wouldn't work, but does some non-obvoius operations (example: fuser, lsof, losetup); detailed audit often turns out that it's a leaker +hardware: performs unusual hardware ops which may take long, + or even hang due to hardware or firmware bugs Interesting example of "interactive" applet which is nevertheless can be (and is) NOEXEC is "rm". Yes, "rm -i" is interactive - but it's not that typical @@ -42,8 +44,8 @@ adduser - noexec. leaks adjtimex - NOFORK ar - runner arch - NOFORK -arp - complex, rare -arping - runner +arp - runner, needs ^C: arp -n talks to DNS servers +arping - longterm ash - interactive, longterm awk - noexec. runner base64 - runner @@ -87,7 +89,7 @@ dd - noexec. runner deallocvt - noexec. leaks: get_console_fd_or_die() may open a new fd, or return one of stdio fds delgroup - noexec. leaks deluser - noexec. leaks -depmod - complex, rare +depmod - longterm(ish) devmem - runner, complex (access to device memory may hang) df - leaks: nested allocs dhcprelay - daemon @@ -114,19 +116,19 @@ factor - runner (eats stdin if no params) fakeidentd - daemon false - NOFORK fatattr - leaks: open+xioctl, complex -fbset - leaks: open+xfunc, complex, rare +fbset - hardware, leaks: open+xfunc fbsplash - runner, longterm -fdflush - leaks: open+ioctl_or_perror_and_die, needs ^C (floppy may be unresponsive), rare -fdformat - needs ^C (floppy may be unresponsive), longterm, rare +fdflush - hardware, leaks: open+ioctl_or_perror_and_die +fdformat - hardware, needs ^C (floppy may be unresponsive), longterm fdisk - interactive, longterm fgconsole - noexec. leaks: get_console_fd_or_die() may open a new fd, or return one of stdio fds fgrep - longterm runner ("CMD | fgrep ..." may run indefinitely, better to exec to conserve memory) find - noexec. runner findfs - suid -flash_eraseall - could be noexec, but I feel flash ops are risky (prone to hw/fw/sw bugs) -flash_lock - could be noexec, but I feel flash ops are risky (prone to hw/fw/sw bugs) -flash_unlock - could be noexec, but I feel flash ops are risky (prone to hw/fw/sw bugs) -flashcp - needs ^C. could be noexec, but I feel flash ops are risky (prone to hw/fw/sw bugs) +flash_eraseall - hardware +flash_lock - hardware +flash_unlock - hardware +flashcp - hardware flock - spawner, changes state (file locks), let's play safe and not be noexec fold - noexec. runner free - nofork candidate(struct globals, needs to close /proc/meminfo fd) @@ -148,18 +150,18 @@ gunzip - runner gzip - runner halt - rare hd - noexec. runner -hdparm - complex, rare +hdparm - hardware head - noexec. runner hexdump - noexec. runner hostid - NOFORK hostname - needs ^C (may talk to DNS servers, which may be down) httpd - daemon hush - interactive, longterm -hwclock - talks to hardware (xioctl(RTC_RD_TIME)) - needs ^C -i2cdetect -i2cdump -i2cget -i2cset +hwclock - hardware (xioctl(RTC_RD_TIME)) +i2cdetect - hardware +i2cdump - hardware +i2cget - hardware +i2cset - hardware id - noexec ifconfig - leaks: xsocket+ioctl_or_perror_and_die ifenslave - leaks: xsocket+bb_perror_msg_and_die @@ -237,7 +239,7 @@ more - interactive, longterm mount - suid mountpoint - noexec. leaks: option -n "print dev name": find_block_device -> readdir+xstrdup mpstat - longterm: "mpstat 1" runs indefinitely -mt - rare +mt - hardware mv - noexec candidate, runner nameif - noexec. openlog(), leaks: config_open2+ioctl_or_perror_and_die nbd-client - noexec @@ -257,8 +259,8 @@ paste - noexec. runner patch - needs ^C pgrep - nofork candidate(xregcomp, procps_scan - are they ok?) pidof - nofork candidate(uses find_pid_by_name, is that ok?) -ping - suid, runner -ping6 - suid, runner +ping - suid, longterm +ping6 - suid, longterm pipe_progress - longterm pivot_root - NOFORK pkill - nofork candidate(xregcomp, procps_scan - are they ok?) @@ -282,7 +284,7 @@ realpath - NOFORK reboot - rare reformime - runner remove-shell - noexec. leaks: open+xfunc -renice - nofork candidate(uses getpwnam, is that ok?) +renice - noexec. nofork candidate(uses getpwnam, is that ok?) reset - noexec. spawner (execs "stty") resize - noexec. changes state (signal handlers) rev - runner @@ -358,21 +360,21 @@ timeout - spawner, longterm, changes state (signals) top - interactive, longterm touch - NOFORK tr - runner -traceroute - suid, runner -traceroute6 - suid, runner +traceroute - suid, longterm +traceroute6 - suid, longterm true - NOFORK truncate - NOFORK tty - NOFORK ttysize - NOFORK tunctl - noexec tune2fs - noexec. leaks: open+xfunc -ubiattach - could be noexec, but I feel flash ops are risky (prone to hw/fw/sw bugs) -ubidetach - could be noexec, but I feel flash ops are risky (prone to hw/fw/sw bugs) -ubimkvol - could be noexec, but I feel flash ops are risky (prone to hw/fw/sw bugs) -ubirename - could be noexec, but I feel flash ops are risky (prone to hw/fw/sw bugs) -ubirmvol - could be noexec, but I feel flash ops are risky (prone to hw/fw/sw bugs) -ubirsvol - could be noexec, but I feel flash ops are risky (prone to hw/fw/sw bugs) -ubiupdatevol - could be noexec, but I feel flash ops are risky (prone to hw/fw/sw bugs) +ubiattach - hardware +ubidetach - hardware +ubimkvol - hardware +ubirename - hardware +ubirmvol - hardware +ubirsvol - hardware +ubiupdatevol - hardware udhcpc - daemon udhcpd - daemon udpsvd - daemon @@ -388,8 +390,8 @@ unlzma - runner unlzop - runner unxz - runner unzip - runner -uptime - nofork candidate(is getutxent ok?) -users - nofork candidate(is getutxent ok?) +uptime - noexec. nofork candidate(is getutxent ok?) +users - noexec. nofork candidate(is getutxent ok?) usleep - NOFORK uudecode - runner uuencode - runner @@ -397,14 +399,14 @@ vconfig - leaks: xsocket+ioctl_or_perror_and_die vi - interactive, longterm vlock - suid volname - runner -w - nofork candidate(is getutxent ok?) +w - noexec. nofork candidate(is getutxent ok?) wall - suid watch - longterm watchdog - daemon wc - runner wget - longterm which - NOFORK -who - nofork candidate(is getutxent ok?) +who - noexec. nofork candidate(is getutxent ok?) whoami - NOFORK whois - needs ^C xargs - noexec. spawner diff --git a/coreutils/who.c b/coreutils/who.c index 91f99138c..6be3d692e 100644 --- a/coreutils/who.c +++ b/coreutils/who.c @@ -38,10 +38,10 @@ //config: help //config: Print users currently logged on. -// APPLET_ODDNAME:name main location suid_type help -//applet:IF_USERS(APPLET_ODDNAME(users, who, BB_DIR_USR_BIN, BB_SUID_DROP, users)) -//applet:IF_W( APPLET_ODDNAME(w, who, BB_DIR_USR_BIN, BB_SUID_DROP, w)) -//applet:IF_WHO( APPLET( who, BB_DIR_USR_BIN, BB_SUID_DROP)) +// APPLET_NOEXEC:name main location suid_type help +//applet:IF_USERS(APPLET_NOEXEC(users, who, BB_DIR_USR_BIN, BB_SUID_DROP, users)) +//applet:IF_W( APPLET_NOEXEC(w, who, BB_DIR_USR_BIN, BB_SUID_DROP, w)) +//applet:IF_WHO( APPLET_NOEXEC(who, who, BB_DIR_USR_BIN, BB_SUID_DROP, who)) //kbuild:lib-$(CONFIG_USERS) += who.o //kbuild:lib-$(CONFIG_W) += who.o diff --git a/miscutils/i2c_tools.c b/miscutils/i2c_tools.c index ca2580e92..8d04d2259 100644 --- a/miscutils/i2c_tools.c +++ b/miscutils/i2c_tools.c @@ -42,6 +42,7 @@ //applet:IF_I2CSET(APPLET(i2cset, BB_DIR_USR_SBIN, BB_SUID_DROP)) //applet:IF_I2CDUMP(APPLET(i2cdump, BB_DIR_USR_SBIN, BB_SUID_DROP)) //applet:IF_I2CDETECT(APPLET(i2cdetect, BB_DIR_USR_SBIN, BB_SUID_DROP)) +/* not NOEXEC: if hw operation stalls, use less memory in "hung" process */ //kbuild:lib-$(CONFIG_I2CGET) += i2c_tools.o //kbuild:lib-$(CONFIG_I2CSET) += i2c_tools.o diff --git a/procps/uptime.c b/procps/uptime.c index 24b2b39df..b0ee8391b 100644 --- a/procps/uptime.c +++ b/procps/uptime.c @@ -27,7 +27,7 @@ //config: help //config: Display the number of users currently logged on. -//applet:IF_UPTIME(APPLET(uptime, BB_DIR_USR_BIN, BB_SUID_DROP)) +//applet:IF_UPTIME(APPLET_NOEXEC(uptime, uptime, BB_DIR_USR_BIN, BB_SUID_DROP, uptime)) //kbuild:lib-$(CONFIG_UPTIME) += uptime.o diff --git a/util-linux/renice.c b/util-linux/renice.c index 23cbca88d..70c494b3d 100644 --- a/util-linux/renice.c +++ b/util-linux/renice.c @@ -25,7 +25,7 @@ //config: Renice alters the scheduling priority of one or more running //config: processes. -//applet:IF_RENICE(APPLET(renice, BB_DIR_USR_BIN, BB_SUID_DROP)) +//applet:IF_RENICE(APPLET_NOEXEC(renice, renice, BB_DIR_USR_BIN, BB_SUID_DROP, renice)) //kbuild:lib-$(CONFIG_RENICE) += renice.o -- cgit v1.2.3-55-g6feb From 316d38e25883c68e51533029dbab059ae0731de8 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Mon, 7 Aug 2017 17:36:41 +0200 Subject: setconsole: much better help text Was: Usage: setconsole [-r] [DEVICE] Redirect system console output to DEVICE (default: /dev/tty) -r Reset output to /dev/console Now: Usage: setconsole [-r] [DEVICE] Make writes to /dev/console appear on DEVICE (default: /dev/tty). Does not redirect kernel log output or reads from /dev/console. -r Reset: writes to /dev/console go to kernel log tty(s) function old new delta packed_usage 31766 31777 +11 setconsole_main 84 78 -6 Signed-off-by: Denys Vlasenko --- console-tools/setconsole.c | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/console-tools/setconsole.c b/console-tools/setconsole.c index 9a8ca3821..8f4b7b7a6 100644 --- a/console-tools/setconsole.c +++ b/console-tools/setconsole.c @@ -12,8 +12,10 @@ //config: default y //config: select PLATFORM_LINUX //config: help -//config: This program redirects the system console to another device, +//config: Redirect writes to /dev/console to another device, //config: like the current tty while logged in via telnet. +//config: This does not redirect kernel log, only writes +//config: from user space. //config: //config:config FEATURE_SETCONSOLE_LONG_OPTIONS //config: bool "Enable long options" @@ -27,8 +29,10 @@ //usage:#define setconsole_trivial_usage //usage: "[-r] [DEVICE]" //usage:#define setconsole_full_usage "\n\n" -//usage: "Redirect system console output to DEVICE (default: /dev/tty)\n" -//usage: "\n -r Reset output to /dev/console" +//usage: "Make writes to /dev/console appear on DEVICE (default: /dev/tty)." +//usage: "\n""Does not redirect kernel log output or reads from /dev/console." +//usage: "\n" +//usage: "\n"" -r Reset: writes to /dev/console go to kernel log tty(s)" /* It was a bbox-specific invention, but SUSE does have a similar utility. * SUSE has no -r option, though. @@ -40,7 +44,7 @@ int setconsole_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; int setconsole_main(int argc UNUSED_PARAM, char **argv) { const char *device = CURRENT_TTY; - bool reset; + int reset; /* at most one non-option argument */ opt_complementary = "?1"; @@ -54,6 +58,9 @@ int setconsole_main(int argc UNUSED_PARAM, char **argv) device = DEV_CONSOLE; } +//TODO: fails if TIOCCONS redir is already active to some tty. +//I think SUSE version first does TIOCCONS on /dev/console fd (iow: resets) +//then TIOCCONS to new tty? xioctl(xopen(device, O_WRONLY), TIOCCONS, NULL); return EXIT_SUCCESS; } -- cgit v1.2.3-55-g6feb From 248a67fb75a0d2c98f4f9935b7bb9e11382b2c78 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Mon, 7 Aug 2017 18:18:09 +0200 Subject: free,stat: make NOEXEC pkill/pgrep/pidof uncovered another quirk: what about noexec's _process names_? Signed-off-by: Denys Vlasenko --- NOFORK_NOEXEC.lst | 18 ++++++++++-------- coreutils/stat.c | 2 +- libbb/vfork_daemon_rexec.c | 2 ++ procps/free.c | 7 +++++-- procps/pgrep.c | 6 +++++- procps/pidof.c | 4 ++++ shell/ash.c | 2 ++ shell/hush.c | 2 ++ 8 files changed, 31 insertions(+), 12 deletions(-) diff --git a/NOFORK_NOEXEC.lst b/NOFORK_NOEXEC.lst index 70f38d867..8ec3bdbe6 100644 --- a/NOFORK_NOEXEC.lst +++ b/NOFORK_NOEXEC.lst @@ -16,6 +16,8 @@ leak categories. Why can't be NOEXEC: suid: runs under different uid - must fork+exec +if it's important that /proc/PID/cmdline and comm are correct. + ("pkill sh" killing itself before it kills real "sh" is no fun) Why shouldn't be NOFORK/NOEXEC: rare: not started often enough to bother optimizing (example: poweroff) @@ -131,7 +133,7 @@ flash_unlock - hardware flashcp - hardware flock - spawner, changes state (file locks), let's play safe and not be noexec fold - noexec. runner -free - nofork candidate(struct globals, needs to close /proc/meminfo fd) +free - noexec. nofork candidate(struct globals, needs to close /proc/meminfo fd) freeramdisk - leaks: open+ioctl_or_perror_and_die fsck - interactive, longterm fsck.minix - needs ^C @@ -172,7 +174,7 @@ inotifyd - daemon insmod - noexec install - runner ionice - noexec. spawner -iostat - runner +iostat - longterm: "iostat 1" runs indefinitely ip - noexec candidate ipaddr - noexec candidate ipcalc - noexec candidate @@ -244,7 +246,7 @@ mv - noexec candidate, runner nameif - noexec. openlog(), leaks: config_open2+ioctl_or_perror_and_die nbd-client - noexec nc - runner -netstat - runner with -c +netstat - longterm with -c (continuous listing) nice - noexec. spawner nl - runner nmeter - longterm @@ -257,13 +259,13 @@ partprobe - noexec. leaks: open+ioctl_or_perror_and_die(BLKRRPART) passwd - suid paste - noexec. runner patch - needs ^C -pgrep - nofork candidate(xregcomp, procps_scan - are they ok?) -pidof - nofork candidate(uses find_pid_by_name, is that ok?) +pgrep - must fork+exec to get correct /proc/PID/cmdline and comm field +pidof - must fork+exec to get correct /proc/PID/cmdline and comm field ping - suid, longterm ping6 - suid, longterm pipe_progress - longterm pivot_root - NOFORK -pkill - nofork candidate(xregcomp, procps_scan - are they ok?) +pkill - must fork+exec to get correct /proc/PID/cmdline and comm field pmap - noexec candidate, leaks: open+xstrdup popmaildir - runner poweroff - rare @@ -329,7 +331,7 @@ sort - noexec. runner split - runner ssl_client - longterm start-stop-daemon - not noexec: uses bb_common_bufsiz1 -stat - nofork candidate(needs fewer allocs) +stat - noexec. nofork candidate(needs fewer allocs) strings - runner stty - noexec. nofork candidate: has no allocs or opens except xmove_fd(xopen("-F DEVICE"),STDIN). tcsetattr(STDIN) is not a problem: it would work the same across processes sharing this fd su - suid, spawner @@ -338,7 +340,7 @@ sum - runner sv - noexec. needs ^C (uses usleep(420000)) svc - noexec. needs ^C (uses usleep(420000)) svlogd - daemon -swapoff - rare +swapoff - longterm: may cause memory pressure, execing is beneficial swapon - rare switch_root - spawner, rare, changes state (oh yes), execing may be important to free binary's inode sync - NOFORK diff --git a/coreutils/stat.c b/coreutils/stat.c index 3b85808b5..4e926a908 100644 --- a/coreutils/stat.c +++ b/coreutils/stat.c @@ -36,7 +36,7 @@ //config: Without this, stat will not support the '-f' option to display //config: information about filesystem status. -//applet:IF_STAT(APPLET(stat, BB_DIR_BIN, BB_SUID_DROP)) +//applet:IF_STAT(APPLET_NOEXEC(stat, stat, BB_DIR_BIN, BB_SUID_DROP, stat)) //kbuild:lib-$(CONFIG_STAT) += stat.o diff --git a/libbb/vfork_daemon_rexec.c b/libbb/vfork_daemon_rexec.c index f84e678b5..50ecea762 100644 --- a/libbb/vfork_daemon_rexec.c +++ b/libbb/vfork_daemon_rexec.c @@ -175,6 +175,8 @@ int FAST_FUNC spawn_and_wait(char **argv) return wait4pid(rc); /* child */ +//TODO: prctl(PR_SET_NAME, (long)argv[0], 0, 0, 0);? [think pidof, pgrep, pkill] +//Rewrite /proc/PID/cmdline? (need to save argv0 and length at init for this to work!) /* reset some state and run without execing */ /* msg_eol = "\n"; - no caller needs this reinited yet */ diff --git a/procps/free.c b/procps/free.c index 618664e08..b57e4a322 100644 --- a/procps/free.c +++ b/procps/free.c @@ -15,7 +15,7 @@ //config: memory in the system, as well as the buffers used by the kernel. //config: The shared memory column should be ignored; it is obsolete. -//applet:IF_FREE(APPLET(free, BB_DIR_USR_BIN, BB_SUID_DROP)) +//applet:IF_FREE(APPLET_NOEXEC(free, free, BB_DIR_USR_BIN, BB_SUID_DROP, free)) //kbuild:lib-$(CONFIG_FREE) += free.o @@ -47,7 +47,10 @@ struct globals { #endif } FIX_ALIASING; #define G (*(struct globals*)bb_common_bufsiz1) -#define INIT_G() do { setup_common_bufsiz(); } while (0) +#define INIT_G() do { \ + setup_common_bufsiz(); \ + /* NB: noexec applet - globals not zeroed */ \ +} while (0) static unsigned long long scale(unsigned long d) diff --git a/procps/pgrep.c b/procps/pgrep.c index a3ca9e295..a16a6e959 100644 --- a/procps/pgrep.c +++ b/procps/pgrep.c @@ -18,9 +18,13 @@ //config: help //config: Send signals to processes by name. -//applet:IF_PGREP(APPLET(pgrep, BB_DIR_USR_BIN, BB_SUID_DROP)) +//applet:IF_PGREP(APPLET_ODDNAME(pgrep, pgrep, BB_DIR_USR_BIN, BB_SUID_DROP, pgrep)) // APPLET_ODDNAME:name main location suid_type help //applet:IF_PKILL(APPLET_ODDNAME(pkill, pgrep, BB_DIR_USR_BIN, BB_SUID_DROP, pkill)) +/* can't be noexec: can find _itself_ under wrong name, since after fork only, + * /proc/PID/cmdline and comm are wrong! Can fix comm (prctl(PR_SET_NAME)), + * but cmdline? + */ //kbuild:lib-$(CONFIG_PGREP) += pgrep.o //kbuild:lib-$(CONFIG_PKILL) += pgrep.o diff --git a/procps/pidof.c b/procps/pidof.c index 41247a02c..98d7949f8 100644 --- a/procps/pidof.c +++ b/procps/pidof.c @@ -30,6 +30,10 @@ //config: of the pidof, in other words the calling shell or shell script. //applet:IF_PIDOF(APPLET(pidof, BB_DIR_BIN, BB_SUID_DROP)) +/* can't be noexec: can find _itself_ under wrong name, since after fork only, + * /proc/PID/cmdline and comm are wrong! Can fix comm (prctl(PR_SET_NAME)), + * but cmdline? + */ //kbuild:lib-$(CONFIG_PIDOF) += pidof.o diff --git a/shell/ash.c b/shell/ash.c index e8f3ed26b..0a323e957 100644 --- a/shell/ash.c +++ b/shell/ash.c @@ -7803,6 +7803,8 @@ tryexec(IF_FEATURE_SH_STANDALONE(int applet_no,) const char *cmd, char **argv, c while (*envp) putenv(*envp++); popredir(/*drop:*/ 1); +//TODO: prctl(PR_SET_NAME, (long)argv[0], 0, 0, 0);? [think pidof, pgrep, pkill] +//Rewrite /proc/PID/cmdline? (need to save argv0 and length at init for this to work!) run_applet_no_and_exit(applet_no, cmd, argv); } /* re-exec ourselves with the new arguments */ diff --git a/shell/hush.c b/shell/hush.c index bb80f422c..b4fe7146b 100644 --- a/shell/hush.c +++ b/shell/hush.c @@ -7387,6 +7387,8 @@ static NOINLINE void pseudo_exec_argv(nommu_save_t *nommu_save, /* Without this, "rm -i FILE" can't be ^C'ed: */ switch_off_special_sigs(G.special_sig_mask); debug_printf_exec("running applet '%s'\n", argv[0]); +//TODO: prctl(PR_SET_NAME, (long)argv[0], 0, 0, 0);? [think pidof, pgrep, pkill] +//Rewrite /proc/PID/cmdline? (need to save argv0 and length at init for this to work!) run_applet_no_and_exit(a, argv[0], argv); } # endif -- cgit v1.2.3-55-g6feb From f2cf1cc716216308a8a6d07e3afab23be07a6b02 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Mon, 7 Aug 2017 18:45:33 +0200 Subject: noexec: set comm field for noexecs function old new delta set_task_comm - 18 +18 tryexec 152 159 +7 pseudo_exec_argv 321 328 +7 main 106 97 -9 ------------------------------------------------------------------------------ (add/remove: 1/0 grow/shrink: 3/2 up/down: 34/-13) Total: 23 bytes Signed-off-by: Denys Vlasenko --- include/libbb.h | 5 +++++ libbb/appletlib.c | 13 ++++++++++--- libbb/vfork_daemon_rexec.c | 7 +++++-- shell/ash.c | 5 ++++- shell/hush.c | 5 ++++- 5 files changed, 28 insertions(+), 7 deletions(-) diff --git a/include/libbb.h b/include/libbb.h index 51e8f27a5..e4a19ac04 100644 --- a/include/libbb.h +++ b/include/libbb.h @@ -1116,6 +1116,11 @@ int run_nofork_applet(int applet_no, char **argv) FAST_FUNC; extern int find_applet_by_name(const char *name) FAST_FUNC; extern void run_applet_no_and_exit(int a, const char *name, char **argv) NORETURN FAST_FUNC; #endif +#if defined(__linux__) +void set_task_comm(const char *comm) FAST_FUNC; +#else +# define set_task_comm(name) ((void)0) +#endif /* Helpers for daemonization. * diff --git a/libbb/appletlib.c b/libbb/appletlib.c index fa28d433b..ce259446b 100644 --- a/libbb/appletlib.c +++ b/libbb/appletlib.c @@ -911,6 +911,14 @@ int busybox_main(int argc UNUSED_PARAM, char **argv) } # endif +#if defined(__linux__) && (NUM_APPLETS > 1) +void FAST_FUNC set_task_comm(const char *comm) +{ + /* okay if too long (truncates) */ + prctl(PR_SET_NAME, (long)comm, 0, 0, 0); +} +#endif + # if NUM_APPLETS > 0 void FAST_FUNC run_applet_no_and_exit(int applet_no, const char *name, char **argv) { @@ -1064,15 +1072,14 @@ int main(int argc UNUSED_PARAM, char **argv) applet_name++; applet_name = bb_basename(applet_name); -# if defined(__linux__) /* If we are a result of execv("/proc/self/exe"), fix ugly comm of "exe" */ if (ENABLE_FEATURE_SH_STANDALONE || ENABLE_FEATURE_PREFER_APPLETS || !BB_MMU ) { - prctl(PR_SET_NAME, (long)applet_name, 0, 0, 0); + if (NUM_APPLETS > 1) + set_task_comm(applet_name); } -# endif parse_config_file(); /* ...maybe, if FEATURE_SUID_CONFIG */ run_applet_and_exit(applet_name, argv); diff --git a/libbb/vfork_daemon_rexec.c b/libbb/vfork_daemon_rexec.c index 50ecea762..546cc9e36 100644 --- a/libbb/vfork_daemon_rexec.c +++ b/libbb/vfork_daemon_rexec.c @@ -175,8 +175,6 @@ int FAST_FUNC spawn_and_wait(char **argv) return wait4pid(rc); /* child */ -//TODO: prctl(PR_SET_NAME, (long)argv[0], 0, 0, 0);? [think pidof, pgrep, pkill] -//Rewrite /proc/PID/cmdline? (need to save argv0 and length at init for this to work!) /* reset some state and run without execing */ /* msg_eol = "\n"; - no caller needs this reinited yet */ @@ -185,6 +183,11 @@ int FAST_FUNC spawn_and_wait(char **argv) * init, or a NOFORK applet. But none of those call us * as of yet (and that should probably always stay true). */ +//TODO: think pidof, pgrep, pkill! +//set_task_comm() makes our pidof find NOEXECs (e.g. "yes >/dev/null"), +//but one from procps-ng-3.3.10 needs more! +//Rewrite /proc/PID/cmdline? (need to save argv0 and length at init for this to work!) + set_task_comm(argv[0]); /* xfunc_error_retval and applet_name are init by: */ run_applet_no_and_exit(a, argv[0], argv); } diff --git a/shell/ash.c b/shell/ash.c index 0a323e957..507d15c90 100644 --- a/shell/ash.c +++ b/shell/ash.c @@ -7803,8 +7803,11 @@ tryexec(IF_FEATURE_SH_STANDALONE(int applet_no,) const char *cmd, char **argv, c while (*envp) putenv(*envp++); popredir(/*drop:*/ 1); -//TODO: prctl(PR_SET_NAME, (long)argv[0], 0, 0, 0);? [think pidof, pgrep, pkill] +//TODO: think pidof, pgrep, pkill! +//set_task_comm() makes our pidof find NOEXECs (e.g. "yes >/dev/null"), +//but one from procps-ng-3.3.10 needs more! //Rewrite /proc/PID/cmdline? (need to save argv0 and length at init for this to work!) + set_task_comm(argv[0]); run_applet_no_and_exit(applet_no, cmd, argv); } /* re-exec ourselves with the new arguments */ diff --git a/shell/hush.c b/shell/hush.c index b4fe7146b..021c1f0ff 100644 --- a/shell/hush.c +++ b/shell/hush.c @@ -7387,8 +7387,11 @@ static NOINLINE void pseudo_exec_argv(nommu_save_t *nommu_save, /* Without this, "rm -i FILE" can't be ^C'ed: */ switch_off_special_sigs(G.special_sig_mask); debug_printf_exec("running applet '%s'\n", argv[0]); -//TODO: prctl(PR_SET_NAME, (long)argv[0], 0, 0, 0);? [think pidof, pgrep, pkill] +//TODO: think pidof, pgrep, pkill! +//set_task_comm() makes our pidof find NOEXECs (e.g. "yes >/dev/null"), +//but one from procps-ng-3.3.10 needs more! //Rewrite /proc/PID/cmdline? (need to save argv0 and length at init for this to work!) + set_task_comm(argv[0]); run_applet_no_and_exit(a, argv[0], argv); } # endif -- cgit v1.2.3-55-g6feb From c9c1ccc4ed7e7525a2e3c07d855c7a27c3534430 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Mon, 7 Aug 2017 18:59:35 +0200 Subject: noexec: do GETOPT_RESET() before entering APPLET_main() hush -c 'yes | head -1' was not happy. function old new delta tryexec 159 169 +10 pseudo_exec_argv 328 338 +10 Signed-off-by: Denys Vlasenko --- libbb/vfork_daemon_rexec.c | 1 + shell/ash.c | 1 + shell/hush.c | 3 ++- 3 files changed, 4 insertions(+), 1 deletion(-) diff --git a/libbb/vfork_daemon_rexec.c b/libbb/vfork_daemon_rexec.c index 546cc9e36..9d3cb9d54 100644 --- a/libbb/vfork_daemon_rexec.c +++ b/libbb/vfork_daemon_rexec.c @@ -176,6 +176,7 @@ int FAST_FUNC spawn_and_wait(char **argv) /* child */ /* reset some state and run without execing */ + GETOPT_RESET(); /* msg_eol = "\n"; - no caller needs this reinited yet */ logmode = LOGMODE_STDIO; diff --git a/shell/ash.c b/shell/ash.c index 507d15c90..bedd27b0d 100644 --- a/shell/ash.c +++ b/shell/ash.c @@ -7803,6 +7803,7 @@ tryexec(IF_FEATURE_SH_STANDALONE(int applet_no,) const char *cmd, char **argv, c while (*envp) putenv(*envp++); popredir(/*drop:*/ 1); + GETOPT_RESET(); //TODO: think pidof, pgrep, pkill! //set_task_comm() makes our pidof find NOEXECs (e.g. "yes >/dev/null"), //but one from procps-ng-3.3.10 needs more! diff --git a/shell/hush.c b/shell/hush.c index 021c1f0ff..b890107a2 100644 --- a/shell/hush.c +++ b/shell/hush.c @@ -7386,12 +7386,13 @@ static NOINLINE void pseudo_exec_argv(nommu_save_t *nommu_save, //FIXME: should also close saved redir fds /* Without this, "rm -i FILE" can't be ^C'ed: */ switch_off_special_sigs(G.special_sig_mask); - debug_printf_exec("running applet '%s'\n", argv[0]); + GETOPT_RESET(); //TODO: think pidof, pgrep, pkill! //set_task_comm() makes our pidof find NOEXECs (e.g. "yes >/dev/null"), //but one from procps-ng-3.3.10 needs more! //Rewrite /proc/PID/cmdline? (need to save argv0 and length at init for this to work!) set_task_comm(argv[0]); + debug_printf_exec("running applet '%s'\n", argv[0]); run_applet_no_and_exit(a, argv[0], argv); } # endif -- cgit v1.2.3-55-g6feb From 80e8e3cc0542ac6242d49eaf223146dcbf2fa0da Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Mon, 7 Aug 2017 19:24:57 +0200 Subject: noexec: consolidate code function old new delta run_noexec_applet_and_exit - 61 +61 find_applet_by_name 128 124 -4 run_applet_no_and_exit 441 434 -7 tryexec 169 152 -17 pseudo_exec_argv 338 321 -17 ------------------------------------------------------------------------------ (add/remove: 1/0 grow/shrink: 0/6 up/down: 61/-48) Total: 13 bytes Signed-off-by: Denys Vlasenko --- include/libbb.h | 5 +++-- libbb/appletlib.c | 2 -- libbb/vfork_daemon_rexec.c | 37 +++++++++++++++++++++---------------- shell/ash.c | 8 +------- shell/hush.c | 8 +------- 5 files changed, 26 insertions(+), 34 deletions(-) diff --git a/include/libbb.h b/include/libbb.h index e4a19ac04..3f3e033fe 100644 --- a/include/libbb.h +++ b/include/libbb.h @@ -1112,9 +1112,10 @@ int wait_for_exitstatus(pid_t pid) FAST_FUNC; int spawn_and_wait(char **argv) FAST_FUNC; /* Does NOT check that applet is NOFORK, just blindly runs it */ int run_nofork_applet(int applet_no, char **argv) FAST_FUNC; +void run_noexec_applet_and_exit(int a, const char *name, char **argv) NORETURN FAST_FUNC; #ifndef BUILD_INDIVIDUAL -extern int find_applet_by_name(const char *name) FAST_FUNC; -extern void run_applet_no_and_exit(int a, const char *name, char **argv) NORETURN FAST_FUNC; +int find_applet_by_name(const char *name) FAST_FUNC; +void run_applet_no_and_exit(int a, const char *name, char **argv) NORETURN FAST_FUNC; #endif #if defined(__linux__) void set_task_comm(const char *comm) FAST_FUNC; diff --git a/libbb/appletlib.c b/libbb/appletlib.c index ce259446b..5b84920a4 100644 --- a/libbb/appletlib.c +++ b/libbb/appletlib.c @@ -924,8 +924,6 @@ void FAST_FUNC run_applet_no_and_exit(int applet_no, const char *name, char **ar { int argc = string_array_len(argv); - /* Reinit some shared global data */ - xfunc_error_retval = EXIT_FAILURE; /* * We do not use argv[0]: do not want to repeat massaging of * "-/sbin/halt" -> "halt", for example. diff --git a/libbb/vfork_daemon_rexec.c b/libbb/vfork_daemon_rexec.c index 9d3cb9d54..a349459f0 100644 --- a/libbb/vfork_daemon_rexec.c +++ b/libbb/vfork_daemon_rexec.c @@ -158,6 +158,26 @@ int FAST_FUNC run_nofork_applet(int applet_no, char **argv) } #endif /* FEATURE_PREFER_APPLETS || FEATURE_SH_NOFORK */ +#if (NUM_APPLETS > 1) && (ENABLE_FEATURE_PREFER_APPLETS || ENABLE_FEATURE_SH_STANDALONE) +void FAST_FUNC run_noexec_applet_and_exit(int a, const char *name, char **argv) +{ + /* reset some state and run without execing */ + /* msg_eol = "\n"; - no caller needs this reinited yet */ + logmode = LOGMODE_STDIO; + xfunc_error_retval = EXIT_FAILURE; + die_func = NULL; + GETOPT_RESET(); + +//TODO: think pidof, pgrep, pkill! +//set_task_comm() makes our pidof find NOEXECs (e.g. "yes >/dev/null"), +//but one from procps-ng-3.3.10 needs more! +//Rewrite /proc/PID/cmdline? (need to save argv0 and length at init for this to work!) + set_task_comm(name); + /* xfunc_error_retval and applet_name are init by: */ + run_applet_no_and_exit(a, name, argv); +} +#endif + int FAST_FUNC spawn_and_wait(char **argv) { int rc; @@ -175,22 +195,7 @@ int FAST_FUNC spawn_and_wait(char **argv) return wait4pid(rc); /* child */ - /* reset some state and run without execing */ - GETOPT_RESET(); - - /* msg_eol = "\n"; - no caller needs this reinited yet */ - logmode = LOGMODE_STDIO; - /* die_func = NULL; - needed if the caller is a shell, - * init, or a NOFORK applet. But none of those call us - * as of yet (and that should probably always stay true). - */ -//TODO: think pidof, pgrep, pkill! -//set_task_comm() makes our pidof find NOEXECs (e.g. "yes >/dev/null"), -//but one from procps-ng-3.3.10 needs more! -//Rewrite /proc/PID/cmdline? (need to save argv0 and length at init for this to work!) - set_task_comm(argv[0]); - /* xfunc_error_retval and applet_name are init by: */ - run_applet_no_and_exit(a, argv[0], argv); + run_noexec_applet_and_exit(a, argv[0], argv); } # endif } diff --git a/shell/ash.c b/shell/ash.c index bedd27b0d..6dc1cfef7 100644 --- a/shell/ash.c +++ b/shell/ash.c @@ -7803,13 +7803,7 @@ tryexec(IF_FEATURE_SH_STANDALONE(int applet_no,) const char *cmd, char **argv, c while (*envp) putenv(*envp++); popredir(/*drop:*/ 1); - GETOPT_RESET(); -//TODO: think pidof, pgrep, pkill! -//set_task_comm() makes our pidof find NOEXECs (e.g. "yes >/dev/null"), -//but one from procps-ng-3.3.10 needs more! -//Rewrite /proc/PID/cmdline? (need to save argv0 and length at init for this to work!) - set_task_comm(argv[0]); - run_applet_no_and_exit(applet_no, cmd, argv); + run_noexec_applet_and_exit(applet_no, cmd, argv); } /* re-exec ourselves with the new arguments */ execve(bb_busybox_exec_path, argv, envp); diff --git a/shell/hush.c b/shell/hush.c index b890107a2..8dc531657 100644 --- a/shell/hush.c +++ b/shell/hush.c @@ -7386,14 +7386,8 @@ static NOINLINE void pseudo_exec_argv(nommu_save_t *nommu_save, //FIXME: should also close saved redir fds /* Without this, "rm -i FILE" can't be ^C'ed: */ switch_off_special_sigs(G.special_sig_mask); - GETOPT_RESET(); -//TODO: think pidof, pgrep, pkill! -//set_task_comm() makes our pidof find NOEXECs (e.g. "yes >/dev/null"), -//but one from procps-ng-3.3.10 needs more! -//Rewrite /proc/PID/cmdline? (need to save argv0 and length at init for this to work!) - set_task_comm(argv[0]); debug_printf_exec("running applet '%s'\n", argv[0]); - run_applet_no_and_exit(a, argv[0], argv); + run_noexec_applet_and_exit(a, argv[0], argv); } # endif /* Re-exec ourselves */ -- cgit v1.2.3-55-g6feb From ed4393bdc7a4d3b1b59293a3393eb1d6953bac99 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Mon, 7 Aug 2017 20:34:26 +0200 Subject: dnsdomainname,hostname: make NOEXEC Signed-off-by: Denys Vlasenko --- NOFORK_NOEXEC.lst | 4 ++-- networking/hostname.c | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/NOFORK_NOEXEC.lst b/NOFORK_NOEXEC.lst index 8ec3bdbe6..6595b9d2f 100644 --- a/NOFORK_NOEXEC.lst +++ b/NOFORK_NOEXEC.lst @@ -99,7 +99,7 @@ diff - runner dirname - NOFORK dmesg - runner dnsd - daemon -dnsdomainname - needs ^C (may talk to DNS servers, which may be down) +dnsdomainname - noexec. needs ^C (may talk to DNS servers, which may be down) dos2unix - noexec. runner dpkg - runner du - runner @@ -156,7 +156,7 @@ hdparm - hardware head - noexec. runner hexdump - noexec. runner hostid - NOFORK -hostname - needs ^C (may talk to DNS servers, which may be down) +hostname - noexec. needs ^C (may talk to DNS servers, which may be down) httpd - daemon hush - interactive, longterm hwclock - hardware (xioctl(RTC_RD_TIME)) diff --git a/networking/hostname.c b/networking/hostname.c index 7d7c60d18..ea0ff95b7 100644 --- a/networking/hostname.c +++ b/networking/hostname.c @@ -22,9 +22,9 @@ //config: help //config: Alias to "hostname -d". -// APPLET_ODDNAME:name main location suid_type help -//applet:IF_DNSDOMAINNAME(APPLET_ODDNAME(dnsdomainname, hostname, BB_DIR_BIN, BB_SUID_DROP, dnsdomainname)) -//applet:IF_HOSTNAME(APPLET(hostname, BB_DIR_BIN, BB_SUID_DROP)) +// APPLET_NOEXEC:name main location suid_type help +//applet:IF_DNSDOMAINNAME(APPLET_NOEXEC(dnsdomainname, hostname, BB_DIR_BIN, BB_SUID_DROP, dnsdomainname)) +//applet:IF_HOSTNAME( APPLET_NOEXEC(hostname, hostname, BB_DIR_BIN, BB_SUID_DROP, hostname )) //kbuild: lib-$(CONFIG_HOSTNAME) += hostname.o //kbuild: lib-$(CONFIG_DNSDOMAINNAME) += hostname.o -- cgit v1.2.3-55-g6feb From 76b65624b93dc969334dbc5d72ff58ffd465f619 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Mon, 7 Aug 2017 20:56:54 +0200 Subject: unxz: get_le32 macro is obviously wrong Signed-off-by: Denys Vlasenko --- archival/libarchive/decompress_unxz.c | 1 - 1 file changed, 1 deletion(-) diff --git a/archival/libarchive/decompress_unxz.c b/archival/libarchive/decompress_unxz.c index 350e5358a..0be85500c 100644 --- a/archival/libarchive/decompress_unxz.c +++ b/archival/libarchive/decompress_unxz.c @@ -37,7 +37,6 @@ static uint32_t xz_crc32(const uint8_t *buf, size_t size, uint32_t crc) || !defined(put_unaligned_be32) # error get_unaligned_le32 accessors are not defined #endif -#define get_le32(p) (*(uint32_t*)(p)) #include "unxz/xz_dec_bcj.c" #include "unxz/xz_dec_lzma2.c" -- cgit v1.2.3-55-g6feb From fc9efcb53bf59edb47be7f25d2a374907af2e6a8 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Mon, 7 Aug 2017 22:19:17 +0200 Subject: df: make NOEXEC Signed-off-by: Denys Vlasenko --- NOFORK_NOEXEC.lst | 4 ++-- coreutils/df.c | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/NOFORK_NOEXEC.lst b/NOFORK_NOEXEC.lst index 6595b9d2f..8580593cb 100644 --- a/NOFORK_NOEXEC.lst +++ b/NOFORK_NOEXEC.lst @@ -92,8 +92,8 @@ deallocvt - noexec. leaks: get_console_fd_or_die() may open a new fd, or return delgroup - noexec. leaks deluser - noexec. leaks depmod - longterm(ish) -devmem - runner, complex (access to device memory may hang) -df - leaks: nested allocs +devmem - hardware (access to device memory may hang) +df - noexec. leaks: nested allocs dhcprelay - daemon diff - runner dirname - NOFORK diff --git a/coreutils/df.c b/coreutils/df.c index 27dd2b5a8..4d6534bc2 100644 --- a/coreutils/df.c +++ b/coreutils/df.c @@ -33,7 +33,7 @@ //config: -i Inodes //config: -B Blocksize -//applet:IF_DF(APPLET(df, BB_DIR_BIN, BB_SUID_DROP)) +//applet:IF_DF(APPLET_NOEXEC(df, df, BB_DIR_BIN, BB_SUID_DROP, df)) //kbuild:lib-$(CONFIG_DF) += df.o -- cgit v1.2.3-55-g6feb From 354b104df1f5a07bbac554603f69d6d8c3077e07 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Mon, 7 Aug 2017 22:21:54 +0200 Subject: fatattr: make NOEXEC Signed-off-by: Denys Vlasenko --- NOFORK_NOEXEC.lst | 2 +- util-linux/fatattr.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/NOFORK_NOEXEC.lst b/NOFORK_NOEXEC.lst index 8580593cb..d7e60b442 100644 --- a/NOFORK_NOEXEC.lst +++ b/NOFORK_NOEXEC.lst @@ -117,7 +117,7 @@ expr - leaks: nested allocs factor - runner (eats stdin if no params) fakeidentd - daemon false - NOFORK -fatattr - leaks: open+xioctl, complex +fatattr - noexec. leaks: open+xioctl, complex fbset - hardware, leaks: open+xfunc fbsplash - runner, longterm fdflush - hardware, leaks: open+ioctl_or_perror_and_die diff --git a/util-linux/fatattr.c b/util-linux/fatattr.c index 9fb566d5a..770b1d2f9 100644 --- a/util-linux/fatattr.c +++ b/util-linux/fatattr.c @@ -15,7 +15,7 @@ //config: help //config: fatattr lists or changes the file attributes on a fat file system. -//applet:IF_FATATTR(APPLET(fatattr, BB_DIR_BIN, BB_SUID_DROP)) +//applet:IF_FATATTR(APPLET_NOEXEC(fatattr, fatattr, BB_DIR_BIN, BB_SUID_DROP, fatattr)) //kbuild:lib-$(CONFIG_FATATTR) += fatattr.o -- cgit v1.2.3-55-g6feb From 93c1a25c59efa0e3848e17cb9bd1849646a0d4b1 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Mon, 7 Aug 2017 22:30:59 +0200 Subject: ifenslave: remove longopts from --help text Signed-off-by: Denys Vlasenko --- networking/ifenslave.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/networking/ifenslave.c b/networking/ifenslave.c index 26e5e8cf3..7e6a8b1c4 100644 --- a/networking/ifenslave.c +++ b/networking/ifenslave.c @@ -113,10 +113,10 @@ //usage: "[-cdf] MASTER_IFACE SLAVE_IFACE..." //usage:#define ifenslave_full_usage "\n\n" //usage: "Configure network interfaces for parallel routing\n" -//usage: "\n -c,--change-active Change active slave" -//usage: "\n -d,--detach Remove slave interface from bonding device" -//usage: "\n -f,--force Force, even if interface is not Ethernet" -/* //usage: "\n -r,--receive-slave Create a receive-only slave" */ +//usage: "\n -c Change active slave" +//usage: "\n -d Remove slave interface from bonding device" +//usage: "\n -f Force, even if interface is not Ethernet" +/* //usage: "\n -r Create a receive-only slave" */ //usage: //usage:#define ifenslave_example_usage //usage: "To create a bond device, simply follow these three steps:\n" -- cgit v1.2.3-55-g6feb From a907b828d6e9f1357fc2e1db09d3eb1d3fb9b826 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Mon, 7 Aug 2017 22:31:51 +0200 Subject: ifenslave: make NOEXEC Signed-off-by: Denys Vlasenko --- networking/ifenslave.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/networking/ifenslave.c b/networking/ifenslave.c index 7e6a8b1c4..a845c4e7e 100644 --- a/networking/ifenslave.c +++ b/networking/ifenslave.c @@ -105,7 +105,7 @@ //config: Userspace application to bind several interfaces //config: to a logical interface (use with kernel bonding driver). -//applet:IF_IFENSLAVE(APPLET(ifenslave, BB_DIR_SBIN, BB_SUID_DROP)) +//applet:IF_IFENSLAVE(APPLET_NOEXEC(ifenslave, ifenslave, BB_DIR_SBIN, BB_SUID_DROP, ifenslave)) //kbuild:lib-$(CONFIG_IFENSLAVE) += ifenslave.o interface.o -- cgit v1.2.3-55-g6feb From ae84418d269ea44a710b9effa6d64b6334208973 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Mon, 7 Aug 2017 23:14:49 +0200 Subject: losetup: make NOEXEC Signed-off-by: Denys Vlasenko --- NOFORK_NOEXEC.lst | 8 ++++---- util-linux/losetup.c | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/NOFORK_NOEXEC.lst b/NOFORK_NOEXEC.lst index d7e60b442..a8823beff 100644 --- a/NOFORK_NOEXEC.lst +++ b/NOFORK_NOEXEC.lst @@ -165,8 +165,8 @@ i2cdump - hardware i2cget - hardware i2cset - hardware id - noexec -ifconfig - leaks: xsocket+ioctl_or_perror_and_die -ifenslave - leaks: xsocket+bb_perror_msg_and_die +ifconfig - hardware? (mem_start NN io_addr NN irq NN), leaks: xsocket+ioctl_or_perror_and_die +ifenslave - noexec. leaks: xsocket+bb_perror_msg_and_die ifplugd - daemon inetd - daemon init - daemon @@ -202,7 +202,7 @@ loadkmap - noexec. leaks: get_console_fd_or_die() may open a new fd, or return o logger - runner login - suid, interactive, longterm logname - NOFORK -losetup - complex +losetup - noexec. complex lpd - daemon lpq - runner lpr - runner @@ -400,7 +400,7 @@ uuencode - runner vconfig - leaks: xsocket+ioctl_or_perror_and_die vi - interactive, longterm vlock - suid -volname - runner +volname - hardware (reads CDROM, this can take long-ish if need to spin up) w - noexec. nofork candidate(is getutxent ok?) wall - suid watch - longterm diff --git a/util-linux/losetup.c b/util-linux/losetup.c index c608de6cc..2f7dc10f5 100644 --- a/util-linux/losetup.c +++ b/util-linux/losetup.c @@ -15,9 +15,9 @@ //config: file or block device, and to query the status of a loop device. This //config: version does not currently support enabling data encryption. -//kbuild:lib-$(CONFIG_LOSETUP) += losetup.o +//applet:IF_LOSETUP(APPLET_NOEXEC(losetup, losetup, BB_DIR_SBIN, BB_SUID_DROP, losetup)) -//applet:IF_LOSETUP(APPLET(losetup, BB_DIR_SBIN, BB_SUID_DROP)) +//kbuild:lib-$(CONFIG_LOSETUP) += losetup.o //usage:#define losetup_trivial_usage //usage: "[-r] [-o OFS] {-f|LOOPDEV} FILE - associate loop devices\n" -- cgit v1.2.3-55-g6feb From ec98e3a628b06f6cb8823e5197dcd413113d7ed6 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Mon, 7 Aug 2017 23:17:14 +0200 Subject: freeramdisk: make NOEXEC Signed-off-by: Denys Vlasenko --- NOFORK_NOEXEC.lst | 2 +- util-linux/freeramdisk.c | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/NOFORK_NOEXEC.lst b/NOFORK_NOEXEC.lst index a8823beff..fd5306317 100644 --- a/NOFORK_NOEXEC.lst +++ b/NOFORK_NOEXEC.lst @@ -134,7 +134,7 @@ flashcp - hardware flock - spawner, changes state (file locks), let's play safe and not be noexec fold - noexec. runner free - noexec. nofork candidate(struct globals, needs to close /proc/meminfo fd) -freeramdisk - leaks: open+ioctl_or_perror_and_die +freeramdisk - noexec. leaks: open+ioctl_or_perror_and_die fsck - interactive, longterm fsck.minix - needs ^C fsfreeze - noexec. leaks: open+xioctl diff --git a/util-linux/freeramdisk.c b/util-linux/freeramdisk.c index a73578404..6752e49d8 100644 --- a/util-linux/freeramdisk.c +++ b/util-linux/freeramdisk.c @@ -33,9 +33,9 @@ //config: ramdisk. If you have no use for freeing memory from a ramdisk, leave //config: this disabled. -// APPLET_ODDNAME:name main location suid_type help -//applet:IF_FDFLUSH(APPLET_ODDNAME(fdflush, freeramdisk, BB_DIR_BIN, BB_SUID_DROP, fdflush)) -//applet:IF_FREERAMDISK(APPLET(freeramdisk, BB_DIR_SBIN, BB_SUID_DROP)) +// APPLET_ODDNAME:name main location suid_type help +//applet:IF_FDFLUSH( APPLET_ODDNAME(fdflush, freeramdisk, BB_DIR_BIN, BB_SUID_DROP, fdflush )) +//applet:IF_FREERAMDISK(APPLET_NOEXEC(freeramdisk, freeramdisk, BB_DIR_SBIN, BB_SUID_DROP, freeramdisk)) //kbuild:lib-$(CONFIG_FDFLUSH) += freeramdisk.o //kbuild:lib-$(CONFIG_FREERAMDISK) += freeramdisk.o -- cgit v1.2.3-55-g6feb From af5d0086694b9c9b7cbf896e49e1997ec7039904 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Mon, 7 Aug 2017 23:23:18 +0200 Subject: expr: make it NOEXEC Signed-off-by: Denys Vlasenko --- NOFORK_NOEXEC.lst | 4 ++-- coreutils/expr.c | 7 +++++-- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/NOFORK_NOEXEC.lst b/NOFORK_NOEXEC.lst index fd5306317..acbe29e6f 100644 --- a/NOFORK_NOEXEC.lst +++ b/NOFORK_NOEXEC.lst @@ -108,12 +108,12 @@ dumpleases - leaks: open+xread echo - NOFORK ed - interactive, longterm egrep - longterm runner ("CMD | egrep ..." may run indefinitely, better to exec to conserve memory) -eject - leaks: open+ioctl_or_perror_and_die, changes state (moves fds) +eject - hardware, leaks: open+ioctl_or_perror_and_die, changes state (moves fds) env - noexec. spawner, changes state (env) envdir - noexec. spawner envuidgid - noexec. spawner expand - runner -expr - leaks: nested allocs +expr - noexec. leaks: nested allocs factor - runner (eats stdin if no params) fakeidentd - daemon false - NOFORK diff --git a/coreutils/expr.c b/coreutils/expr.c index a2bbfdd69..e54afbb62 100644 --- a/coreutils/expr.c +++ b/coreutils/expr.c @@ -38,7 +38,7 @@ //config: the applet slightly larger, but will allow computation with very //config: large numbers. -//applet:IF_EXPR(APPLET(expr, BB_DIR_USR_BIN, BB_SUID_DROP)) +//applet:IF_EXPR(APPLET_NOEXEC(expr, expr, BB_DIR_USR_BIN, BB_SUID_DROP, expr)) //kbuild:lib-$(CONFIG_EXPR) += expr.o @@ -118,7 +118,10 @@ struct globals { char **args; } FIX_ALIASING; #define G (*(struct globals*)bb_common_bufsiz1) -#define INIT_G() do { setup_common_bufsiz(); } while (0) +#define INIT_G() do { \ + setup_common_bufsiz(); \ + /* NB: noexec applet - globals not zeroed */ \ +} while (0) /* forward declarations */ static VALUE *eval(void); -- cgit v1.2.3-55-g6feb From dbbc3f2e644c38e9b4993a674269478792195127 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Mon, 7 Aug 2017 23:30:22 +0200 Subject: dumpleases: make NOEXEC Signed-off-by: Denys Vlasenko --- NOFORK_NOEXEC.lst | 8 ++++---- networking/udhcp/dumpleases.c | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/NOFORK_NOEXEC.lst b/NOFORK_NOEXEC.lst index acbe29e6f..cd83ff1d6 100644 --- a/NOFORK_NOEXEC.lst +++ b/NOFORK_NOEXEC.lst @@ -68,7 +68,7 @@ chattr - noexec. runner chgrp - noexec. runner chmod - noexec. runner chown - noexec. runner -chpasswd - runner (list of "user:password"s from stdin) +chpasswd - longterm (list of "user:password"s from stdin) chpst - noexec. spawner chroot - noexec. spawner chrt - noexec. spawner @@ -86,7 +86,7 @@ cryptpw - noexec. changes state: with --password-fd=N, moves N to stdin cttyhack - noexec. spawner cut - noexec. runner date - noexec. nofork candidate(needs to stop messing up env, free xasprintf result, not use xfuncs after xasprintf) -dc - runner (eats stdin if no params) +dc - longterm (eats stdin if no params) dd - noexec. runner deallocvt - noexec. leaks: get_console_fd_or_die() may open a new fd, or return one of stdio fds delgroup - noexec. leaks @@ -104,7 +104,7 @@ dos2unix - noexec. runner dpkg - runner du - runner dumpkmap - noexec. leaks: get_console_fd_or_die() may open a new fd, or return one of stdio fds -dumpleases - leaks: open+xread +dumpleases - noexec. leaks: open+xread echo - NOFORK ed - interactive, longterm egrep - longterm runner ("CMD | egrep ..." may run indefinitely, better to exec to conserve memory) @@ -114,7 +114,7 @@ envdir - noexec. spawner envuidgid - noexec. spawner expand - runner expr - noexec. leaks: nested allocs -factor - runner (eats stdin if no params) +factor - longterm (eats stdin if no params) fakeidentd - daemon false - NOFORK fatattr - noexec. leaks: open+xioctl, complex diff --git a/networking/udhcp/dumpleases.c b/networking/udhcp/dumpleases.c index dce9084b3..8aafc0d57 100644 --- a/networking/udhcp/dumpleases.c +++ b/networking/udhcp/dumpleases.c @@ -2,7 +2,7 @@ /* * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ -//applet:IF_DUMPLEASES(APPLET(dumpleases, BB_DIR_USR_BIN, BB_SUID_DROP)) +//applet:IF_DUMPLEASES(APPLET_NOEXEC(dumpleases, dumpleases, BB_DIR_USR_BIN, BB_SUID_DROP, dumpleases)) //kbuild:lib-$(CONFIG_DUMPLEASES) += dumpleases.o -- cgit v1.2.3-55-g6feb From 90ad4ba9db2927d6b616993cc27274bbc17d51a9 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Tue, 8 Aug 2017 00:42:15 +0200 Subject: ipcalc,rdev: make NOEXEC Signed-off-by: Denys Vlasenko --- NOFORK_NOEXEC.lst | 23 +++++++++++++---------- networking/ipcalc.c | 2 +- util-linux/rdev.c | 2 +- 3 files changed, 15 insertions(+), 12 deletions(-) diff --git a/NOFORK_NOEXEC.lst b/NOFORK_NOEXEC.lst index cd83ff1d6..98e1bffdf 100644 --- a/NOFORK_NOEXEC.lst +++ b/NOFORK_NOEXEC.lst @@ -7,6 +7,9 @@ changes state: e.g. environment, signal handlers leaks: does not free allocated memory or opened fds alloc+xfunc: xmalloc, then xfunc - leaks memory if xfunc dies open+xfunc: opens fd, then calls xfunc - fd is leaked if xfunc dies +talks to network/serial/etc: it's not known how long the delay can be, + it's reasonable to expect it might be many seconds + (even if usually it is not), so ^C has to work runner: sometimes may run for long(ish) time, and/or works with network: ^C has to work (cat BIGFILE, chmod -R, ftpget, nc) @@ -46,7 +49,7 @@ adduser - noexec. leaks adjtimex - NOFORK ar - runner arch - NOFORK -arp - runner, needs ^C: arp -n talks to DNS servers +arp - talks to network: arp -n queries DNS arping - longterm ash - interactive, longterm awk - noexec. runner @@ -62,13 +65,13 @@ bunzip2 - runner bzcat - runner bzip2 - runner cal - runner: cal -n9999 -cat - runner -chat - needs ^C to work +cat - runner: cat HUGEFILE +chat - longterm (when used as intended - talking to modem over stdin/out) chattr - noexec. runner chgrp - noexec. runner chmod - noexec. runner chown - noexec. runner -chpasswd - longterm (list of "user:password"s from stdin) +chpasswd - longterm? (list of "user:password"s from stdin) chpst - noexec. spawner chroot - noexec. spawner chrt - noexec. spawner @@ -99,7 +102,7 @@ diff - runner dirname - NOFORK dmesg - runner dnsd - daemon -dnsdomainname - noexec. needs ^C (may talk to DNS servers, which may be down) +dnsdomainname - noexec. talks to network (may query DNS) dos2unix - noexec. runner dpkg - runner du - runner @@ -156,7 +159,7 @@ hdparm - hardware head - noexec. runner hexdump - noexec. runner hostid - NOFORK -hostname - noexec. needs ^C (may talk to DNS servers, which may be down) +hostname - noexec. talks to network (hostname -d may query DNS) httpd - daemon hush - interactive, longterm hwclock - hardware (xioctl(RTC_RD_TIME)) @@ -177,7 +180,7 @@ ionice - noexec. spawner iostat - longterm: "iostat 1" runs indefinitely ip - noexec candidate ipaddr - noexec candidate -ipcalc - noexec candidate +ipcalc - noexec. ipcalc -h talks to network ipcrm - noexec candidate ipcs - noexec candidate iplink - noexec candidate @@ -278,8 +281,8 @@ pstree - noexec pwd - NOFORK pwdx - NOFORK raidautorun - noexec. very simple. leaks: open+xioctl -rdate - needs ^C (may talk to DNS servers, which may be down) -rdev - leaks: find_block_device -> readdir+xstrdup +rdate - talks to network +rdev - noexec. leaks: find_block_device -> readdir+xstrdup readlink - NOFORK readprofile - reads /boot/System.map and /proc/profile, better to free more memory by execing? realpath - NOFORK @@ -293,7 +296,7 @@ rev - runner rm - noexec. rm -i interactive rmdir - NOFORK rmmod - noexec -route - needs ^C (may talk to DNS servers, which may be down) +route - talks to network (may query DNS to convert IPs to names) rpm - runner rpm2cpio - runner rtcwake - longterm: puts system to sleep, optimizing this for speed is pointless diff --git a/networking/ipcalc.c b/networking/ipcalc.c index 9888a6ff2..4f192e0a5 100644 --- a/networking/ipcalc.c +++ b/networking/ipcalc.c @@ -31,7 +31,7 @@ //config: Adds the options hostname, prefix and silent to the output of //config: "ipcalc". -//applet:IF_IPCALC(APPLET(ipcalc, BB_DIR_BIN, BB_SUID_DROP)) +//applet:IF_IPCALC(APPLET_NOEXEC(ipcalc, ipcalc, BB_DIR_BIN, BB_SUID_DROP, ipcalc)) //kbuild:lib-$(CONFIG_IPCALC) += ipcalc.o diff --git a/util-linux/rdev.c b/util-linux/rdev.c index 2ffe07688..7eb7413a8 100644 --- a/util-linux/rdev.c +++ b/util-linux/rdev.c @@ -14,7 +14,7 @@ //config: help //config: Print the device node associated with the filesystem mounted at '/'. -//applet:IF_RDEV(APPLET(rdev, BB_DIR_USR_SBIN, BB_SUID_DROP)) +//applet:IF_RDEV(APPLET_NOEXEC(rdev, rdev, BB_DIR_USR_SBIN, BB_SUID_DROP, rdev)) //kbuild:lib-$(CONFIG_RDEV) += rdev.o -- cgit v1.2.3-55-g6feb From 73adef14b25533b71238362da75bfb482d43d98b Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Tue, 8 Aug 2017 00:49:48 +0200 Subject: ipcalc: trim help text Signed-off-by: Denys Vlasenko --- networking/ipcalc.c | 26 +++++++------------------- 1 file changed, 7 insertions(+), 19 deletions(-) diff --git a/networking/ipcalc.c b/networking/ipcalc.c index 4f192e0a5..83937828f 100644 --- a/networking/ipcalc.c +++ b/networking/ipcalc.c @@ -39,26 +39,14 @@ //usage: "[OPTIONS] ADDRESS" //usage: IF_FEATURE_IPCALC_FANCY("[/PREFIX]") " [NETMASK]" //usage:#define ipcalc_full_usage "\n\n" -//usage: "Calculate IP network settings from a IP address\n" -//usage: IF_FEATURE_IPCALC_LONG_OPTIONS( -//usage: "\n -b,--broadcast Display calculated broadcast address" -//usage: "\n -n,--network Display calculated network address" -//usage: "\n -m,--netmask Display default netmask for IP" +//usage: "Calculate and display network settings from IP address\n" +//usage: "\n -b Broadcast address" +//usage: "\n -n Network address" +//usage: "\n -m Default netmask for IP" //usage: IF_FEATURE_IPCALC_FANCY( -//usage: "\n -p,--prefix Display the prefix for IP/NETMASK" -//usage: "\n -h,--hostname Display first resolved host name" -//usage: "\n -s,--silent Don't ever display error messages" -//usage: ) -//usage: ) -//usage: IF_NOT_FEATURE_IPCALC_LONG_OPTIONS( -//usage: "\n -b Display calculated broadcast address" -//usage: "\n -n Display calculated network address" -//usage: "\n -m Display default netmask for IP" -//usage: IF_FEATURE_IPCALC_FANCY( -//usage: "\n -p Display the prefix for IP/NETMASK" -//usage: "\n -h Display first resolved host name" -//usage: "\n -s Don't ever display error messages" -//usage: ) +//usage: "\n -p Prefix for IP/NETMASK" +//usage: "\n -h Resolved host name" +//usage: "\n -s No error messages" //usage: ) #include "libbb.h" -- cgit v1.2.3-55-g6feb From 8858a9864e1d56cfc121755d613d1292727d15f3 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Tue, 8 Aug 2017 01:21:49 +0200 Subject: libbb: rearrange NOFORK/NOEXEC code, logic is not changed Signed-off-by: Denys Vlasenko --- NOFORK_NOEXEC.lst | 4 +- libbb/vfork_daemon_rexec.c | 125 +++++++++++++++++++++++++-------------------- 2 files changed, 71 insertions(+), 58 deletions(-) diff --git a/NOFORK_NOEXEC.lst b/NOFORK_NOEXEC.lst index 98e1bffdf..bfb76a12e 100644 --- a/NOFORK_NOEXEC.lst +++ b/NOFORK_NOEXEC.lst @@ -124,7 +124,7 @@ fatattr - noexec. leaks: open+xioctl, complex fbset - hardware, leaks: open+xfunc fbsplash - runner, longterm fdflush - hardware, leaks: open+ioctl_or_perror_and_die -fdformat - hardware, needs ^C (floppy may be unresponsive), longterm +fdformat - hardware, longterm fdisk - interactive, longterm fgconsole - noexec. leaks: get_console_fd_or_die() may open a new fd, or return one of stdio fds fgrep - longterm runner ("CMD | fgrep ..." may run indefinitely, better to exec to conserve memory) @@ -413,7 +413,7 @@ wget - longterm which - NOFORK who - noexec. nofork candidate(is getutxent ok?) whoami - NOFORK -whois - needs ^C +whois - talks to network xargs - noexec. spawner xxd - noexec. runner xz - runner diff --git a/libbb/vfork_daemon_rexec.c b/libbb/vfork_daemon_rexec.c index a349459f0..c96cd61a5 100644 --- a/libbb/vfork_daemon_rexec.c +++ b/libbb/vfork_daemon_rexec.c @@ -14,61 +14,12 @@ * * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ - #include "busybox.h" /* uses applet tables */ #include "NUM_APPLETS.h" -/* This does a fork/exec in one call, using vfork(). Returns PID of new child, - * -1 for failure. Runs argv[0], searching path if that has no / in it. */ -pid_t FAST_FUNC spawn(char **argv) -{ - /* Compiler should not optimize stores here */ - volatile int failed; - pid_t pid; - - fflush_all(); - - /* Be nice to nommu machines. */ - failed = 0; - pid = vfork(); - if (pid < 0) /* error */ - return pid; - if (!pid) { /* child */ - /* This macro is ok - it doesn't do NOEXEC/NOFORK tricks */ - BB_EXECVP(argv[0], argv); - - /* We are (maybe) sharing a stack with blocked parent, - * let parent know we failed and then exit to unblock parent - * (but don't run atexit() stuff, which would screw up parent.) - */ - failed = errno; - /* mount, for example, does not want the message */ - /*bb_perror_msg("can't execute '%s'", argv[0]);*/ - _exit(111); - } - /* parent */ - /* Unfortunately, this is not reliable: according to standards - * vfork() can be equivalent to fork() and we won't see value - * of 'failed'. - * Interested party can wait on pid and learn exit code. - * If 111 - then it (most probably) failed to exec */ - if (failed) { - safe_waitpid(pid, NULL, 0); /* prevent zombie */ - errno = failed; - return -1; - } - return pid; -} - -/* Die with an error message if we can't spawn a child process. */ -pid_t FAST_FUNC xspawn(char **argv) -{ - pid_t pid = spawn(argv); - if (pid < 0) - bb_simple_perror_msg_and_die(*argv); - return pid; -} - +/* + * NOFORK support + */ #if ENABLE_FEATURE_PREFER_APPLETS \ || ENABLE_FEATURE_SH_NOFORK static jmp_buf die_jmp; @@ -127,10 +78,10 @@ int FAST_FUNC run_nofork_applet(int applet_no, char **argv) * reset the libc getopt() function, which keeps internal state. */ GETOPT_RESET(); +//? applet_long_options = NULL; +//? opt_complementary = NULL; - argc = 1; - while (argv[argc]) - argc++; + argc = string_array_len(argv); /* If xfunc "dies" in NOFORK applet, die_func longjmp's here instead */ die_func = jump; @@ -153,11 +104,16 @@ int FAST_FUNC run_nofork_applet(int applet_no, char **argv) restore_nofork_data(&old); /* Other globals can be simply reset to defaults */ GETOPT_RESET(); +//? applet_long_options = NULL; +//? opt_complementary = NULL; return rc & 0xff; /* don't confuse people with "exitcodes" >255 */ } #endif /* FEATURE_PREFER_APPLETS || FEATURE_SH_NOFORK */ +/* + * NOEXEC support + */ #if (NUM_APPLETS > 1) && (ENABLE_FEATURE_PREFER_APPLETS || ENABLE_FEATURE_SH_STANDALONE) void FAST_FUNC run_noexec_applet_and_exit(int a, const char *name, char **argv) { @@ -167,17 +123,74 @@ void FAST_FUNC run_noexec_applet_and_exit(int a, const char *name, char **argv) xfunc_error_retval = EXIT_FAILURE; die_func = NULL; GETOPT_RESET(); +//? applet_long_options = NULL; +//? opt_complementary = NULL; //TODO: think pidof, pgrep, pkill! //set_task_comm() makes our pidof find NOEXECs (e.g. "yes >/dev/null"), //but one from procps-ng-3.3.10 needs more! //Rewrite /proc/PID/cmdline? (need to save argv0 and length at init for this to work!) set_task_comm(name); - /* xfunc_error_retval and applet_name are init by: */ + /* applet_name is set by this function: */ run_applet_no_and_exit(a, name, argv); } #endif +/* + * Higher-level code, hiding optional NOFORK/NOEXEC trickery. + */ + +/* This does a fork/exec in one call, using vfork(). Returns PID of new child, + * -1 for failure. Runs argv[0], searching path if that has no / in it. */ +pid_t FAST_FUNC spawn(char **argv) +{ + /* Compiler should not optimize stores here */ + volatile int failed; + pid_t pid; + + fflush_all(); + + /* Be nice to nommu machines. */ + failed = 0; + pid = vfork(); + if (pid < 0) /* error */ + return pid; + if (!pid) { /* child */ + /* This macro is ok - it doesn't do NOEXEC/NOFORK tricks */ + BB_EXECVP(argv[0], argv); + + /* We are (maybe) sharing a stack with blocked parent, + * let parent know we failed and then exit to unblock parent + * (but don't run atexit() stuff, which would screw up parent.) + */ + failed = errno; + /* mount, for example, does not want the message */ + /*bb_perror_msg("can't execute '%s'", argv[0]);*/ + _exit(111); + } + /* parent */ + /* Unfortunately, this is not reliable: according to standards + * vfork() can be equivalent to fork() and we won't see value + * of 'failed'. + * Interested party can wait on pid and learn exit code. + * If 111 - then it (most probably) failed to exec */ + if (failed) { + safe_waitpid(pid, NULL, 0); /* prevent zombie */ + errno = failed; + return -1; + } + return pid; +} + +/* Die with an error message if we can't spawn a child process. */ +pid_t FAST_FUNC xspawn(char **argv) +{ + pid_t pid = spawn(argv); + if (pid < 0) + bb_simple_perror_msg_and_die(*argv); + return pid; +} + int FAST_FUNC spawn_and_wait(char **argv) { int rc; -- cgit v1.2.3-55-g6feb From ddd1ee44436c2ec7e0125ca128c9a148bea8a2c0 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Tue, 8 Aug 2017 14:09:23 +0200 Subject: libbb: simplify NOFORK/NOEXEC defines, move set_task_comm to libbb Signed-off-by: Denys Vlasenko --- libbb/appletlib.c | 16 ---------------- libbb/vfork_daemon_rexec.c | 33 ++++++++++++++++++++++++--------- 2 files changed, 24 insertions(+), 25 deletions(-) diff --git a/libbb/appletlib.c b/libbb/appletlib.c index 5b84920a4..cbca7ef17 100644 --- a/libbb/appletlib.c +++ b/libbb/appletlib.c @@ -34,14 +34,6 @@ # include /* for mallopt */ #endif -#include -#ifndef PR_SET_NAME -#define PR_SET_NAME 15 -#endif -#ifndef PR_GET_NAME -#define PR_GET_NAME 16 -#endif - /* Declare _main() */ #define PROTOTYPES #include "applets.h" @@ -911,14 +903,6 @@ int busybox_main(int argc UNUSED_PARAM, char **argv) } # endif -#if defined(__linux__) && (NUM_APPLETS > 1) -void FAST_FUNC set_task_comm(const char *comm) -{ - /* okay if too long (truncates) */ - prctl(PR_SET_NAME, (long)comm, 0, 0, 0); -} -#endif - # if NUM_APPLETS > 0 void FAST_FUNC run_applet_no_and_exit(int applet_no, const char *name, char **argv) { diff --git a/libbb/vfork_daemon_rexec.c b/libbb/vfork_daemon_rexec.c index c96cd61a5..e55847f93 100644 --- a/libbb/vfork_daemon_rexec.c +++ b/libbb/vfork_daemon_rexec.c @@ -14,14 +14,32 @@ * * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ +#include +#ifndef PR_SET_NAME +#define PR_SET_NAME 15 +#endif +#ifndef PR_GET_NAME +#define PR_GET_NAME 16 +#endif + #include "busybox.h" /* uses applet tables */ #include "NUM_APPLETS.h" +#define NOFORK_SUPPORT ((NUM_APPLETS > 1) && (ENABLE_FEATURE_PREFER_APPLETS || ENABLE_FEATURE_SH_NOFORK)) +#define NOEXEC_SUPPORT ((NUM_APPLETS > 1) && (ENABLE_FEATURE_PREFER_APPLETS || ENABLE_FEATURE_SH_STANDALONE)) + +#if defined(__linux__) && (NUM_APPLETS > 1) +void FAST_FUNC set_task_comm(const char *comm) +{ + /* okay if too long (truncates) */ + prctl(PR_SET_NAME, (long)comm, 0, 0, 0); +} +#endif + /* - * NOFORK support + * NOFORK/NOEXEC support */ -#if ENABLE_FEATURE_PREFER_APPLETS \ - || ENABLE_FEATURE_SH_NOFORK +#if NOFORK_SUPPORT static jmp_buf die_jmp; static void jump(void) { @@ -109,12 +127,9 @@ int FAST_FUNC run_nofork_applet(int applet_no, char **argv) return rc & 0xff; /* don't confuse people with "exitcodes" >255 */ } -#endif /* FEATURE_PREFER_APPLETS || FEATURE_SH_NOFORK */ +#endif -/* - * NOEXEC support - */ -#if (NUM_APPLETS > 1) && (ENABLE_FEATURE_PREFER_APPLETS || ENABLE_FEATURE_SH_STANDALONE) +#if NOEXEC_SUPPORT void FAST_FUNC run_noexec_applet_and_exit(int a, const char *name, char **argv) { /* reset some state and run without execing */ @@ -212,7 +227,7 @@ int FAST_FUNC spawn_and_wait(char **argv) } # endif } -#endif /* FEATURE_PREFER_APPLETS */ +#endif rc = spawn(argv); return wait4pid(rc); } -- cgit v1.2.3-55-g6feb From 00677b5e35dd97f415f0b0bef25b55865f55ab33 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Tue, 8 Aug 2017 14:59:35 +0200 Subject: *: fix up use of "getopt_longopts" for longopts not in getopt applet Signed-off-by: Denys Vlasenko --- miscutils/conspy.c | 4 ++-- util-linux/flock.c | 4 ++-- util-linux/fstrim.c | 4 ++-- util-linux/script.c | 4 ++-- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/miscutils/conspy.c b/miscutils/conspy.c index 47b9e7207..22b29cbf3 100644 --- a/miscutils/conspy.c +++ b/miscutils/conspy.c @@ -367,7 +367,7 @@ int conspy_main(int argc UNUSED_PARAM, char **argv) unsigned ttynum; int poll_timeout_ms; #if ENABLE_LONG_OPTS - static const char getopt_longopts[] ALIGN1 = + static const char conspy_longopts[] ALIGN1 = "viewonly\0" No_argument "v" "createdevice\0" No_argument "c" "neverquit\0" No_argument "Q" @@ -378,7 +378,7 @@ int conspy_main(int argc UNUSED_PARAM, char **argv) "framebuffer\0" No_argument "F" ; - applet_long_options = getopt_longopts; + applet_long_options = conspy_longopts; #endif #define keybuf bb_common_bufsiz1 setup_common_bufsiz(); diff --git a/util-linux/flock.c b/util-linux/flock.c index ec35af18f..b55e07adb 100644 --- a/util-linux/flock.c +++ b/util-linux/flock.c @@ -38,13 +38,13 @@ int flock_main(int argc UNUSED_PARAM, char **argv) }; #if ENABLE_LONG_OPTS - static const char getopt_longopts[] ALIGN1 = + static const char flock_longopts[] ALIGN1 = "shared\0" No_argument "s" "exclusive\0" No_argument "x" "unlock\0" No_argument "u" "nonblock\0" No_argument "n" ; - applet_long_options = getopt_longopts; + applet_long_options = flock_longopts; #endif opt_complementary = "-1"; diff --git a/util-linux/fstrim.c b/util-linux/fstrim.c index 49b3ceb72..1fbf0c857 100644 --- a/util-linux/fstrim.c +++ b/util-linux/fstrim.c @@ -63,13 +63,13 @@ int fstrim_main(int argc UNUSED_PARAM, char **argv) }; #if ENABLE_LONG_OPTS - static const char getopt_longopts[] ALIGN1 = + static const char fstrim_longopts[] ALIGN1 = "offset\0" Required_argument "o" "length\0" Required_argument "l" "minimum\0" Required_argument "m" "verbose\0" No_argument "v" ; - applet_long_options = getopt_longopts; + applet_long_options = fstrim_longopts; #endif opt_complementary = "=1"; /* exactly one non-option arg: the mountpoint */ diff --git a/util-linux/script.c b/util-linux/script.c index 89b439163..4cb9842a0 100644 --- a/util-linux/script.c +++ b/util-linux/script.c @@ -71,7 +71,7 @@ int script_main(int argc UNUSED_PARAM, char **argv) }; #if ENABLE_LONG_OPTS - static const char getopt_longopts[] ALIGN1 = + static const char script_longopts[] ALIGN1 = "append\0" No_argument "a" "command\0" Required_argument "c" "flush\0" No_argument "f" @@ -79,7 +79,7 @@ int script_main(int argc UNUSED_PARAM, char **argv) "timing\0" Optional_argument "t" ; - applet_long_options = getopt_longopts; + applet_long_options = script_longopts; #endif opt_complementary = "?1"; /* max one arg */ -- cgit v1.2.3-55-g6feb From 036585a911a5fe6c2cd77b808dd9150500f37272 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Tue, 8 Aug 2017 16:38:18 +0200 Subject: getopt32: remove applet_long_options FEATURE_GETOPT_LONG made dependent on LONG_OPTS. The folloving options are removed, now LONG_OPTS enables long options for affected applets: FEATURE_ENV_LONG_OPTIONS FEATURE_EXPAND_LONG_OPTIONS FEATURE_UNEXPAND_LONG_OPTIONS FEATURE_MKDIR_LONG_OPTIONS FEATURE_MV_LONG_OPTIONS FEATURE_RMDIR_LONG_OPTIONS FEATURE_ADDGROUP_LONG_OPTIONS FEATURE_ADDUSER_LONG_OPTIONS FEATURE_HWCLOCK_LONG_OPTIONS FEATURE_NSENTER_LONG_OPTS FEATURE_CHCON_LONG_OPTIONS FEATURE_RUNCON_LONG_OPTIONS They either had a small number of long options, or their long options are essential. Example: upstream addgroup and adduser have ONLY longopts, we should probably go further and get rid of non-standard short options. To this end, make addgroup and adduser "select LONG_OPTS". We had this breakage caused by us even in our own package! #if ENABLE_LONG_OPTS || !ENABLE_ADDGROUP /* We try to use --gid, not -g, because "standard" addgroup * has no short option -g, it has only long --gid. */ argv[1] = (char*)"--gid"; #else /* Breaks if system in fact does NOT use busybox addgroup */ argv[1] = (char*)"-g"; #endif xargs: its lone longopt no longer depends on DESKTOP, only on LONG_OPTS. hwclock TODO: get rid of incompatible -t, -l aliases to --systz, --localtime Shorten help texts by omitting long option when short opt alternative exists. Reduction of size comes from the fact that store of an immediate (an address of longopts) to a fixed address (global variable) is a longer insn than pushing that immediate or passing it in a register. This effect is CPU-agnostic. function old new delta getopt32 1350 22 -1328 vgetopt32 - 1318 +1318 getopt32long - 24 +24 tftpd_main 562 567 +5 scan_recursive 376 380 +4 collect_cpu 545 546 +1 date_main 1096 1095 -1 hostname_main 262 259 -3 uname_main 259 255 -4 setpriv_main 362 358 -4 rmdir_main 191 187 -4 mv_main 562 558 -4 ipcalc_main 548 544 -4 ifenslave_main 641 637 -4 gzip_main 192 188 -4 gunzip_main 77 73 -4 fsfreeze_main 81 77 -4 flock_main 318 314 -4 deluser_main 337 333 -4 cp_main 374 370 -4 chown_main 175 171 -4 applet_long_options 4 - -4 xargs_main 894 889 -5 wget_main 2540 2535 -5 udhcpc_main 2767 2762 -5 touch_main 436 431 -5 tar_main 1014 1009 -5 start_stop_daemon_main 1033 1028 -5 sed_main 682 677 -5 script_main 1082 1077 -5 run_parts_main 330 325 -5 rtcwake_main 459 454 -5 od_main 2169 2164 -5 nl_main 201 196 -5 modprobe_main 773 768 -5 mkdir_main 160 155 -5 ls_main 568 563 -5 install_main 773 768 -5 hwclock_main 411 406 -5 getopt_main 622 617 -5 fstrim_main 256 251 -5 env_main 198 193 -5 dumpleases_main 635 630 -5 dpkg_main 3991 3986 -5 diff_main 1355 1350 -5 cryptpw_main 233 228 -5 cpio_main 593 588 -5 conspy_main 1135 1130 -5 chpasswd_main 313 308 -5 adduser_main 887 882 -5 addgroup_main 416 411 -5 ftpgetput_main 351 345 -6 get_terminal_width_height 242 234 -8 expand_main 690 680 -10 static.expand_longopts 18 - -18 static.unexpand_longopts 27 - -27 mkdir_longopts 28 - -28 env_longopts 30 - -30 static.ifenslave_longopts 34 - -34 mv_longopts 46 - -46 static.rmdir_longopts 48 - -48 packed_usage 31739 31687 -52 ------------------------------------------------------------------------------ (add/remove: 2/8 grow/shrink: 3/49 up/down: 1352/-1840) Total: -488 bytes text data bss dec hex filename 915681 485 6880 923046 e15a6 busybox_old 915428 485 6876 922789 e14a5 busybox_unstripped Signed-off-by: Denys Vlasenko --- archival/bbunzip.c | 5 +-- archival/cpio.c | 7 ++-- archival/dpkg.c | 3 +- archival/gzip.c | 7 ++-- archival/tar.c | 11 ++++--- coreutils/chown.c | 7 ++-- coreutils/cp.c | 7 ++-- coreutils/date.c | 5 ++- coreutils/env.c | 21 +++--------- coreutils/expand.c | 53 +++++++----------------------- coreutils/install.c | 18 +++++++---- coreutils/ls.c | 3 +- coreutils/mkdir.c | 33 +++++++------------ coreutils/mv.c | 38 +++++++--------------- coreutils/nl.c | 5 ++- coreutils/nproc.c | 1 - coreutils/od_bloaty.c | 7 ++-- coreutils/rmdir.c | 27 ++++------------ coreutils/touch.c | 13 +++++--- coreutils/uname.c | 3 +- debianutils/run_parts.c | 14 ++++---- debianutils/start_stop_daemon.c | 12 ++++--- editors/diff.c | 10 +++--- editors/patch_bbox.c | 3 +- editors/sed.c | 8 ++--- findutils/xargs.c | 9 ++---- include/libbb.h | 25 +++++++++------ libbb/getopt32.c | 71 ++++++++++++++++++++++++++--------------- libbb/vfork_daemon_rexec.c | 17 +++++----- loginutils/addgroup.c | 14 ++------ loginutils/adduser.c | 25 +++------------ loginutils/chpasswd.c | 3 +- loginutils/cryptpw.c | 4 +-- loginutils/deluser.c | 5 ++- miscutils/conspy.c | 4 +-- miscutils/nandwrite.c | 8 ++--- modutils/modprobe.c | 3 +- networking/ftpgetput.c | 10 +++--- networking/hostname.c | 12 +++---- networking/ifenslave.c | 14 +++----- networking/ipcalc.c | 10 +++--- networking/udhcp/d6_dhcpc.c | 4 +-- networking/udhcp/dhcpc.c | 4 +-- networking/udhcp/dumpleases.c | 3 +- networking/wget.c | 9 ++++-- selinux/chcon.c | 41 +++++++----------------- selinux/runcon.c | 22 ++----------- util-linux/flock.c | 3 +- util-linux/fsfreeze.c | 9 +++--- util-linux/fstrim.c | 3 +- util-linux/getopt.c | 22 ++----------- util-linux/hwclock.c | 28 ++++++++-------- util-linux/nsenter.c | 35 ++++---------------- util-linux/rtcwake.c | 4 +-- util-linux/script.c | 4 +-- util-linux/setpriv.c | 9 ++++-- util-linux/unshare.c | 3 +- 57 files changed, 299 insertions(+), 459 deletions(-) diff --git a/archival/bbunzip.c b/archival/bbunzip.c index 9b9fdc87b..20ab893da 100644 --- a/archival/bbunzip.c +++ b/archival/bbunzip.c @@ -389,9 +389,10 @@ int gunzip_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; int gunzip_main(int argc UNUSED_PARAM, char **argv) { #if ENABLE_FEATURE_GUNZIP_LONG_OPTIONS - applet_long_options = gunzip_longopts; -#endif + getopt32long(argv, "cfkvqdtn", gunzip_longopts); +#else getopt32(argv, "cfkvqdtn"); +#endif argv += optind; /* If called as zcat... diff --git a/archival/cpio.c b/archival/cpio.c index 38bab8257..f2165be3a 100644 --- a/archival/cpio.c +++ b/archival/cpio.c @@ -360,9 +360,8 @@ int cpio_main(int argc UNUSED_PARAM, char **argv) char *cpio_owner; IF_FEATURE_CPIO_O(const char *cpio_fmt = "";) unsigned opt; - #if ENABLE_LONG_OPTS - applet_long_options = + const char *long_opts = "extract\0" No_argument "i" "list\0" No_argument "t" #if ENABLE_FEATURE_CPIO_O @@ -390,9 +389,9 @@ int cpio_main(int argc UNUSED_PARAM, char **argv) /* -L makes sense only with -o or -p */ #if !ENABLE_FEATURE_CPIO_O - opt = getopt32(argv, OPTION_STR, &cpio_filename, &cpio_owner); + opt = getopt32long(argv, OPTION_STR, long_opts, &cpio_filename, &cpio_owner); #else - opt = getopt32(argv, OPTION_STR "oH:" IF_FEATURE_CPIO_P("p"), + opt = getopt32long(argv, OPTION_STR "oH:" IF_FEATURE_CPIO_P("p"), long_opts, &cpio_filename, &cpio_owner, &cpio_fmt); #endif argv += optind; diff --git a/archival/dpkg.c b/archival/dpkg.c index 90ad8766c..852e0cac2 100644 --- a/archival/dpkg.c +++ b/archival/dpkg.c @@ -1766,8 +1766,7 @@ int dpkg_main(int argc UNUSED_PARAM, char **argv) INIT_G(); - IF_LONG_OPTS(applet_long_options = dpkg_longopts); - opt = getopt32(argv, "CilPruF:", &str_f); + opt = getopt32long(argv, "CilPruF:", dpkg_longopts, &str_f); argv += optind; //if (opt & OPT_configure) ... // -C if (opt & OPT_force) { // -F (--force in official dpkg) diff --git a/archival/gzip.c b/archival/gzip.c index 4cf34ac28..9c53895e9 100644 --- a/archival/gzip.c +++ b/archival/gzip.c @@ -2216,11 +2216,12 @@ int gzip_main(int argc UNUSED_PARAM, char **argv) SET_PTR_TO_GLOBALS((char *)xzalloc(sizeof(struct globals)+sizeof(struct globals2)) + sizeof(struct globals)); -#if ENABLE_FEATURE_GZIP_LONG_OPTIONS - applet_long_options = gzip_longopts; -#endif /* Must match bbunzip's constants OPT_STDOUT, OPT_FORCE! */ +#if ENABLE_FEATURE_GZIP_LONG_OPTIONS + opt = getopt32long(argv, "cfkv" IF_FEATURE_GZIP_DECOMPRESS("dt") "qn123456789", gzip_longopts); +#else opt = getopt32(argv, "cfkv" IF_FEATURE_GZIP_DECOMPRESS("dt") "qn123456789"); +#endif #if ENABLE_FEATURE_GZIP_DECOMPRESS /* gunzip_main may not be visible... */ if (opt & 0x30) // -d and/or -t return gunzip_main(argc, argv); diff --git a/archival/tar.c b/archival/tar.c index f62b33005..44ab246c0 100644 --- a/archival/tar.c +++ b/archival/tar.c @@ -940,6 +940,11 @@ static const char tar_longopts[] ALIGN1 = "exclude\0" Required_argument "\xff" # endif ; +# define GETOPT32 getopt32long +# define LONGOPTS ,tar_longopts +#else +# define GETOPT32 getopt32 +# define LONGOPTS #endif int tar_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; @@ -980,9 +985,6 @@ int tar_main(int argc UNUSED_PARAM, char **argv) ":\xf9+" // --strip-components=NUM #endif ; -#if ENABLE_FEATURE_TAR_LONG_OPTIONS - applet_long_options = tar_longopts; -#endif #if ENABLE_DESKTOP /* Lie to buildroot when it starts asking stupid questions. */ if (argv[1] && strcmp(argv[1], "--version") == 0) { @@ -1019,7 +1021,7 @@ int tar_main(int argc UNUSED_PARAM, char **argv) } } #endif - opt = getopt32(argv, + opt = GETOPT32(argv, "txC:f:Oopvk" IF_FEATURE_TAR_CREATE( "ch" ) IF_FEATURE_SEAMLESS_BZ2( "j" ) @@ -1030,6 +1032,7 @@ int tar_main(int argc UNUSED_PARAM, char **argv) IF_FEATURE_SEAMLESS_Z( "Z" ) IF_FEATURE_TAR_NOPRESERVE_TIME("m") IF_FEATURE_TAR_LONG_OPTIONS("\xf9:") // --strip-components + LONGOPTS , &base_dir // -C dir , &tar_filename // -f filename IF_FEATURE_TAR_FROM(, &(tar_handle->accept)) // T diff --git a/coreutils/chown.c b/coreutils/chown.c index 1bfc725cc..0c77529ec 100644 --- a/coreutils/chown.c +++ b/coreutils/chown.c @@ -127,11 +127,12 @@ int chown_main(int argc UNUSED_PARAM, char **argv) int opt, flags; struct param_t param; -#if ENABLE_FEATURE_CHOWN_LONG_OPTIONS - applet_long_options = chown_longopts; -#endif opt_complementary = "-2"; +#if ENABLE_FEATURE_CHOWN_LONG_OPTIONS + opt = getopt32long(argv, OPT_STR, chown_longopts); +#else opt = getopt32(argv, OPT_STR); +#endif argv += optind; /* This matches coreutils behavior (almost - see below) */ diff --git a/coreutils/cp.c b/coreutils/cp.c index 092e39583..fe408950a 100644 --- a/coreutils/cp.c +++ b/coreutils/cp.c @@ -81,7 +81,7 @@ int cp_main(int argc, char **argv) // -a = -pdR opt_complementary = "-2:l--s:s--l:Pd:rRd:Rd:apdR"; #if ENABLE_FEATURE_CP_LONG_OPTIONS - applet_long_options = + flags = getopt32long(argv, FILEUTILS_CP_OPTSTR, "archive\0" No_argument "a" "force\0" No_argument "f" "interactive\0" No_argument "i" @@ -94,9 +94,10 @@ int cp_main(int argc, char **argv) "update\0" No_argument "u" "remove-destination\0" No_argument "\xff" "parents\0" No_argument "\xfe" - ; -#endif + ); +#else flags = getopt32(argv, FILEUTILS_CP_OPTSTR); +#endif /* Options of cp from GNU coreutils 6.10: * -a, --archive * -f, --force diff --git a/coreutils/date.c b/coreutils/date.c index 5a4ad5fe5..33f210434 100644 --- a/coreutils/date.c +++ b/coreutils/date.c @@ -194,9 +194,8 @@ int date_main(int argc UNUSED_PARAM, char **argv) opt_complementary = "d--s:s--d" IF_FEATURE_DATE_ISOFMT(":R--I:I--R"); - IF_LONG_OPTS(applet_long_options = date_longopts;) - opt = getopt32(argv, "Rs:ud:r:" - IF_FEATURE_DATE_ISOFMT("I::D:"), + opt = getopt32long(argv, "Rs:ud:r:" + IF_FEATURE_DATE_ISOFMT("I::D:"), date_longopts, &date_str, &date_str, &filename IF_FEATURE_DATE_ISOFMT(, &isofmt_arg, &fmt_str2dt)); argv += optind; diff --git a/coreutils/env.c b/coreutils/env.c index 3242446f5..20453e871 100644 --- a/coreutils/env.c +++ b/coreutils/env.c @@ -30,11 +30,6 @@ //config: env is used to set an environment variable and run //config: a command; without options it displays the current //config: environment. -//config: -//config:config FEATURE_ENV_LONG_OPTIONS -//config: bool "Enable long options" -//config: default y -//config: depends on ENV && LONG_OPTS //applet:IF_ENV(APPLET_NOEXEC(env, env, BB_DIR_USR_BIN, BB_SUID_DROP, env)) @@ -53,23 +48,17 @@ #include "libbb.h" -#if ENABLE_FEATURE_ENV_LONG_OPTIONS -static const char env_longopts[] ALIGN1 = - "ignore-environment\0" No_argument "i" - "unset\0" Required_argument "u" - ; -#endif - int env_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; int env_main(int argc UNUSED_PARAM, char **argv) { unsigned opts; llist_t *unset_env = NULL; -#if ENABLE_FEATURE_ENV_LONG_OPTIONS - applet_long_options = env_longopts; -#endif - opts = getopt32(argv, "+iu:+", &unset_env); + opts = getopt32long(argv, "+iu:+", + "ignore-environment\0" No_argument "i" + "unset\0" Required_argument "u" + , &unset_env + ); argv += optind; if (argv[0] && LONE_DASH(argv[0])) { opts |= 1; diff --git a/coreutils/expand.c b/coreutils/expand.c index 64f2a539d..fa3ff18f4 100644 --- a/coreutils/expand.c +++ b/coreutils/expand.c @@ -26,21 +26,11 @@ //config: help //config: By default, convert all tabs to spaces. //config: -//config:config FEATURE_EXPAND_LONG_OPTIONS -//config: bool "Enable long options" -//config: default y -//config: depends on EXPAND && LONG_OPTS -//config: //config:config UNEXPAND //config: bool "unexpand (6 kb)" //config: default y //config: help //config: By default, convert only leading sequences of blanks to tabs. -//config: -//config:config FEATURE_UNEXPAND_LONG_OPTIONS -//config: bool "Enable long options" -//config: default y -//config: depends on UNEXPAND && LONG_OPTS //applet:IF_EXPAND(APPLET(expand, BB_DIR_USR_BIN, BB_SUID_DROP)) // APPLET_ODDNAME:name main location suid_type help @@ -53,29 +43,16 @@ //usage: "[-i] [-t N] [FILE]..." //usage:#define expand_full_usage "\n\n" //usage: "Convert tabs to spaces, writing to stdout\n" -//usage: IF_FEATURE_EXPAND_LONG_OPTIONS( -//usage: "\n -i,--initial Don't convert tabs after non blanks" -//usage: "\n -t,--tabs N Tabstops every N chars" -//usage: ) -//usage: IF_NOT_FEATURE_EXPAND_LONG_OPTIONS( //usage: "\n -i Don't convert tabs after non blanks" //usage: "\n -t Tabstops every N chars" -//usage: ) //usage:#define unexpand_trivial_usage //usage: "[-fa][-t N] [FILE]..." //usage:#define unexpand_full_usage "\n\n" //usage: "Convert spaces to tabs, writing to stdout\n" -//usage: IF_FEATURE_UNEXPAND_LONG_OPTIONS( -//usage: "\n -a,--all Convert all blanks" -//usage: "\n -f,--first-only Convert only leading blanks" -//usage: "\n -t,--tabs N Tabstops every N chars" -//usage: ) -//usage: IF_NOT_FEATURE_UNEXPAND_LONG_OPTIONS( //usage: "\n -a Convert all blanks" //usage: "\n -f Convert only leading blanks" //usage: "\n -t N Tabstops every N chars" -//usage: ) #include "libbb.h" #include "unicode.h" @@ -188,31 +165,23 @@ int expand_main(int argc UNUSED_PARAM, char **argv) unsigned opt; int exit_status = EXIT_SUCCESS; -#if ENABLE_FEATURE_EXPAND_LONG_OPTIONS - static const char expand_longopts[] ALIGN1 = - /* name, has_arg, val */ - "initial\0" No_argument "i" - "tabs\0" Required_argument "t" - ; -#endif -#if ENABLE_FEATURE_UNEXPAND_LONG_OPTIONS - static const char unexpand_longopts[] ALIGN1 = - /* name, has_arg, val */ - "first-only\0" No_argument "i" - "tabs\0" Required_argument "t" - "all\0" No_argument "a" - ; -#endif init_unicode(); if (ENABLE_EXPAND && (!ENABLE_UNEXPAND || applet_name[0] == 'e')) { - IF_FEATURE_EXPAND_LONG_OPTIONS(applet_long_options = expand_longopts); - opt = getopt32(argv, "it:", &opt_t); + opt = getopt32long(argv, "it:", + "initial\0" No_argument "i" + "tabs\0" Required_argument "t" + , &opt_t + ); } else { - IF_FEATURE_UNEXPAND_LONG_OPTIONS(applet_long_options = unexpand_longopts); /* -t NUM sets also -a */ opt_complementary = "ta"; - opt = getopt32(argv, "ft:a", &opt_t); + opt = getopt32long(argv, "ft:a", + "first-only\0" No_argument "i" + "tabs\0" Required_argument "t" + "all\0" No_argument "a" + , &opt_t + ); /* -f --first-only is the default */ if (!(opt & OPT_ALL)) opt |= OPT_INITIAL; } diff --git a/coreutils/install.c b/coreutils/install.c index a1342bb13..c01750f81 100644 --- a/coreutils/install.c +++ b/coreutils/install.c @@ -55,12 +55,17 @@ static const char install_longopts[] ALIGN1 = "target-directory\0" Required_argument "t" /* autofs build insists of using -b --suffix=.orig */ /* TODO? (short option for --suffix is -S) */ -#if ENABLE_SELINUX +# if ENABLE_SELINUX "context\0" Required_argument "Z" "preserve_context\0" No_argument "\xff" "preserve-context\0" No_argument "\xff" -#endif +# endif ; +# define GETOPT32 getopt32long +# define LONGOPTS install_longopts, +#else +# define GETOPT32 getopt32 +# define LONGOPTS #endif @@ -135,15 +140,14 @@ int install_main(int argc, char **argv) #endif }; -#if ENABLE_FEATURE_INSTALL_LONG_OPTIONS - applet_long_options = install_longopts; -#endif opt_complementary = "t--d:d--t:s--d:d--s" IF_FEATURE_INSTALL_LONG_OPTIONS(IF_SELINUX(":Z--\xff:\xff--Z")); /* -c exists for backwards compatibility, it's needed */ /* -b is ignored ("make a backup of each existing destination file") */ - opts = getopt32(argv, "cvb" "Ddpsg:m:o:t:" IF_SELINUX("Z:"), + opts = GETOPT32(argv, "cvb" "Ddpsg:m:o:t:" IF_SELINUX("Z:"), + LONGOPTS &gid_str, &mode_str, &uid_str, &last - IF_SELINUX(, &scontext)); + IF_SELINUX(, &scontext) + ); argc -= optind; argv += optind; diff --git a/coreutils/ls.c b/coreutils/ls.c index 0fe0345b3..0834cdc63 100644 --- a/coreutils/ls.c +++ b/coreutils/ls.c @@ -1093,7 +1093,6 @@ int ls_main(int argc UNUSED_PARAM, char **argv) #endif /* process options */ - IF_LONG_OPTS(applet_long_options = ls_longopts;) opt_complementary = /* -n and -g imply -l */ "nl:gl" @@ -1111,7 +1110,7 @@ int ls_main(int argc UNUSED_PARAM, char **argv) IF_FEATURE_LS_TIMESTAMPS(":c-u:u-c") /* mtime/atime */ /* -w NUM: */ IF_FEATURE_LS_WIDTH(":w+"); - opt = getopt32(argv, ls_options + opt = getopt32long(argv, ls_options, ls_longopts IF_FEATURE_LS_WIDTH(, /*-T*/ NULL, /*-w*/ &G_terminal_width) IF_FEATURE_LS_COLOR(, &color_opt) ); diff --git a/coreutils/mkdir.c b/coreutils/mkdir.c index 22851187c..986353dc6 100644 --- a/coreutils/mkdir.c +++ b/coreutils/mkdir.c @@ -18,11 +18,6 @@ //config: default y //config: help //config: mkdir is used to create directories with the specified names. -//config: -//config:config FEATURE_MKDIR_LONG_OPTIONS -//config: bool "Enable long options" -//config: default y -//config: depends on MKDIR && LONG_OPTS //applet:IF_MKDIR(APPLET_NOFORK(mkdir, mkdir, BB_DIR_BIN, BB_SUID_DROP, mkdir)) @@ -53,19 +48,6 @@ /* This is a NOFORK applet. Be very careful! */ -#if ENABLE_FEATURE_MKDIR_LONG_OPTIONS -static const char mkdir_longopts[] ALIGN1 = - "mode\0" Required_argument "m" - "parents\0" No_argument "p" -#if ENABLE_SELINUX - "context\0" Required_argument "Z" -#endif -#if ENABLE_FEATURE_VERBOSE - "verbose\0" No_argument "v" -#endif - ; -#endif - int mkdir_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; int mkdir_main(int argc UNUSED_PARAM, char **argv) { @@ -78,10 +60,17 @@ int mkdir_main(int argc UNUSED_PARAM, char **argv) security_context_t scontext; #endif -#if ENABLE_FEATURE_MKDIR_LONG_OPTIONS - applet_long_options = mkdir_longopts; -#endif - opt = getopt32(argv, "m:pv" IF_SELINUX("Z:"), &smode IF_SELINUX(,&scontext)); + opt = getopt32long(argv, "m:pv" IF_SELINUX("Z:"), + "mode\0" Required_argument "m" + "parents\0" No_argument "p" +# if ENABLE_SELINUX + "context\0" Required_argument "Z" +# endif +# if ENABLE_FEATURE_VERBOSE + "verbose\0" No_argument "v" +# endif + , &smode IF_SELINUX(,&scontext) + ); if (opt & 1) { mode_t mmode = bb_parse_mode(smode, 0777); if (mmode == (mode_t)-1) { diff --git a/coreutils/mv.c b/coreutils/mv.c index 147dd3bb2..7f6e9fef5 100644 --- a/coreutils/mv.c +++ b/coreutils/mv.c @@ -16,11 +16,6 @@ //config: default y //config: help //config: mv is used to move or rename files or directories. -//config: -//config:config FEATURE_MV_LONG_OPTIONS -//config: bool "Enable long options" -//config: default y -//config: depends on MV && LONG_OPTS //applet:IF_MV(APPLET(mv, BB_DIR_BIN, BB_SUID_DROP)) @@ -41,23 +36,6 @@ #include "libbb.h" #include "libcoreutils/coreutils.h" -#if ENABLE_FEATURE_MV_LONG_OPTIONS -static const char mv_longopts[] ALIGN1 = - "interactive\0" No_argument "i" - "force\0" No_argument "f" - "no-clobber\0" No_argument "n" - IF_FEATURE_VERBOSE( - "verbose\0" No_argument "v" - ) - ; -#endif - -#define OPT_FORCE (1 << 0) -#define OPT_INTERACTIVE (1 << 1) -#define OPT_NOCLOBBER (1 << 2) -#define OPT_VERBOSE ((1 << 3) * ENABLE_FEATURE_VERBOSE) - - int mv_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; int mv_main(int argc, char **argv) { @@ -69,15 +47,23 @@ int mv_main(int argc, char **argv) int status = 0; int copy_flag = 0; -#if ENABLE_FEATURE_MV_LONG_OPTIONS - applet_long_options = mv_longopts; -#endif +#define OPT_FORCE (1 << 0) +#define OPT_INTERACTIVE (1 << 1) +#define OPT_NOCLOBBER (1 << 2) +#define OPT_VERBOSE ((1 << 3) * ENABLE_FEATURE_VERBOSE) /* Need at least two arguments. * If more than one of -f, -i, -n is specified , only the final one * takes effect (it unsets previous options). */ opt_complementary = "-2:f-in:i-fn:n-fi"; - flags = getopt32(argv, "finv"); + flags = getopt32long(argv, "finv", + "interactive\0" No_argument "i" + "force\0" No_argument "f" + "no-clobber\0" No_argument "n" + IF_FEATURE_VERBOSE( + "verbose\0" No_argument "v" + ) + ); argc -= optind; argv += optind; last = argv[argc - 1]; diff --git a/coreutils/nl.c b/coreutils/nl.c index 93e78c490..c2f8b1042 100644 --- a/coreutils/nl.c +++ b/coreutils/nl.c @@ -57,14 +57,13 @@ int nl_main(int argc UNUSED_PARAM, char **argv) "starting-line-number\0"Required_argument "v" "number-width\0" Required_argument "w" ; - - applet_long_options = nl_longopts; #endif ns.width = 6; ns.start = 1; ns.inc = 1; ns.sep = "\t"; - getopt32(argv, "pw:+s:v:+i:+b:", &ns.width, &ns.sep, &ns.start, &ns.inc, &opt_b); + getopt32long(argv, "pw:+s:v:+i:+b:", nl_longopts, + &ns.width, &ns.sep, &ns.start, &ns.inc, &opt_b); ns.all = (opt_b[0] == 'a'); ns.nonempty = (opt_b[0] == 't'); ns.empty_str = xasprintf("%*s\n", ns.width + (int)strlen(ns.sep), ""); diff --git a/coreutils/nproc.c b/coreutils/nproc.c index 0ae55e70a..336b176ca 100644 --- a/coreutils/nproc.c +++ b/coreutils/nproc.c @@ -28,7 +28,6 @@ int nproc_main(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) unsigned long mask[1024]; unsigned i, count = 0; - //applet_long_options = ...; //getopt32(argv, ""); //if --all, count /sys/devices/system/cpu/cpuN dirs, else: diff --git a/coreutils/od_bloaty.c b/coreutils/od_bloaty.c index fa0196ca4..f19875c42 100644 --- a/coreutils/od_bloaty.c +++ b/coreutils/od_bloaty.c @@ -61,8 +61,8 @@ enum { OPT_traditional = (1 << 18) * ENABLE_LONG_OPTS, }; -#define OD_GETOPT32() getopt32(argv, \ - "A:N:abcdfhij:lot:*vxsS:w:+:", \ +#define OD_GETOPT32() getopt32long(argv, \ + "A:N:abcdfhij:lot:*vxsS:w:+:", od_longopts, \ /* -w with optional param */ \ /* -S was -s and also had optional parameter */ \ /* but in coreutils 6.3 it was renamed and now has */ \ @@ -1213,9 +1213,6 @@ int od_main(int argc UNUSED_PARAM, char **argv) address_pad_len_char = '7'; /* Parse command line */ -#if ENABLE_LONG_OPTS - applet_long_options = od_longopts; -#endif opt = OD_GETOPT32(); argv += optind; if (opt & OPT_A) { diff --git a/coreutils/rmdir.c b/coreutils/rmdir.c index c04ce78f8..955740494 100644 --- a/coreutils/rmdir.c +++ b/coreutils/rmdir.c @@ -11,14 +11,6 @@ //config: default y //config: help //config: rmdir is used to remove empty directories. -//config: -//config:config FEATURE_RMDIR_LONG_OPTIONS -//config: bool "Enable long options" -//config: default y -//config: depends on RMDIR && LONG_OPTS -//config: help -//config: Support long options for the rmdir applet, including -//config: --ignore-fail-on-non-empty for compatibility with GNU rmdir. //applet:IF_RMDIR(APPLET_NOFORK(rmdir, rmdir, BB_DIR_BIN, BB_SUID_DROP, rmdir)) @@ -31,12 +23,9 @@ //usage: "[OPTIONS] DIRECTORY..." //usage:#define rmdir_full_usage "\n\n" //usage: "Remove DIRECTORY if it is empty\n" -//usage: IF_FEATURE_RMDIR_LONG_OPTIONS( -//usage: "\n -p|--parents Include parents" -//usage: "\n --ignore-fail-on-non-empty" -//usage: ) -//usage: IF_NOT_FEATURE_RMDIR_LONG_OPTIONS( //usage: "\n -p Include parents" +//usage: IF_LONG_OPTS( +//usage: "\n --ignore-fail-on-non-empty" //usage: ) //usage: //usage:#define rmdir_example_usage @@ -49,7 +38,7 @@ #define PARENTS (1 << 0) #define VERBOSE ((1 << 1) * ENABLE_FEATURE_VERBOSE) -#define IGNORE_NON_EMPTY (1 << 2) +#define IGNORE_NON_EMPTY ((1 << 2) * ENABLE_LONG_OPTS) int rmdir_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; int rmdir_main(int argc UNUSED_PARAM, char **argv) @@ -58,8 +47,7 @@ int rmdir_main(int argc UNUSED_PARAM, char **argv) int flags; char *path; -#if ENABLE_FEATURE_RMDIR_LONG_OPTIONS - static const char rmdir_longopts[] ALIGN1 = + flags = getopt32long(argv, "pv", "parents\0" No_argument "p" /* Debian etch: many packages fail to be purged or installed * because they desperately want this option: */ @@ -67,10 +55,7 @@ int rmdir_main(int argc UNUSED_PARAM, char **argv) IF_FEATURE_VERBOSE( "verbose\0" No_argument "v" ) - ; - applet_long_options = rmdir_longopts; -#endif - flags = getopt32(argv, "pv"); + ); argv += optind; if (!*argv) { @@ -86,7 +71,7 @@ int rmdir_main(int argc UNUSED_PARAM, char **argv) } if (rmdir(path) < 0) { -#if ENABLE_FEATURE_RMDIR_LONG_OPTIONS +#if ENABLE_LONG_OPTS if ((flags & IGNORE_NON_EMPTY) && errno == ENOTEMPTY) break; #endif diff --git a/coreutils/touch.c b/coreutils/touch.c index 11b40d427..857761578 100644 --- a/coreutils/touch.c +++ b/coreutils/touch.c @@ -103,6 +103,11 @@ int touch_main(int argc UNUSED_PARAM, char **argv) "date\0" Required_argument "d" IF_FEATURE_TOUCH_NODEREF("no-dereference\0" No_argument "h") ; +# define GETOPT32 getopt32long +# define LONGOPTS ,touch_longopts +# else +# define GETOPT32 getopt32 +# define LONGOPTS # endif char *reference_file = NULL; char *date_str = NULL; @@ -112,17 +117,17 @@ int touch_main(int argc UNUSED_PARAM, char **argv) # define reference_file NULL # define date_str NULL # define timebuf ((struct timeval*)NULL) +# define GETOPT32 getopt32 +# define LONGOPTS #endif -#if ENABLE_FEATURE_TOUCH_SUSV3 && ENABLE_LONG_OPTS - applet_long_options = touch_longopts; -#endif /* -d and -t both set time. In coreutils, * accepted data format differs a bit between -d and -t. * We accept the same formats for both */ - opts = getopt32(argv, "c" IF_FEATURE_TOUCH_SUSV3("r:d:t:") + opts = GETOPT32(argv, "c" IF_FEATURE_TOUCH_SUSV3("r:d:t:") IF_FEATURE_TOUCH_NODEREF("h") /*ignored:*/ "fma" + LONGOPTS IF_FEATURE_TOUCH_SUSV3(, &reference_file) IF_FEATURE_TOUCH_SUSV3(, &date_str) IF_FEATURE_TOUCH_SUSV3(, &date_str) diff --git a/coreutils/uname.c b/coreutils/uname.c index be9a3f90d..bb2d1fe8d 100644 --- a/coreutils/uname.c +++ b/coreutils/uname.c @@ -147,8 +147,7 @@ int uname_main(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) "operating-system\0" No_argument "o" ; # endif - IF_LONG_OPTS(applet_long_options = uname_longopts); - toprint = getopt32(argv, options); + toprint = getopt32long(argv, options, uname_longopts); if (argv[optind]) { /* coreutils-6.9 compat */ bb_show_usage(); } diff --git a/debianutils/run_parts.c b/debianutils/run_parts.c index c6a90a486..b770383c4 100644 --- a/debianutils/run_parts.c +++ b/debianutils/run_parts.c @@ -159,10 +159,15 @@ static const char runparts_longopts[] ALIGN1 = "reverse\0" No_argument "\xf0" "test\0" No_argument "\xf1" "exit-on-error\0" No_argument "\xf2" -#if ENABLE_FEATURE_RUN_PARTS_FANCY +# if ENABLE_FEATURE_RUN_PARTS_FANCY "list\0" No_argument "\xf3" -#endif +# endif ; +# define GETOPT32 getopt32long +# define LONGOPTS ,runparts_longopts +#else +# define GETOPT32 getopt32 +# define LONGOPTS #endif int run_parts_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; @@ -175,12 +180,9 @@ int run_parts_main(int argc UNUSED_PARAM, char **argv) INIT_G(); -#if ENABLE_FEATURE_RUN_PARTS_LONG_OPTIONS - applet_long_options = runparts_longopts; -#endif /* We require exactly one argument: the directory name */ opt_complementary = "=1"; - getopt32(argv, "a:*u:", &arg_list, &umask_p); + GETOPT32(argv, "a:*u:" LONGOPTS, &arg_list, &umask_p); umask(xstrtou_range(umask_p, 8, 0, 07777)); diff --git a/debianutils/start_stop_daemon.c b/debianutils/start_stop_daemon.c index 9effdc80b..45c277a53 100644 --- a/debianutils/start_stop_daemon.c +++ b/debianutils/start_stop_daemon.c @@ -426,6 +426,11 @@ static const char start_stop_daemon_longopts[] ALIGN1 = "retry\0" Required_argument "R" # endif ; +# define GETOPT32 getopt32long +# define LONGOPTS start_stop_daemon_longopts, +#else +# define GETOPT32 getopt32 +# define LONGOPTS #endif int start_stop_daemon_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; @@ -446,10 +451,6 @@ int start_stop_daemon_main(int argc UNUSED_PARAM, char **argv) INIT_G(); -#if ENABLE_FEATURE_START_STOP_DAEMON_LONG_OPTIONS - applet_long_options = start_stop_daemon_longopts; -#endif - /* -K or -S is required; they are mutually exclusive */ /* -p is required if -m is given */ /* -xpun (at least one) is required if -K is given */ @@ -457,8 +458,9 @@ int start_stop_daemon_main(int argc UNUSED_PARAM, char **argv) /* -q turns off -v */ opt_complementary = "K:S:K--S:S--K:m?p:K?xpun:S?xa" IF_FEATURE_START_STOP_DAEMON_FANCY("q-v"); - opt = getopt32(argv, "KSbqtma:n:s:u:c:x:p:" + opt = GETOPT32(argv, "KSbqtma:n:s:u:c:x:p:" IF_FEATURE_START_STOP_DAEMON_FANCY("ovN:R:"), + LONGOPTS &startas, &cmdname, &signame, &userspec, &chuid, &execname, &pidfile IF_FEATURE_START_STOP_DAEMON_FANCY(,&opt_N) /* We accept and ignore -R / --retry */ diff --git a/editors/diff.c b/editors/diff.c index 03c13908e..d90ac8f94 100644 --- a/editors/diff.c +++ b/editors/diff.c @@ -967,6 +967,11 @@ static const char diff_longopts[] ALIGN1 = "starting-file\0" Required_argument "S" "minimal\0" No_argument "d" ; +# define GETOPT32 getopt32long +# define LONGOPTS ,diff_longopts +#else +# define GETOPT32 getopt32 +# define LONGOPTS #endif int diff_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; @@ -980,10 +985,7 @@ int diff_main(int argc UNUSED_PARAM, char **argv) /* exactly 2 params; collect multiple -L