mirror of
https://github.com/systemd/systemd
synced 2026-04-24 07:55:12 +02:00
Compare commits
24 Commits
b8529cf376
...
bd4dea76de
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
bd4dea76de | ||
|
|
95cd21928f | ||
|
|
b17a681be5 | ||
|
|
0d08db7f89 | ||
|
|
37ebfe49de | ||
|
|
356ad32dc2 | ||
|
|
798931160e | ||
|
|
72dce85a60 | ||
|
|
fdf02a4f26 | ||
|
|
6cdd6d1acc | ||
|
|
ca782b85fc | ||
|
|
aed3c5eca3 | ||
|
|
dd51e725df | ||
|
|
1449b0f8a9 | ||
|
|
9cce7fb193 | ||
|
|
49888d31b6 | ||
|
|
63e8df046b | ||
|
|
556560495e | ||
|
|
0a5c6a57c6 | ||
|
|
5674aa7a2c | ||
|
|
2e37ebdae9 | ||
|
|
09bbaa419b | ||
|
|
ed59b44309 | ||
|
|
8419213d99 |
4
TODO
4
TODO
@ -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
|
||||||
|
|||||||
@ -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>
|
||||||
|
|||||||
@ -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"
|
||||||
|
|||||||
@ -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",
|
||||||
|
|||||||
@ -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;
|
||||||
|
|
||||||
|
if (ret)
|
||||||
*ret = TAKE_PTR(c);
|
*ret = TAKE_PTR(c);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -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;
|
||||||
|
|
||||||
|
|||||||
@ -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;
|
||||||
|
|
||||||
|
if (ret) {
|
||||||
d = endswith(*ret, " (deleted)");
|
d = endswith(*ret, " (deleted)");
|
||||||
if (d)
|
if (d)
|
||||||
*d = '\0';
|
*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)
|
||||||
|
|||||||
@ -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;
|
||||||
|
|||||||
@ -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 "}"
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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 "}"
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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,12 +331,37 @@ 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;
|
||||||
|
|
||||||
|
/* First test if CLONE_NEWUSER/CLONE_NEWNET can actually work for us, i.e. we can open the namespaces
|
||||||
|
* and then still access the build dir we are run from. We do that in a child process since it's
|
||||||
|
* 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) {
|
if (unshare(CLONE_NEWUSER | CLONE_NEWNET) < 0) {
|
||||||
log_warning("test-resolved-stream: Can't create user and network ns, running on host");
|
log_warning_errno(errno, "test-resolved-stream: Can't create user and network ns, running on host: %m");
|
||||||
return;
|
_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);
|
||||||
|
|||||||
@ -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) {
|
||||||
|
|||||||
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@ -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);
|
||||||
|
|||||||
@ -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;
|
||||||
|
|||||||
@ -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);
|
||||||
|
|||||||
@ -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");
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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;
|
||||||
|
|
||||||
|
|||||||
@ -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 \
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user