mirror of
https://github.com/systemd/systemd.git
synced 2024-11-23 18:23:32 +08:00
logind: enable limiting of user session scopes using pam context objects (#8397)
This commit is contained in:
parent
2cb36f7c1e
commit
22f9331412
@ -249,6 +249,60 @@
|
||||
based on the <varname>$DISPLAY</varname> variable.</para>
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
<title>Session limits</title>
|
||||
|
||||
<para>PAM modules earlier in the stack, that is those that come before <command>pam_systemd.so</command>,
|
||||
can set session scope limits using the PAM context objects. The data for these objects is provided as NUL-terminated C strings
|
||||
and maps directly to the respective unit resource control directives. Note that these limits apply to individual sessions of the user,
|
||||
they do not apply to all user processes as a combined whole. In particular, the per-user <command>user@.service</command> unit instance,
|
||||
which runs the <command>systemd --user</command> manager process and its children, and is tracked outside of any session, being shared
|
||||
by all the user's sessions, is not covered by these limits.
|
||||
</para>
|
||||
|
||||
<para> See
|
||||
<citerefentry><refentrytitle>systemd.resource-control</refentrytitle><manvolnum>5</manvolnum></citerefentry> for more information about the resources.
|
||||
Also, see <citerefentry><refentrytitle>pam_set_data</refentrytitle><manvolnum>3</manvolnum></citerefentry> for additional information about how to set
|
||||
the context objects.
|
||||
</para>
|
||||
|
||||
<variablelist>
|
||||
<varlistentry>
|
||||
<term><varname>systemd.memory_max</varname></term>
|
||||
|
||||
<listitem><para>Sets unit <varname>MemoryMax=</varname>.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><varname>systemd.tasks_max</varname></term>
|
||||
|
||||
<listitem><para>Sets unit <varname>TasksMax=</varname>.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><varname>systemd.cpu_weight</varname></term>
|
||||
|
||||
<listitem><para>Sets unit <varname>CPUWeight=</varname>.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><varname>systemd.io_weight</varname></term>
|
||||
|
||||
<listitem><para>Sets unit <varname>IOWeight=</varname>.</para></listitem>
|
||||
</varlistentry>
|
||||
</variablelist>
|
||||
|
||||
<para>Example data as can be provided from an another PAM module:
|
||||
<programlisting>
|
||||
pam_set_data(handle, "systemd.memory_max", (void *)"200M", cleanup);
|
||||
pam_set_data(handle, "systemd.tasks_max", (void *)"50", cleanup);
|
||||
pam_set_data(handle, "systemd.cpu_weight", (void *)"100", cleanup);
|
||||
pam_set_data(handle, "systemd.io_weight", (void *)"340", cleanup);
|
||||
</programlisting>
|
||||
</para>
|
||||
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
<title>Example</title>
|
||||
|
||||
|
@ -744,10 +744,6 @@ static int method_create_session(sd_bus_message *message, void *userdata, sd_bus
|
||||
}
|
||||
}
|
||||
|
||||
r = sd_bus_message_enter_container(message, 'a', "(sv)");
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (t == _SESSION_TYPE_INVALID) {
|
||||
if (!isempty(display))
|
||||
t = SESSION_X11;
|
||||
@ -903,7 +899,15 @@ static int method_create_session(sd_bus_message *message, void *userdata, sd_bus
|
||||
goto fail;
|
||||
}
|
||||
|
||||
r = session_start(session);
|
||||
r = sd_bus_message_enter_container(message, 'a', "(sv)");
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = session_start(session, message);
|
||||
if (r < 0)
|
||||
goto fail;
|
||||
|
||||
r = sd_bus_message_exit_container(message);
|
||||
if (r < 0)
|
||||
goto fail;
|
||||
|
||||
@ -3056,7 +3060,7 @@ int manager_start_scope(
|
||||
const char *description,
|
||||
const char *after,
|
||||
const char *after2,
|
||||
uint64_t tasks_max,
|
||||
sd_bus_message *more_properties,
|
||||
sd_bus_error *error,
|
||||
char **job) {
|
||||
|
||||
@ -3120,9 +3124,17 @@ int manager_start_scope(
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = sd_bus_message_append(m, "(sv)", "TasksMax", "t", tasks_max);
|
||||
/* disable TasksMax= for the session scope, rely on the slice setting for it */
|
||||
r = sd_bus_message_append(m, "(sv)", "TasksMax", "t", (uint64_t)-1);
|
||||
if (r < 0)
|
||||
return r;
|
||||
return bus_log_create_error(r);
|
||||
|
||||
if (more_properties) {
|
||||
/* If TasksMax also appears here, it will overwrite the default value set above */
|
||||
r = sd_bus_message_copy(m, more_properties, true);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
r = sd_bus_message_close_container(m);
|
||||
if (r < 0)
|
||||
|
@ -545,7 +545,7 @@ int session_activate(Session *s) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int session_start_scope(Session *s) {
|
||||
static int session_start_scope(Session *s, sd_bus_message *properties) {
|
||||
int r;
|
||||
|
||||
assert(s);
|
||||
@ -570,7 +570,7 @@ static int session_start_scope(Session *s) {
|
||||
description,
|
||||
"systemd-logind.service",
|
||||
"systemd-user-sessions.service",
|
||||
(uint64_t) -1, /* disable TasksMax= for the scope, rely on the slice setting for it */
|
||||
properties,
|
||||
&error,
|
||||
&job);
|
||||
if (r < 0) {
|
||||
@ -591,7 +591,7 @@ static int session_start_scope(Session *s) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int session_start(Session *s) {
|
||||
int session_start(Session *s, sd_bus_message *properties) {
|
||||
int r;
|
||||
|
||||
assert(s);
|
||||
@ -607,7 +607,7 @@ int session_start(Session *s) {
|
||||
return r;
|
||||
|
||||
/* Create cgroup */
|
||||
r = session_start_scope(s);
|
||||
r = session_start_scope(s, properties);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
|
@ -127,7 +127,7 @@ void session_set_idle_hint(Session *s, bool b);
|
||||
int session_get_locked_hint(Session *s);
|
||||
void session_set_locked_hint(Session *s, bool b);
|
||||
int session_create_fifo(Session *s);
|
||||
int session_start(Session *s);
|
||||
int session_start(Session *s, sd_bus_message *properties);
|
||||
int session_stop(Session *s, bool force);
|
||||
int session_finalize(Session *s);
|
||||
int session_release(Session *s);
|
||||
|
@ -1195,7 +1195,7 @@ static int manager_startup(Manager *m) {
|
||||
user_start(user);
|
||||
|
||||
HASHMAP_FOREACH(session, m->sessions, i)
|
||||
session_start(session);
|
||||
session_start(session, NULL);
|
||||
|
||||
HASHMAP_FOREACH(inhibitor, m->inhibitors, i)
|
||||
inhibitor_start(inhibitor);
|
||||
|
@ -164,7 +164,7 @@ int bus_manager_shutdown_or_sleep_now_or_later(Manager *m, const char *unit_name
|
||||
int manager_send_changed(Manager *manager, const char *property, ...) _sentinel_;
|
||||
|
||||
int manager_start_slice(Manager *manager, const char *slice, const char *description, const char *after, const char *after2, uint64_t tasks_max, sd_bus_error *error, char **job);
|
||||
int manager_start_scope(Manager *manager, const char *scope, pid_t pid, const char *slice, const char *description, const char *after, const char *after2, uint64_t tasks_max, sd_bus_error *error, char **job);
|
||||
int manager_start_scope(Manager *manager, const char *scope, pid_t pid, const char *slice, const char *description, const char *after, const char *after2, sd_bus_message *more_properties, sd_bus_error *error, char **job);
|
||||
int manager_start_unit(Manager *manager, const char *unit, sd_bus_error *error, char **job);
|
||||
int manager_stop_unit(Manager *manager, const char *unit, sd_bus_error *error, char **job);
|
||||
int manager_abandon_scope(Manager *manager, const char *scope, sd_bus_error *error);
|
||||
|
@ -35,6 +35,7 @@
|
||||
#include "terminal-util.h"
|
||||
#include "util.h"
|
||||
#include "path-util.h"
|
||||
#include "cgroup-util.h"
|
||||
|
||||
static int parse_argv(
|
||||
pam_handle_t *handle,
|
||||
@ -198,13 +199,93 @@ error:
|
||||
return r;
|
||||
}
|
||||
|
||||
static int append_session_memory_max(pam_handle_t *handle, sd_bus_message *m, const char *limit) {
|
||||
uint64_t val;
|
||||
int r;
|
||||
|
||||
if (isempty(limit))
|
||||
return 0;
|
||||
|
||||
if (streq(limit, "infinity")) {
|
||||
r = sd_bus_message_append(m, "(sv)", "MemoryMax", "t", (uint64_t)-1);
|
||||
if (r < 0) {
|
||||
pam_syslog(handle, LOG_ERR, "Failed to append to bus message: %s", strerror(-r));
|
||||
return r;
|
||||
}
|
||||
} else {
|
||||
r = parse_percent(limit);
|
||||
if (r >= 0) {
|
||||
r = sd_bus_message_append(m, "(sv)", "MemoryMaxScale", "u", (uint32_t) (((uint64_t) UINT32_MAX * r) / 100U));
|
||||
if (r < 0) {
|
||||
pam_syslog(handle, LOG_ERR, "Failed to append to bus message: %s", strerror(-r));
|
||||
return r;
|
||||
}
|
||||
} else {
|
||||
r = parse_size(limit, 1024, &val);
|
||||
if (r >= 0) {
|
||||
r = sd_bus_message_append(m, "(sv)", "MemoryMax", "t", val);
|
||||
if (r < 0) {
|
||||
pam_syslog(handle, LOG_ERR, "Failed to append to bus message: %s", strerror(-r));
|
||||
return r;
|
||||
}
|
||||
} else
|
||||
pam_syslog(handle, LOG_WARNING, "Failed to parse systemd.limit: %s, ignoring.", limit);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int append_session_tasks_max(pam_handle_t *handle, sd_bus_message *m, const char *limit)
|
||||
{
|
||||
uint64_t val;
|
||||
int r;
|
||||
|
||||
/* No need to parse "infinity" here, it will be set unconditionally later in manager_start_scope() */
|
||||
if (isempty(limit) || streq(limit, "infinity"))
|
||||
return 0;
|
||||
|
||||
r = safe_atou64(limit, &val);
|
||||
if (r >= 0) {
|
||||
r = sd_bus_message_append(m, "(sv)", "TasksMax", "t", val);
|
||||
if (r < 0) {
|
||||
pam_syslog(handle, LOG_ERR, "Failed to append to bus message: %s", strerror(-r));
|
||||
return r;
|
||||
}
|
||||
} else
|
||||
pam_syslog(handle, LOG_WARNING, "Failed to parse systemd.limit: %s, ignoring.", limit);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int append_session_cg_weight(pam_handle_t *handle, sd_bus_message *m, const char *limit, const char *field) {
|
||||
uint64_t val;
|
||||
int r;
|
||||
|
||||
if (!isempty(limit)) {
|
||||
r = cg_weight_parse(limit, &val);
|
||||
if (r >= 0) {
|
||||
r = sd_bus_message_append(m, "(sv)", field, "t", val);
|
||||
if (r < 0) {
|
||||
pam_syslog(handle, LOG_ERR, "Failed to append to bus message: %s", strerror(-r));
|
||||
return r;
|
||||
}
|
||||
} else if (streq(field, "CPUWeight"))
|
||||
pam_syslog(handle, LOG_WARNING, "Failed to parse systemd.cpu_weight: %s, ignoring.", limit);
|
||||
else
|
||||
pam_syslog(handle, LOG_WARNING, "Failed to parse systemd.io_weight: %s, ignoring.", limit);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
_public_ PAM_EXTERN int pam_sm_open_session(
|
||||
pam_handle_t *handle,
|
||||
int flags,
|
||||
int argc, const char **argv) {
|
||||
|
||||
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
|
||||
_cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
|
||||
_cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL, *reply = NULL;
|
||||
const char
|
||||
*username, *id, *object_path, *runtime_path,
|
||||
*service = NULL,
|
||||
@ -212,7 +293,8 @@ _public_ PAM_EXTERN int pam_sm_open_session(
|
||||
*remote_user = NULL, *remote_host = NULL,
|
||||
*seat = NULL,
|
||||
*type = NULL, *class = NULL,
|
||||
*class_pam = NULL, *type_pam = NULL, *cvtnr = NULL, *desktop = NULL;
|
||||
*class_pam = NULL, *type_pam = NULL, *cvtnr = NULL, *desktop = NULL,
|
||||
*memory_max = NULL, *tasks_max = NULL, *cpu_weight = NULL, *io_weight = NULL;
|
||||
_cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
|
||||
int session_fd = -1, existing, r;
|
||||
bool debug = false, remote;
|
||||
@ -353,6 +435,11 @@ _public_ PAM_EXTERN int pam_sm_open_session(
|
||||
|
||||
remote = !isempty(remote_host) && !is_localhost(remote_host);
|
||||
|
||||
(void) pam_get_data(handle, "systemd.memory_max", (const void **)&memory_max);
|
||||
(void) pam_get_data(handle, "systemd.tasks_max", (const void **)&tasks_max);
|
||||
(void) pam_get_data(handle, "systemd.cpu_weight", (const void **)&cpu_weight);
|
||||
(void) pam_get_data(handle, "systemd.io_weight", (const void **)&io_weight);
|
||||
|
||||
/* Talk to logind over the message bus */
|
||||
|
||||
r = sd_bus_open_system(&bus);
|
||||
@ -361,7 +448,7 @@ _public_ PAM_EXTERN int pam_sm_open_session(
|
||||
return PAM_SESSION_ERR;
|
||||
}
|
||||
|
||||
if (debug)
|
||||
if (debug) {
|
||||
pam_syslog(handle, LOG_DEBUG, "Asking logind to create session: "
|
||||
"uid="UID_FMT" pid="PID_FMT" service=%s type=%s class=%s desktop=%s seat=%s vtnr=%"PRIu32" tty=%s display=%s remote=%s remote_user=%s remote_host=%s",
|
||||
pw->pw_uid, getpid_cached(),
|
||||
@ -369,29 +456,71 @@ _public_ PAM_EXTERN int pam_sm_open_session(
|
||||
type, class, strempty(desktop),
|
||||
strempty(seat), vtnr, strempty(tty), strempty(display),
|
||||
yes_no(remote), strempty(remote_user), strempty(remote_host));
|
||||
pam_syslog(handle, LOG_DEBUG, "Session limits: "
|
||||
"memory_max=%s tasks_max=%s cpu_weight=%s io_weight=%s",
|
||||
strna(memory_max), strna(tasks_max), strna(cpu_weight), strna(io_weight));
|
||||
}
|
||||
|
||||
r = sd_bus_call_method(bus,
|
||||
"org.freedesktop.login1",
|
||||
"/org/freedesktop/login1",
|
||||
"org.freedesktop.login1.Manager",
|
||||
"CreateSession",
|
||||
&error,
|
||||
&reply,
|
||||
"uusssssussbssa(sv)",
|
||||
(uint32_t) pw->pw_uid,
|
||||
(uint32_t) getpid_cached(),
|
||||
service,
|
||||
type,
|
||||
class,
|
||||
desktop,
|
||||
seat,
|
||||
vtnr,
|
||||
tty,
|
||||
display,
|
||||
remote,
|
||||
remote_user,
|
||||
remote_host,
|
||||
0);
|
||||
r = sd_bus_message_new_method_call(
|
||||
bus,
|
||||
&m,
|
||||
"org.freedesktop.login1",
|
||||
"/org/freedesktop/login1",
|
||||
"org.freedesktop.login1.Manager",
|
||||
"CreateSession");
|
||||
if (r < 0) {
|
||||
pam_syslog(handle, LOG_ERR, "Failed to create CreateSession method call: %s", strerror(-r));
|
||||
return PAM_SESSION_ERR;
|
||||
}
|
||||
|
||||
r = sd_bus_message_append(m, "uusssssussbss",
|
||||
(uint32_t) pw->pw_uid,
|
||||
(uint32_t) getpid_cached(),
|
||||
service,
|
||||
type,
|
||||
class,
|
||||
desktop,
|
||||
seat,
|
||||
vtnr,
|
||||
tty,
|
||||
display,
|
||||
remote,
|
||||
remote_user,
|
||||
remote_host);
|
||||
if (r < 0) {
|
||||
pam_syslog(handle, LOG_ERR, "Failed to append to bus message: %s", strerror(-r));
|
||||
return PAM_SESSION_ERR;
|
||||
}
|
||||
|
||||
r = sd_bus_message_open_container(m, 'a', "(sv)");
|
||||
if (r < 0) {
|
||||
pam_syslog(handle, LOG_ERR, "Failed to open message container: %s", strerror(-r));
|
||||
return PAM_SYSTEM_ERR;
|
||||
}
|
||||
|
||||
r = append_session_memory_max(handle, m, memory_max);
|
||||
if (r < 0)
|
||||
return PAM_SESSION_ERR;
|
||||
|
||||
r = append_session_tasks_max(handle, m, tasks_max);
|
||||
if (r < 0)
|
||||
return PAM_SESSION_ERR;
|
||||
|
||||
r = append_session_cg_weight(handle, m, cpu_weight, "CPUWeight");
|
||||
if (r < 0)
|
||||
return PAM_SESSION_ERR;
|
||||
|
||||
r = append_session_cg_weight(handle, m, io_weight, "IOWeight");
|
||||
if (r < 0)
|
||||
return PAM_SESSION_ERR;
|
||||
|
||||
r = sd_bus_message_close_container(m);
|
||||
if (r < 0) {
|
||||
pam_syslog(handle, LOG_ERR, "Failed to close message container: %s", strerror(-r));
|
||||
return PAM_SYSTEM_ERR;
|
||||
}
|
||||
|
||||
r = sd_bus_call(bus, m, 0, &error, &reply);
|
||||
if (r < 0) {
|
||||
if (sd_bus_error_has_name(&error, BUS_ERROR_SESSION_BUSY)) {
|
||||
pam_syslog(handle, LOG_DEBUG, "Cannot create session: %s", bus_error_message(&error, r));
|
||||
|
Loading…
Reference in New Issue
Block a user