3
0

nofork_noexec.txt 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143
  1. NOEXEC and NOFORK applets.
  2. Unix shells traditionally execute some commands internally in the attempt
  3. to dramatically speed up execution. It will be slow as hell if for every
  4. "echo blah" shell will fork and exec /bin/echo. To this end, shells
  5. have to _reimplement_ these commands internally.
  6. Busybox is unique in this regard because it already is a collection
  7. of reimplemented Unix commands, and we can do the same trick
  8. for speeding up busybox shells, and more. NOEXEC and NOFORK applets
  9. are exactly those applets which are eligible for these tricks.
  10. Applet will be subject to NOFORK/NOEXEC tricks only if it is marked
  11. as such in applets.src.h or in their inline "//applet:" directives.
  12. In C, if you want to call a program and wait for it, use
  13. spawn_and_wait(argv), BB_EXECVP(prog,argv) or BB_EXECLP(prog,argv0,...).
  14. They check whether program name is an applet name and optionally
  15. do NOFORK/NOEXEC thing depending on configuration.
  16. Relevant CONFIG options
  17. FEATURE_PREFER_APPLETS
  18. Globally enables NOFORK/NOEXEC tricks for such programs as xargs
  19. and find:
  20. BB_EXECVP(cmd, argv) will try to exec /proc/self/exe
  21. if command's name matches some applet name;
  22. spawn_and_wait(argv) will do NOFORK/NOEXEC tricks
  23. //TODO: the above two things probably should have separate options?
  24. FEATURE_SH_STANDALONE
  25. shells will try to exec /proc/self/exe if command's name matches
  26. some applet name; shells will do NOEXEC trick on NOEXEC applets
  27. //TODO: split (same as for PREFER_APPLETS)
  28. FEATURE_SH_NOFORK
  29. shells will do NOFORK trick on NOFORK applets
  30. NB: shell builtins use these tricks regardless of FEATURE_SH_STANDALONE,
  31. FEATURE_PREFER_APPLETS or FEATURE_SH_NOFORK. In effect, builtins
  32. are "always NOFORK".
  33. NOEXEC
  34. NOEXEC applet should work correctly if another applet forks and then
  35. executes exit(<applet>_main(argc,argv)) in the child. The rules
  36. roughly are:
  37. * do not expect shared global variables/buffers to be in their
  38. "initialized" state. Examples: xfunc_error_retval can be != 1,
  39. bb_common_bufsiz1 can be scribbled over, ...
  40. (although usually xfunc_error_retval's state is not a problem).
  41. * do not expect that stdio wasn't used before. Calling set[v]buf()
  42. can be disastrous.
  43. * ...
  44. NOEXEC applets save only one half of fork+exec overhead.
  45. NOEXEC trick is disabled for NOMMU build.
  46. NOFORK
  47. NOFORK applet should work correctly if another applet simply runs
  48. <applet>_main(argc,argv) and then continues with its business.
  49. xargs, find, shells do it (grep for "spawn_and_wait" and
  50. "run_nofork_applet" to find more users).
  51. This poses much more serious limitations on what applet can do:
  52. * all NOEXEC limitations apply.
  53. * do not run for a long time or wait for user input:
  54. hush shell only handles signals (like ^C) after you return
  55. from APPLET_main().
  56. * do not ever exit() or exec().
  57. - xfuncs are okay. They are using special trick to return
  58. to the caller applet instead of dying when they detect "x" condition.
  59. - you may "exit" to caller applet by calling xfunc_die(). Return value
  60. is taken from xfunc_error_retval.
  61. - fflush_stdout_and_exit(n) is ok to use.
  62. * do not use shared global data, or save/restore shared global data
  63. (e.g. bb_common_bufsiz1) prior to returning.
  64. - getopt32() is ok to use. You do not need to save/restore option_mask32,
  65. xfunc_error_retval, and logmode - it is already done by core code.
  66. * if you allocate memory, you can use xmalloc() only on the very first
  67. allocation. All other allocations should use malloc[_or_warn]().
  68. After first allocation, you cannot use any xfuncs.
  69. Otherwise, failing xfunc will return to caller applet
  70. without freeing malloced data!
  71. * the same applies to other resources, such as open fds: no xfuncs after
  72. acquiring them!
  73. * All allocated data, opened files, signal handlers, termios settings
  74. etc should be freed/closed/restored prior to return.
  75. Currently, ash shell signal handling is implemented in a way that signals
  76. have non-SA_RESTARTed handlers. This means that system calls can
  77. return EINTR. An example of such problem is "yes" applet:
  78. it is implemented so that it has a writing loop, this loop is exited on
  79. any write error, and in the case of user pressing ^C the error was EINTR.
  80. The problem is, the error causes stdout FILE* object to get into error
  81. state, needing clearerr() - or else subsequent shell output will also
  82. not work. ("yes" has been downgraded to NOEXEC, since hush signal handling
  83. does not have this problem - which makes "yes" to not exit on ^C (bug).
  84. But stray EINTRs can be seen in any NOFORK under ash, until ash is fixed).
  85. NOFORK applets give the most of speed advantage, but are trickiest
  86. to implement. In order to minimize amount of bugs and maintenance,
  87. prime candidates for NOFORK-ification are those applets which
  88. are small and easy to audit, and those which are more likely to be
  89. frequently executed from shell/find/xargs, particularly in shell
  90. script loops. Applets which mess with signal handlers, termios etc
  91. are probably not worth the effort.
  92. Applets which must be interruptible by ^C in shells can not be NOFORKs.
  93. Any NOFORK applet is also a NOEXEC applet.
  94. Calling NOFORK applets
  95. API to call NOFORK applets is two functions:
  96. run_nofork_applet(appno, argv)
  97. spawn_and_wait(argv) // only if FEATURE_PREFER_APPLETS=y
  98. First one is directly used by shells if FEATURE_SH_NOFORK=y.
  99. Second one is used by many applets, but main users are xargs and find.
  100. It itself calls run_nofork_applet(), if argv[0] is a name
  101. of a NOFORK applet.
  102. run_nofork_applet() saves/inits/restores option parsing, xfunc_error_retval,
  103. logmode, applet_name. Thus, for example, caller does not need to worry about
  104. option_mask32 getting trashed.
  105. Calling NOEXEC applets
  106. It's the same trusty spawn_and_wait(argv). If FEATURE_PREFER_APPLETS=y,
  107. it does NOEXEC trick. It resets xfunc_error_retval = 1 and
  108. logmode = LOGMODE_STDIO in the child.