git: f3dba162bd46 - main - init: allow to start script executions with sh -o verify
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Tue, 11 Oct 2022 07:51:54 UTC
The branch main has been updated by wma: URL: https://cgit.FreeBSD.org/src/commit/?id=f3dba162bd46cd851a5491db680c1e6292c15a39 commit f3dba162bd46cd851a5491db680c1e6292c15a39 Author: Sebastien Bini <Sebastien.BINI@stormshield.eu> AuthorDate: 2022-10-11 07:48:04 +0000 Commit: Wojciech Macek <wma@FreeBSD.org> CommitDate: 2022-10-11 07:48:04 +0000 init: allow to start script executions with sh -o verify On systems where mac_veriexec is enforced, init should run its scripts in verified mode. This relies on the verify shell option introduced by D30464. init will detect if the shell is /bin/sh, and in which case, add the verify option to the argument vector. The verify option propagates to all files sourced by the shell, ensuring a better protection than if the script was tested against an open(O_VERIFY) before running it. This security can be bypassed with the kenv which overloads the shell to use. However we feel confident that on systems running with mac_veriexec, this kenv will be blocked somehow. Also, the verify option has no effect on systems where mac_veriexec is not loaded nor enforced. Differential revision: https://reviews.freebsd.org/D34622 Reviewed by: sjg, wma --- sbin/init/init.c | 53 ++++++++++++++++++++++++++++++----------------------- 1 file changed, 30 insertions(+), 23 deletions(-) diff --git a/sbin/init/init.c b/sbin/init/init.c index cf48721faf8d..dd8800d21910 100644 --- a/sbin/init/init.c +++ b/sbin/init/init.c @@ -99,6 +99,7 @@ static const char rcsid[] = #define RESOURCE_RC "daemon" #define RESOURCE_WINDOW "default" #define RESOURCE_GETTY "default" +#define SCRIPT_ARGV_SIZE 3 /* size of argv passed to execute_script, can be increased if needed */ static void handle(sig_t, ...); static void delset(sigset_t *, ...); @@ -1044,8 +1045,9 @@ static void execute_script(char *argv[]) { struct sigaction sa; + char* sh_argv[3 + SCRIPT_ARGV_SIZE]; const char *shell, *script; - int error; + int error, sh_argv_len, i; bzero(&sa, sizeof(sa)); sigemptyset(&sa.sa_mask); @@ -1066,17 +1068,28 @@ execute_script(char *argv[]) * to sh(1). Don't complain if it fails because of * the missing execute bit. */ - script = argv[1]; + script = argv[0]; error = access(script, X_OK); if (error == 0) { - execv(script, argv + 1); + execv(script, argv); warning("can't directly exec %s: %m", script); } else if (errno != EACCES) { warning("can't access %s: %m", script); } shell = get_shell(); - execv(shell, argv); + sh_argv[0] = __DECONST(char*, shell); + sh_argv_len = 1; +#ifdef SECURE + if (strcmp(shell, _PATH_BSHELL) == 0) { + sh_argv[1] = __DECONST(char*, "-o"); + sh_argv[2] = __DECONST(char*, "verify"); + sh_argv_len = 3; + } +#endif + for (i = 0; i != SCRIPT_ARGV_SIZE; ++i) + sh_argv[i + sh_argv_len] = argv[i]; + execv(shell, sh_argv); stall("can't exec %s for %s: %m", shell, script); } @@ -1086,12 +1099,10 @@ execute_script(char *argv[]) static void replace_init(char *path) { - char *argv[3]; - char sh[] = "sh"; + char *argv[SCRIPT_ARGV_SIZE]; - argv[0] = sh; - argv[1] = path; - argv[2] = NULL; + argv[0] = path; + argv[1] = NULL; execute_script(argv); } @@ -1108,20 +1119,18 @@ run_script(const char *script) { pid_t pid, wpid; int status; - char *argv[4]; + char *argv[SCRIPT_ARGV_SIZE]; const char *shell; shell = get_shell(); if ((pid = fork()) == 0) { - char _sh[] = "sh"; - char _autoboot[] = "autoboot"; + char _autoboot[] = "autoboot"; - argv[0] = _sh; - argv[1] = __DECONST(char *, script); - argv[2] = runcom_mode == AUTOBOOT ? _autoboot : 0; - argv[3] = NULL; + argv[0] = __DECONST(char *, script); + argv[1] = runcom_mode == AUTOBOOT ? _autoboot : NULL; + argv[2] = NULL; execute_script(argv); sleep(STALL_TIMEOUT); @@ -1957,7 +1966,7 @@ runshutdown(void) int status; int shutdowntimeout; size_t len; - char *argv[4]; + char *argv[SCRIPT_ARGV_SIZE]; struct stat sb; BOOTTRACE("init(8): start rc.shutdown"); @@ -1972,16 +1981,14 @@ runshutdown(void) return 0; if ((pid = fork()) == 0) { - char _sh[] = "sh"; char _reboot[] = "reboot"; char _single[] = "single"; char _path_rundown[] = _PATH_RUNDOWN; - argv[0] = _sh; - argv[1] = _path_rundown; - argv[2] = Reboot ? _reboot : _single; - argv[3] = NULL; - + argv[0] = _path_rundown; + argv[1] = Reboot ? _reboot : _single; + argv[2] = NULL; + execute_script(argv); _exit(1); /* force single user mode */ }