| 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 state and execs - must fork |
| 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) |
| |
| "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, |
| 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) |
| daemon: runs indefinitely; these are also always fit "rare" category |
| 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); |
| 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 |
| 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". |
| |
| Interesting example of an applet which can be NOFORK but if not, |
| then should not be NOEXEC, is "usleep". As NOFORK, it amount to simply |
| nanosleep()ing in the calling program (usually shell). No memory wasted. |
| But if ran as NOEXEC, it would create a potentially long-term process, |
| which would be taking more memory because it did not exec |
| and did not free much of the copied memory of the parent |
| (COW helps with this only as long as parent doesn't modify its memory). |
| |
| |
| [ - NOFORK |
| [[ - NOFORK |
| acpid - daemon |
| add-shell - noexec. leaks: open+xfunc |
| addgroup - noexec. leaks |
| adduser - noexec. leaks |
| adjtimex - NOFORK |
| ar - runner |
| arch - NOFORK |
| arp - talks to network: arp -n queries DNS |
| arping - longterm |
| ash - interactive, longterm |
| awk - noexec. runner |
| base64 - runner |
| basename - NOFORK |
| beep - longterm: beep -r 999999999 |
| blkdiscard - noexec. leaks: open+xioctl |
| blkid - noexec |
| blockdev - noexec. leaks fd |
| bootchartd - daemon |
| brctl - noexec |
| bunzip2 - runner |
| bzcat - runner |
| bzip2 - runner |
| cal - runner: cal -n9999 |
| 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) |
| chpst - noexec. spawner |
| chroot - noexec. spawner |
| chrt - noexec. spawner |
| 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 |
| comm - runner |
| conspy - interactive, longterm |
| cp - noexec. runner |
| cpio - runner |
| crond - daemon |
| 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 |
| date - noexec. nofork candidate(needs to stop messing up env, free xasprintf result, not use xfuncs after xasprintf) |
| 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 |
| deluser - noexec. leaks |
| depmod - longterm(ish) |
| devmem - hardware (access to device memory may hang) |
| df - noexec. leaks: nested allocs |
| dhcprelay - daemon |
| diff - runner |
| dirname - NOFORK |
| dmesg - runner |
| dnsd - daemon |
| dnsdomainname - noexec. talks to network (may query DNS) |
| 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 - noexec. leaks: open+xread |
| echo - NOFORK |
| ed - interactive, longterm |
| egrep - longterm runner ("CMD | egrep ..." may run indefinitely, better to exec to conserve memory) |
| 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 - noexec. leaks: nested allocs |
| factor - longterm (eats stdin if no params) |
| fakeidentd - daemon |
| false - NOFORK |
| 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, 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 - 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 |
| freeramdisk - noexec. leaks: open+ioctl_or_perror_and_die |
| fsck - interactive, longterm |
| fsck.minix - needs ^C |
| fsfreeze - noexec. leaks: open+xioctl |
| fstrim - noexec. leaks: open+xioctl, find_block_device -> readdir+xstrdup |
| fsync - NOFORK |
| ftpd - daemon |
| ftpget - runner |
| ftpput - runner |
| fuser - complex |
| getopt - noexec. leaks: many allocs |
| getty - interactive, longterm |
| grep - longterm runner ("CMD | grep ..." may run indefinitely, better to exec to conserve memory) |
| groups - noexec |
| gunzip - runner |
| gzip - runner |
| halt - rare |
| hd - noexec. runner |
| hdparm - hardware |
| head - noexec. runner |
| hexdump - noexec. runner |
| hexedit - interactive, longterm |
| hostid - NOFORK |
| hostname - noexec. talks to network (hostname -d may query DNS) |
| httpd - daemon |
| hush - interactive, longterm |
| hwclock - hardware (xioctl(RTC_RD_TIME)) |
| i2cdetect - hardware |
| i2cdump - hardware |
| i2cget - hardware |
| i2cset - hardware |
| id - noexec |
| 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 |
| inotifyd - daemon |
| insmod - noexec |
| install - runner |
| ionice - noexec. spawner |
| iostat - longterm: "iostat 1" runs indefinitely |
| ip - noexec |
| ipaddr - noexec |
| ipcalc - noexec. ipcalc -h talks to network |
| ipcrm - noexec |
| ipcs - noexec |
| iplink - noexec |
| ipneigh - noexec |
| iproute - noexec |
| iprule - noexec |
| iptunnel - noexec |
| kbd_mode - noexec. leaks: xopen_nonblocking+xioctl |
| kill - NOFORK |
| killall - NOFORK |
| killall5 - NOFORK |
| klogd - daemon |
| last - runner (I've got 1300 lines of output when tried it) |
| less - interactive, longterm |
| link - NOFORK |
| linux32 - noexec. spawner |
| linux64 - noexec. spawner |
| linuxrc - daemon |
| ln - noexec |
| 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 |
| logname - NOFORK |
| losetup - noexec. complex |
| lpd - daemon |
| lpq - runner |
| lpr - runner |
| ls - noexec. runner |
| lsattr - noexec. runner |
| lsmod - noexec |
| lsof - complex |
| 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 |
| lzopcat - runner |
| makedevs - noexec |
| makemime - runner |
| man - spawner, interactive, longterm |
| md5sum - noexec. runner |
| mdev - daemon |
| mesg - NOFORK |
| microcom - interactive, longterm |
| minips - noexec |
| mkdir - NOFORK |
| mkdosfs - needs ^C |
| mke2fs - needs ^C |
| mkfifo - noexec |
| mkfs.ext2 - needs ^C |
| mkfs.minix - needs ^C |
| mkfs.vfat - needs ^C |
| mknod - noexec |
| mkpasswd - noexec. changes state: with --password-fd=N, moves N to stdin |
| mkswap - needs ^C |
| mktemp - noexec. leaks: xstrdup+concat_path_file |
| modinfo - noexec |
| modprobe - noexec |
| 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 - hardware |
| mv - noexec candidate, runner |
| nameif - noexec. openlog(), leaks: config_open2+ioctl_or_perror_and_die |
| nbd-client - noexec |
| nc - runner |
| netstat - longterm with -c (continuous listing) |
| nice - noexec. spawner |
| nl - runner |
| nmeter - longterm |
| nohup - noexec. spawner |
| nproc - NOFORK |
| ntpd - daemon |
| nuke - noexec |
| od - runner |
| openvt - longterm: spawns a child and waits for it |
| partprobe - noexec. leaks: open+ioctl_or_perror_and_die(BLKRRPART) |
| passwd - suid |
| paste - noexec. runner |
| patch - needs ^C |
| 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 - must fork+exec to get correct /proc/PID/cmdline and comm field |
| pmap - noexec candidate, leaks: open+xstrdup |
| popmaildir - runner |
| poweroff - rare |
| powertop - interactive, longterm |
| printenv - NOFORK |
| printf - NOFORK |
| ps - noexec |
| pscan - talks to network |
| pstree - noexec |
| pwd - NOFORK |
| pwdx - NOFORK |
| raidautorun - noexec. very simple. leaks: open+xioctl |
| 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 |
| reboot - rare |
| reformime - runner |
| remove-shell - noexec. leaks: open+xfunc |
| renice - noexec. nofork candidate(uses getpwnam, is that ok?) |
| reset - noexec. spawner (execs "stty") |
| resize - noexec. changes state (signal handlers) |
| resume - noexec |
| rev - runner |
| rm - noexec. rm -i interactive |
| rmdir - NOFORK |
| rmmod - noexec |
| 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 |
| run-init - spawner, rare, changes state (oh yes), execing may be important to free binary's inode |
| run-parts - longterm |
| runlevel - noexec. can be nofork if "endutxent()" is called unconditionally, but too rare to bother? |
| runsv - daemon |
| runsvdir - daemon |
| rx - runner |
| 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 |
| setarch - noexec. spawner |
| setconsole - noexec |
| setfattr - noexec |
| setfont - noexec. leaks a lot of stuff |
| setkeycodes - noexec |
| 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 |
| setuidgid - noexec. spawner |
| sha1sum - noexec. runner |
| sha256sum - noexec. runner |
| sha3sum - noexec. runner |
| sha512sum - noexec. runner |
| showkey - interactive, longterm |
| shred - runner |
| shuf - noexec. runner |
| slattach - longterm (may sleep forever), uses bb_common_bufsiz1 |
| sleep - longterm. Could be nofork, if not the problem of "killall sleep" not killing it. |
| smemcap - runner |
| softlimit - noexec. spawner |
| sort - noexec. runner |
| split - runner |
| ssl_client - longterm |
| start-stop-daemon - not noexec: uses bb_common_bufsiz1 |
| 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 |
| sulogin - noexec. spawner |
| sum - runner |
| sv - noexec. needs ^C (uses usleep(420000)) |
| svc - noexec. needs ^C (uses usleep(420000)) |
| svlogd - daemon |
| 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 |
| sysctl - noexec. leaks: xstrdup+xmalloc_read |
| syslogd - daemon |
| tac - noexec. runner |
| tail - runner |
| tar - runner |
| taskset - noexec. spawner |
| tcpsvd - daemon |
| tee - runner |
| telnet - interactive, longterm |
| telnetd - daemon |
| test - NOFORK |
| tftp - runner |
| tftpd - daemon |
| time - spawner, longterm, changes state (signals) |
| timeout - spawner, longterm, changes state (signals) |
| top - interactive, longterm |
| touch - NOFORK |
| tr - runner |
| traceroute - suid, longterm |
| traceroute6 - suid, longterm |
| true - NOFORK |
| truncate - NOFORK |
| tty - NOFORK |
| ttysize - NOFORK |
| tunctl - noexec |
| tune2fs - noexec. leaks: open+xfunc |
| ubiattach - hardware |
| ubidetach - hardware |
| ubimkvol - hardware |
| ubirename - hardware |
| ubirmvol - hardware |
| ubirsvol - hardware |
| ubiupdatevol - hardware |
| udhcpc - daemon |
| udhcpd - daemon |
| udpsvd - daemon |
| uevent - daemon |
| umount - noexec. leaks: nested xmalloc |
| uname - NOFORK |
| uncompress - runner |
| unexpand - runner |
| uniq - runner |
| unix2dos - noexec. runner |
| unlink - NOFORK |
| unlzma - runner |
| unlzop - runner |
| unxz - runner |
| unzip - runner |
| uptime - noexec. nofork candidate(is getutxent ok?) |
| users - noexec. nofork candidate(is getutxent ok?) |
| usleep - NOFORK. But what about "killall usleep"? |
| uudecode - runner |
| uuencode - runner |
| vconfig - noexec. leaks: xsocket+ioctl_or_perror_and_die |
| vi - interactive, longterm |
| vlock - suid |
| 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 |
| watchdog - daemon |
| wc - runner |
| wget - longterm |
| which - NOFORK |
| who - noexec. nofork candidate(is getutxent ok?) |
| whoami - NOFORK |
| whois - talks to network |
| xargs - noexec. spawner |
| xxd - noexec. runner |
| xz - runner |
| xzcat - runner |
| yes - noexec. runner |
| zcat - runner |
| zcip - daemon |