diff --git a/man/common-variables.xml b/man/common-variables.xml index 2d26bf7242..991946f60d 100644 --- a/man/common-variables.xml +++ b/man/common-variables.xml @@ -96,17 +96,22 @@ $SYSTEMD_PAGER + $PAGER - Pager to use when is not given; overrides - $PAGER. If neither $SYSTEMD_PAGER nor $PAGER are set, a - set of well-known pager implementations are tried in turn, including - less1 and - more1, until one is found. If - no pager implementation is discovered no pager is invoked. Setting this environment variable to an empty string - or the value cat is equivalent to passing . + Pager to use when is not given. + $SYSTEMD_PAGER is used if set; otherwise $PAGER is used. + If neither $SYSTEMD_PAGER nor $PAGER are set, a set of well-known + pager implementations is tried in turn, including + less1 + and + more1, + until one is found. If no pager implementation is discovered, no pager is invoked. Setting those + environment variables to an empty string or the value cat is equivalent to passing + . Note: if $SYSTEMD_PAGERSECURE is not set, $SYSTEMD_PAGER - (as well as $PAGER) will be silently ignored. + and $PAGER can only be used to disable the pager (with cat or + ), and are otherwise ignored. @@ -167,28 +172,53 @@ $SYSTEMD_PAGERSECURE - Takes a boolean argument. When true, the "secure" mode of the pager is enabled; if - false, disabled. If $SYSTEMD_PAGERSECURE is not set at all, secure mode is enabled - if the effective UID is not the same as the owner of the login session, see - geteuid2 - and sd_pid_get_owner_uid3. - In secure mode, will be set when invoking the pager, and the pager shall - disable commands that open or create new files or start new subprocesses. When - $SYSTEMD_PAGERSECURE is not set at all, pagers which are not known to implement - secure mode will not be used. (Currently only - less1 - implements secure mode.) - - Note: when commands are invoked with elevated privileges, for example under + Common pager commands like less1, in + addition to "paging", i.e. scrolling through the output, support opening of or writing to other files + and running arbitrary shell commands. When commands are invoked with elevated privileges, for example + under sudo8 or pkexec1, care - must be taken to ensure that unintended interactive features are not enabled. "Secure" mode for the - pager may be enabled automatically as describe above. Setting SYSTEMD_PAGERSECURE=0 - or not removing it from the inherited environment allows the user to invoke arbitrary commands. Note - that if the $SYSTEMD_PAGER or $PAGER variables are to be - honoured, $SYSTEMD_PAGERSECURE must be set too. It might be reasonable to completely - disable the pager using instead. + project='die-net'>pkexec1, the + pager becomes a security boundary. Care must be taken that only programs with strictly limited + functionality are used as pagers, and unintended interactive features like opening or creation of new + files or starting of subprocesses are not allowed. "Secure mode" for the pager may be enabled as + described below, if the pager supports that (most pagers are not written in a way + that takes this into consideration). It is recommended to either explicitly enable "secure mode" or to + completely disable the pager using or PAGER=cat when + allowing untrusted users to execute commands with elevated privileges. + + This option takes a boolean argument. When set to true, the "secure mode" of the pager is + enabled. In "secure mode", will be set when invoking the pager, which + instructs the pager to disable commands that open or create new files or start new subprocesses. + Currently only less1 is known + to understand this variable and implement "secure mode". + + When set to false, no limitation is placed on the pager. Setting + SYSTEMD_PAGERSECURE=0 or not removing it from the inherited environment may allow + the user to invoke arbitrary commands. + + When $SYSTEMD_PAGERSECURE is not set, systemd tools attempt to automatically + figure out if "secure mode" should be enabled and whether the pager supports it. "Secure mode" is + enabled if the effective UID is not the same as the owner of the login session, see + geteuid2 + and + sd_pid_get_owner_uid3, + or when running under + sudo8 or similar + tools ($SUDO_UID is set + It is recommended for other tools to set and check $SUDO_UID as appropriate, + treating it is a common interface.). In those cases, + SYSTEMD_PAGERSECURE=1 will be set and pagers which are not known to implement + "secure mode" will not be used at all. Note that this autodetection only covers the most common + mechanisms to elevate privileges and is intended as convenience. It is recommended to explicitly set + $SYSTEMD_PAGERSECURE or disable the pager. + + Note that if the $SYSTEMD_PAGER or $PAGER variables are to + be honoured, other than to disable the pager, $SYSTEMD_PAGERSECURE must be set + too. diff --git a/src/shared/pager.c b/src/shared/pager.c index 9b8ae76700..f1043ec132 100644 --- a/src/shared/pager.c +++ b/src/shared/pager.c @@ -82,6 +82,22 @@ static int no_quit_on_interrupt(int exe_name_fd, const char *less_opts) { return r; } +static bool running_with_escalated_privileges(void) { + int r; + + if (getenv("SUDO_UID")) + return true; + + uid_t uid; + r = sd_pid_get_owner_uid(0, &uid); + if (r < 0) { + log_debug_errno(r, "sd_pid_get_owner_uid() failed, enabling pager secure mode: %m"); + return true; + } + + return uid != geteuid(); +} + void pager_open(PagerFlags flags) { _cleanup_close_pair_ int fd[2] = EBADF_PAIR, exe_name_pipe[2] = EBADF_PAIR; _cleanup_strv_free_ char **pager_args = NULL; @@ -177,16 +193,9 @@ void pager_open(PagerFlags flags) { * know to be good. */ int use_secure_mode = secure_getenv_bool("SYSTEMD_PAGERSECURE"); bool trust_pager = use_secure_mode >= 0; - if (use_secure_mode == -ENXIO) { - uid_t uid; - - r = sd_pid_get_owner_uid(0, &uid); - if (r < 0) - log_debug_errno(r, "sd_pid_get_owner_uid() failed, enabling pager secure mode: %m"); - - use_secure_mode = r < 0 || uid != geteuid(); - - } else if (use_secure_mode < 0) { + if (use_secure_mode == -ENXIO) + use_secure_mode = running_with_escalated_privileges(); + else if (use_secure_mode < 0) { log_warning_errno(use_secure_mode, "Unable to parse $SYSTEMD_PAGERSECURE, assuming true: %m"); use_secure_mode = true; }