mirror of
https://github.com/morgan9e/systemd
synced 2026-04-14 00:14:32 +09:00
run0: Add --empower
--empower gives full privileges to a non-root user. Currently this includes all capabilities but we leave the option open to add more privileges via this option in the future. Why is this useful? When running privileged development or debugging commands from your home directory (think bpftrace, strace and such), you want any files written by these tools to be owned by your current user, and not by the root user. run0 --empower will allow you to run all privileged operations (assuming the tools check for capabilities and not UIDs), while any files written by the tools will still be owned by the current user.
This commit is contained in:
15
man/run0.xml
15
man/run0.xml
@@ -139,8 +139,8 @@
|
||||
<term><option>-g</option></term>
|
||||
|
||||
<listitem><para>Switches to the specified user/group. If not specified defaults to
|
||||
<literal>root</literal>, unless <option>--area=</option> is used (see below), in which case this
|
||||
defaults to the invoking user.</para>
|
||||
<literal>root</literal>, unless <option>--area=</option> or <option>--empower</option> are used (see
|
||||
below), in which case this defaults to the invoking user.</para>
|
||||
|
||||
<xi:include href="version-info.xml" xpointer="v256"/>
|
||||
</listitem>
|
||||
@@ -290,6 +290,17 @@
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><option>--empower</option></term>
|
||||
|
||||
<listitem><para>If specified, run0 will elevate the privileges of the selected user (using
|
||||
<option>--user=</option>) or the current user if no user is explicitly selected. Currently this means
|
||||
we give the user all available capabilities, but other privileges may be granted in the future as
|
||||
well when using this option.</para>
|
||||
|
||||
<xi:include href="version-info.xml" xpointer="v259"/></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><option>--machine=</option></term>
|
||||
|
||||
|
||||
@@ -37,7 +37,7 @@ _run0() {
|
||||
--machine --unit --property --description --slice -u --user -g --group --nice -D --chdir
|
||||
--setenv --background
|
||||
)
|
||||
local OPTS="${opts_with_values[*]} -h --help -V --version --no-ask-password --slice-inherit"
|
||||
local OPTS="${opts_with_values[*]} -h --help -V --version --no-ask-password --slice-inherit --empower"
|
||||
|
||||
local i
|
||||
for (( i=1; i <= COMP_CWORD; i++ )); do
|
||||
|
||||
@@ -52,6 +52,7 @@ local -a args=(
|
||||
'--machine=[Execute the operation on a local container]:machine:_sd_machines'
|
||||
{-h,--help}'[Show the help text and exit]'
|
||||
'--version[Print a short version string and exit]'
|
||||
'--empower[Give privileges to selected or current user]'
|
||||
)
|
||||
|
||||
_arguments -S $args '*:: :{_normal -p $service}'
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
#include "bus-util.h"
|
||||
#include "bus-wait-for-jobs.h"
|
||||
#include "calendarspec.h"
|
||||
#include "capability-util.h"
|
||||
#include "capsule-util.h"
|
||||
#include "chase.h"
|
||||
#include "env-util.h"
|
||||
@@ -117,6 +118,7 @@ static char *arg_shell_prompt_prefix = NULL;
|
||||
static int arg_lightweight = -1;
|
||||
static char *arg_area = NULL;
|
||||
static bool arg_via_shell = false;
|
||||
static bool arg_empower = false;
|
||||
|
||||
STATIC_DESTRUCTOR_REGISTER(arg_description, freep);
|
||||
STATIC_DESTRUCTOR_REGISTER(arg_environment, strv_freep);
|
||||
@@ -244,6 +246,7 @@ static int help_sudo_mode(void) {
|
||||
" --lightweight=BOOLEAN Control whether to register a session with service manager\n"
|
||||
" or without\n"
|
||||
" --area=AREA Home area to log into\n"
|
||||
" --empower Give privileges to selected or current user\n"
|
||||
"\nSee the %s for details.\n",
|
||||
program_invocation_short_name,
|
||||
ansi_highlight(),
|
||||
@@ -253,11 +256,15 @@ static int help_sudo_mode(void) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool become_root(void) {
|
||||
return !arg_exec_user || STR_IN_SET(arg_exec_user, "root", "0");
|
||||
}
|
||||
|
||||
static bool privileged_execution(void) {
|
||||
if (arg_runtime_scope != RUNTIME_SCOPE_SYSTEM)
|
||||
return false;
|
||||
|
||||
return !arg_exec_user || STR_IN_SET(arg_exec_user, "root", "0");
|
||||
return become_root() || arg_empower;
|
||||
}
|
||||
|
||||
static int add_timer_property(const char *name, const char *val) {
|
||||
@@ -859,6 +866,7 @@ static int parse_argv_sudo_mode(int argc, char *argv[]) {
|
||||
ARG_LIGHTWEIGHT,
|
||||
ARG_AREA,
|
||||
ARG_VIA_SHELL,
|
||||
ARG_EMPOWER,
|
||||
};
|
||||
|
||||
/* If invoked as "run0" binary, let's expose a more sudo-like interface. We add various extensions
|
||||
@@ -888,6 +896,7 @@ static int parse_argv_sudo_mode(int argc, char *argv[]) {
|
||||
{ "shell-prompt-prefix", required_argument, NULL, ARG_SHELL_PROMPT_PREFIX },
|
||||
{ "lightweight", required_argument, NULL, ARG_LIGHTWEIGHT },
|
||||
{ "area", required_argument, NULL, ARG_AREA },
|
||||
{ "empower", no_argument, NULL, ARG_EMPOWER },
|
||||
{},
|
||||
};
|
||||
|
||||
@@ -1027,6 +1036,10 @@ static int parse_argv_sudo_mode(int argc, char *argv[]) {
|
||||
arg_via_shell = true;
|
||||
break;
|
||||
|
||||
case ARG_EMPOWER:
|
||||
arg_empower = true;
|
||||
break;
|
||||
|
||||
case '?':
|
||||
return -EINVAL;
|
||||
|
||||
@@ -1034,9 +1047,13 @@ static int parse_argv_sudo_mode(int argc, char *argv[]) {
|
||||
assert_not_reached();
|
||||
}
|
||||
|
||||
if (!arg_exec_user && arg_area) {
|
||||
if (!arg_exec_user && (arg_area || arg_empower)) {
|
||||
/* If the user specifies --area= but not --user= then consider this an area switch request,
|
||||
* and default to logging into our own account */
|
||||
* and default to logging into our own account.
|
||||
*
|
||||
* If the user specifies --empower but not --user= then consider this a request to empower
|
||||
* the current user. */
|
||||
|
||||
arg_exec_user = getusername_malloc();
|
||||
if (!arg_exec_user)
|
||||
return log_oom();
|
||||
@@ -1211,8 +1228,8 @@ static int parse_argv_sudo_mode(int argc, char *argv[]) {
|
||||
|
||||
if (arg_lightweight >= 0) {
|
||||
const char *class =
|
||||
arg_lightweight ? (arg_stdio == ARG_STDIO_PTY ? (privileged_execution() ? "user-early-light" : "user-light") : "background-light") :
|
||||
(arg_stdio == ARG_STDIO_PTY ? (privileged_execution() ? "user-early" : "user") : "background");
|
||||
arg_lightweight ? (arg_stdio == ARG_STDIO_PTY ? (become_root() ? "user-early-light" : "user-light") : "background-light") :
|
||||
(arg_stdio == ARG_STDIO_PTY ? (become_root() ? "user-early" : "user") : "background");
|
||||
|
||||
log_debug("Setting XDG_SESSION_CLASS to '%s'.", class);
|
||||
|
||||
@@ -1371,6 +1388,12 @@ static int transient_service_set_properties(sd_bus_message *m, const char *pty_p
|
||||
return bus_log_create_error(r);
|
||||
}
|
||||
|
||||
if (arg_empower) {
|
||||
r = sd_bus_message_append(m, "(sv)", "AmbientCapabilities", "t", CAP_MASK_ALL);
|
||||
if (r < 0)
|
||||
return bus_log_create_error(r);
|
||||
}
|
||||
|
||||
if (arg_nice_set) {
|
||||
r = sd_bus_message_append(m, "(sv)", "Nice", "i", arg_nice);
|
||||
if (r < 0)
|
||||
|
||||
@@ -297,6 +297,14 @@ if [[ -e /usr/lib/pam.d/systemd-run0 ]] || [[ -e /etc/pam.d/systemd-run0 ]]; the
|
||||
# Validate when we invoke run0 without a tty, that depending on --pty it either allocates a tty or not
|
||||
assert_neq "$(run0 --pty tty < /dev/null)" "not a tty"
|
||||
assert_eq "$(run0 --pipe tty < /dev/null)" "not a tty"
|
||||
|
||||
# Validate that --empower gives all capabilities to a non-root user.
|
||||
caps="$(run0 -u testuser --empower systemd-analyze capability --mask "$(grep CapEff /proc/self/status | cut -d':' -f2)" --json=pretty | jq -r length)"
|
||||
assert_neq "$caps" "0"
|
||||
|
||||
run0 -u testuser --empower touch /run/empower
|
||||
assert_eq "$(stat -c "%U" /run/empower)" testuser
|
||||
rm /run/empower
|
||||
fi
|
||||
|
||||
# Tests whether intermediate disconnects corrupt us (modified testcase from https://github.com/systemd/systemd/issues/27204)
|
||||
|
||||
Reference in New Issue
Block a user