mirror of
https://github.com/systemd/systemd.git
synced 2024-12-14 04:33:37 +08:00
cgroup: Extend DeviceAllow= syntax to whitelist groups of devices, not just particular devices nodes
This commit is contained in:
parent
1620510ada
commit
90060676c4
@ -247,17 +247,31 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>.
|
||||
<listitem>
|
||||
<para>Control access to specific device nodes by the
|
||||
executed processes. Takes two space-separated strings: a
|
||||
device node path (such as <filename>/dev/null</filename>)
|
||||
followed by a combination of <constant>r</constant>,
|
||||
<constant>w</constant>, <constant>m</constant> to control
|
||||
device node specifier followed by a combination of
|
||||
<constant>r</constant>, <constant>w</constant>,
|
||||
<constant>m</constant> to control
|
||||
<emphasis>r</emphasis>eading, <emphasis>w</emphasis>riting,
|
||||
or creation of the specific device node by the unit
|
||||
or creation of the specific device node(s) by the unit
|
||||
(<emphasis>m</emphasis>knod), respectively. This controls
|
||||
the <literal>devices.allow</literal> and
|
||||
<literal>devices.deny</literal> control group
|
||||
attributes. For details about these control group attributes,
|
||||
see <ulink
|
||||
attributes. For details about these control group
|
||||
attributes, see <ulink
|
||||
url="https://www.kernel.org/doc/Documentation/cgroups/devices.txt">devices.txt</ulink>.</para>
|
||||
|
||||
<para>The device node specifier is either a path to a device
|
||||
node in the file system, starting with
|
||||
<filename>/dev/</filename>, or a string starting with either
|
||||
<literal>char-</literal> or <literal>block-</literal>
|
||||
followed by a device group name, as listed in
|
||||
<filename>/proc/devices</filename>. The latter is useful to
|
||||
whitelist all current and future devices belonging to a
|
||||
specific device group at once. Examples:
|
||||
<filename>/dev/sda5</filename> is a path to a device node,
|
||||
referring to an ATA or SCSI block
|
||||
device. <literal>char-pts</literal> and
|
||||
<literal>char-alsa</literal> are specifiers for all pseudo
|
||||
TTYs and all ALSA sound devices, respectively.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
|
@ -191,6 +191,82 @@ static int whitelist_device(const char *path, const char *node, const char *acc)
|
||||
return r;
|
||||
}
|
||||
|
||||
static int whitelist_major(const char *path, const char *name, char type, const char *acc) {
|
||||
_cleanup_fclose_ FILE *f = NULL;
|
||||
char line[LINE_MAX];
|
||||
bool good = false;
|
||||
int r;
|
||||
|
||||
assert(path);
|
||||
assert(acc);
|
||||
assert(type == 'b' || type == 'c');
|
||||
|
||||
f = fopen("/proc/devices", "re");
|
||||
if (!f) {
|
||||
log_warning("Cannot open /proc/devices to resolve %s (%c): %m", name, type);
|
||||
return -errno;
|
||||
}
|
||||
|
||||
FOREACH_LINE(line, f, goto fail) {
|
||||
char buf[2+DECIMAL_STR_MAX(unsigned)+3+4], *p, *w;
|
||||
unsigned maj;
|
||||
|
||||
truncate_nl(line);
|
||||
|
||||
if (type == 'c' && streq(line, "Character devices:")) {
|
||||
good = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (type == 'b' && streq(line, "Block devices:")) {
|
||||
good = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (isempty(line)) {
|
||||
good = false;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!good)
|
||||
continue;
|
||||
|
||||
p = strstrip(line);
|
||||
|
||||
w = strpbrk(p, WHITESPACE);
|
||||
if (!w)
|
||||
continue;
|
||||
*w = 0;
|
||||
|
||||
r = safe_atou(p, &maj);
|
||||
if (r < 0)
|
||||
continue;
|
||||
if (maj <= 0)
|
||||
continue;
|
||||
|
||||
w++;
|
||||
w += strspn(w, WHITESPACE);
|
||||
if (!streq(w, name))
|
||||
continue;
|
||||
|
||||
sprintf(buf,
|
||||
"%c %u:* %s",
|
||||
type,
|
||||
maj,
|
||||
acc);
|
||||
|
||||
r = cg_set_attribute("devices", path, "devices.allow", buf);
|
||||
if (r < 0)
|
||||
log_warning("Failed to set devices.allow on %s: %s", path, strerror(-r));
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
log_warning("Failed to read /proc/devices: %m");
|
||||
return -errno;
|
||||
}
|
||||
|
||||
void cgroup_context_apply(CGroupContext *c, CGroupControllerMask mask, const char *path) {
|
||||
int r;
|
||||
|
||||
@ -306,7 +382,15 @@ void cgroup_context_apply(CGroupContext *c, CGroupControllerMask mask, const cha
|
||||
continue;
|
||||
|
||||
acc[k++] = 0;
|
||||
whitelist_device(path, a->path, acc);
|
||||
|
||||
if (startswith(a->path, "/dev/"))
|
||||
whitelist_device(path, a->path, acc);
|
||||
else if (startswith(a->path, "block-"))
|
||||
whitelist_major(path, a->path + 6, 'b', acc);
|
||||
else if (startswith(a->path, "char-"))
|
||||
whitelist_major(path, a->path + 5, 'c', acc);
|
||||
else
|
||||
log_debug("Ignoring device %s while writing cgroup attribute.", a->path);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -442,8 +442,11 @@ int bus_cgroup_set_property(
|
||||
|
||||
while ((r = sd_bus_message_read(message, "(ss)", &path, &rwm)) > 0) {
|
||||
|
||||
if (!path_startswith(path, "/dev"))
|
||||
return sd_bus_error_set_errnof(error, EINVAL, "DeviceAllow= requires device node");
|
||||
if ((!startswith(path, "/dev/") &&
|
||||
!startswith(path, "block-") &&
|
||||
!startswith(path, "char-")) ||
|
||||
strpbrk(path, WHITESPACE))
|
||||
return sd_bus_error_set_errnof(error, EINVAL, "DeviceAllow= requires device node");
|
||||
|
||||
if (isempty(rwm))
|
||||
rwm = "rwm";
|
||||
|
@ -2368,9 +2368,10 @@ int config_parse_device_allow(
|
||||
if (!path)
|
||||
return log_oom();
|
||||
|
||||
if (!path_startswith(path, "/dev")) {
|
||||
log_syntax(unit, LOG_ERR, filename, line, EINVAL,
|
||||
"Invalid device node path '%s'. Ignoring.", path);
|
||||
if (!startswith(path, "/dev/") &&
|
||||
!startswith(path, "block-") &&
|
||||
!startswith(path, "char-")) {
|
||||
log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Invalid device node path '%s'. Ignoring.", path);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -2379,8 +2380,7 @@ int config_parse_device_allow(
|
||||
m = "rwm";
|
||||
|
||||
if (!in_charset(m, "rwm")) {
|
||||
log_syntax(unit, LOG_ERR, filename, line, EINVAL,
|
||||
"Invalid device rights '%s'. Ignoring.", m);
|
||||
log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Invalid device rights '%s'. Ignoring.", m);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user