new NOFORKs: pwdx,kill[all5],ttysize,realpath,readlink NOEXECs: date,resize
No binary (build failed)
—
(log yok)
| @@ -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 | |
| @@ -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 | |
| @@ -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) | |
| { | |
| @@ -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); | |
| } | |
| @@ -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); | |
| @@ -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. | |
| @@ -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; | |
| } | |
| @@ -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(); | |
| @@ -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 | |
| @@ -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 ' -<process group>' by shell (note space!) | |
| * This is needed to avoid collision with kill -9 ... syntax | |
| @@ -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)); | |