From owner-svn-src-all@freebsd.org Sun Apr 21 04:00:21 2019 Return-Path: Delivered-To: svn-src-all@mailman.ysv.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mailman.ysv.freebsd.org (Postfix) with ESMTP id C24DD1580987; Sun, 21 Apr 2019 04:00:20 +0000 (UTC) (envelope-from kevans@FreeBSD.org) Received: from mxrelay.nyi.freebsd.org (mxrelay.nyi.freebsd.org [IPv6:2610:1c1:1:606c::19:3]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) server-signature RSA-PSS (4096 bits) client-signature RSA-PSS (4096 bits) client-digest SHA256) (Client CN "mxrelay.nyi.freebsd.org", Issuer "Let's Encrypt Authority X3" (verified OK)) by mx1.freebsd.org (Postfix) with ESMTPS id 74D38897FC; Sun, 21 Apr 2019 04:00:20 +0000 (UTC) (envelope-from kevans@FreeBSD.org) Received: from repo.freebsd.org (repo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) by mxrelay.nyi.freebsd.org (Postfix) with ESMTPS id 4FB851FEEE; Sun, 21 Apr 2019 04:00:20 +0000 (UTC) (envelope-from kevans@FreeBSD.org) Received: from repo.freebsd.org ([127.0.1.37]) by repo.freebsd.org (8.15.2/8.15.2) with ESMTP id x3L40Kvd031628; Sun, 21 Apr 2019 04:00:20 GMT (envelope-from kevans@FreeBSD.org) Received: (from kevans@localhost) by repo.freebsd.org (8.15.2/8.15.2/Submit) id x3L40JGZ031625; Sun, 21 Apr 2019 04:00:19 GMT (envelope-from kevans@FreeBSD.org) Message-Id: <201904210400.x3L40JGZ031625@repo.freebsd.org> X-Authentication-Warning: repo.freebsd.org: kevans set sender to kevans@FreeBSD.org using -f From: Kyle Evans Date: Sun, 21 Apr 2019 04:00:19 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-11@freebsd.org Subject: svn commit: r346479 - in stable/11: sbin/init stand/man X-SVN-Group: stable-11 X-SVN-Commit-Author: kevans X-SVN-Commit-Paths: in stable/11: sbin/init stand/man X-SVN-Commit-Revision: 346479 X-SVN-Commit-Repository: base MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-Rspamd-Queue-Id: 74D38897FC X-Spamd-Bar: -- Authentication-Results: mx1.freebsd.org X-Spamd-Result: default: False [-2.96 / 15.00]; local_wl_from(0.00)[FreeBSD.org]; NEURAL_HAM_MEDIUM(-1.00)[-0.999,0]; NEURAL_HAM_SHORT(-0.96)[-0.963,0]; ASN(0.00)[asn:11403, ipnet:2610:1c1:1::/48, country:US]; NEURAL_HAM_LONG(-1.00)[-1.000,0] X-BeenThere: svn-src-all@freebsd.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: "SVN commit messages for the entire src tree \(except for " user" and " projects" \)" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Sun, 21 Apr 2019 04:00:21 -0000 Author: kevans Date: Sun Apr 21 04:00:19 2019 New Revision: 346479 URL: https://svnweb.freebsd.org/changeset/base/346479 Log: MFC r337321, r337435, r337707, r337740, r337834, r337836, r337968 r337321: Make it possible for init to execute any executable, not just sh(1) scripts. This means one should be able to eg rewrite their /etc/rc in Python. r337435: Move description of init_shell, init_script, and init_chroot kenv tunables from loader(8) to init(8), since it's init that actually uses them. Add .Xrs at their old place. r337707: Move around text in loader(8), in particular stuff related to ZFS, to restore the usual section order. r337740: Add init_exec kenv(1) variable, to make init(8) execute a file after opening the console, replacing init as PID 1. From the user point of view, it makes it possible to run eg the shell as PID 1, using 'set init_exec=/bin/sh' at the loader(8) prompt. r337834: Add SECURITY section to loader(8). r337836: Improve formatting. r337968: Consistently use NULL to terminate the argv; no functional changes. Relnotes: yes (init_exec kenv(1) variable) Modified: stable/11/sbin/init/init.8 stable/11/sbin/init/init.c stable/11/stand/man/loader.8 Directory Properties: stable/11/ (props changed) Modified: stable/11/sbin/init/init.8 ============================================================================== --- stable/11/sbin/init/init.8 Sun Apr 21 03:54:49 2019 (r346478) +++ stable/11/sbin/init/init.8 Sun Apr 21 04:00:19 2019 (r346479) @@ -31,7 +31,7 @@ .\" @(#)init.8 8.3 (Berkeley) 4/18/94 .\" $FreeBSD$ .\" -.Dd October 3, 2016 +.Dd August 15, 2018 .Dt INIT 8 .Os .Sh NAME @@ -86,6 +86,15 @@ The password check is skipped if the .Em console is marked as .Dq secure . +Note that the password check does not protect from variables +such as +.Va init_script +being set from the +.Xr loader 8 +command line; see the +.Sx SECURITY +section of +.Xr loader 8 . .Pp If the system security level (see .Xr security 7 ) @@ -293,6 +302,84 @@ as follows: .Xr ttys 5 file .El +.Sh KERNEL ENVIRONMENT VARIABLES +The following +.Xr kenv 2 +variables are available as +.Xr loader 8 +tunables: +.Bl -tag -width indent +.It Va init_chroot +If set to a valid directory in the root file system, it causes +.Nm +to perform a +.Xr chroot 2 +operation on that directory, making it the new root directory. +That happens before entering single-user mode or multi-user +mode (but after executing the +.Va init_script +if enabled). +This functionality has generally been eclipsed by rerooting. +See +.Xr reboot 8 +.Fl r +for details. +.It Va init_exec +If set to a valid file name in the root file system, +instructs +.Nm +to directly execute that file as the very first action, +replacing +.Nm +as PID 1. +.It Va init_script +If set to a valid file name in the root file system, +instructs +.Nm +to run that script as the very first action, +before doing anything else. +Signal handling and exit code interpretation is similar to +running the +.Pa /etc/rc +script. +In particular, single-user operation is enforced +if the script terminates with a non-zero exit code, +or if a SIGTERM is delivered to the +.Nm +process (PID 1). +This functionality has generally been eclipsed by rerooting. +See +.Xr reboot 8 +.Fl r +for details. +.It Va init_shell +Defines the shell binary to be used for executing the various shell scripts. +The default is +.Dq Li /bin/sh . +It is used for running the +.Va init_exec +or +.Va init_script +if set, as well as for the +.Pa /etc/rc +and +.Pa /etc/rc.shutdown +scripts. +The value of the corresponding +.Xr kenv 2 +variable is evaluated every time +.Nm +calls a shell script, so it can be changed later on using the +.Xr kenv 1 +utility. +In particular, if a non-default shell is used for running an +.Va init_script , +it might be desirable to have that script reset the value of +.Va init_shell +back to the default, so that the +.Pa /etc/rc +script is executed with the standard shell +.Pa /bin/sh . .Sh FILES .Bl -tag -width /var/log/init.log -compact .It Pa /dev/console Modified: stable/11/sbin/init/init.c ============================================================================== --- stable/11/sbin/init/init.c Sun Apr 21 03:54:49 2019 (r346478) +++ stable/11/sbin/init/init.c Sun Apr 21 04:00:19 2019 (r346479) @@ -146,6 +146,7 @@ static state_t current_state = death_single; static void open_console(void); static const char *get_shell(void); +static void replace_init(char *path); static void write_stderr(const char *message); typedef struct init_session { @@ -327,6 +328,11 @@ invalid: close(1); close(2); + if (kenv(KENV_GET, "init_exec", kenv_value, sizeof(kenv_value)) > 0) { + replace_init(kenv_value); + _exit(0); /* reboot */ + } + if (kenv(KENV_GET, "init_script", kenv_value, sizeof(kenv_value)) > 0) { state_func_t next_transition; @@ -965,7 +971,7 @@ single_user(void) char name[] = "-sh"; argv[0] = name; - argv[1] = 0; + argv[1] = NULL; execv(shell, argv); emergency("can't exec %s for single user: %m", shell); execv(_PATH_BSHELL, argv); @@ -1045,6 +1051,22 @@ runcom(void) } /* + * Execute binary, replacing init(8) as PID 1. + */ +static void +replace_init(char *path) +{ + char *argv[3]; + char sh[] = "sh"; + + argv[0] = sh; + argv[1] = path; + argv[2] = NULL; + + execute_script(argv); +} + +/* * Run a shell script. * Returns 0 on success, otherwise the next transition to enter: * - single_user if fork/execv/waitpid failed, or if the script @@ -1055,7 +1077,7 @@ static state_func_t run_script(const char *script) { pid_t pid, wpid; - int status; + int error, status; char *argv[4]; const char *shell; struct sigaction sa; @@ -1077,13 +1099,28 @@ run_script(const char *script) argv[0] = _sh; argv[1] = __DECONST(char *, script); argv[2] = runcom_mode == AUTOBOOT ? _autoboot : 0; - argv[3] = 0; + argv[3] = NULL; sigprocmask(SIG_SETMASK, &sa.sa_mask, (sigset_t *) 0); #ifdef LOGIN_CAP setprocresources(RESOURCE_RC); #endif + + /* + * Try to directly execute the script first. If it + * fails, try the old method of passing the script path + * to sh(1). Don't complain if it fails because of + * the missing execute bit. + */ + error = access(script, X_OK); + if (error == 0) { + execv(script, argv + 1); + warning("can't exec %s: %m", script); + } else if (errno != EACCES) { + warning("can't access %s: %m", script); + } + execv(shell, argv); stall("can't exec %s for %s: %m", shell, script); _exit(1); /* force single user mode */ @@ -1426,10 +1463,10 @@ start_window_system(session_t *sp) strcpy(term, "TERM="); strlcat(term, sp->se_type, sizeof(term)); env[0] = term; - env[1] = 0; + env[1] = NULL; } else - env[0] = 0; + env[0] = NULL; execve(sp->se_window_argv[0], sp->se_window_argv, env); stall("can't exec window system '%s' for port %s: %m", sp->se_window_argv[0], sp->se_device); @@ -1490,9 +1527,9 @@ start_getty(session_t *sp) strcpy(term, "TERM="); strlcat(term, sp->se_type, sizeof(term)); env[0] = term; - env[1] = 0; + env[1] = NULL; } else - env[0] = 0; + env[0] = NULL; execve(sp->se_getty_argv[0], sp->se_getty_argv, env); stall("can't exec getty '%s' for port %s: %m", sp->se_getty_argv[0], sp->se_device); @@ -1851,7 +1888,7 @@ static int runshutdown(void) { pid_t pid, wpid; - int status; + int error, status; int shutdowntimeout; size_t len; char *argv[4]; @@ -1887,13 +1924,28 @@ runshutdown(void) argv[0] = _sh; argv[1] = _path_rundown; argv[2] = Reboot ? _reboot : _single; - argv[3] = 0; + argv[3] = NULL; sigprocmask(SIG_SETMASK, &sa.sa_mask, (sigset_t *) 0); #ifdef LOGIN_CAP setprocresources(RESOURCE_RC); #endif + + /* + * Try to directly execute the script first. If it + * fails, try the old method of passing the script path + * to sh(1). Don't complain if it fails because of + * the missing execute bit. + */ + error = access(_path_rundown, X_OK); + if (error == 0) { + execv(_path_rundown, argv + 1); + warning("can't exec %s: %m", _path_rundown); + } else if (errno != EACCES) { + warning("can't access %s: %m", _path_rundown); + } + execv(shell, argv); warning("can't exec %s for %s: %m", shell, _PATH_RUNDOWN); _exit(1); /* force single user mode */ Modified: stable/11/stand/man/loader.8 ============================================================================== --- stable/11/stand/man/loader.8 Sun Apr 21 03:54:49 2019 (r346478) +++ stable/11/stand/man/loader.8 Sun Apr 21 04:00:19 2019 (r346479) @@ -244,10 +244,14 @@ If is specified, file sizes will be shown too. .Pp .It Ic lsdev Op Fl v -Lists all of the devices from which it may be possible to load modules. +Lists all of the devices from which it may be possible to load modules, +as well as ZFS pools. If .Fl v -is specified, more details are printed. +is specified, more details are printed, including ZFS pool information +in a format that resembles +.Nm zpool Cm status +output. .Pp .It Ic lsmod Op Fl v Displays loaded modules. @@ -255,6 +259,14 @@ If .Fl v is specified, more details are shown. .Pp +.It Ic lszfs Ar filesystem +A ZFS extended command that can be used to explore the ZFS filesystem +hierarchy in a pool. +Lists the immediate children of the +.Ar filesystem . +The filesystem hierarchy is rooted at a filesystem with the same name +as the pool. +.Pp .It Ic more Ar file Op Ar Display the files specified, with a pause at each .Va LINES @@ -478,20 +490,11 @@ directive from has been processed, allowing kernel panics that happen during the early stages of boot to be captured. .It Va init_chroot -If set to a valid directory in the root file system, it causes -.Xr init 8 -to perform a -.Xr chroot 2 -operation on that directory, making it the new root directory. -That happens before entering single-user mode or multi-user -mode (but after executing the -.Va init_script -if enabled). -This functionality has generally been eclipsed by rerooting. See -.Xr reboot 8 -.Fl r -for details. +.Xr init 8 . +.It Va init_exec +See +.Xr init 8 . .It Va init_path Sets the list of binaries which the kernel will try to run as the initial process. @@ -499,51 +502,11 @@ The first matching binary is used. The default list is .Dq Li /sbin/init:/sbin/oinit:/sbin/init.bak:\:/rescue/init . .It Va init_script -If set to a valid file name in the root file system, -instructs -.Xr init 8 -to run that script as the very first action, -before doing anything else. -Signal handling and exit code interpretation is similar to -running the -.Pa /etc/rc -script. -In particular, single-user operation is enforced -if the script terminates with a non-zero exit code, -or if a SIGTERM is delivered to the -.Xr init 8 -process (PID 1). -This functionality has generally been eclipsed by rerooting. See -.Xr reboot 8 -.Fl r -for details. +.Xr init 8 . .It Va init_shell -Defines the shell binary to be used for executing the various shell scripts. -The default is -.Dq Li /bin/sh . -It is used for running the -.Va init_script -if set, as well as for the -.Pa /etc/rc -and -.Pa /etc/rc.shutdown -scripts. -The value of the corresponding -.Xr kenv 2 -variable is evaluated every time -.Xr init 8 -calls a shell script, so it can be changed later on using the -.Xr kenv 1 -utility. -In particular, if a non-default shell is used for running an -.Va init_script , -it might be desirable to have that script reset the value of -.Va init_shell -back to the default, so that the -.Pa /etc/rc -script is executed with the standard shell -.Pa /bin/sh . +See +.Xr init 8 . .It Va interpret Has the value .Dq Li OK @@ -718,6 +681,29 @@ Modifies and .Dv VM_KMEM_SIZE_MAX . .El +.Ss ZFS FEATURES +.Nm +supports the following format for specifying ZFS filesystems which +can be used wherever +.Xr loader 8 +refers to a device specification: +.Pp +.Ar zfs:pool/filesystem: +.Pp +where +.Pa pool/filesystem +is a ZFS filesystem name as described in +.Xr zfs 8 . +.Pp +If +.Pa /etc/fstab +does not have an entry for the root filesystem and +.Va vfs.root.mountfrom +is not set, but +.Va currdev +refers to a ZFS filesystem, then +.Nm +will instruct kernel to use that filesystem as the root filesystem. .Ss BUILTIN PARSER When a builtin command is executed, the rest of the line is taken by it as arguments, and it is processed by a special parser which @@ -959,9 +945,44 @@ version at compile time. .Nm version. .El -.Ss SYSTEM DOCUMENTATION +.Sh SECURITY +Access to the +.Nm +command line provides several ways of compromising system security, +including, but not limited to: +.Pp +.Bl -bullet +.It +Booting from removable storage, by setting the +.Va currdev +or +.Va loaddev +variables +.It +Executing binary of choice, by setting the +.Va init_path +or +.Va init_script +variables +.It +Overriding ACPI DSDT to inject arbitrary code into the ACPI subsystem +.El +.Pp +One can prevent unauthorized access +to the +.Nm +command line by setting the +.Va password , +or setting +.Va autoboot_delay +to -1. +See +.Xr loader.conf 5 +for details. +In order for this to be effective, one should also configure the firmware +(BIOS or UEFI) to prevent booting from unauthorized devices. .Sh FILES -.Bl -tag -width /boot/defaults/loader.conf -compact +.Bl -tag -width /usr/share/examples/bootforth/ -compact .It Pa /boot/loader .Nm itself. @@ -970,6 +991,8 @@ Additional .Tn FICL initialization. .It Pa /boot/defaults/loader.conf +.It Pa /boot/loader.4th +Extra builtin-like words. .It Pa /boot/loader.conf .It Pa /boot/loader.conf.local .Nm @@ -982,6 +1005,11 @@ bootstrapping script. Loaded by .Ic help . Contains the help messages. +.It Pa /boot/support.4th +.Pa loader.conf +processing words. +.It Pa /usr/share/examples/bootforth/ +Assorted examples. .El .Sh EXAMPLES Boot in single user mode: @@ -1007,16 +1035,11 @@ set root_disk_unit=2 boot /boot/kernel/kernel .Ed .Pp -See also: -.Bl -tag -width /usr/share/examples/bootforth/X -.It Pa /boot/loader.4th -Extra builtin-like words. -.It Pa /boot/support.4th -.Pa loader.conf -processing words. -.It Pa /usr/share/examples/bootforth/ -Assorted examples. -.El +Set the default device used for loading a kernel from a ZFS filesystem: +.Bd -literal -offset indent +set currdev=zfs:tank/ROOT/knowngood: +.Ed +.Pp .Sh ERRORS The following values are thrown by .Nm : @@ -1042,52 +1065,6 @@ executed. .It -259 Unspecified error. .El -.Sh ZFS FEATURES -.Nm -supports the following format for specifying ZFS filesystems which -can be used wherever -.Xr loader 8 -refers to a device specification: -.Pp -.Ar zfs:pool/filesystem: -.Pp -where -.Pa pool/filesystem -is a ZFS filesystem name as described in -.Xr zfs 8 . -.Pp -If -.Pa /etc/fstab -does not have an entry for the root filesystem and -.Va vfs.root.mountfrom -is not set, but -.Va currdev -refers to a ZFS filesystem, then -.Nm -will instruct kernel to use that filesystem as the root filesystem. -.Sh ZFS COMMAND EXTENSIONS -.Bl -tag -width Ds -compact -.It Ic lsdev Op Fl v -Lists ZFS pools in addition to disks and partitions. -Adding -.Fl v -shows more ZFS pool details in a format that resembles -.Nm zpool Cm status -output. -.Pp -.It Ic lszfs Ar filesystem -A ZFS extended command that can be used to explore the ZFS filesystem -hierarchy in a pool. -Lists the immediate children of the -.Ar filesystem . -The filesystem hierarchy is rooted at a filesystem with the same name -as the pool. -.El -.Sh EXAMPLES -Set the default device used for loading a kernel from a ZFS filesystem: -.Bd -literal -offset indent -set currdev=zfs:tank/ROOT/knowngood: -.Ed .Sh SEE ALSO .Xr libstand 3 , .Xr loader.conf 5 ,