1
0
mirror of https://github.com/systemd/systemd synced 2026-04-24 07:55:12 +02:00

Compare commits

...

24 Commits

Author SHA1 Message Date
Lennart Poettering
bd4dea76de veritysetup: fix memory corruption
We must copy the option string, since in one case we are called with a
pointer into dynamic memory that will be freed by the caller.

As discussed here: https://github.com/systemd/systemd/pull/22908/files#r839394490

Follow-up for: #22908
2022-04-02 02:22:39 +09:00
Yu Watanabe
95cd21928f
Merge pull request #22939 from yuwata/tree-wide-space
tree-wide: add space after if, switch, for, and while
2022-04-02 01:32:26 +09:00
Yu Watanabe
b17a681be5 tree-wide: fix typo 2022-04-02 00:34:39 +09:00
Lennart Poettering
0d08db7f89 udev: add /dev/disk/by-diskseq symlink for block devices
This adds another symlink for block devices:

    /dev/disk/by-diskseq/<number>

where the number is the diskseq number as exposed by the kernel. It's
useful for apps because they can use it to open a device by diskseq, in
a way that is safe against device node reuse. I.e. if a device node path
like this is passed to an app it could open the device node via the
symlink and also parse the diskseq from the path. Once the device is
opened it could compare the parsed diskseq with the one returned by
BLKGETDISKSEQ on the open node, and if it matches they know they are
talking to the right device.

Fixes: #22906
2022-04-01 23:44:37 +09:00
Yu Watanabe
37ebfe49de
Merge pull request #22926 from bluca/analyze_offline_filter
analyze: fix offline checks for syscall filter and 'native' architecture
2022-04-01 23:43:18 +09:00
Lennart Poettering
356ad32dc2
Merge pull request #22921 from poettering/uid-range-tweaks
userns uid range tweaks: taint systemd if assigned userns uid range too short, and show userns uid range in userdbctl output
2022-04-01 15:58:55 +02:00
Yu Watanabe
798931160e tree-wide: add a space after if, switch, for, and while 2022-04-01 22:48:42 +09:00
Yu Watanabe
72dce85a60 test: add space between arguments 2022-04-01 22:28:13 +09:00
Lennart Poettering
fdf02a4f26 path-util: use STR_IN_SET() where appropriate 2022-04-01 15:23:43 +02:00
Lennart Poettering
6cdd6d1acc notify: remove spurious whitespace 2022-04-01 15:23:43 +02:00
Lennart Poettering
ca782b85fc
Merge pull request #22934 from poettering/tls-test-fix-root
tests: make test-resolved-stream suceed even when run as root with restrictive access mode on build tree dir
2022-04-01 15:22:43 +02:00
Lennart Poettering
aed3c5eca3 process-util: refactor APIs for reading /proc/self/xyz symlinks
The three functions for reading cwd, exe and root symlinks of processes
already share a common core: get_process_link_contents(). Let's refactor
that a bit, and move formatting of the /proc/self/ path into this helper
function instead of doing that in the caller, thus sharing more code.

While we are at it, make the return parameters optional, in case the
information if the links are readable is interesting, but the contents
is not. (This also means safe_getcwd() and readlinkat_malloc() are
updated to make the return parameter optional, as these are called by
the relevant three functions)
2022-04-01 15:22:27 +02:00
Luca Boccassi
dd51e725df analyze: fix offline check for syscal filter
The deny/allow list check was inverted, if we are deny listing and the
hashmap contains the syscall then that's good

Fixes https://github.com/systemd/systemd/issues/22914
2022-04-01 10:42:48 +01:00
Luca Boccassi
1449b0f8a9 analyze: fix offline check for 'native' syscall architecture
Enum values are stored in the set, not strings
2022-04-01 10:42:48 +01:00
Lennart Poettering
9cce7fb193 userdbctl: also show available UID range in current userns
Containers generally have a smaller UID range assigned than host
systems. Let's visualize this in the user/group tables. We insert
markers for unavailable regions. This way display is identical to status
quo ante on host systems, but in containers unavailable ranges will be
shown as that.

And while we are at it, also hide well-known UID ranges when they are
outside of userns uid_map range. This is mostly about the "container"
range. It's pointless showing the cotnainer range (i.e. a range UID >
65535) if that range isn#t available in the container anyway.
2022-04-01 11:21:44 +02:00
Lennart Poettering
49888d31b6 update TODO 2022-04-01 11:21:44 +02:00
Lennart Poettering
63e8df046b pid1: add taint flag if uid/gid userns range too small
This will taint systemd if invoked in containers that do not have the
full 16bit range of UIDs defined.

we pretty much need uid root…nobody to be defined for a variety of
purposes, hence let's add this taint flag. Of course taints are
graceful, but it at least communicates the mess in some way...
2022-04-01 11:21:44 +02:00
Lennart Poettering
556560495e uid-range: replace uid_range_contains() by more generalized uid_range_covers()
The former checks if one UID is inside the uid range set. The latter
checks if a full UID range is inside the uid range set. The former is
hence a special case of the latter.
2022-04-01 11:20:12 +02:00
Lennart Poettering
0a5c6a57c6 uid-range: add some overflow checks 2022-04-01 11:20:12 +02:00
Lennart Poettering
5674aa7a2c uid-range: add new uid_range_load_userns() for loading /proc/self/uid_map 2022-04-01 11:20:12 +02:00
Lennart Poettering
2e37ebdae9 test: port test-uid-range to tests.h 2022-04-01 11:20:12 +02:00
Lennart Poettering
09bbaa419b uid-range: use size_t for array size 2022-04-01 11:20:12 +02:00
Lennart Poettering
ed59b44309 test-resolved-stream: before entering user/network namespaces check if that's safe
I regularly run my tests also as root, since some of the tested code
uses privileged APIs. The test-resolved-stream so far tried to run its
tests in a user/network namespace if that can be allocated. This caused
the tests to fail on my system where once the user namespace is opened
access to the build tree in my $HOME is prohibited (due to restricted
access modes on my home dir). Let's add a check for that: before
actually isolating the test in a user/network namespace, let's see if
that would make it impossible for us to access the build tree (which we
need to do load the TLS certificates the test requires).

This should make the test pass when run as root from a build tree with
restrictive access mode.
2022-04-01 11:14:56 +02:00
Lennart Poettering
8419213d99 tests: modernize load_testdata_env() a bit
Let's add assert() around everyhing we don't expect to fail.

Port to path_extract_directory().

Log errrors from load_env_file_pairs() which we ignore.
2022-04-01 11:14:56 +02:00
74 changed files with 571 additions and 188 deletions

4
TODO
View File

@ -122,7 +122,7 @@ Features:
* maybe add a generator that reads /proc/cmdline, looks for * maybe add a generator that reads /proc/cmdline, looks for
systemd.pull-raw-portable=, systemd-pull-raw-sysext= and similar switches systemd.pull-raw-portable=, systemd-pull-raw-sysext= and similar switches
that take an URL as parameter. It then generates service units for that take an URL as parameter. It then generates service units for
systemd-pull calls thta download these URLs if not installed yet. usecase: systemd-pull calls that download these URLs if not installed yet. usecase:
invoke a VM or nspawn container in a way it automatically deploys/runs these invoke a VM or nspawn container in a way it automatically deploys/runs these
images as OS payloads. i.e. have a generic OS image you can point to any images as OS payloads. i.e. have a generic OS image you can point to any
payload you like, which is then downloaded, securely verified and run. payload you like, which is then downloaded, securely verified and run.
@ -761,8 +761,6 @@ Features:
systemd-journald writes to /var/log/journal, which could be useful when we systemd-journald writes to /var/log/journal, which could be useful when we
doing disk usage calculations and so on. doing disk usage calculations and so on.
* taint systemd if there are fewer than 65536 users assigned (userns) to the system.
* deprecate RootDirectoryStartOnly= in favour of a new ExecStart= prefix char * deprecate RootDirectoryStartOnly= in favour of a new ExecStart= prefix char
* add a new RuntimeDirectoryPreserve= mode that defines a similar lifecycle for * add a new RuntimeDirectoryPreserve= mode that defines a similar lifecycle for

View File

@ -943,7 +943,7 @@ Table=1234</programlisting></para>
<para>When <varname>Bond=</varname> is specified to a wireless interface, defaults to 3 <para>When <varname>Bond=</varname> is specified to a wireless interface, defaults to 3
seconds. When the DHCPv4 client is enabled and <varname>UseMTU=</varname> in the [DHCPv4] seconds. When the DHCPv4 client is enabled and <varname>UseMTU=</varname> in the [DHCPv4]
sectionis enabled, defaults to 5 seconds. Otherwise, defaults to the value specified with section enabled, defaults to 5 seconds. Otherwise, defaults to the value specified with
<varname>ConfigureWithoutCarrier=</varname>. When <varname>ActivationPolicy=</varname> is set <varname>ConfigureWithoutCarrier=</varname>. When <varname>ActivationPolicy=</varname> is set
to <literal>always-up</literal>, this is forced to <literal>yes</literal>, and ignored any to <literal>always-up</literal>, this is forced to <literal>yes</literal>, and ignored any
user specified values.</para> user specified values.</para>

View File

@ -121,4 +121,9 @@ ENV{DEVTYPE}=="partition", ENV{ID_WWN_WITH_EXTENSION}=="?*", SYMLINK+="disk/by-i
ENV{ID_PART_ENTRY_UUID}=="?*", SYMLINK+="disk/by-partuuid/$env{ID_PART_ENTRY_UUID}" ENV{ID_PART_ENTRY_UUID}=="?*", SYMLINK+="disk/by-partuuid/$env{ID_PART_ENTRY_UUID}"
ENV{ID_PART_ENTRY_SCHEME}=="gpt", ENV{ID_PART_ENTRY_NAME}=="?*", SYMLINK+="disk/by-partlabel/$env{ID_PART_ENTRY_NAME}" ENV{ID_PART_ENTRY_SCHEME}=="gpt", ENV{ID_PART_ENTRY_NAME}=="?*", SYMLINK+="disk/by-partlabel/$env{ID_PART_ENTRY_NAME}"
# by-diskseq link (if an app is told to open a path like this, they may parse
# the diskseq number from the path, then issue BLKGETDISKSEQ to verify they really got
# the right device, to access specific disks in a race-free fashion)
ENV{DISKSEQ}=="?*", ENV{DEVTYPE}!="partition", SYMLINK+="disk/by-diskseq/$env{DISKSEQ}"
LABEL="persistent_storage_end" LABEL="persistent_storage_end"

View File

