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 */
}