#include <sys/utsname.h>
+#include "af-list.h"
#include "analyze-security.h"
#include "bus-error.h"
#include "bus-map-properties.h"
#if HAVE_SECCOMP
# include "seccomp-util.h"
#endif
+#include "service.h"
#include "set.h"
#include "stdio-util.h"
#include "strv.h"
#include "terminal-util.h"
#include "unit-def.h"
#include "unit-name.h"
+#include "unit-serialize.h"
-struct security_info {
+typedef struct SecurityInfo {
char *id;
char *type;
char *load_state;
bool restrict_address_family_packet;
bool restrict_address_family_other;
- uint64_t restrict_namespaces;
+ unsigned long long restrict_namespaces;
bool restrict_realtime;
bool restrict_suid_sgid;
char *device_policy;
bool device_allow_non_empty;
- char **system_call_architectures;
+ Set *system_call_architectures;
bool system_call_filter_allow_list;
- Set *system_call_filter;
+ Hashmap *system_call_filter;
- uint32_t _umask;
-};
+ mode_t _umask;
+} SecurityInfo;
struct security_assessor {
const char *id;
uint64_t range;
int (*assess)(
const struct security_assessor *a,
- const struct security_info *info,
+ const SecurityInfo *info,
const void *data,
uint64_t *ret_badness,
char **ret_description);
bool default_dependencies_only;
};
-static void security_info_free(struct security_info *i) {
+static SecurityInfo *security_info_new(void) {
+ SecurityInfo *info = new(SecurityInfo, 1);
+ if (!info)
+ return NULL;
+
+ *info = (SecurityInfo) {
+ .default_dependencies = true,
+ .capability_bounding_set = UINT64_MAX,
+ .restrict_namespaces = UINT64_MAX,
+ ._umask = 0002,
+ };
+
+ return info;
+}
+
+static SecurityInfo *security_info_free(SecurityInfo *i) {
if (!i)
- return;
+ return NULL;
free(i->id);
free(i->type);
free(i->device_policy);
strv_free(i->supplementary_groups);
- strv_free(i->system_call_architectures);
+ set_free(i->system_call_architectures);
- set_free(i->system_call_filter);
+ hashmap_free(i->system_call_filter);
+
+ return mfree(i);
}
-static bool security_info_runs_privileged(const struct security_info *i) {
+DEFINE_TRIVIAL_CLEANUP_FUNC(SecurityInfo*, security_info_free);
+
+static bool security_info_runs_privileged(const SecurityInfo *i) {
assert(i);
if (STRPTR_IN_SET(i->user, "0", "root"))
static int assess_bool(
const struct security_assessor *a,
- const struct security_info *info,
+ const SecurityInfo *info,
const void *data,
uint64_t *ret_badness,
char **ret_description) {
static int assess_user(
const struct security_assessor *a,
- const struct security_info *info,
+ const SecurityInfo *info,
const void *data,
uint64_t *ret_badness,
char **ret_description) {
static int assess_protect_home(
const struct security_assessor *a,
- const struct security_info *info,
+ const SecurityInfo *info,
const void *data,
uint64_t *ret_badness,
char **ret_description) {
static int assess_protect_system(
const struct security_assessor *a,
- const struct security_info *info,
+ const SecurityInfo *info,
const void *data,
uint64_t *ret_badness,
char **ret_description) {
static int assess_root_directory(
const struct security_assessor *a,
- const struct security_info *info,
+ const SecurityInfo *info,
const void *data,
uint64_t *ret_badness,
char **ret_description) {
static int assess_capability_bounding_set(
const struct security_assessor *a,
- const struct security_info *info,
+ const SecurityInfo *info,
const void *data,
uint64_t *ret_badness,
char **ret_description) {
static int assess_umask(
const struct security_assessor *a,
- const struct security_info *info,
+ const SecurityInfo *info,
const void *data,
uint64_t *ret_badness,
char **ret_description) {
static int assess_keyring_mode(
const struct security_assessor *a,
- const struct security_info *info,
+ const SecurityInfo *info,
const void *data,
uint64_t *ret_badness,
char **ret_description) {
static int assess_protect_proc(
const struct security_assessor *a,
- const struct security_info *info,
+ const SecurityInfo *info,
const void *data,
uint64_t *ret_badness,
char **ret_description) {
static int assess_proc_subset(
const struct security_assessor *a,
- const struct security_info *info,
+ const SecurityInfo *info,
const void *data,
uint64_t *ret_badness,
char **ret_description) {
static int assess_notify_access(
const struct security_assessor *a,
- const struct security_info *info,
+ const SecurityInfo *info,
const void *data,
uint64_t *ret_badness,
char **ret_description) {
static int assess_remove_ipc(
const struct security_assessor *a,
- const struct security_info *info,
+ const SecurityInfo *info,
const void *data,
uint64_t *ret_badness,
char **ret_description) {
static int assess_supplementary_groups(
const struct security_assessor *a,
- const struct security_info *info,
+ const SecurityInfo *info,
const void *data,
uint64_t *ret_badness,
char **ret_description) {
static int assess_restrict_namespaces(
const struct security_assessor *a,
- const struct security_info *info,
+ const SecurityInfo *info,
const void *data,
uint64_t *ret_badness,
char **ret_description) {
static int assess_system_call_architectures(
const struct security_assessor *a,
- const struct security_info *info,
+ const SecurityInfo *info,
const void *data,
uint64_t *ret_badness,
char **ret_description) {
assert(ret_badness);
assert(ret_description);
- if (strv_isempty(info->system_call_architectures)) {
+ if (set_isempty(info->system_call_architectures)) {
b = 10;
d = strdup("Service may execute system calls with all ABIs");
- } else if (strv_equal(info->system_call_architectures, STRV_MAKE("native"))) {
+ } else if (set_contains(info->system_call_architectures, "native") &&
+ set_size(info->system_call_architectures) == 1) {
b = 0;
d = strdup("Service may execute system calls only with native ABI");
} else {
#if HAVE_SECCOMP
-static bool syscall_names_in_filter(Set *s, bool allow_list, const SyscallFilterSet *f, const char **ret_offending_syscall) {
+static bool syscall_names_in_filter(Hashmap *s, bool allow_list, const SyscallFilterSet *f, const char **ret_offending_syscall) {
const char *syscall;
NULSTR_FOREACH(syscall, f->value) {
if (id < 0)
continue;
- if (set_contains(s, syscall) == allow_list) {
+ if (hashmap_contains(s, syscall) == allow_list) {
log_debug("Offending syscall filter item: %s", syscall);
if (ret_offending_syscall)
*ret_offending_syscall = syscall;
static int assess_system_call_filter(
const struct security_assessor *a,
- const struct security_info *info,
+ const SecurityInfo *info,
const void *data,
uint64_t *ret_badness,
char **ret_description) {
uint64_t b;
int r;
- if (!info->system_call_filter_allow_list && set_isempty(info->system_call_filter)) {
+ if (!info->system_call_filter_allow_list && hashmap_isempty(info->system_call_filter)) {
r = free_and_strdup(&d, "Service does not filter system calls");
b = 10;
} else {
static int assess_ip_address_allow(
const struct security_assessor *a,
- const struct security_info *info,
+ const SecurityInfo *info,
const void *data,
uint64_t *ret_badness,
char **ret_description) {
static int assess_device_allow(
const struct security_assessor *a,
- const struct security_info *info,
+ const SecurityInfo *info,
const void *data,
uint64_t *ret_badness,
char **ret_description) {
static int assess_ambient_capabilities(
const struct security_assessor *a,
- const struct security_info *info,
+ const SecurityInfo *info,
const void *data,
uint64_t *ret_badness,
char **ret_description) {
.weight = 1000,
.range = 1,
.assess = assess_bool,
- .offset = offsetof(struct security_info, private_devices),
+ .offset = offsetof(SecurityInfo, private_devices),
},
{
.id = "PrivateMounts=",
.weight = 1000,
.range = 1,
.assess = assess_bool,
- .offset = offsetof(struct security_info, private_mounts),
+ .offset = offsetof(SecurityInfo, private_mounts),
},
{
.id = "PrivateNetwork=",
.weight = 2500,
.range = 1,
.assess = assess_bool,
- .offset = offsetof(struct security_info, private_network),
+ .offset = offsetof(SecurityInfo, private_network),
},
{
.id = "PrivateTmp=",
.weight = 1000,
.range = 1,
.assess = assess_bool,
- .offset = offsetof(struct security_info, private_tmp),
+ .offset = offsetof(SecurityInfo, private_tmp),
.default_dependencies_only = true,
},
{
.weight = 1000,
.range = 1,
.assess = assess_bool,
- .offset = offsetof(struct security_info, private_users),
+ .offset = offsetof(SecurityInfo, private_users),
},
{
.id = "ProtectControlGroups=",
.weight = 1000,
.range = 1,
.assess = assess_bool,
- .offset = offsetof(struct security_info, protect_control_groups),
+ .offset = offsetof(SecurityInfo, protect_control_groups),
},
{
.id = "ProtectKernelModules=",
.weight = 1000,
.range = 1,
.assess = assess_bool,
- .offset = offsetof(struct security_info, protect_kernel_modules),
+ .offset = offsetof(SecurityInfo, protect_kernel_modules),
},
{
.id = "ProtectKernelTunables=",
.weight = 1000,
.range = 1,
.assess = assess_bool,
- .offset = offsetof(struct security_info, protect_kernel_tunables),
+ .offset = offsetof(SecurityInfo, protect_kernel_tunables),
},
{
.id = "ProtectKernelLogs=",
.weight = 1000,
.range = 1,
.assess = assess_bool,
- .offset = offsetof(struct security_info, protect_kernel_logs),
+ .offset = offsetof(SecurityInfo, protect_kernel_logs),
},
{
.id = "ProtectClock=",
.weight = 1000,
.range = 1,
.assess = assess_bool,
- .offset = offsetof(struct security_info, protect_clock),
+ .offset = offsetof(SecurityInfo, protect_clock),
},
{
.id = "ProtectHome=",
.weight = 50,
.range = 1,
.assess = assess_bool,
- .offset = offsetof(struct security_info, protect_hostname),
+ .offset = offsetof(SecurityInfo, protect_hostname),
},
{
.id = "ProtectSystem=",
.weight = 100,
.range = 1,
.assess = assess_bool,
- .offset = offsetof(struct security_info, lock_personality),
+ .offset = offsetof(SecurityInfo, lock_personality),
},
{
.id = "MemoryDenyWriteExecute=",
.weight = 100,
.range = 1,
.assess = assess_bool,
- .offset = offsetof(struct security_info, memory_deny_write_execute),
+ .offset = offsetof(SecurityInfo, memory_deny_write_execute),
},
{
.id = "NoNewPrivileges=",
.weight = 1000,
.range = 1,
.assess = assess_bool,
- .offset = offsetof(struct security_info, no_new_privileges),
+ .offset = offsetof(SecurityInfo, no_new_privileges),
},
{
.id = "CapabilityBoundingSet=~CAP_SYS_ADMIN",
.weight = 100,
.range = 1,
.assess = assess_remove_ipc,
- .offset = offsetof(struct security_info, remove_ipc),
+ .offset = offsetof(SecurityInfo, remove_ipc),
},
{
.id = "Delegate=",
.weight = 100,
.range = 1,
.assess = assess_bool,
- .offset = offsetof(struct security_info, delegate),
+ .offset = offsetof(SecurityInfo, delegate),
.parameter = true, /* invert! */
},
{
.weight = 500,
.range = 1,
.assess = assess_bool,
- .offset = offsetof(struct security_info, restrict_realtime),
+ .offset = offsetof(SecurityInfo, restrict_realtime),
},
{
.id = "RestrictSUIDSGID=",
.weight = 1000,
.range = 1,
.assess = assess_bool,
- .offset = offsetof(struct security_info, restrict_suid_sgid),
+ .offset = offsetof(SecurityInfo, restrict_suid_sgid),
},
{
.id = "RestrictNamespaces=~CLONE_NEWUSER",
.weight = 1500,
.range = 1,
.assess = assess_bool,
- .offset = offsetof(struct security_info, restrict_address_family_inet),
+ .offset = offsetof(SecurityInfo, restrict_address_family_inet),
},
{
.id = "RestrictAddressFamilies=~AF_UNIX",
.weight = 25,
.range = 1,
.assess = assess_bool,
- .offset = offsetof(struct security_info, restrict_address_family_unix),
+ .offset = offsetof(SecurityInfo, restrict_address_family_unix),
},
{
.id = "RestrictAddressFamilies=~AF_NETLINK",
.weight = 200,
.range = 1,
.assess = assess_bool,
- .offset = offsetof(struct security_info, restrict_address_family_netlink),
+ .offset = offsetof(SecurityInfo, restrict_address_family_netlink),
},
{
.id = "RestrictAddressFamilies=~AF_PACKET",
.weight = 1000,
.range = 1,
.assess = assess_bool,
- .offset = offsetof(struct security_info, restrict_address_family_packet),
+ .offset = offsetof(SecurityInfo, restrict_address_family_packet),
},
{
.id = "RestrictAddressFamilies=~…",
.weight = 1250,
.range = 1,
.assess = assess_bool,
- .offset = offsetof(struct security_info, restrict_address_family_other),
+ .offset = offsetof(SecurityInfo, restrict_address_family_other),
},
{
.id = "SystemCallArchitectures=",
},
};
-static int assess(const struct security_info *info, Table *overview_table, AnalyzeSecurityFlags flags) {
+static int assess(const SecurityInfo *info, Table *overview_table, AnalyzeSecurityFlags flags) {
static const struct {
uint64_t exposure;
const char *name;
return 0;
}
+static int property_read_restrict_namespaces(
+ sd_bus *bus,
+ const char *member,
+ sd_bus_message *m,
+ sd_bus_error *error,
+ void *userdata) {
+
+ SecurityInfo *info = userdata;
+ int r;
+ uint64_t namespaces;
+
+ assert(bus);
+ assert(member);
+ assert(m);
+ assert(info);
+
+ r = sd_bus_message_read(m, "t", &namespaces);
+ if (r < 0)
+ return r;
+
+ info->restrict_namespaces = (unsigned long long) namespaces;
+
+ return 0;
+}
+
+static int property_read_umask(
+ sd_bus *bus,
+ const char *member,
+ sd_bus_message *m,
+ sd_bus_error *error,
+ void *userdata) {
+
+ SecurityInfo *info = userdata;
+ int r;
+ uint32_t umask;
+
+ assert(bus);
+ assert(member);
+ assert(m);
+ assert(info);
+
+ r = sd_bus_message_read(m, "u", &umask);
+ if (r < 0)
+ return r;
+
+ info->_umask = (mode_t) umask;
+
+ return 0;
+}
+
static int property_read_restrict_address_families(
sd_bus *bus,
const char *member,
sd_bus_error *error,
void *userdata) {
- struct security_info *info = userdata;
+ SecurityInfo *info = userdata;
int allow_list, r;
assert(bus);
return sd_bus_message_exit_container(m);
}
+static int property_read_syscall_archs(
+ sd_bus *bus,
+ const char *member,
+ sd_bus_message *m,
+ sd_bus_error *error,
+ void *userdata) {
+
+ SecurityInfo *info = userdata;
+ int r;
+
+ assert(bus);
+ assert(member);
+ assert(m);
+ assert(info);
+
+ r = sd_bus_message_enter_container(m, 'a', "s");
+ if (r < 0)
+ return r;
+
+ for (;;) {
+ const char *name;
+
+ r = sd_bus_message_read(m, "s", &name);
+ if (r < 0)
+ return r;
+ if (r == 0)
+ break;
+
+ r = set_put_strdup(&info->system_call_architectures, name);
+ if (r < 0)
+ return r;
+ }
+
+ return sd_bus_message_exit_container(m);
+}
+
static int property_read_system_call_filter(
sd_bus *bus,
const char *member,
sd_bus_error *error,
void *userdata) {
- struct security_info *info = userdata;
+ SecurityInfo *info = userdata;
int allow_list, r;
assert(bus);
if (r == 0)
break;
- r = set_put_strdup(&info->system_call_filter, name);
+ /* The actual ExecContext stores the system call id as the map value, which we don't
+ * need. So we assign NULL to all values here. */
+ r = hashmap_put_strdup(&info->system_call_filter, name, NULL);
if (r < 0)
return r;
}
sd_bus_error *error,
void *userdata) {
- struct security_info *info = userdata;
+ SecurityInfo *info = userdata;
bool deny_ipv4 = false, deny_ipv6 = false;
int r;
sd_bus_error *error,
void *userdata) {
- struct security_info *info = userdata;
+ SecurityInfo *info = userdata;
_cleanup_(strv_freep) char **l = NULL;
int r;
sd_bus_error *error,
void *userdata) {
- struct security_info *info = userdata;
+ SecurityInfo *info = userdata;
size_t n = 0;
int r;
return sd_bus_message_exit_container(m);
}
-static int acquire_security_info(sd_bus *bus, const char *name, struct security_info *info, AnalyzeSecurityFlags flags) {
+static int acquire_security_info(sd_bus *bus, const char *name, SecurityInfo *info, AnalyzeSecurityFlags flags) {
static const struct bus_properties_map security_map[] = {
- { "AmbientCapabilities", "t", NULL, offsetof(struct security_info, ambient_capabilities) },
- { "CapabilityBoundingSet", "t", NULL, offsetof(struct security_info, capability_bounding_set) },
- { "DefaultDependencies", "b", NULL, offsetof(struct security_info, default_dependencies) },
- { "Delegate", "b", NULL, offsetof(struct security_info, delegate) },
- { "DeviceAllow", "a(ss)", property_read_device_allow, 0 },
- { "DevicePolicy", "s", NULL, offsetof(struct security_info, device_policy) },
- { "DynamicUser", "b", NULL, offsetof(struct security_info, dynamic_user) },
- { "FragmentPath", "s", NULL, offsetof(struct security_info, fragment_path) },
- { "IPAddressAllow", "a(iayu)", property_read_ip_address_allow, 0 },
- { "IPAddressDeny", "a(iayu)", property_read_ip_address_allow, 0 },
- { "IPIngressFilterPath", "as", property_read_ip_filters, 0 },
- { "IPEgressFilterPath", "as", property_read_ip_filters, 0 },
- { "Id", "s", NULL, offsetof(struct security_info, id) },
- { "KeyringMode", "s", NULL, offsetof(struct security_info, keyring_mode) },
- { "ProtectProc", "s", NULL, offsetof(struct security_info, protect_proc) },
- { "ProcSubset", "s", NULL, offsetof(struct security_info, proc_subset) },
- { "LoadState", "s", NULL, offsetof(struct security_info, load_state) },
- { "LockPersonality", "b", NULL, offsetof(struct security_info, lock_personality) },
- { "MemoryDenyWriteExecute", "b", NULL, offsetof(struct security_info, memory_deny_write_execute) },
- { "NoNewPrivileges", "b", NULL, offsetof(struct security_info, no_new_privileges) },
- { "NotifyAccess", "s", NULL, offsetof(struct security_info, notify_access) },
- { "PrivateDevices", "b", NULL, offsetof(struct security_info, private_devices) },
- { "PrivateMounts", "b", NULL, offsetof(struct security_info, private_mounts) },
- { "PrivateNetwork", "b", NULL, offsetof(struct security_info, private_network) },
- { "PrivateTmp", "b", NULL, offsetof(struct security_info, private_tmp) },
- { "PrivateUsers", "b", NULL, offsetof(struct security_info, private_users) },
- { "ProtectControlGroups", "b", NULL, offsetof(struct security_info, protect_control_groups) },
- { "ProtectHome", "s", NULL, offsetof(struct security_info, protect_home) },
- { "ProtectHostname", "b", NULL, offsetof(struct security_info, protect_hostname) },
- { "ProtectKernelModules", "b", NULL, offsetof(struct security_info, protect_kernel_modules) },
- { "ProtectKernelTunables", "b", NULL, offsetof(struct security_info, protect_kernel_tunables) },
- { "ProtectKernelLogs", "b", NULL, offsetof(struct security_info, protect_kernel_logs) },
- { "ProtectClock", "b", NULL, offsetof(struct security_info, protect_clock) },
- { "ProtectSystem", "s", NULL, offsetof(struct security_info, protect_system) },
- { "RemoveIPC", "b", NULL, offsetof(struct security_info, remove_ipc) },
- { "RestrictAddressFamilies", "(bas)", property_read_restrict_address_families, 0 },
- { "RestrictNamespaces", "t", NULL, offsetof(struct security_info, restrict_namespaces) },
- { "RestrictRealtime", "b", NULL, offsetof(struct security_info, restrict_realtime) },
- { "RestrictSUIDSGID", "b", NULL, offsetof(struct security_info, restrict_suid_sgid) },
- { "RootDirectory", "s", NULL, offsetof(struct security_info, root_directory) },
- { "RootImage", "s", NULL, offsetof(struct security_info, root_image) },
- { "SupplementaryGroups", "as", NULL, offsetof(struct security_info, supplementary_groups) },
- { "SystemCallArchitectures", "as", NULL, offsetof(struct security_info, system_call_architectures) },
- { "SystemCallFilter", "(as)", property_read_system_call_filter, 0 },
- { "Type", "s", NULL, offsetof(struct security_info, type) },
- { "UMask", "u", NULL, offsetof(struct security_info, _umask) },
- { "User", "s", NULL, offsetof(struct security_info, user) },
+ { "AmbientCapabilities", "t", NULL, offsetof(SecurityInfo, ambient_capabilities) },
+ { "CapabilityBoundingSet", "t", NULL, offsetof(SecurityInfo, capability_bounding_set) },
+ { "DefaultDependencies", "b", NULL, offsetof(SecurityInfo, default_dependencies) },
+ { "Delegate", "b", NULL, offsetof(SecurityInfo, delegate) },
+ { "DeviceAllow", "a(ss)", property_read_device_allow, 0 },
+ { "DevicePolicy", "s", NULL, offsetof(SecurityInfo, device_policy) },
+ { "DynamicUser", "b", NULL, offsetof(SecurityInfo, dynamic_user) },
+ { "FragmentPath", "s", NULL, offsetof(SecurityInfo, fragment_path) },
+ { "IPAddressAllow", "a(iayu)", property_read_ip_address_allow, 0 },
+ { "IPAddressDeny", "a(iayu)", property_read_ip_address_allow, 0 },
+ { "IPIngressFilterPath", "as", property_read_ip_filters, 0 },
+ { "IPEgressFilterPath", "as", property_read_ip_filters, 0 },
+ { "Id", "s", NULL, offsetof(SecurityInfo, id) },
+ { "KeyringMode", "s", NULL, offsetof(SecurityInfo, keyring_mode) },
+ { "ProtectProc", "s", NULL, offsetof(SecurityInfo, protect_proc) },
+ { "ProcSubset", "s", NULL, offsetof(SecurityInfo, proc_subset) },
+ { "LoadState", "s", NULL, offsetof(SecurityInfo, load_state) },
+ { "LockPersonality", "b", NULL, offsetof(SecurityInfo, lock_personality) },
+ { "MemoryDenyWriteExecute", "b", NULL, offsetof(SecurityInfo, memory_deny_write_execute) },
+ { "NoNewPrivileges", "b", NULL, offsetof(SecurityInfo, no_new_privileges) },
+ { "NotifyAccess", "s", NULL, offsetof(SecurityInfo, notify_access) },
+ { "PrivateDevices", "b", NULL, offsetof(SecurityInfo, private_devices) },
+ { "PrivateMounts", "b", NULL, offsetof(SecurityInfo, private_mounts) },
+ { "PrivateNetwork", "b", NULL, offsetof(SecurityInfo, private_network) },
+ { "PrivateTmp", "b", NULL, offsetof(SecurityInfo, private_tmp) },
+ { "PrivateUsers", "b", NULL, offsetof(SecurityInfo, private_users) },
+ { "ProtectControlGroups", "b", NULL, offsetof(SecurityInfo, protect_control_groups) },
+ { "ProtectHome", "s", NULL, offsetof(SecurityInfo, protect_home) },
+ { "ProtectHostname", "b", NULL, offsetof(SecurityInfo, protect_hostname) },
+ { "ProtectKernelModules", "b", NULL, offsetof(SecurityInfo, protect_kernel_modules) },
+ { "ProtectKernelTunables", "b", NULL, offsetof(SecurityInfo, protect_kernel_tunables) },
+ { "ProtectKernelLogs", "b", NULL, offsetof(SecurityInfo, protect_kernel_logs) },
+ { "ProtectClock", "b", NULL, offsetof(SecurityInfo, protect_clock) },
+ { "ProtectSystem", "s", NULL, offsetof(SecurityInfo, protect_system) },
+ { "RemoveIPC", "b", NULL, offsetof(SecurityInfo, remove_ipc) },
+ { "RestrictAddressFamilies", "(bas)", property_read_restrict_address_families, 0 },
+ { "RestrictNamespaces", "t", property_read_restrict_namespaces, 0 },
+ { "RestrictRealtime", "b", NULL, offsetof(SecurityInfo, restrict_realtime) },
+ { "RestrictSUIDSGID", "b", NULL, offsetof(SecurityInfo, restrict_suid_sgid) },
+ { "RootDirectory", "s", NULL, offsetof(SecurityInfo, root_directory) },
+ { "RootImage", "s", NULL, offsetof(SecurityInfo, root_image) },
+ { "SupplementaryGroups", "as", NULL, offsetof(SecurityInfo, supplementary_groups) },
+ { "SystemCallArchitectures", "as", property_read_syscall_archs, 0 },
+ { "SystemCallFilter", "(as)", property_read_system_call_filter, 0 },
+ { "Type", "s", NULL, offsetof(SecurityInfo, type) },
+ { "UMask", "u", property_read_umask, 0 },
+ { "User", "s", NULL, offsetof(SecurityInfo, user) },
{}
};
}
static int analyze_security_one(sd_bus *bus, const char *name, Table *overview_table, AnalyzeSecurityFlags flags) {
- _cleanup_(security_info_free) struct security_info info = {
- .default_dependencies = true,
- .capability_bounding_set = UINT64_MAX,
- .restrict_namespaces = UINT64_MAX,
- ._umask = 0002,
- };
+ _cleanup_(security_info_freep) SecurityInfo *info = security_info_new();
+ if (!info)
+ return log_oom();
+
int r;
assert(bus);
assert(name);
- r = acquire_security_info(bus, name, &info, flags);
+ r = acquire_security_info(bus, name, info, flags);
if (r == -EMEDIUMTYPE) /* Ignore this one because not loaded or Type is oneshot */
return 0;
if (r < 0)
return r;
- r = assess(&info, overview_table, flags);
+ r = assess(info, overview_table, flags);
if (r < 0)
return r;
return 0;
}
+/* Refactoring SecurityInfo so that it can make use of existing struct variables instead of reading from dbus */
+static int get_security_info(Unit *u, ExecContext *c, CGroupContext *g, SecurityInfo **ret_info) {
+ assert(ret_info);
+
+ _cleanup_(security_info_freep) SecurityInfo *info = security_info_new();
+ if (!info)
+ return log_oom();
+
+ if (u) {
+ if (u->id) {
+ info->id = strdup(u->id);
+ if (!info->id)
+ return log_oom();
+ }
+ if (unit_type_to_string(u->type)) {
+ info->type = strdup(unit_type_to_string(u->type));
+ if (!info->type)
+ return log_oom();
+ }
+ if (unit_load_state_to_string(u->load_state)) {
+ info->load_state = strdup(unit_load_state_to_string(u->load_state));
+ if (!info->load_state)
+ return log_oom();
+ }
+ if (u->fragment_path) {
+ info->fragment_path = strdup(u->fragment_path);
+ if (!info->fragment_path)
+ return log_oom();
+ }
+ info->default_dependencies = u->default_dependencies;
+ if (u->type == UNIT_SERVICE && notify_access_to_string(SERVICE(u)->notify_access)) {
+ info->notify_access = strdup(notify_access_to_string(SERVICE(u)->notify_access));
+ if (!info->notify_access)
+ return log_oom();
+ }
+ }
+
+ if (c) {
+ info->ambient_capabilities = c->capability_ambient_set;
+ info->capability_bounding_set = c->capability_bounding_set;
+ if (c->user) {
+ info->user = strdup(c->user);
+ if (!info->user)
+ return log_oom();
+ }
+ if (c->supplementary_groups) {
+ info->supplementary_groups = strv_copy(c->supplementary_groups);
+ if (!info->supplementary_groups)
+ return log_oom();
+ }
+ info->dynamic_user = c->dynamic_user;
+ if (exec_keyring_mode_to_string(c->keyring_mode)) {
+ info->keyring_mode = strdup(exec_keyring_mode_to_string(c->keyring_mode));
+ if (!info->keyring_mode)
+ return log_oom();
+ }
+ if (protect_proc_to_string(c->protect_proc)) {
+ info->protect_proc = strdup(protect_proc_to_string(c->protect_proc));
+ if (!info->protect_proc)
+ return log_oom();
+ }
+ if (proc_subset_to_string(c->proc_subset)) {
+ info->proc_subset = strdup(proc_subset_to_string(c->proc_subset));
+ if (!info->proc_subset)
+ return log_oom();
+ }
+ info->lock_personality = c->lock_personality;
+ info->memory_deny_write_execute = c->memory_deny_write_execute;
+ info->no_new_privileges = c->no_new_privileges;
+ info->protect_hostname = c->protect_hostname;
+ info->private_devices = c->private_devices;
+ info->private_mounts = c->private_mounts;
+ info->private_network = c->private_network;
+ info->private_tmp = c->private_tmp;
+ info->private_users = c->private_users;
+ info->protect_control_groups = c->protect_control_groups;
+ info->protect_kernel_modules = c->protect_kernel_modules;
+ info->protect_kernel_tunables = c->protect_kernel_tunables;
+ info->protect_kernel_logs = c->protect_kernel_logs;
+ info->protect_clock = c->protect_clock;
+ if (protect_home_to_string(c->protect_home)) {
+ info->protect_home = strdup(protect_home_to_string(c->protect_home));
+ if (!info->protect_home)
+ return log_oom();
+ }
+ if (protect_system_to_string(c->protect_system)) {
+ info->protect_system = strdup(protect_system_to_string(c->protect_system));
+ if (!info->protect_system)
+ return log_oom();
+ }
+ info->remove_ipc = c->remove_ipc;
+ info->restrict_address_family_inet =
+ info->restrict_address_family_unix =
+ info->restrict_address_family_netlink =
+ info->restrict_address_family_packet =
+ info->restrict_address_family_other =
+ c->address_families_allow_list;
+
+ void *key;
+ SET_FOREACH(key, c->address_families) {
+ int family = PTR_TO_INT(key);
+ if (family == 0)
+ continue;
+ if (IN_SET(family, AF_INET, AF_INET6))
+ info->restrict_address_family_inet = !c->address_families_allow_list;
+ else if (family == AF_UNIX)
+ info->restrict_address_family_unix = !c->address_families_allow_list;
+ else if (family == AF_NETLINK)
+ info->restrict_address_family_netlink = !c->address_families_allow_list;
+ else if (family == AF_PACKET)
+ info->restrict_address_family_packet = !c->address_families_allow_list;
+ else
+ info->restrict_address_family_other = !c->address_families_allow_list;
+ }
+
+ info->restrict_namespaces = c->restrict_namespaces;
+ info->restrict_realtime = c->restrict_realtime;
+ info->restrict_suid_sgid = c->restrict_suid_sgid;
+ if (c->root_directory) {
+ info->root_directory = strdup(c->root_directory);
+ if (!info->root_directory)
+ return log_oom();
+ }
+ if (c->root_image) {
+ info->root_image = strdup(c->root_image);
+ if (!info->root_image)
+ return log_oom();
+ }
+ info->_umask = c->umask;
+ if (c->syscall_archs) {
+ info->system_call_architectures = set_copy(c->syscall_archs);
+ if (!info->system_call_architectures)
+ return log_oom();
+ }
+ info->system_call_filter_allow_list = c->syscall_allow_list;
+ if (c->syscall_filter) {
+ info->system_call_filter = hashmap_copy(c->syscall_filter);
+ if (!info->system_call_filter)
+ return log_oom();
+ }
+ }
+
+ if (g) {
+ info->delegate = g->delegate;
+ if (cgroup_device_policy_to_string(g->device_policy)) {
+ info->device_policy = strdup(cgroup_device_policy_to_string(g->device_policy));
+ if (!info->device_policy)
+ return log_oom();
+ }
+
+ IPAddressAccessItem *i;
+ bool deny_ipv4 = false, deny_ipv6 = false;
+
+ LIST_FOREACH(items, i, g->ip_address_deny) {
+ if (i->family == AF_INET && i->prefixlen == 0)
+ deny_ipv4 = true;
+ else if (i->family == AF_INET6 && i->prefixlen == 0)
+ deny_ipv6 = true;
+ }
+ info->ip_address_deny_all = deny_ipv4 && deny_ipv6;
+
+ info->ip_address_allow_localhost = info->ip_address_allow_other = false;
+ LIST_FOREACH(items, i, g->ip_address_allow) {
+ if (in_addr_is_localhost(i->family, &i->address))
+ info->ip_address_allow_localhost = true;
+ else
+ info->ip_address_allow_other = true;
+ }
+
+ info->ip_filters_custom_ingress = !strv_isempty(g->ip_filters_ingress);
+ info->ip_filters_custom_egress = !strv_isempty(g->ip_filters_egress);
+ info->device_allow_non_empty = !LIST_IS_EMPTY(g->device_allow);
+ }
+
+ *ret_info = TAKE_PTR(info);
+
+ return 0;
+}
+
int analyze_security(sd_bus *bus, char **units, AnalyzeSecurityFlags flags) {
_cleanup_(table_unrefp) Table *overview_table = NULL;
int ret = 0, r;