#include "bpf-firewall.h"
#include "bpf-foreign.h"
#include "bus-get-properties.h"
+#include "bus-util.h"
#include "cgroup-util.h"
#include "cgroup.h"
#include "core-varlink.h"
#include "dbus-cgroup.h"
#include "dbus-util.h"
#include "errno-util.h"
+#include "escape.h"
#include "fd-util.h"
#include "fileio.h"
+#include "firewall-util.h"
#include "in-addr-prefix-util.h"
#include "ip-protocol-list.h"
#include "limits-util.h"
#include "percent-util.h"
#include "socket-util.h"
-BUS_DEFINE_PROPERTY_GET(bus_property_get_tasks_max, "t", TasksMax, tasks_max_resolve);
+BUS_DEFINE_PROPERTY_GET(bus_property_get_tasks_max, "t", CGroupTasksMax, cgroup_tasks_max_resolve);
BUS_DEFINE_PROPERTY_GET_ENUM(bus_property_get_cgroup_pressure_watch, cgroup_pressure_watch, CGroupPressureWatch);
static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_cgroup_device_policy, cgroup_device_policy, CGroupDevicePolicy);
return r;
LIST_FOREACH(device_allow, a, c->device_allow) {
- unsigned k = 0;
- char rwm[4];
-
- if (a->r)
- rwm[k++] = 'r';
- if (a->w)
- rwm[k++] = 'w';
- if (a->m)
- rwm[k++] = 'm';
-
- rwm[k] = 0;
-
- r = sd_bus_message_append(reply, "(ss)", a->path, rwm);
+ r = sd_bus_message_append(reply, "(ss)", a->path, cgroup_device_permissions_to_string(a->permissions));
if (r < 0)
return r;
}
sd_bus_message *reply,
void *userdata,
sd_bus_error *error) {
- int r;
+
CGroupContext *c = ASSERT_PTR(userdata);
- char *iface;
+ int r;
assert(bus);
assert(reply);
if (r < 0)
return r;
- r = sd_bus_message_open_container(reply, 'a', "s");
+ r = bus_message_append_string_set(reply, c->restrict_network_interfaces);
if (r < 0)
return r;
- SET_FOREACH(iface, c->restrict_network_interfaces) {
- r = sd_bus_message_append(reply, "s", iface);
- if (r < 0)
- return r;
- }
+ return sd_bus_message_close_container(reply);
+}
+
+static int property_get_cgroup_nft_set(
+ sd_bus *bus,
+ const char *path,
+ const char *interface,
+ const char *property,
+ sd_bus_message *reply,
+ void *userdata,
+ sd_bus_error *error) {
+ int r;
+ CGroupContext *c = userdata;
+
+ assert(bus);
+ assert(reply);
+ assert(c);
- r = sd_bus_message_close_container(reply);
+ r = sd_bus_message_open_container(reply, 'a', "(iiss)");
if (r < 0)
return r;
+ FOREACH_ARRAY(nft_set, c->nft_set_context.sets, c->nft_set_context.n_sets) {
+ r = sd_bus_message_append(reply, "(iiss)", nft_set->source, nft_set->nfproto, nft_set->table, nft_set->set);
+ if (r < 0)
+ return r;
+ }
+
return sd_bus_message_close_container(reply);
}
SD_BUS_PROPERTY("RestrictNetworkInterfaces", "(bas)", property_get_restrict_network_interfaces, 0, 0),
SD_BUS_PROPERTY("MemoryPressureWatch", "s", bus_property_get_cgroup_pressure_watch, offsetof(CGroupContext, memory_pressure_watch), 0),
SD_BUS_PROPERTY("MemoryPressureThresholdUSec", "t", bus_property_get_usec, offsetof(CGroupContext, memory_pressure_threshold_usec), 0),
+ SD_BUS_PROPERTY("NFTSet", "a(iiss)", property_get_cgroup_nft_set, 0, 0),
+ SD_BUS_PROPERTY("CoredumpReceive", "b", bus_property_get_bool, offsetof(CGroupContext, coredump_receive), 0),
SD_BUS_VTABLE_END
};
name);
if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
- r = cgroup_add_bpf_foreign_program(c, attach_type, p);
+ r = cgroup_context_add_bpf_foreign_program(c, attach_type, p);
if (r < 0)
return r;
}
unit_write_settingf(u, flags, name, "MemoryPressureThresholdUSec=%" PRIu64, t);
}
+ return 1;
+ } else if (streq(name, "CoredumpReceive")) {
+ int b;
+
+ if (!UNIT_VTABLE(u)->can_delegate)
+ return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "Delegation not available for unit type");
+
+ r = sd_bus_message_read(message, "b", &b);
+ if (r < 0)
+ return r;
+
+ if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
+ c->coredump_receive = b;
+
+ unit_write_settingf(u, flags, name, "CoredumpReceive=%s", yes_no(b));
+ }
+
return 1;
}
static int bus_cgroup_set_tasks_max(
Unit *u,
const char *name,
- TasksMax *p,
+ CGroupTasksMax *p,
sd_bus_message *message,
UnitWriteFlags flags,
sd_bus_error *error) {
"Value specified in %s is out of range", name);
if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
- *p = (TasksMax) { .value = v, .scale = 0 }; /* When .scale==0, .value is the absolute value */
+ *p = (CGroupTasksMax) { .value = v, .scale = 0 }; /* When .scale==0, .value is the absolute value */
unit_invalidate_cgroup(u, CGROUP_MASK_PIDS);
if (v == CGROUP_LIMIT_MAX)
static int bus_cgroup_set_tasks_max_scale(
Unit *u,
const char *name,
- TasksMax *p,
+ CGroupTasksMax *p,
sd_bus_message *message,
UnitWriteFlags flags,
sd_bus_error *error) {
"Value specified in %s is out of range", name);
if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
- *p = (TasksMax) { v, UINT32_MAX }; /* .scale is not 0, so this is interpreted as v/UINT32_MAX. */
+ *p = (CGroupTasksMax) { v, UINT32_MAX }; /* .scale is not 0, so this is interpreted as v/UINT32_MAX. */
unit_invalidate_cgroup(u, CGROUP_MASK_PIDS);
uint32_t scaled = DIV_ROUND_UP((uint64_t) v * 100U, (uint64_t) UINT32_MAX);
new_set = (CPUSet) {};
unit_invalidate_cgroup(u, CGROUP_MASK_CPUSET);
- unit_write_settingf(u, flags, name, "%s=%s", name, setstr);
+ unit_write_settingf(u, flags, name, "%s=\n%s=%s", name, name, setstr);
}
return 1;
return r;
while ((r = sd_bus_message_read(message, "(ss)", &path, &rwm)) > 0) {
+ CGroupDevicePermissions p;
if (!valid_device_allow_pattern(path) || strpbrk(path, WHITESPACE))
return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "DeviceAllow= requires device node or pattern");
if (isempty(rwm))
- rwm = "rwm";
- else if (!in_charset(rwm, "rwm"))
- return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "DeviceAllow= requires combination of rwm flags");
+ p = _CGROUP_DEVICE_PERMISSIONS_ALL;
+ else {
+ p = cgroup_device_permissions_from_string(rwm);
+ if (p < 0)
+ return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "DeviceAllow= requires combination of rwm flags");
+ }
if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
- CGroupDeviceAllow *a = NULL;
-
- LIST_FOREACH(device_allow, b, c->device_allow)
- if (path_equal(b->path, path)) {
- a = b;
- break;
- }
-
- if (!a) {
- a = new0(CGroupDeviceAllow, 1);
- if (!a)
- return -ENOMEM;
-
- a->path = strdup(path);
- if (!a->path) {
- free(a);
- return -ENOMEM;
- }
-
- LIST_PREPEND(device_allow, c->device_allow, a);
- }
-
- a->r = strchr(rwm, 'r');
- a->w = strchr(rwm, 'w');
- a->m = strchr(rwm, 'm');
+ r = cgroup_context_add_or_update_device_allow(c, path, p);
+ if (r < 0)
+ return r;
}
n++;
fputs("DeviceAllow=\n", f);
LIST_FOREACH(device_allow, a, c->device_allow)
- fprintf(f, "DeviceAllow=%s %s%s%s\n", a->path, a->r ? "r" : "", a->w ? "w" : "", a->m ? "m" : "");
+ fprintf(f, "DeviceAllow=%s %s\n", a->path, cgroup_device_permissions_to_string(a->permissions));
r = memstream_finalize(&m, &buf, NULL);
if (r < 0)
if (strv_isempty(l)) {
c->restrict_network_interfaces_is_allow_list = false;
- c->restrict_network_interfaces = set_free(c->restrict_network_interfaces);
+ c->restrict_network_interfaces = set_free_free(c->restrict_network_interfaces);
unit_write_settingf(u, flags, name, "%s=", name);
return 1;
c->restrict_network_interfaces_is_allow_list = is_allow_list;
STRV_FOREACH(s, l) {
- if (!ifname_valid(*s)) {
+ if (!ifname_valid_full(*s, IFNAME_VALID_ALTERNATIVE)) {
log_full(LOG_WARNING, "Invalid interface name, ignoring: %s", *s);
continue;
}
return 1;
}
+ if (streq(name, "NFTSet")) {
+ int source, nfproto;
+ const char *table, *set;
+ bool empty = true;
+
+ r = sd_bus_message_enter_container(message, 'a', "(iiss)");
+ if (r < 0)
+ return r;
+
+ while ((r = sd_bus_message_read(message, "(iiss)", &source, &nfproto, &table, &set)) > 0) {
+ const char *source_name, *nfproto_name;
+
+ if (!IN_SET(source, NFT_SET_SOURCE_CGROUP, NFT_SET_SOURCE_USER, NFT_SET_SOURCE_GROUP))
+ return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid source %d.", source);
+
+ source_name = nft_set_source_to_string(source);
+ assert(source_name);
+
+ nfproto_name = nfproto_to_string(nfproto);
+ if (!nfproto_name)
+ return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid protocol %d.", nfproto);
+
+ if (!nft_identifier_valid(table)) {
+ _cleanup_free_ char *esc = NULL;
+
+ esc = cescape(table);
+ return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid NFT table name %s.", strna(esc));
+ }
+
+ if (!nft_identifier_valid(set)) {
+ _cleanup_free_ char *esc = NULL;
+
+ esc = cescape(set);
+ return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid NFT set name %s.", strna(esc));
+ }
+
+ if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
+ r = nft_set_add(&c->nft_set_context, source, nfproto, table, set);
+ if (r < 0)
+ return r;
+
+ unit_write_settingf(
+ u, flags|UNIT_ESCAPE_SPECIFIERS, name,
+ "%s=%s:%s:%s:%s",
+ name,
+ source_name,
+ nfproto_name,
+ table,
+ set);
+ }
+
+ empty = false;
+ }
+ if (r < 0)
+ return r;
+
+ r = sd_bus_message_exit_container(message);
+ if (r < 0)
+ return r;
+
+ if (empty && !UNIT_WRITE_FLAGS_NOOP(flags)) {
+ nft_set_context_clear(&c->nft_set_context);
+ unit_write_settingf(u, flags, name, "%s=", name);
+ }
+
+ return 1;
+ }
+
+ /* must be last */
if (streq(name, "DisableControllers") || (u->transient && u->load_state == UNIT_STUB))
return bus_cgroup_set_transient_property(u, c, name, message, flags, error);