@ -530,6 +530,8 @@ static int assess_restrict_namespaces(
return 0; return 0;
} }
#if HAVE_SECCOMP
static int assess_system_call_architectures( static int assess_system_call_architectures(
const struct security_assessor *a, const struct security_assessor *a,
const SecurityInfo *info, const SecurityInfo *info,
@ -537,16 +539,19 @@ static int assess_system_call_architectures(
uint64_t *ret_badness, uint64_t *ret_badness,
char **ret_description) { char **ret_description) {
uint32_t native = 0;
char *d; char *d;
uint64_t b; uint64_t b;
assert(ret_badness); assert(ret_badness);
assert(ret_description); assert(ret_description);
assert_se(seccomp_arch_from_string("native", &native) >= 0);
if (set_isempty(info->system_call_architectures)) { if (set_isempty(info->system_call_architectures)) {
b = 10; b = 10;
d = strdup("Service may execute system calls with all ABIs"); d = strdup("Service may execute system calls with all ABIs");
} else if (set_contains(info->system_call_architectures, "native") && } else if (set_contains(info->system_call_architectures, UINT32_TO_PTR(native + 1)) &&
set_size(info->system_call_architectures) == 1) { set_size(info->system_call_architectures) == 1) {
b = 0; b = 0;
d = strdup("Service may execute system calls only with native ABI"); d = strdup("Service may execute system calls only with native ABI");
@ -564,8 +569,6 @@ static int assess_system_call_architectures(
return 0; return 0;
} }
#if HAVE_SECCOMP
static bool syscall_names_in_filter(Hashmap *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; const char *syscall;
@ -587,7 +590,7 @@ static bool syscall_names_in_filter(Hashmap *s, bool allow_list, const SyscallFi
if (id < 0) if (id < 0)
continue; continue;
if (hashmap_contains(s, syscall) == allow_list) { if (hashmap_contains(s, syscall) != allow_list) {
log_debug("Offending syscall filter item: %s", syscall); log_debug("Offending syscall filter item: %s", syscall);
if (ret_offending_syscall) if (ret_offending_syscall)
*ret_offending_syscall = syscall; *ret_offending_syscall = syscall;
@ -1476,6 +1479,7 @@ static const struct security_assessor security_assessor_table[] = {
.assess = assess_bool, .assess = assess_bool,
.offset = offsetof(SecurityInfo, restrict_address_family_other), .offset = offsetof(SecurityInfo, restrict_address_family_other),
}, },
#if HAVE_SECCOMP
{ {
.id = "SystemCallArchitectures=", .id = "SystemCallArchitectures=",
.json_field = "SystemCallArchitectures", .json_field = "SystemCallArchitectures",
@ -1484,7 +1488,6 @@ static const struct security_assessor security_assessor_table[] = {
.range = 10, .range = 10,
.assess = assess_system_call_architectures, .assess = assess_system_call_architectures,
}, },
#if HAVE_SECCOMP
{ {
.id = "SystemCallFilter=~@swap", .id = "SystemCallFilter=~@swap",
.json_field = "SystemCallFilter_swap", .json_field = "SystemCallFilter_swap",

View File

@ -2,7 +2,7 @@
BEGIN{ BEGIN{
print "const char *arphrd_to_name(int id) {" print "const char *arphrd_to_name(int id) {"
print " switch(id) {" print " switch (id) {"
} }
!/^HDLC$/ { !/^HDLC$/ {
printf " case ARPHRD_%s: return \"%s\";\n", $1, $1 printf " case ARPHRD_%s: return \"%s\";\n", $1, $1

View File

@ -119,7 +119,6 @@ int readlinkat_malloc(int fd, const char *p, char **ret) {
size_t l = PATH_MAX; size_t l = PATH_MAX;
assert(p); assert(p);
assert(ret);
for (;;) { for (;;) {
_cleanup_free_ char *c = NULL; _cleanup_free_ char *c = NULL;
@ -135,7 +134,10 @@ int readlinkat_malloc(int fd, const char *p, char **ret) {
if ((size_t) n < l) { if ((size_t) n < l) {
c[n] = 0; c[n] = 0;
*ret = TAKE_PTR(c);
if (ret)
*ret = TAKE_PTR(c);
return 0; return 0;
} }

View File

@ -162,7 +162,7 @@ struct _packed_ indirect_storage {
unsigned n_buckets; /* number of buckets */ unsigned n_buckets; /* number of buckets */
unsigned idx_lowest_entry; /* Index below which all buckets are free. unsigned idx_lowest_entry; /* Index below which all buckets are free.
Makes "while(hashmap_steal_first())" loops Makes "while (hashmap_steal_first())" loops
O(n) instead of O(n^2) for unordered hashmaps. */ O(n) instead of O(n^2) for unordered hashmaps. */
uint8_t _pad[3]; /* padding for the whole HashmapBase */ uint8_t _pad[3]; /* padding for the whole HashmapBase */
/* The bitfields in HashmapBase complete the alignment of the whole thing. */ /* The bitfields in HashmapBase complete the alignment of the whole thing. */

View File

@ -63,7 +63,7 @@ char *path_make_absolute(const char *p, const char *prefix) {
} }
int safe_getcwd(char **ret) { int safe_getcwd(char **ret) {
char *cwd; _cleanup_free_ char *cwd = NULL;
cwd = get_current_dir_name(); cwd = get_current_dir_name();
if (!cwd) if (!cwd)
@ -71,12 +71,12 @@ int safe_getcwd(char **ret) {
/* Let's make sure the directory is really absolute, to protect us from the logic behind /* Let's make sure the directory is really absolute, to protect us from the logic behind
* CVE-2018-1000001 */ * CVE-2018-1000001 */
if (cwd[0] != '/') { if (cwd[0] != '/')
free(cwd);
return -ENOMEDIUM; return -ENOMEDIUM;
}
*ret = cwd; if (ret)
*ret = TAKE_PTR(cwd);
return 0; return 0;
} }
@ -1235,9 +1235,10 @@ bool hidden_or_backup_file(const char *filename) {
assert(filename); assert(filename);
if (filename[0] == '.' || if (filename[0] == '.' ||
streq(filename, "lost+found") || STR_IN_SET(filename,
streq(filename, "aquota.user") || "lost+found",
streq(filename, "aquota.group") || "aquota.user",
"aquota.group") ||
endswith(filename, "~")) endswith(filename, "~"))
return true; return true;

View File

@ -472,37 +472,33 @@ int get_process_capeff(pid_t pid, char **ret) {
return r; return r;
} }
static int get_process_link_contents(const char *proc_file, char **ret) { static int get_process_link_contents(pid_t pid, const char *proc_file, char **ret) {
const char *p;
int r; int r;
assert(proc_file); assert(proc_file);
assert(ret);
r = readlink_malloc(proc_file, ret); p = procfs_file_alloca(pid, proc_file);
if (r == -ENOENT)
return -ESRCH;
if (r < 0)
return r;
return 0; r = readlink_malloc(p, ret);
return r == -ENOENT ? -ESRCH : r;
} }
int get_process_exe(pid_t pid, char **ret) { int get_process_exe(pid_t pid, char **ret) {
const char *p;
char *d; char *d;
int r; int r;
assert(pid >= 0); assert(pid >= 0);
assert(ret);
p = procfs_file_alloca(pid, "exe"); r = get_process_link_contents(pid, "exe", ret);
r = get_process_link_contents(p, ret);
if (r < 0) if (r < 0)
return r; return r;
d = endswith(*ret, " (deleted)"); if (ret) {
if (d) d = endswith(*ret, " (deleted)");
*d = '\0'; if (d)
*d = '\0';
}
return 0; return 0;
} }
@ -572,28 +568,17 @@ int get_process_gid(pid_t pid, gid_t *ret) {
} }
int get_process_cwd(pid_t pid, char **ret) { int get_process_cwd(pid_t pid, char **ret) {
const char *p;
assert(pid >= 0); assert(pid >= 0);
assert(ret);
if (pid == 0 || pid == getpid_cached()) if (pid == 0 || pid == getpid_cached())
return safe_getcwd(ret); return safe_getcwd(ret);
p = procfs_file_alloca(pid, "cwd"); return get_process_link_contents(pid, "cwd", ret);
return get_process_link_contents(p, ret);
} }
int get_process_root(pid_t pid, char **ret) { int get_process_root(pid_t pid, char **ret) {
const char *p;
assert(pid >= 0); assert(pid >= 0);
assert(ret); return get_process_link_contents(pid, "root", ret);
p = procfs_file_alloca(pid, "root");
return get_process_link_contents(p, ret);
} }
#define ENVIRONMENT_BLOCK_MAX (5U*1024U*1024U) #define ENVIRONMENT_BLOCK_MAX (5U*1024U*1024U)

View File

@ -228,7 +228,7 @@ struct cmsghdr* cmsg_find(struct msghdr *mh, int level, int type, socklen_t leng
({ \ ({ \
const union sockaddr_union *__sa = &(sa); \ const union sockaddr_union *__sa = &(sa); \
size_t _len; \ size_t _len; \
switch(__sa->sa.sa_family) { \ switch (__sa->sa.sa_family) { \
case AF_INET: \ case AF_INET: \
_len = sizeof(struct sockaddr_in); \ _len = sizeof(struct sockaddr_in); \
break; \ break; \

View File

@ -113,4 +113,4 @@ ssize_t string_table_lookup(const char * const *table, size_t len, const char *k
fputc_unlocked('\n', stdout); \ fputc_unlocked('\n', stdout); \
} \ } \
funlockfile(stdout); \ funlockfile(stdout); \
} while(false) } while (false)

View File

@ -70,7 +70,7 @@ int getxattr_at_malloc(
by_procfs = true; /* fgetxattr() is not going to work, go via /proc/ link right-away */ by_procfs = true; /* fgetxattr() is not going to work, go via /proc/ link right-away */
} }
for(;;) { for (;;) {
_cleanup_free_ char *v = NULL; _cleanup_free_ char *v = NULL;
ssize_t n; ssize_t n;

View File

@ -35,7 +35,7 @@ static BOOLEAN verify_gpt(union GptHeaderBuffer *gpt_header_buffer, EFI_LBA lba_
h = &gpt_header_buffer->gpt_header; h = &gpt_header_buffer->gpt_header;
/* Some superficial validation of the GPT header */ /* Some superficial validation of the GPT header */
if(CompareMem(&h->Header.Signature, "EFI PART", sizeof(h->Header.Signature) != 0)) if (CompareMem(&h->Header.Signature, "EFI PART", sizeof(h->Header.Signature) != 0))
return FALSE; return FALSE;
if (h->Header.HeaderSize < 92 || h->Header.HeaderSize > 512) if (h->Header.HeaderSize < 92 || h->Header.HeaderSize > 512)

View File

@ -22,7 +22,7 @@ static int bpf_access_type(const char *acc) {
assert(acc); assert(acc);
for (; *acc; acc++) for (; *acc; acc++)
switch(*acc) { switch (*acc) {
case 'r': case 'r':
r |= BPF_DEVCG_ACC_READ; r |= BPF_DEVCG_ACC_READ;
break; break;

View File

@ -2162,7 +2162,7 @@ static int install_error(
for (size_t i = 0; i < n_changes; i++) for (size_t i = 0; i < n_changes; i++)
switch(changes[i].type_or_errno) { switch (changes[i].type_or_errno) {
case 0 ... _UNIT_FILE_CHANGE_TYPE_MAX: /* not errors */ case 0 ... _UNIT_FILE_CHANGE_TYPE_MAX: /* not errors */
continue; continue;

View File

@ -82,6 +82,7 @@
#include "terminal-util.h" #include "terminal-util.h"
#include "time-util.h" #include "time-util.h"
#include "transaction.h" #include "transaction.h"
#include "uid-range.h"
#include "umask-util.h" #include "umask-util.h"
#include "unit-name.h" #include "unit-name.h"
#include "user-util.h" #include "user-util.h"
@ -4350,16 +4351,34 @@ int manager_dispatch_user_lookup_fd(sd_event_source *source, int fd, uint32_t re
return 0; return 0;
} }
static int short_uid_range(const char *path) {
_cleanup_free_ UidRange *p = NULL;
size_t n = 0;
int r;
assert(path);
/* Taint systemd if we the UID range assigned to this environment doesn't at least cover 0…65534,
* i.e. from root to nobody. */
r = uid_range_load_userns(&p, &n, path);
if (ERRNO_IS_NOT_SUPPORTED(r))
return false;
if (r < 0)
return log_debug_errno(r, "Failed to load %s: %m", path);
return !uid_range_covers(p, n, 0, 65535);
}
char *manager_taint_string(Manager *m) { char *manager_taint_string(Manager *m) {
_cleanup_free_ char *destination = NULL, *overflowuid = NULL, *overflowgid = NULL; _cleanup_free_ char *destination = NULL, *overflowuid = NULL, *overflowgid = NULL;
struct utsname uts; struct utsname uts;
char *buf, *e; char *buf, *e;
int r; int r;
/* Returns a "taint string", e.g. "local-hwclock:var-run-bad". /* Returns a "taint string", e.g. "local-hwclock:var-run-bad". Only things that are detected at
* Only things that are detected at runtime should be tagged * runtime should be tagged here. For stuff that is set during compilation, emit a warning in the
* here. For stuff that is set during compilation, emit a warning * configuration phase. */
* in the configuration phase. */
assert(m); assert(m);
@ -4370,7 +4389,9 @@ char *manager_taint_string(Manager *m) {
"var-run-bad:" "var-run-bad:"
"overflowuid-not-65534:" "overflowuid-not-65534:"
"overflowgid-not-65534:" "overflowgid-not-65534:"
"old-kernel:")); "old-kernel:"
"short-uid-range:"
"short-gid-range:"));
if (!buf) if (!buf)
return NULL; return NULL;
@ -4396,7 +4417,6 @@ char *manager_taint_string(Manager *m) {
r = read_one_line_file("/proc/sys/kernel/overflowuid", &overflowuid); r = read_one_line_file("/proc/sys/kernel/overflowuid", &overflowuid);
if (r >= 0 && !streq(overflowuid, "65534")) if (r >= 0 && !streq(overflowuid, "65534"))
e = stpcpy(e, "overflowuid-not-65534:"); e = stpcpy(e, "overflowuid-not-65534:");
r = read_one_line_file("/proc/sys/kernel/overflowgid", &overflowgid); r = read_one_line_file("/proc/sys/kernel/overflowgid", &overflowgid);
if (r >= 0 && !streq(overflowgid, "65534")) if (r >= 0 && !streq(overflowgid, "65534"))
e = stpcpy(e, "overflowgid-not-65534:"); e = stpcpy(e, "overflowgid-not-65534:");
@ -4405,6 +4425,11 @@ char *manager_taint_string(Manager *m) {
if (strverscmp_improved(uts.release, KERNEL_BASELINE_VERSION) < 0) if (strverscmp_improved(uts.release, KERNEL_BASELINE_VERSION) < 0)
e = stpcpy(e, "old-kernel:"); e = stpcpy(e, "old-kernel:");
if (short_uid_range("/proc/self/uid_map") > 0)
e = stpcpy(e, "short-uid-range:");
if (short_uid_range("/proc/self/gid_map") > 0)
e = stpcpy(e, "short-gid-range:");
/* remove the last ':' */ /* remove the last ':' */
if (e != buf) if (e != buf)
e[-1] = 0; e[-1] = 0;

View File

@ -69,7 +69,7 @@ static int audit_callback(
} }
static int callback_type_to_priority(int type) { static int callback_type_to_priority(int type) {
switch(type) { switch (type) {
case SELINUX_ERROR: case SELINUX_ERROR:
return LOG_ERR; return LOG_ERR;

View File

@ -304,7 +304,7 @@ int mac_smack_setup(bool *loaded_policy) {
assert(loaded_policy); assert(loaded_policy);
r = write_access2_rules("/etc/smack/accesses.d/"); r = write_access2_rules("/etc/smack/accesses.d/");
switch(r) { switch (r) {
case -ENOENT: case -ENOENT:
log_debug("Smack is not enabled in the kernel."); log_debug("Smack is not enabled in the kernel.");
return 0; return 0;
@ -336,7 +336,7 @@ int mac_smack_setup(bool *loaded_policy) {
#endif #endif
r = write_cipso2_rules("/etc/smack/cipso.d/"); r = write_cipso2_rules("/etc/smack/cipso.d/");
switch(r) { switch (r) {
case -ENOENT: case -ENOENT:
log_debug("Smack/CIPSO is not enabled in the kernel."); log_debug("Smack/CIPSO is not enabled in the kernel.");
return 0; return 0;
@ -352,7 +352,7 @@ int mac_smack_setup(bool *loaded_policy) {
} }
r = write_netlabel_rules("/etc/smack/netlabel.d/"); r = write_netlabel_rules("/etc/smack/netlabel.d/");
switch(r) { switch (r) {
case -ENOENT: case -ENOENT:
log_debug("Smack/CIPSO is not enabled in the kernel."); log_debug("Smack/CIPSO is not enabled in the kernel.");
return 0; return 0;
@ -368,7 +368,7 @@ int mac_smack_setup(bool *loaded_policy) {
} }
r = write_onlycap_list(); r = write_onlycap_list();
switch(r) { switch (r) {
case -ENOENT: case -ENOENT:
log_debug("Smack is not enabled in the kernel."); log_debug("Smack is not enabled in the kernel.");
break; break;

View File

@ -439,7 +439,7 @@ static int peer_address_compare_func(const SocketPeer *x, const SocketPeer *y) {
if (r != 0) if (r != 0)
return r; return r;
switch(x->peer.sa.sa_family) { switch (x->peer.sa.sa_family) {
case AF_INET: case AF_INET:
return memcmp(&x->peer.in.sin_addr, &y->peer.in.sin_addr, sizeof(x->peer.in.sin_addr)); return memcmp(&x->peer.in.sin_addr, &y->peer.in.sin_addr, sizeof(x->peer.in.sin_addr));
case AF_INET6: case AF_INET6:

View File

@ -233,7 +233,7 @@ static int parse_argv(int argc, char *argv[]) {
assert(argv); assert(argv);
while ((c = getopt_long(argc, argv, "hA:o:F:1D:rS:U:qn:", options, NULL)) >= 0) while ((c = getopt_long(argc, argv, "hA:o:F:1D:rS:U:qn:", options, NULL)) >= 0)
switch(c) { switch (c) {
case 'h': case 'h':
return verb_help(0, NULL, NULL); return verb_help(0, NULL, NULL);

View File

@ -252,23 +252,23 @@
CASE_F_10,CASE_F_9,CASE_F_8,CASE_F_7,CASE_F_6,CASE_F_5,CASE_F_4,CASE_F_3,CASE_F_2,CASE_F_1) \ CASE_F_10,CASE_F_9,CASE_F_8,CASE_F_7,CASE_F_6,CASE_F_5,CASE_F_4,CASE_F_3,CASE_F_2,CASE_F_1) \
(CASE_F,__VA_ARGS__) (CASE_F,__VA_ARGS__)
#define IN_SET(x, ...) \ #define IN_SET(x, ...) \
({ \ ({ \
sd_bool _found = sd_false; \ sd_bool _found = sd_false; \
/* If the build breaks in the line below, you need to extend the case macros. (We use "long double" as \ /* If the build breaks in the line below, you need to extend the case macros. (We use "long double" as \
* type for the array, in the hope that checkers such as ubsan don't complain that the initializers for \ * type for the array, in the hope that checkers such as ubsan don't complain that the initializers for \
* the array are not representable by the base type. Ideally we'd use typeof(x) as base type, but that \ * the array are not representable by the base type. Ideally we'd use typeof(x) as base type, but that \
* doesn't work, as we want to use this on bitfields and gcc refuses typeof() on bitfields.) */ \ * doesn't work, as we want to use this on bitfields and gcc refuses typeof() on bitfields.) */ \
static const long double __assert_in_set[] _unused_ = { __VA_ARGS__ }; \ static const long double __assert_in_set[] _unused_ = { __VA_ARGS__ }; \
assert_cc(ELEMENTSOF(__assert_in_set) <= 20); \ assert_cc(ELEMENTSOF(__assert_in_set) <= 20); \
switch(x) { \ switch (x) { \
FOR_EACH_MAKE_CASE(__VA_ARGS__) \ FOR_EACH_MAKE_CASE(__VA_ARGS__) \
_found = sd_true; \ _found = sd_true; \
break; \ break; \
default: \ default: \
break; \ break; \
} \ } \
_found; \ _found; \
}) })
/* Takes inspiration from Rust's Option::take() method: reads and returns a pointer, but at the same time /* Takes inspiration from Rust's Option::take() method: reads and returns a pointer, but at the same time

View File

@ -353,7 +353,7 @@ try_acpi:
* http://www.acpi.info/DOWNLOADS/ACPIspec50.pdf * http://www.acpi.info/DOWNLOADS/ACPIspec50.pdf
*/ */
switch(t) { switch (t) {
case 1: /* Desktop */ case 1: /* Desktop */
case 3: /* Workstation */ case 3: /* Workstation */

View File

@ -74,7 +74,7 @@ static int parse_argv(int argc, char *argv[]) {
assert(argv); assert(argv);
while ((c = getopt_long(argc, argv, "ust:r:h", options, NULL)) >= 0) while ((c = getopt_long(argc, argv, "ust:r:h", options, NULL)) >= 0)
switch(c) { switch (c) {
case 'h': case 'h':
return help(); return help();

View File

@ -911,7 +911,7 @@ static int parse_argv(int argc, char *argv[]) {
while ((c = getopt_long(argc, argv, "hD:", options, NULL)) >= 0) while ((c = getopt_long(argc, argv, "hD:", options, NULL)) >= 0)
switch(c) { switch (c) {
case 'h': case 'h':
return help(); return help();

View File

@ -858,7 +858,7 @@ static int parse_argv(int argc, char *argv[]) {
assert(argv); assert(argv);
while ((c = getopt_long(argc, argv, "ho:", options, NULL)) >= 0) while ((c = getopt_long(argc, argv, "ho:", options, NULL)) >= 0)
switch(c) { switch (c) {
case 'h': case 'h':
return help(); return help();

View File

@ -104,7 +104,7 @@ int journal_remote_get_writer(RemoteServer *s, const char *host, Writer **writer
const void *key; const void *key;
int r; int r;
switch(s->split_mode) { switch (s->split_mode) {
case JOURNAL_WRITE_SPLIT_NONE: case JOURNAL_WRITE_SPLIT_NONE:
key = "one and only"; key = "one and only";
break; break;
@ -495,7 +495,7 @@ static int accept_connection(
return log_error_errno(errno, "accept() on fd:%d failed: %m", fd); return log_error_errno(errno, "accept() on fd:%d failed: %m", fd);
} }
switch(socket_address_family(addr)) { switch (socket_address_family(addr)) {
case AF_INET: case AF_INET:
case AF_INET6: { case AF_INET6: {
_cleanup_free_ char *a = NULL; _cleanup_free_ char *a = NULL;

View File

@ -24,7 +24,7 @@ static ssize_t write_entry(char *buf, size_t size, Uploader *u) {
for (;;) { for (;;) {
switch(u->entry_state) { switch (u->entry_state) {
case ENTRY_CURSOR: { case ENTRY_CURSOR: {
u->current_cursor = mfree(u->current_cursor); u->current_cursor = mfree(u->current_cursor);

View File

@ -668,7 +668,7 @@ static int parse_argv(int argc, char *argv[]) {
opterr = 0; opterr = 0;
while ((c = getopt_long(argc, argv, "hu:mM:D:", options, NULL)) >= 0) while ((c = getopt_long(argc, argv, "hu:mM:D:", options, NULL)) >= 0)
switch(c) { switch (c) {
case 'h': case 'h':
return help(); return help();

View File

@ -772,7 +772,7 @@ static void server_cache_hostname(Server *s) {
} }
static bool shall_try_append_again(JournalFile *f, int r) { static bool shall_try_append_again(JournalFile *f, int r) {
switch(r) { switch (r) {
case -E2BIG: /* Hit configured limit */ case -E2BIG: /* Hit configured limit */
case -EFBIG: /* Hit fs limit */ case -EFBIG: /* Hit fs limit */

View File

@ -548,7 +548,7 @@ static int dhcp6_option_parse_ia_options(sd_dhcp6_client *client, const uint8_t
assert(buf || buflen == 0); assert(buf || buflen == 0);
for(size_t offset = 0; offset < buflen;) { for (size_t offset = 0; offset < buflen;) {
const uint8_t *data; const uint8_t *data;
size_t data_len; size_t data_len;
uint16_t code; uint16_t code;
@ -557,7 +557,7 @@ static int dhcp6_option_parse_ia_options(sd_dhcp6_client *client, const uint8_t
if (r < 0) if (r < 0)
return r; return r;
switch(code) { switch (code) {
case SD_DHCP6_OPTION_STATUS_CODE: { case SD_DHCP6_OPTION_STATUS_CODE: {
_cleanup_free_ char *msg = NULL; _cleanup_free_ char *msg = NULL;

View File

@ -247,7 +247,7 @@ int sd_dhcp_client_set_request_option(sd_dhcp_client *client, uint8_t option) {
assert_return(client, -EINVAL); assert_return(client, -EINVAL);
assert_return(IN_SET(client->state, DHCP_STATE_INIT, DHCP_STATE_STOPPED), -EBUSY); assert_return(IN_SET(client->state, DHCP_STATE_INIT, DHCP_STATE_STOPPED), -EBUSY);
switch(option) { switch (option) {
case SD_DHCP_OPTION_PAD: case SD_DHCP_OPTION_PAD:
case SD_DHCP_OPTION_OVERLOAD: case SD_DHCP_OPTION_OVERLOAD:

View File

@ -629,7 +629,7 @@ int dhcp_lease_parse_options(uint8_t code, uint8_t len, const void *option, void
assert(lease); assert(lease);
switch(code) { switch (code) {
case SD_DHCP_OPTION_IP_ADDRESS_LEASE_TIME: case SD_DHCP_OPTION_IP_ADDRESS_LEASE_TIME:
r = lease_parse_u32(option, len, &lease->lifetime, 1); r = lease_parse_u32(option, len, &lease->lifetime, 1);

View File

@ -737,7 +737,7 @@ static int parse_request(uint8_t code, uint8_t len, const void *option, void *us
assert(req); assert(req);
switch(code) { switch (code) {
case SD_DHCP_OPTION_IP_ADDRESS_LEASE_TIME: case SD_DHCP_OPTION_IP_ADDRESS_LEASE_TIME:
if (len == 4) if (len == 4)
req->lifetime = unaligned_read_be32(option); req->lifetime = unaligned_read_be32(option);
@ -1096,7 +1096,7 @@ int dhcp_server_handle_message(sd_dhcp_server *server, DHCPMessage *message, siz
existing_lease = hashmap_get(server->bound_leases_by_client_id, &req->client_id); existing_lease = hashmap_get(server->bound_leases_by_client_id, &req->client_id);
static_lease = hashmap_get(server->static_leases_by_client_id, &req->client_id); static_lease = hashmap_get(server->static_leases_by_client_id, &req->client_id);
switch(type) { switch (type) {
case DHCP_DISCOVER: { case DHCP_DISCOVER: {
be32_t address = INADDR_ANY; be32_t address = INADDR_ANY;

View File

@ -338,7 +338,7 @@ int dhcp6_lease_add_ntp(sd_dhcp6_lease *lease, const uint8_t *optval, size_t opt
if (r < 0) if (r < 0)
return r; return r;
switch(subopt) { switch (subopt) {
case DHCP6_NTP_SUBOPTION_SRV_ADDR: case DHCP6_NTP_SUBOPTION_SRV_ADDR:
case DHCP6_NTP_SUBOPTION_MC_ADDR: case DHCP6_NTP_SUBOPTION_MC_ADDR:
if (sublen != 16) if (sublen != 16)

View File

@ -156,7 +156,7 @@ static void test_dhcp_identifier_set_iaid(void) {
} }
static int check_options(uint8_t code, uint8_t len, const void *option, void *userdata) { static int check_options(uint8_t code, uint8_t len, const void *option, void *userdata) {
switch(code) { switch (code) {
case SD_DHCP_OPTION_CLIENT_IDENTIFIER: case SD_DHCP_OPTION_CLIENT_IDENTIFIER:
{ {
uint32_t iaid; uint32_t iaid;

View File

@ -53,7 +53,7 @@ static struct option_desc option_tests[] = {
}; };
static const char *dhcp_type(int type) { static const char *dhcp_type(int type) {
switch(type) { switch (type) {
case DHCP_DISCOVER: case DHCP_DISCOVER:
return "DHCPDISCOVER"; return "DHCPDISCOVER";
case DHCP_OFFER: case DHCP_OFFER:
@ -125,7 +125,7 @@ static void test_ignore_opts(uint8_t *descoption, int *descpos, int *desclen) {
assert_se(*descpos >= 0); assert_se(*descpos >= 0);
while (*descpos < *desclen) { while (*descpos < *desclen) {
switch(descoption[*descpos]) { switch (descoption[*descpos]) {
case SD_DHCP_OPTION_PAD: case SD_DHCP_OPTION_PAD:
*descpos += 1; *descpos += 1;
break; break;

View File

@ -29,7 +29,7 @@ static void* basic_request_handler_userdata = (void*) 0xCABCAB;
static void basic_request_handler(sd_ipv4ll *ll, int event, void *userdata) { static void basic_request_handler(sd_ipv4ll *ll, int event, void *userdata) {
assert_se(userdata == basic_request_handler_userdata); assert_se(userdata == basic_request_handler_userdata);
switch(event) { switch (event) {
case SD_IPV4LL_EVENT_STOP: case SD_IPV4LL_EVENT_STOP:
basic_request_handler_stop = 1; basic_request_handler_stop = 1;
break; break;

View File

@ -1,11 +1,14 @@
# SPDX-License-Identifier: LGPL-2.1-or-later # SPDX-License-Identifier: LGPL-2.1-or-later
BEGIN{ BEGIN{
print "const char *audit_type_to_string(int type) {\n\tswitch(type) {" print "const char *audit_type_to_string(int type) {"
print " switch (type) {"
} }
{ {
printf " case AUDIT_%s: return \"%s\";\n", $1, $1 printf " case AUDIT_%s: return \"%s\";\n", $1, $1
} }
END{ END{
print " default: return NULL;\n\t}\n}\n" print " default: return NULL;"
print " }"
print "}"
} }

View File

@ -277,7 +277,7 @@ int sd_rtnl_message_new_nexthop(sd_netlink *rtnl, sd_netlink_message **ret,
int r; int r;
assert_return(rtnl_message_type_is_nexthop(nlmsg_type), -EINVAL); assert_return(rtnl_message_type_is_nexthop(nlmsg_type), -EINVAL);
switch(nlmsg_type) { switch (nlmsg_type) {
case RTM_DELNEXTHOP: case RTM_DELNEXTHOP:
assert_return(nh_family == AF_UNSPEC, -EINVAL); assert_return(nh_family == AF_UNSPEC, -EINVAL);
_fallthrough_; _fallthrough_;

View File

@ -63,7 +63,7 @@ int type_system_root_get_type_system_and_header_size(
if (IN_SET(type, NLMSG_DONE, NLMSG_ERROR)) if (IN_SET(type, NLMSG_DONE, NLMSG_ERROR))
nl_type = type_system_get_type(&basic_type_system, type); nl_type = type_system_get_type(&basic_type_system, type);
else else
switch(nl->protocol) { switch (nl->protocol) {
case NETLINK_ROUTE: case NETLINK_ROUTE:
nl_type = rtnl_get_type(type); nl_type = rtnl_get_type(type);
break; break;

View File

@ -516,7 +516,7 @@ static int get_search(uint64_t type, char ***list) {
assert(list); assert(list);
switch(type) { switch (type) {
case SD_PATH_SEARCH_BINARIES: case SD_PATH_SEARCH_BINARIES:
return search_from_environment(list, return search_from_environment(list,

View File

@ -285,4 +285,4 @@ static int run(int argc, char* argv[]) {
return 0; return 0;
} }
DEFINE_MAIN_FUNCTION_WITH_POSITIVE_FAILURE (run); DEFINE_MAIN_FUNCTION_WITH_POSITIVE_FAILURE(run);

View File

@ -165,7 +165,7 @@ static int parse_argv(int argc, char *argv[]) {
assert(argv); assert(argv);
while ((c = getopt_long(argc, argv, "hn", options, NULL)) >= 0) while ((c = getopt_long(argc, argv, "hn", options, NULL)) >= 0)
switch(c) { switch (c) {
case 'h': case 'h':
return help(); return help();

View File

@ -1,7 +1,8 @@
# SPDX-License-Identifier: LGPL-2.1-or-later # SPDX-License-Identifier: LGPL-2.1-or-later
BEGIN{ BEGIN{
print "const char *dns_type_to_string(int type) {\n\tswitch(type) {" print "const char *dns_type_to_string(int type) {"
print " switch (type) {"
} }
{ {
printf " case DNS_TYPE_%s: return ", $1; printf " case DNS_TYPE_%s: return ", $1;
@ -9,5 +10,7 @@ BEGIN{
printf "\"%s\";\n", $1 printf "\"%s\";\n", $1
} }
END{ END{
print " default: return NULL;\n\t}\n}\n" print " default: return NULL;"
print " }"
print "}"
} }

View File

@ -136,7 +136,7 @@ int resolvconf_parse_argv(int argc, char *argv[]) {
arg_mode = _MODE_INVALID; arg_mode = _MODE_INVALID;
while ((c = getopt_long(argc, argv, "hadxpfm:uIi:l:Rr:vV", options, NULL)) >= 0) while ((c = getopt_long(argc, argv, "hadxpfm:uIi:l:Rr:vV", options, NULL)) >= 0)
switch(c) { switch (c) {
case 'h': case 'h':
return resolvconf_help(); return resolvconf_help();

View File

@ -2753,7 +2753,7 @@ static int compat_parse_argv(int argc, char *argv[]) {
assert(argv); assert(argv);
while ((c = getopt_long(argc, argv, "h46i:t:c:p:", options, NULL)) >= 0) while ((c = getopt_long(argc, argv, "h46i:t:c:p:", options, NULL)) >= 0)
switch(c) { switch (c) {
case 'h': case 'h':
return compat_help(); return compat_help();
@ -3048,7 +3048,7 @@ static int native_parse_argv(int argc, char *argv[]) {
assert(argv); assert(argv);
while ((c = getopt_long(argc, argv, "h46i:t:c:p:", options, NULL)) >= 0) while ((c = getopt_long(argc, argv, "h46i:t:c:p:", options, NULL)) >= 0)
switch(c) { switch (c) {
case 'h': case 'h':
return native_help(); return native_help();

View File

@ -102,7 +102,7 @@ void dns_packet_set_flags(DnsPacket *p, bool dnssec_checking_disabled, bool trun
h = DNS_PACKET_HEADER(p); h = DNS_PACKET_HEADER(p);
switch(p->protocol) { switch (p->protocol) {
case DNS_PROTOCOL_LLMNR: case DNS_PROTOCOL_LLMNR:
assert(!truncated); assert(!truncated);

View File

@ -403,7 +403,7 @@ static DnsResourceRecord* dns_resource_record_free(DnsResourceRecord *rr) {
assert(rr); assert(rr);
if (rr->key) { if (rr->key) {
switch(rr->key->type) { switch (rr->key->type) {
case DNS_TYPE_SRV: case DNS_TYPE_SRV:
free(rr->srv.name); free(rr->srv.name);
@ -1166,7 +1166,7 @@ ssize_t dns_resource_record_payload(DnsResourceRecord *rr, void **out) {
assert(rr); assert(rr);
assert(out); assert(out);
switch(rr->unparsable ? _DNS_TYPE_INVALID : rr->key->type) { switch (rr->unparsable ? _DNS_TYPE_INVALID : rr->key->type) {
case DNS_TYPE_SRV: case DNS_TYPE_SRV:
case DNS_TYPE_PTR: case DNS_TYPE_PTR:
case DNS_TYPE_NS: case DNS_TYPE_NS:

View File

@ -185,7 +185,7 @@ ssize_t dnstls_stream_writev(DnsStream *stream, const struct iovec *iov, size_t
ss = gnutls_record_uncork(stream->dnstls_data.session, 0); ss = gnutls_record_uncork(stream->dnstls_data.session, 0);
if (ss < 0) if (ss < 0)
switch(ss) { switch (ss) {
case GNUTLS_E_INTERRUPTED: case GNUTLS_E_INTERRUPTED:
return -EINTR; return -EINTR;
case GNUTLS_E_AGAIN: case GNUTLS_E_AGAIN:
@ -209,7 +209,7 @@ ssize_t dnstls_stream_read(DnsStream *stream, void *buf, size_t count) {
ss = gnutls_record_recv(stream->dnstls_data.session, buf, count); ss = gnutls_record_recv(stream->dnstls_data.session, buf, count);
if (ss < 0) if (ss < 0)
switch(ss) { switch (ss) {
case GNUTLS_E_INTERRUPTED: case GNUTLS_E_INTERRUPTED:
return -EINTR; return -EINTR;
case GNUTLS_E_AGAIN: case GNUTLS_E_AGAIN:

View File

@ -16,6 +16,7 @@
#include "fd-util.h" #include "fd-util.h"
#include "log.h" #include "log.h"
#include "macro.h" #include "macro.h"
#include "path-util.h"
#include "process-util.h" #include "process-util.h"
#include "resolved-dns-packet.h" #include "resolved-dns-packet.h"
#include "resolved-dns-question.h" #include "resolved-dns-question.h"
@ -330,16 +331,41 @@ static void test_dns_stream(bool tls) {
static void try_isolate_network(void) { static void try_isolate_network(void) {
_cleanup_close_ int socket_fd = -1; _cleanup_close_ int socket_fd = -1;
int r;
if (unshare(CLONE_NEWUSER | CLONE_NEWNET) < 0) { /* First test if CLONE_NEWUSER/CLONE_NEWNET can actually work for us, i.e. we can open the namespaces
log_warning("test-resolved-stream: Can't create user and network ns, running on host"); * and then still access the build dir we are run from. We do that in a child process since it's
return; * nasty if we have to go back from the namespace once we entered it and realized it cannot work. */
r = safe_fork("(usernstest)", FORK_DEATHSIG|FORK_LOG|FORK_WAIT, NULL);
if (r == 0) { /* child */
_cleanup_free_ char *rt = NULL, *d = NULL;
if (unshare(CLONE_NEWUSER | CLONE_NEWNET) < 0) {
log_warning_errno(errno, "test-resolved-stream: Can't create user and network ns, running on host: %m");
_exit(EXIT_FAILURE);
}
assert_se(get_process_exe(0, &rt) >= 0);
assert_se(path_extract_directory(rt, &d) >= 0);
if (access(d, F_OK) < 0) {
log_warning_errno(errno, "test-resolved-stream: Can't access /proc/self/exe from user/network ns, running on host: %m");
_exit(EXIT_FAILURE);
}
_exit(EXIT_SUCCESS);
} }
if (r == -EPROTO) /* EPROTO means nonzero exit code of child, i.e. the tests in the child failed */
return;
assert_se(r > 0);
/* Now that we know that the unshare() is safe, let's actually do it */
assert_se(unshare(CLONE_NEWUSER | CLONE_NEWNET) >= 0);
/* Bring up the loopback interfaceon the newly created network namespace */ /* Bring up the loopback interfaceon the newly created network namespace */
struct ifreq req = { .ifr_ifindex = 1 }; struct ifreq req = { .ifr_ifindex = 1 };
assert_se((socket_fd = socket(AF_INET, SOCK_STREAM | SOCK_CLOEXEC, 0)) >= 0); assert_se((socket_fd = socket(AF_INET, SOCK_STREAM | SOCK_CLOEXEC, 0)) >= 0);
assert_se(ioctl(socket_fd,SIOCGIFNAME,&req) >= 0); assert_se(ioctl(socket_fd, SIOCGIFNAME, &req) >= 0);
assert_se(ioctl(socket_fd, SIOCGIFFLAGS, &req) >= 0); assert_se(ioctl(socket_fd, SIOCGIFFLAGS, &req) >= 0);
assert_se(FLAGS_SET(req.ifr_flags, IFF_LOOPBACK)); assert_se(FLAGS_SET(req.ifr_flags, IFF_LOOPBACK));
req.ifr_flags |= IFF_UP; req.ifr_flags |= IFF_UP;

View File

@ -1074,7 +1074,7 @@ int config_parse_warn_compat(
Disabled reason = ltype; Disabled reason = ltype;
switch(reason) { switch (reason) {
case DISABLED_CONFIGURATION: case DISABLED_CONFIGURATION:
log_syntax(unit, LOG_DEBUG, filename, line, 0, log_syntax(unit, LOG_DEBUG, filename, line, 0,

View File

@ -393,7 +393,7 @@ int ethtool_get_permanent_hw_addr(int *ethtool_fd, const char *ifname, struct hw
if (dest != _v) \ if (dest != _v) \
updated = true; \ updated = true; \
dest = _v; \ dest = _v; \
} while(false) } while (false)
#define UPDATE_WITH_MAX(dest, max, val, updated) \ #define UPDATE_WITH_MAX(dest, max, val, updated) \
do { \ do { \
@ -404,7 +404,7 @@ int ethtool_get_permanent_hw_addr(int *ethtool_fd, const char *ifname, struct hw
if (dest != _v) \ if (dest != _v) \
updated = true; \ updated = true; \
dest = _v; \ dest = _v; \
} while(false) } while (false)
int ethtool_set_wol( int ethtool_set_wol(
int *ethtool_fd, int *ethtool_fd,

View File

@ -108,7 +108,7 @@ int in_addr_prefixes_reduce(Set *prefixes) {
struct in_addr_prefix *p; struct in_addr_prefix *p;
SET_FOREACH(p, prefixes) SET_FOREACH(p, prefixes)
switch(p->family) { switch (p->family) {
case AF_INET: case AF_INET:
assert(p->prefixlen <= 32); assert(p->prefixlen <= 32);
if (p->prefixlen == 0) if (p->prefixlen == 0)
@ -147,7 +147,7 @@ int in_addr_prefixes_reduce(Set *prefixes) {
if (p->prefixlen == 0) if (p->prefixlen == 0)
continue; continue;
switch(p->family) { switch (p->family) {
case AF_INET: case AF_INET:
prefixlens = ipv4_prefixlens; prefixlens = ipv4_prefixlens;
n = &ipv4_n_prefixlens; n = &ipv4_n_prefixlens;

View File

@ -330,7 +330,7 @@ void unit_file_dump_changes(int r, const char *verb, const UnitFileChange *chang
for (size_t i = 0; i < n_changes; i++) { for (size_t i = 0; i < n_changes; i++) {
assert(verb || changes[i].type_or_errno >= 0); assert(verb || changes[i].type_or_errno >= 0);
switch(changes[i].type_or_errno) { switch (changes[i].type_or_errno) {
case UNIT_FILE_SYMLINK: case UNIT_FILE_SYMLINK:
if (!quiet) if (!quiet)
log_info("Created symlink %s %s %s.", log_info("Created symlink %s %s %s.",

View File

@ -281,7 +281,7 @@ static int process_special_field(JournalImporter *imp, char *line) {
int journal_importer_process_data(JournalImporter *imp) { int journal_importer_process_data(JournalImporter *imp) {
int r; int r;
switch(imp->state) { switch (imp->state) {
case IMPORTER_STATE_LINE: { case IMPORTER_STATE_LINE: {
char *line, *sep; char *line, *sep;
size_t n = 0; size_t n = 0;

View File

@ -531,7 +531,7 @@ int mode_to_inaccessible_node(
if (!runtime_dir) if (!runtime_dir)
runtime_dir = "/run"; runtime_dir = "/run";
switch(mode & S_IFMT) { switch (mode & S_IFMT) {
case S_IFREG: case S_IFREG:
node = "/systemd/inaccessible/reg"; node = "/systemd/inaccessible/reg";
break; break;

View File

@ -107,7 +107,7 @@ const char* seccomp_arch_to_string(uint32_t c) {
* Names used here should be the same as those used for ConditionArchitecture=, * Names used here should be the same as those used for ConditionArchitecture=,
* except for "subarchitectures" like x32. */ * except for "subarchitectures" like x32. */
switch(c) { switch (c) {
case SCMP_ARCH_NATIVE: case SCMP_ARCH_NATIVE:
return "native"; return "native";
case SCMP_ARCH_X86: case SCMP_ARCH_X86:

View File

@ -58,7 +58,7 @@ int service_parse_argv(
assert(argv); assert(argv);
while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0) while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0)
switch(c) { switch (c) {
case 'h': case 'h':
return help(argv[0], service, description, bus_objects); return help(argv[0], service, description, bus_objects);

View File

@ -48,23 +48,26 @@ char* setup_fake_runtime_dir(void) {
static void load_testdata_env(void) { static void load_testdata_env(void) {
static bool called = false; static bool called = false;
_cleanup_free_ char *s = NULL; _cleanup_free_ char *s = NULL, *d = NULL, *envpath = NULL;
_cleanup_free_ char *envpath = NULL;
_cleanup_strv_free_ char **pairs = NULL; _cleanup_strv_free_ char **pairs = NULL;
int r;
if (called) if (called)
return; return;
called = true; called = true;
assert_se(readlink_and_make_absolute("/proc/self/exe", &s) >= 0); assert_se(readlink_and_make_absolute("/proc/self/exe", &s) >= 0);
dirname(s); assert_se(path_extract_directory(s, &d) >= 0);
assert_se(envpath = path_join(d, "systemd-runtest.env"));
envpath = path_join(s, "systemd-runtest.env"); r = load_env_file_pairs(NULL, envpath, &pairs);
if (load_env_file_pairs(NULL, envpath, &pairs) < 0) if (r < 0) {
log_debug_errno(r, "Reading %s failed: %m", envpath);
return; return;
}
STRV_FOREACH_PAIR(k, v, pairs) STRV_FOREACH_PAIR(k, v, pairs)
setenv(*k, *v, 0); assert_se(setenv(*k, *v, 0) >= 0);
} }
int get_testdata_dir(const char *suffix, char **ret) { int get_testdata_dir(const char *suffix, char **ret) {

View File

@ -79,7 +79,7 @@ bool udev_available(void);
(void) sd_device_get_syspath(_d, &_p); \ (void) sd_device_get_syspath(_d, &_p); \
(void) sd_device_get_subsystem(_d, &_s); \ (void) sd_device_get_subsystem(_d, &_s); \
STAP_PROBEV(udev, name, device_action_to_string(_a), _n, _p, _s __VA_OPT__(,) __VA_ARGS__);\ STAP_PROBEV(udev, name, device_action_to_string(_a), _n, _p, _s __VA_OPT__(,) __VA_ARGS__);\
} while(false); } while (false);
#else #else
#define DEVICE_TRACE_POINT(name, dev, ...) ((void) 0) #define DEVICE_TRACE_POINT(name, dev, ...) ((void) 0)
#endif #endif

View File

@ -5,8 +5,13 @@
#include <string.h> #include <string.h>
#include "alloc-util.h" #include "alloc-util.h"
#include "errno-util.h"
#include "fd-util.h"
#include "format-util.h"
#include "macro.h" #include "macro.h"
#include "path-util.h"
#include "sort-util.h" #include "sort-util.h"
#include "stat-util.h"
#include "uid-range.h" #include "uid-range.h"
#include "user-util.h" #include "user-util.h"
@ -17,12 +22,12 @@ static bool uid_range_intersect(UidRange *range, uid_t start, uid_t nr) {
range->start + range->nr >= start; range->start + range->nr >= start;
} }
static void uid_range_coalesce(UidRange **p, unsigned *n) { static void uid_range_coalesce(UidRange **p, size_t *n) {
assert(p); assert(p);
assert(n); assert(n);
for (unsigned i = 0; i < *n; i++) { for (size_t i = 0; i < *n; i++) {
for (unsigned j = i + 1; j < *n; j++) { for (size_t j = i + 1; j < *n; j++) {
UidRange *x = (*p)+i, *y = (*p)+j; UidRange *x = (*p)+i, *y = (*p)+j;
if (uid_range_intersect(x, y->start, y->nr)) { if (uid_range_intersect(x, y->start, y->nr)) {
@ -54,7 +59,7 @@ static int uid_range_compare(const UidRange *a, const UidRange *b) {
return CMP(a->nr, b->nr); return CMP(a->nr, b->nr);
} }
int uid_range_add(UidRange **p, unsigned *n, uid_t start, uid_t nr) { int uid_range_add(UidRange **p, size_t *n, uid_t start, uid_t nr) {
bool found = false; bool found = false;
UidRange *x; UidRange *x;
@ -64,7 +69,10 @@ int uid_range_add(UidRange **p, unsigned *n, uid_t start, uid_t nr) {
if (nr <= 0) if (nr <= 0)
return 0; return 0;
for (unsigned i = 0; i < *n; i++) { if (start > UINT32_MAX - nr) /* overflow check */
return -ERANGE;
for (size_t i = 0; i < *n; i++) {
x = (*p) + i; x = (*p) + i;
if (uid_range_intersect(x, start, nr)) { if (uid_range_intersect(x, start, nr)) {
found = true; found = true;
@ -100,7 +108,7 @@ int uid_range_add(UidRange **p, unsigned *n, uid_t start, uid_t nr) {
return *n; return *n;
} }
int uid_range_add_str(UidRange **p, unsigned *n, const char *s) { int uid_range_add_str(UidRange **p, size_t *n, const char *s) {
uid_t start, nr; uid_t start, nr;
const char *t; const char *t;
int r; int r;
@ -138,15 +146,18 @@ int uid_range_add_str(UidRange **p, unsigned *n, const char *s) {
return uid_range_add(p, n, start, nr); return uid_range_add(p, n, start, nr);
} }
int uid_range_next_lower(const UidRange *p, unsigned n, uid_t *uid) { int uid_range_next_lower(const UidRange *p, size_t n, uid_t *uid) {
uid_t closest = UID_INVALID, candidate; uid_t closest = UID_INVALID, candidate;
assert(p); assert(p);
assert(uid); assert(uid);
if (*uid == 0)
return -EBUSY;
candidate = *uid - 1; candidate = *uid - 1;
for (unsigned i = 0; i < n; i++) { for (size_t i = 0; i < n; i++) {
uid_t begin, end; uid_t begin, end;
begin = p[i].start; begin = p[i].start;
@ -168,13 +179,62 @@ int uid_range_next_lower(const UidRange *p, unsigned n, uid_t *uid) {
return 1; return 1;
} }
bool uid_range_contains(const UidRange *p, unsigned n, uid_t uid) { bool uid_range_covers(const UidRange *p, size_t n, uid_t start, uid_t nr) {
assert(p); assert(p || n == 0);
assert(uid);
for (unsigned i = 0; i < n; i++) if (nr == 0) /* empty range? always covered... */
if (uid >= p[i].start && uid < p[i].start + p[i].nr) return true;
if (start > UINT32_MAX - nr) /* range overflows? definitely not covered... */
return false;
for (size_t i = 0; i < n; i++)
if (start >= p[i].start && start + nr <= p[i].start + p[i].nr)
return true; return true;
return false; return false;
} }
int uid_range_load_userns(UidRange **p, size_t *n, const char *path) {
_cleanup_fclose_ FILE *f = NULL;
int r;
/* If 'path' is NULL loads the UID range of the userns namespace we run. Otherwise load the data from
* the specified file (which can be either uid_map or gid_map, in case caller needs to deal with GID
* maps).
*
* To simplify things this will modify the passed array in case of later failure. */
if (!path)
path = "/proc/self/uid_map";
f = fopen(path, "re");
if (!f) {
r = -errno;
if (r == -ENOENT && path_startswith(path, "/proc/") && proc_mounted() > 0)
return -EOPNOTSUPP;
return r;
}
for (;;) {
uid_t uid_base, uid_shift, uid_range;
int k;
errno = 0;
k = fscanf(f, UID_FMT " " UID_FMT " " UID_FMT "\n", &uid_base, &uid_shift, &uid_range);
if (k == EOF) {
if (ferror(f))
return errno_or_else(EIO);
return 0;
}
if (k != 3)
return -EBADMSG;
r = uid_range_add(p, n, uid_base, uid_range);
if (r < 0)
return r;
}
}

View File

@ -8,8 +8,14 @@ typedef struct UidRange {
uid_t start, nr; uid_t start, nr;
} UidRange; } UidRange;
int uid_range_add(UidRange **p, unsigned *n, uid_t start, uid_t nr); int uid_range_add(UidRange **p, size_t *n, uid_t start, uid_t nr);
int uid_range_add_str(UidRange **p, unsigned *n, const char *s); int uid_range_add_str(UidRange **p, size_t *n, const char *s);
int uid_range_next_lower(const UidRange *p, unsigned n, uid_t *uid); int uid_range_next_lower(const UidRange *p, size_t n, uid_t *uid);
bool uid_range_contains(const UidRange *p, unsigned n, uid_t uid); bool uid_range_covers(const UidRange *p, size_t n, uid_t start, uid_t nr);
static inline bool uid_range_contains(const UidRange *p, size_t n, uid_t uid) {
return uid_range_covers(p, n, uid, 1);
}
int uid_range_load_userns(UidRange **p, size_t *n, const char *path);

View File

@ -352,7 +352,7 @@ static int parse_argv(int argc, char *argv[]) {
assert(argv); assert(argv);
while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0) while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0)
switch(c) { switch (c) {
case 'h': case 'h':
return help(); return help();

View File

@ -104,7 +104,7 @@ static Set *database_users = NULL, *database_groups = NULL;
static uid_t search_uid = UID_INVALID; static uid_t search_uid = UID_INVALID;
static UidRange *uid_range = NULL; static UidRange *uid_range = NULL;
static unsigned n_uid_range = 0; static size_t n_uid_range = 0;
static UGIDAllocationRange login_defs = {}; static UGIDAllocationRange login_defs = {};
static bool login_defs_need_warning = false; static bool login_defs_need_warning = false;

View File

@ -163,7 +163,7 @@ TEST(auto_erase_memory) {
assert_se(MALLOC_SIZEOF_SAFE(f) >= sizeof(*f) * n); \ assert_se(MALLOC_SIZEOF_SAFE(f) >= sizeof(*f) * n); \
assert_se(malloc_usable_size(f) >= sizeof(*f) * n); \ assert_se(malloc_usable_size(f) >= sizeof(*f) * n); \
assert_se(__builtin_object_size(f, 0) >= sizeof(*f) * n); \ assert_se(__builtin_object_size(f, 0) >= sizeof(*f) * n); \
} while(false) } while (false)
TEST(malloc_size_safe) { TEST(malloc_size_safe) {
_cleanup_free_ uint32_t *f = NULL; _cleanup_free_ uint32_t *f = NULL;

View File

@ -3,15 +3,26 @@
#include <stddef.h> #include <stddef.h>
#include "alloc-util.h" #include "alloc-util.h"
#include "errno-util.h"
#include "fd-util.h"
#include "fileio.h"
#include "fs-util.h"
#include "tests.h"
#include "tmpfile-util.h"
#include "uid-range.h" #include "uid-range.h"
#include "user-util.h" #include "user-util.h"
#include "util.h" #include "util.h"
#include "virt.h"
int main(int argc, char *argv[]) { TEST(uid_range) {
_cleanup_free_ UidRange *p = NULL; _cleanup_free_ UidRange *p = NULL;
unsigned n = 0; size_t n = 0;
uid_t search; uid_t search;
assert_se(uid_range_covers(p, n, 0, 0));
assert_se(!uid_range_covers(p, n, 0, 1));
assert_se(!uid_range_covers(p, n, 100, UINT32_MAX));
assert_se(uid_range_add_str(&p, &n, "500-999") >= 0); assert_se(uid_range_add_str(&p, &n, "500-999") >= 0);
assert_se(n == 1); assert_se(n == 1);
assert_se(p[0].start == 500); assert_se(p[0].start == 500);
@ -22,6 +33,17 @@ int main(int argc, char *argv[]) {
assert_se(uid_range_contains(p, n, 999)); assert_se(uid_range_contains(p, n, 999));
assert_se(!uid_range_contains(p, n, 1000)); assert_se(!uid_range_contains(p, n, 1000));
assert_se(!uid_range_covers(p, n, 100, 150));
assert_se(!uid_range_covers(p, n, 400, 200));
assert_se(!uid_range_covers(p, n, 499, 1));
assert_se(uid_range_covers(p, n, 500, 1));
assert_se(uid_range_covers(p, n, 501, 10));
assert_se(uid_range_covers(p, n, 999, 1));
assert_se(!uid_range_covers(p, n, 999, 2));
assert_se(!uid_range_covers(p, n, 1000, 1));
assert_se(!uid_range_covers(p, n, 1000, 100));
assert_se(!uid_range_covers(p, n, 1001, 100));
search = UID_INVALID; search = UID_INVALID;
assert_se(uid_range_next_lower(p, n, &search)); assert_se(uid_range_next_lower(p, n, &search));
assert_se(search == 999); assert_se(search == 999);
@ -69,6 +91,49 @@ int main(int argc, char *argv[]) {
assert_se(n == 1); assert_se(n == 1);
assert_se(p[0].start == 20); assert_se(p[0].start == 20);
assert_se(p[0].nr == 1983); assert_se(p[0].nr == 1983);
return 0;
} }
TEST(load_userns) {
_cleanup_(unlink_and_freep) char *fn = NULL;
_cleanup_free_ UidRange *p = NULL;
_cleanup_fclose_ FILE *f = NULL;
size_t n = 0;
int r;
r = uid_range_load_userns(&p, &n, NULL);
if (ERRNO_IS_NOT_SUPPORTED(r))
return;
assert_se(r >= 0);
assert_se(uid_range_contains(p, n, getuid()));
r = running_in_userns();
if (r == 0) {
assert_se(n == 1);
assert_se(p[0].start == 0);
assert_se(p[0].nr == UINT32_MAX);
assert_se(uid_range_covers(p, n, 0, UINT32_MAX));
}
assert_se(fopen_temporary(NULL, &f, &fn) >= 0);
fputs("0 0 20\n"
"100 0 20\n", f);
assert_se(fflush_and_check(f) >= 0);
p = mfree(p);
n = 0;
assert_se(uid_range_load_userns(&p, &n, fn) >= 0);
assert_se(uid_range_contains(p, n, 0));
assert_se(uid_range_contains(p, n, 19));
assert_se(!uid_range_contains(p, n, 20));
assert_se(!uid_range_contains(p, n, 99));
assert_se(uid_range_contains(p, n, 100));
assert_se(uid_range_contains(p, n, 119));
assert_se(!uid_range_contains(p, n, 120));
}
DEFINE_TEST_MAIN(LOG_DEBUG);

View File

@ -51,7 +51,7 @@ static int parse_argv(int argc, char *argv[]) {
assert_se(argv); assert_se(argv);
while ((c = getopt_long(argc, argv, "r:", options, NULL)) >= 0) while ((c = getopt_long(argc, argv, "r:", options, NULL)) >= 0)
switch(c) { switch (c) {
case 'r': case 'r':
arg_root = optarg; arg_root = optarg;
break; break;

View File

@ -541,7 +541,7 @@ static int dvd_ram_media_update_state(Context *c) {
return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), return log_debug_errno(SYNTHETIC_ERRNO(EINVAL),
"Invalid format capacities length."); "Invalid format capacities length.");
switch(format[8] & 3) { switch (format[8] & 3) {
case 1: case 1:
/* This means that last format was interrupted or failed, blank dvd-ram discs are /* This means that last format was interrupted or failed, blank dvd-ram discs are
* factory formatted. Take no action here as it takes quite a while to reformat a * factory formatted. Take no action here as it takes quite a while to reformat a

View File

@ -61,7 +61,7 @@ int probe_smart_media(int mtd_fd, mtd_info_t* info) {
return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), return log_debug_errno(SYNTHETIC_ERRNO(EINVAL),
"Unexpected sector size: %i", sector_size); "Unexpected sector size: %i", sector_size);
switch(size_in_megs) { switch (size_in_megs) {
case 1: case 1:
case 2: case 2:
spare_count = 6; spare_count = 6;

View File

@ -48,7 +48,7 @@ static int parse_argv(int argc, char *argv[]) {
int c; int c;
while ((c = getopt_long(argc, argv, "ust:r:Vh", options, NULL)) >= 0) while ((c = getopt_long(argc, argv, "ust:r:Vh", options, NULL)) >= 0)
switch(c) { switch (c) {
case 'u': case 'u':
arg_update = true; arg_update = true;
break; break;

View File

@ -345,7 +345,7 @@ static int query_device(QueryType query, sd_device* device) {
assert(device); assert(device);
switch(query) { switch (query) {
case QUERY_NAME: { case QUERY_NAME: {
const char *node; const char *node;

View File

@ -17,6 +17,7 @@
#include "socket-util.h" #include "socket-util.h"
#include "strv.h" #include "strv.h"
#include "terminal-util.h" #include "terminal-util.h"
#include "uid-range.h"
#include "user-record-show.h" #include "user-record-show.h"
#include "user-util.h" #include "user-util.h"
#include "userdb.h" #include "userdb.h"
@ -167,14 +168,22 @@ static const struct {
}, },
}; };
static int table_add_uid_boundaries(Table *table) { static int table_add_uid_boundaries(
Table *table,
const UidRange *p,
size_t n) {
int r; int r;
assert(table); assert(table);
assert(p || n == 0);
for (size_t i = 0; i < ELEMENTSOF(uid_range_table); i++) { for (size_t i = 0; i < ELEMENTSOF(uid_range_table); i++) {
_cleanup_free_ char *name = NULL, *comment = NULL; _cleanup_free_ char *name = NULL, *comment = NULL;
if (n > 0 &&
!uid_range_covers(p, n, uid_range_table[i].first, uid_range_table[i].last - uid_range_table[i].first + 1))
continue;
name = strjoin(special_glyph(SPECIAL_GLYPH_ARROW_DOWN), name = strjoin(special_glyph(SPECIAL_GLYPH_ARROW_DOWN),
" begin ", uid_range_table[i].name, " users ", " begin ", uid_range_table[i].name, " users ",
special_glyph(SPECIAL_GLYPH_ARROW_DOWN)); special_glyph(SPECIAL_GLYPH_ARROW_DOWN));
@ -199,7 +208,7 @@ static int table_add_uid_boundaries(Table *table) {
TABLE_SET_COLOR, ansi_grey(), TABLE_SET_COLOR, ansi_grey(),
TABLE_EMPTY, TABLE_EMPTY,
TABLE_EMPTY, TABLE_EMPTY,
TABLE_INT, -1); /* sort before an other entry with the same UID */ TABLE_INT, -1); /* sort before any other entry with the same UID */
if (r < 0) if (r < 0)
return table_log_add_error(r); return table_log_add_error(r);
@ -229,7 +238,7 @@ static int table_add_uid_boundaries(Table *table) {
TABLE_SET_COLOR, ansi_grey(), TABLE_SET_COLOR, ansi_grey(),
TABLE_EMPTY, TABLE_EMPTY,
TABLE_EMPTY, TABLE_EMPTY,
TABLE_INT, 1); /* sort after an other entry with the same UID */ TABLE_INT, 1); /* sort after any other entry with the same UID */
if (r < 0) if (r < 0)
return table_log_add_error(r); return table_log_add_error(r);
} }
@ -237,6 +246,104 @@ static int table_add_uid_boundaries(Table *table) {
return ELEMENTSOF(uid_range_table) * 2; return ELEMENTSOF(uid_range_table) * 2;
} }
static int add_unavailable_uid(Table *table, uid_t start, uid_t end) {
_cleanup_free_ char *name = NULL;
int r;
assert(table);
assert(start <= end);
name = strjoin(special_glyph(SPECIAL_GLYPH_ARROW_DOWN),
" begin unavailable users ",
special_glyph(SPECIAL_GLYPH_ARROW_DOWN));
if (!name)
return log_oom();
r = table_add_many(
table,
TABLE_STRING, special_glyph(SPECIAL_GLYPH_TREE_TOP),
TABLE_STRING, name,
TABLE_SET_COLOR, ansi_grey(),
TABLE_EMPTY,
TABLE_UID, start,
TABLE_SET_COLOR, ansi_grey(),
TABLE_EMPTY,
TABLE_STRING, "First unavailable user",
TABLE_SET_COLOR, ansi_grey(),
TABLE_EMPTY,
TABLE_EMPTY,
TABLE_INT, -1); /* sort before an other entry with the same UID */
if (r < 0)
return table_log_add_error(r);
free(name);
name = strjoin(special_glyph(SPECIAL_GLYPH_ARROW_DOWN),
" end unavailable users ",
special_glyph(SPECIAL_GLYPH_ARROW_DOWN));
if (!name)
return log_oom();
r = table_add_many(
table,
TABLE_STRING, special_glyph(SPECIAL_GLYPH_TREE_RIGHT),
TABLE_STRING, name,
TABLE_SET_COLOR, ansi_grey(),
TABLE_EMPTY,
TABLE_UID, end,
TABLE_SET_COLOR, ansi_grey(),
TABLE_EMPTY,
TABLE_STRING, "Last unavailable user",
TABLE_SET_COLOR, ansi_grey(),
TABLE_EMPTY,
TABLE_EMPTY,
TABLE_INT, 1); /* sort after any other entry with the same UID */
if (r < 0)
return table_log_add_error(r);
return 2;
}
static int table_add_uid_map(
Table *table,
const UidRange *p,
size_t n,
int (*add_unavailable)(Table *t, uid_t start, uid_t end)) {
uid_t focus = 0;
int n_added = 0, r;
assert(table);
assert(p || n == 0);
assert(add_unavailable);
for (size_t i = 0; i < n; i++) {
if (focus < p[i].start) {
r = add_unavailable(table, focus, p[i].start-1);
if (r < 0)
return r;
n_added += r;
}
if (p[i].start > UINT32_MAX - p[i].nr) { /* overflow check */
focus = UINT32_MAX;
break;
}
focus = p[i].start + p[i].nr;
}
if (focus < UINT32_MAX-1) {
r = add_unavailable(table, focus, UINT32_MAX-1);
if (r < 0)
return r;
n_added += r;
}
return n_added;
}
static int display_user(int argc, char *argv[], void *userdata) { static int display_user(int argc, char *argv[], void *userdata) {
_cleanup_(table_unrefp) Table *table = NULL; _cleanup_(table_unrefp) Table *table = NULL;
bool draw_separator = false; bool draw_separator = false;
@ -322,12 +429,22 @@ static int display_user(int argc, char *argv[], void *userdata) {
} }
if (table) { if (table) {
int boundary_lines; _cleanup_free_ UidRange *uid_range = NULL;
int boundary_lines, uid_map_lines;
size_t n_uid_range;
boundary_lines = table_add_uid_boundaries(table); r = uid_range_load_userns(&uid_range, &n_uid_range, "/proc/self/uid_map");
if (r < 0)
log_debug_errno(r, "Failed to load /proc/self/uid_map, ignoring: %m");
boundary_lines = table_add_uid_boundaries(table, uid_range, n_uid_range);
if (boundary_lines < 0) if (boundary_lines < 0)
return boundary_lines; return boundary_lines;
uid_map_lines = table_add_uid_map(table, uid_range, n_uid_range, add_unavailable_uid);
if (uid_map_lines < 0)
return uid_map_lines;
if (table_get_rows(table) > 1) { if (table_get_rows(table) > 1) {
r = table_print_with_pager(table, arg_json_format_flags, arg_pager_flags, arg_legend); r = table_print_with_pager(table, arg_json_format_flags, arg_pager_flags, arg_legend);
if (r < 0) if (r < 0)
@ -335,8 +452,11 @@ static int display_user(int argc, char *argv[], void *userdata) {
} }
if (arg_legend) { if (arg_legend) {
if (table_get_rows(table) > 1) size_t k;
printf("\n%zu users listed.\n", table_get_rows(table) - 1 - boundary_lines);
k = table_get_rows(table) - 1 - boundary_lines - uid_map_lines;
if (k > 0)
printf("\n%zu users listed.\n", k);
else else
printf("No users.\n"); printf("No users.\n");
} }
@ -411,14 +531,22 @@ static int show_group(GroupRecord *gr, Table *table) {
return 0; return 0;
} }
static int table_add_gid_boundaries(Table *table) { static int table_add_gid_boundaries(
Table *table,
const UidRange *p,
size_t n) {
int r; int r;
assert(table); assert(table);
assert(p || n == 0);
for (size_t i = 0; i < ELEMENTSOF(uid_range_table); i++) { for (size_t i = 0; i < ELEMENTSOF(uid_range_table); i++) {
_cleanup_free_ char *name = NULL, *comment = NULL; _cleanup_free_ char *name = NULL, *comment = NULL;
if (n > 0 &&
!uid_range_covers(p, n, uid_range_table[i].first, uid_range_table[i].last))
continue;
name = strjoin(special_glyph(SPECIAL_GLYPH_ARROW_DOWN), name = strjoin(special_glyph(SPECIAL_GLYPH_ARROW_DOWN),
" begin ", uid_range_table[i].name, " groups ", " begin ", uid_range_table[i].name, " groups ",
special_glyph(SPECIAL_GLYPH_ARROW_DOWN)); special_glyph(SPECIAL_GLYPH_ARROW_DOWN));
@ -440,7 +568,7 @@ static int table_add_gid_boundaries(Table *table) {
TABLE_SET_COLOR, ansi_grey(), TABLE_SET_COLOR, ansi_grey(),
TABLE_STRING, comment, TABLE_STRING, comment,
TABLE_SET_COLOR, ansi_grey(), TABLE_SET_COLOR, ansi_grey(),
TABLE_INT, -1); /* sort before an other entry with the same GID */ TABLE_INT, -1); /* sort before any other entry with the same GID */
if (r < 0) if (r < 0)
return table_log_add_error(r); return table_log_add_error(r);
@ -467,7 +595,7 @@ static int table_add_gid_boundaries(Table *table) {
TABLE_SET_COLOR, ansi_grey(), TABLE_SET_COLOR, ansi_grey(),
TABLE_STRING, comment, TABLE_STRING, comment,
TABLE_SET_COLOR, ansi_grey(), TABLE_SET_COLOR, ansi_grey(),
TABLE_INT, 1); /* sort after an other entry with the same GID */ TABLE_INT, 1); /* sort after any other entry with the same GID */
if (r < 0) if (r < 0)
return table_log_add_error(r); return table_log_add_error(r);
} }
@ -475,6 +603,57 @@ static int table_add_gid_boundaries(Table *table) {
return ELEMENTSOF(uid_range_table) * 2; return ELEMENTSOF(uid_range_table) * 2;
} }
static int add_unavailable_gid(Table *table, uid_t start, uid_t end) {
_cleanup_free_ char *name = NULL;
int r;
assert(table);
assert(start <= end);
name = strjoin(special_glyph(SPECIAL_GLYPH_ARROW_DOWN),
" begin unavailable groups ",
special_glyph(SPECIAL_GLYPH_ARROW_DOWN));
if (!name)
return log_oom();
r = table_add_many(
table,
TABLE_STRING, special_glyph(SPECIAL_GLYPH_TREE_TOP),
TABLE_STRING, name,
TABLE_SET_COLOR, ansi_grey(),
TABLE_EMPTY,
TABLE_GID, start,
TABLE_SET_COLOR, ansi_grey(),
TABLE_STRING, "First unavailable group",
TABLE_SET_COLOR, ansi_grey(),
TABLE_INT, -1); /* sort before any other entry with the same GID */
if (r < 0)
return table_log_add_error(r);
free(name);
name = strjoin(special_glyph(SPECIAL_GLYPH_ARROW_DOWN),
" end unavailable groups ",
special_glyph(SPECIAL_GLYPH_ARROW_DOWN));
if (!name)
return log_oom();
r = table_add_many(
table,
TABLE_STRING, special_glyph(SPECIAL_GLYPH_TREE_RIGHT),
TABLE_STRING, name,
TABLE_SET_COLOR, ansi_grey(),
TABLE_EMPTY,
TABLE_GID, end,
TABLE_SET_COLOR, ansi_grey(),
TABLE_STRING, "Last unavailable group",
TABLE_SET_COLOR, ansi_grey(),
TABLE_INT, 1); /* sort after any other entry with the same GID */
if (r < 0)
return table_log_add_error(r);
return 2;
}
static int display_group(int argc, char *argv[], void *userdata) { static int display_group(int argc, char *argv[], void *userdata) {
_cleanup_(table_unrefp) Table *table = NULL; _cleanup_(table_unrefp) Table *table = NULL;
bool draw_separator = false; bool draw_separator = false;
@ -559,12 +738,22 @@ static int display_group(int argc, char *argv[], void *userdata) {
} }
if (table) { if (table) {
int boundary_lines; _cleanup_free_ UidRange *gid_range = NULL;
int boundary_lines, gid_map_lines;
size_t n_gid_range;
boundary_lines = table_add_gid_boundaries(table); r = uid_range_load_userns(&gid_range, &n_gid_range, "/proc/self/gid_map");
if (r < 0)
log_debug_errno(r, "Failed to load /proc/self/gid_map, ignoring: %m");
boundary_lines = table_add_gid_boundaries(table, gid_range, n_gid_range);
if (boundary_lines < 0) if (boundary_lines < 0)
return boundary_lines; return boundary_lines;
gid_map_lines = table_add_uid_map(table, gid_range, n_gid_range, add_unavailable_gid);
if (gid_map_lines < 0)
return gid_map_lines;
if (table_get_rows(table) > 1) { if (table_get_rows(table) > 1) {
r = table_print_with_pager(table, arg_json_format_flags, arg_pager_flags, arg_legend); r = table_print_with_pager(table, arg_json_format_flags, arg_pager_flags, arg_legend);
if (r < 0) if (r < 0)
@ -572,8 +761,11 @@ static int display_group(int argc, char *argv[], void *userdata) {
} }
if (arg_legend) { if (arg_legend) {
if (table_get_rows(table) > 1) size_t k;
printf("\n%zu groups listed.\n", table_get_rows(table) - 1 - boundary_lines);
k = table_get_rows(table) - 1 - boundary_lines - gid_map_lines;
if (k > 0)
printf("\n%zu groups listed.\n", k);
else else
printf("No groups.\n"); printf("No groups.\n");
} }

View File

@ -17,7 +17,9 @@
#include "terminal-util.h" #include "terminal-util.h"
static uint32_t arg_activate_flags = CRYPT_ACTIVATE_READONLY; static uint32_t arg_activate_flags = CRYPT_ACTIVATE_READONLY;
static const char *arg_root_hash_signature = NULL; static char *arg_root_hash_signature = NULL;
STATIC_DESTRUCTOR_REGISTER(arg_root_hash_signature, freep);
static int help(void) { static int help(void) {
_cleanup_free_ char *link = NULL; _cleanup_free_ char *link = NULL;
@ -39,13 +41,17 @@ static int help(void) {
} }
static int save_roothashsig_option(const char *option, bool strict) { static int save_roothashsig_option(const char *option, bool strict) {
int r;
if (path_is_absolute(option) || startswith(option, "base64:")) { if (path_is_absolute(option) || startswith(option, "base64:")) {
if (!HAVE_CRYPT_ACTIVATE_BY_SIGNED_KEY) if (!HAVE_CRYPT_ACTIVATE_BY_SIGNED_KEY)
return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP),
"Activation of verity device with signature requested, but cryptsetup does not support crypt_activate_by_signed_key()."); "Activation of verity device with signature requested, but cryptsetup does not support crypt_activate_by_signed_key().");
arg_root_hash_signature = option; r = free_and_strdup_warn(&arg_root_hash_signature, option);
if (r < 0)
return r;
return true; return true;
} }
@ -60,10 +66,10 @@ static int parse_options(const char *options) {
int r; int r;
/* backward compatibility with the obsolete ROOTHASHSIG positional argument */ /* backward compatibility with the obsolete ROOTHASHSIG positional argument */
r = save_roothashsig_option(options, false); r = save_roothashsig_option(options, /* strict= */ false);
if (r < 0) if (r < 0)
return r; return r;
if (r == 1) { if (r > 0) {
log_warning("Usage of ROOTHASHSIG positional argument is deprecated. " log_warning("Usage of ROOTHASHSIG positional argument is deprecated. "
"Please use the option root-hash-signature=%s instead.", options); "Please use the option root-hash-signature=%s instead.", options);
return 0; return 0;
@ -99,7 +105,7 @@ static int parse_options(const char *options) {
arg_activate_flags |= CRYPT_ACTIVATE_PANIC_ON_CORRUPTION; arg_activate_flags |= CRYPT_ACTIVATE_PANIC_ON_CORRUPTION;
#endif #endif
else if ((val = startswith(word, "root-hash-signature="))) { else if ((val = startswith(word, "root-hash-signature="))) {
r = save_roothashsig_option(val, true); r = save_roothashsig_option(val, /* strict= */ true);
if (r < 0) if (r < 0)
return r; return r;

View File

@ -575,14 +575,14 @@ systemd-analyze security --threshold=90 --offline=true \
--root=/tmp/img/ testfile.service --root=/tmp/img/ testfile.service
# The strict profile adds a lot of sanboxing options # The strict profile adds a lot of sanboxing options
systemd-analyze security --threshold=20 --offline=true \ systemd-analyze security --threshold=25 --offline=true \
--security-policy=/tmp/testfile.json \ --security-policy=/tmp/testfile.json \
--profile=strict \ --profile=strict \
--root=/tmp/img/ testfile.service --root=/tmp/img/ testfile.service
set +e set +e
# The trusted profile doesn't add any sanboxing options # The trusted profile doesn't add any sanboxing options
systemd-analyze security --threshold=20 --offline=true \ systemd-analyze security --threshold=25 --offline=true \
--security-policy=/tmp/testfile.json \ --security-policy=/tmp/testfile.json \
--profile=/usr/lib/systemd/portable/profile/trusted/service.conf \ --profile=/usr/lib/systemd/portable/profile/trusted/service.conf \
--root=/tmp/img/ testfile.service \ --root=/tmp/img/ testfile.service \