shell的骚操作:APPLET_IS_NOFORK

最近在调linux LSM,在do_execve中通过security hooks检查调用的程序。

发现一个神奇的现象,echo不能被do_execve截获。换句话说,执行echo "123"并没有像其他程序一样fork一个进程出来

翻了下busybox的代码,看到这么一段

	/* Execute the command. */
	switch (cmdentry.cmdtype) {
	default: {

#if ENABLE_FEATURE_SH_NOFORK
/* (1) BUG: if variables are set, we need to fork, or save/restore them
 *     around run_nofork_applet() call.
 * (2) Should this check also be done in forkshell()?
 *     (perhaps it should, so that "VAR=VAL nofork" at least avoids exec...)
 */
		/* find_command() encodes applet_no as (-2 - applet_no) */
		int applet_no = (- cmdentry.u.index - 2);
		if (applet_no >= 0 && APPLET_IS_NOFORK(applet_no)) {
			listsetvar(varlist.list, VEXPORT|VSTACK);
			/* run <applet>_main() */
			status = run_nofork_applet(applet_no, argv);
			break;
		}
#endif
30
down vote
accepted
By default, BusyBox doesn't do anything special regarding the applets that it has built in (the commands listed with busybox --help).

However, if the FEATURE_SH_STANDALONE and FEATURE_PREFER_APPLETS options are enabled at compile time, then when BusyBox sh¹ executes a command which is a known applet name, it doesn't do the normal PATH lookup, but instead runs its built-in applets through a shortcut:

Applets that are declared as “noexec” in the source code are executed as function calls in a forked process. As of BusyBox 1.22, the following applets are noexec: chgrp, chmod, chown,  cksum, cp, cut, dd, dos2unix, env, fold, hd, head, hexdump, ln, ls, md5sum, mkfifo, mknod, sha1sum, sha256sum, sha3sum, sha512sum, sort, tac, unix2dos.
Applets that are declared as “nofork” in the source code are executed as function calls in the same process. As of BusyBox 1.22, the following applets are nofork: [[, [, basename, cat,  dirname, echo, false, fsync, length, logname, mkdir, printenv, printf, pwd, rm, rmdir, seq, sync, test, true, usleep, whoami, yes.
Other applets are really executed (with fork and execve), but instead of doing a PATH lookup, BusyBox executes /proc/self/exe, if available (which is normally the case on Linux), and a path defined at compile time otherwise.
This is documented in a bit more detail in docs/nofork_noexec.txt. The applet declarations are in  include/applets.src.h in the source code.

Most default configurations turn these features off, so that BusyBox executes external commands like any other shell. Debian turns these features on in both its busybox and busybox-static packages.

So if you have a BusyBox executable compiled with FEATURE_SH_STANDALONE and FEATURE_PREFER_APPLETS, then you can execute all BusyBox commands from a BusyBox shell even if the executable is deleted (except for the applets that are not listed above, if /proc/self/exe is not available).

shell对内建的applets可以声明为APPLET_IS_NOFORK类型。这样shell在执行对应applet的时候不会fork新的进程,而是在当前上下文执行

stackexchange上也有一个很棒的回答。摘录在下面

https://unix.stackexchange.com/questions/274273/are-busybox-commands-truly-built-in

accepted

By default, BusyBox doesn't do anything special regarding the applets that it has built in (the commands listed with busybox --help).

However, if the FEATURE_SH_STANDALONE and FEATURE_PREFER_APPLETS options are enabled at compile time, then when BusyBox sh¹ executes a command which is a known applet name, it doesn't do the normal PATH lookup, but instead runs its built-in applets through a shortcut:

  • Applets that are declared as “noexec” in the source code are executed as function calls in a forked process. As of BusyBox 1.22, the following applets are noexec: chgrpchmodchowncksumcpcutdddos2unixenvfoldhdheadhexdumplnlsmd5summkfifomknodsha1sumsha256sumsha3sumsha512sumsorttacunix2dos.
  • Applets that are declared as “nofork” in the source code are executed as function calls in the same process. As of BusyBox 1.22, the following applets are nofork: [[[basenamecatdirnameechofalsefsynclengthlognamemkdirprintenvprintfpwdrmrmdirseqsynctesttrueusleepwhoamiyes.
  • Other applets are really executed (with fork and execve), but instead of doing a PATHlookup, BusyBox executes /proc/self/exe, if available (which is normally the case on Linux), and a path defined at compile time otherwise.

This is documented in a bit more detail in docs/nofork_noexec.txt. The applet declarations are in include/applets.src.h in the source code.

Most default configurations turn these features off, so that BusyBox executes external commands like any other shell. Debian turns these features on in both its busybox and busybox-staticpackages.

So if you have a BusyBox executable compiled with FEATURE_SH_STANDALONE and FEATURE_PREFER_APPLETS, then you can execute all BusyBox commands from a BusyBox shell even if the executable is deleted (except for the applets that are not listed above, if /proc/self/exe is not available).



猜你喜欢

转载自blog.csdn.net/thwack/article/details/81021900