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 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, 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 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 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 acpid - daemon add-shell addgroup adduser adjtimex ar - runner arch - NOFORK arp - complex, rare arping - runner ash - interactive, longterm awk - noexec. runner base64 - runner basename - NOFORK beep blkdiscard blkid blockdev - noexec. leaks fd bootchartd - daemon brctl bunzip2 - runner busybox bzcat - runner bzip2 - runner cal - runner: cal -n9999 cat - runner chat - needs ^C to work chattr - noexec. runner chgrp - noexec. runner chmod - noexec. runner chown - noexec. runner chpasswd - runner (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 - 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 depmod - complex, rare devmem - runner, complex (access to device memory may hang) df - leaks: nested allocs dhcprelay - daemon diff - runner dirname - NOFORK dmesg - runner dnsd - daemon dnsdomainname - needs ^C (may talk to DNS servers, which may be down) 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 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. spawner, changes state (env) envdir - noexec. spawner envuidgid - noexec. spawner expand - runner expr - leaks: nested allocs factor - runner (eats stdin if no params) fakeidentd - daemon false - NOFORK 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 fdformat - needs ^C (floppy may be unresponsive), longterm, rare 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 flash_lock flash_unlock flashcp 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 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 - complex, rare 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 id - noexec ifconfig - leaks: xsocket+ioctl_or_perror_and_die ifenslave - leaks: xsocket+bb_perror_msg_and_die ifplugd - daemon inetd - daemon init - daemon inotifyd - daemon insmod - noexec install - runner ionice - noexec. spawner iostat - runner 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 - 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 - 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 makemime - runner man - spawner, interactive, longterm md5sum - noexec. runner mdev - daemon mesg - NOFORK microcom - interactive, longterm 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 - rare mv - noexec candidate, runner nameif - noexec. openlog(), leaks: config_open2+ioctl_or_perror_and_die nbd-client nc - runner netstat - runner with -c nice - noexec. spawner nl - runner nmeter - longterm nohup - noexec. spawner nproc - NOFORK ntpd - daemon 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 - 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 - longterm pivot_root - NOFORK pkill - nofork candidate(xregcomp, procps_scan - are they ok?) pmap - noexec candidate, leaks: open+xstrdup popmaildir - runner poweroff - rare powertop - interactive, longterm printenv - NOFORK printf - NOFORK ps - looks for AT_CLKTCK elf aux vector, therefore can't be noexec pscan - longterm pstree - noexec pwd - NOFORK pwdx - NOFORK raidautorun rdate - needs ^C (may talk to DNS servers, which may be down) rdev - leaks: find_block_device -> readdir+xstrdup readlink - NOFORK readprofile realpath - NOFORK reboot - rare reformime - runner remove-shell renice - nofork candidate(uses getpwnam, is that ok?) reset - noexec. spawner (execs "stty") resize - noexec. changes state (signal handlers) rev - runner rm - noexec. rm -i interactive rmdir - NOFORK rmmod - noexec 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 runlevel - noexec. can be nofork if "endutxent()" is called unconditionally, but too rare to bother? runsv - daemon runsvdir - daemon rx - runner script scriptreplay sed - runner sendmail - runner seq - noexec. runner setarch - noexec. spawner setconsole - 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 - runner, longterm smemcap - runner softlimit - noexec. spawner sort - noexec. runner split - runner 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 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 - rare 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, runner traceroute6 - suid, runner true - NOFORK truncate - NOFORK tty - NOFORK ttysize - NOFORK tunctl - noexec tune2fs - noexec. leaks: open+xfunc ubiattach ubidetach ubimkvol ubirename ubirmvol ubirsvol ubiupdatevol 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 - nofork candidate(is getutxent ok?) users - nofork candidate(is getutxent ok?) usleep - NOFORK uudecode - runner uuencode - runner vconfig - leaks: xsocket+ioctl_or_perror_and_die vi - interactive, longterm vlock - suid volname - runner w - nofork candidate(is getutxent ok?) wall - suid watch - longterm watchdog - daemon wc - runner wget - longterm which - NOFORK who - nofork candidate(is getutxent ok?) whoami - NOFORK whois - needs ^C xargs - noexec. spawner xxd - noexec. runner xz - runner xzcat - runner yes - noexec. runner zcat - runner zcip - daemon