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 - 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 - 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 comm - runner conspy - interactive, longterm 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. 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 - 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 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 - 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) 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 - 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 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 - 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 - 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 losetup - complex lpd - daemon lpq - runner lpr - runner ls - noexec. runner lsattr - runner. noexec candidate (ls is, why not this one?) 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 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 - 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 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 mt - rare mv - noexec candidate, runner nameif - 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 candidate? the code is trivial 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 - noexec candidate pscan - longterm pstree 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 setfont 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 setuidgid - noexec. spawner sha1sum - noexec. runner sha256sum - noexec. runner sha3sum - noexec. runner sha512sum - noexec. runner showkey - interactive, longterm shred - runner shuf - noexec. runner slattach 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 candidate, 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 tune2fs - leaks: open+xfunc ubiattach ubidetach ubimkvol ubirename ubirmvol ubirsvol ubiupdatevol udhcpc - daemon udhcpd - daemon udpsvd - daemon uevent - daemon umount - noexec candidate, 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