summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/basic/mount-util.c1
-rw-r--r--src/basic/path-util.c10
-rw-r--r--src/core/execute.c98
-rw-r--r--src/cryptsetup/cryptsetup.c14
-rw-r--r--src/shared/seccomp-util.c178
-rw-r--r--src/shared/seccomp-util.h2
-rw-r--r--src/systemctl/systemctl.c2
-rw-r--r--src/test/test-path-util.c41
-rw-r--r--src/test/test-seccomp.c33
-rw-r--r--src/test/test-unit-file.c2
-rw-r--r--src/udev/udev-builtin-net_id.c30
11 files changed, 308 insertions, 103 deletions
diff --git a/src/basic/mount-util.c b/src/basic/mount-util.c
index 2985cc475a..c8f8022578 100644
--- a/src/basic/mount-util.c
+++ b/src/basic/mount-util.c
@@ -525,6 +525,7 @@ bool fstype_is_network(const char *fstype) {
"glusterfs\0"
"pvfs2\0" /* OrangeFS */
"ocfs2\0"
+ "lustre\0"
;
const char *x;
diff --git a/src/basic/path-util.c b/src/basic/path-util.c
index 0f5b20cf05..fd38f51c4c 100644
--- a/src/basic/path-util.c
+++ b/src/basic/path-util.c
@@ -354,6 +354,16 @@ char* path_startswith(const char *path, const char *prefix) {
assert(path);
assert(prefix);
+ /* Returns a pointer to the start of the first component after the parts matched by
+ * the prefix, iff
+ * - both paths are absolute or both paths are relative,
+ * and
+ * - each component in prefix in turn matches a component in path at the same position.
+ * An empty string will be returned when the prefix and path are equivalent.
+ *
+ * Returns NULL otherwise.
+ */
+
if ((path[0] == '/') != (prefix[0] == '/'))
return NULL;
diff --git a/src/core/execute.c b/src/core/execute.c
index ae9df41b99..3f053602b5 100644
--- a/src/core/execute.c
+++ b/src/core/execute.c
@@ -787,6 +787,20 @@ static int get_fixed_supplementary_groups(const ExecContext *c,
assert(c);
+ /*
+ * If user is given, then lookup GID and supplementary groups list.
+ * We avoid NSS lookups for gid=0. Also we have to initialize groups
+ * as early as possible so we keep the list of supplementary groups
+ * of the caller.
+ */
+ if (user && gid_is_valid(gid) && gid != 0) {
+ /* First step, initialize groups from /etc/groups */
+ if (initgroups(user, gid) < 0)
+ return -errno;
+
+ keep_groups = true;
+ }
+
if (!c->supplementary_groups)
return 0;
@@ -803,18 +817,6 @@ static int get_fixed_supplementary_groups(const ExecContext *c,
return -EOPNOTSUPP; /* For all other values */
}
- /*
- * If user is given, then lookup GID and supplementary group list.
- * We avoid NSS lookups for gid=0.
- */
- if (user && gid_is_valid(gid) && gid != 0) {
- /* First step, initialize groups from /etc/groups */
- if (initgroups(user, gid) < 0)
- return -errno;
-
- keep_groups = true;
- }
-
l_gids = new(gid_t, ngroups_max);
if (!l_gids)
return -ENOMEM;
@@ -2538,12 +2540,6 @@ static int exec_child(
(void) umask(context->umask);
if ((params->flags & EXEC_APPLY_PERMISSIONS) && !command->privileged) {
- r = setup_smack(context, command);
- if (r < 0) {
- *exit_status = EXIT_SMACK_PROCESS_LABEL;
- return r;
- }
-
if (context->pam_name && username) {
r = setup_pam(context->pam_name, username, uid, gid, context->tty_path, &accum_env, fds, n_fds);
if (r < 0) {
@@ -2577,7 +2573,7 @@ static int exec_child(
return r;
}
- /* Drop group as early as possbile */
+ /* Drop groups as early as possbile */
if ((params->flags & EXEC_APPLY_PERMISSIONS) && !command->privileged) {
r = enforce_groups(context, gid, supplementary_gids, ngids);
if (r < 0) {
@@ -2693,6 +2689,41 @@ static int exec_child(
}
}
+ /* Apply the MAC contexts late, but before seccomp syscall filtering, as those should really be last to
+ * influence our own codepaths as little as possible. Moreover, applying MAC contexts usually requires
+ * syscalls that are subject to seccomp filtering, hence should probably be applied before the syscalls
+ * are restricted. */
+
+#ifdef HAVE_SELINUX
+ if (mac_selinux_use()) {
+ char *exec_context = mac_selinux_context_net ?: context->selinux_context;
+
+ if (exec_context) {
+ r = setexeccon(exec_context);
+ if (r < 0) {
+ *exit_status = EXIT_SELINUX_CONTEXT;
+ return r;
+ }
+ }
+ }
+#endif
+
+ r = setup_smack(context, command);
+ if (r < 0) {
+ *exit_status = EXIT_SMACK_PROCESS_LABEL;
+ return r;
+ }
+
+#ifdef HAVE_APPARMOR
+ if (context->apparmor_profile && mac_apparmor_use()) {
+ r = aa_change_onexec(context->apparmor_profile);
+ if (r < 0 && !context->apparmor_profile_ignore) {
+ *exit_status = EXIT_APPARMOR_PROFILE;
+ return -errno;
+ }
+ }
+#endif
+
/* PR_GET_SECUREBITS is not privileged, while
* PR_SET_SECUREBITS is. So to suppress
* potential EPERMs we'll try not to call
@@ -2758,6 +2789,8 @@ static int exec_child(
}
}
+ /* This really should remain the last step before the execve(), to make sure our own code is unaffected
+ * by the filter as little as possible. */
if (context_has_syscall_filters(context)) {
r = apply_seccomp(unit, context);
if (r < 0) {
@@ -2766,30 +2799,6 @@ static int exec_child(
}
}
#endif
-
-#ifdef HAVE_SELINUX
- if (mac_selinux_use()) {
- char *exec_context = mac_selinux_context_net ?: context->selinux_context;
-
- if (exec_context) {
- r = setexeccon(exec_context);
- if (r < 0) {
- *exit_status = EXIT_SELINUX_CONTEXT;
- return r;
- }
- }
- }
-#endif
-
-#ifdef HAVE_APPARMOR
- if (context->apparmor_profile && mac_apparmor_use()) {
- r = aa_change_onexec(context->apparmor_profile);
- if (r < 0 && !context->apparmor_profile_ignore) {
- *exit_status = EXIT_APPARMOR_PROFILE;
- return -errno;
- }
- }
-#endif
}
final_argv = replace_env_argv(argv, accum_env);
@@ -3611,7 +3620,8 @@ char *exec_command_line(char **argv) {
STRV_FOREACH(a, argv)
k += strlen(*a)+3;
- if (!(n = new(char, k)))
+ n = new(char, k);
+ if (!n)
return NULL;
p = n;
diff --git a/src/cryptsetup/cryptsetup.c b/src/cryptsetup/cryptsetup.c
index 9927621ea0..ff5a3f36fb 100644
--- a/src/cryptsetup/cryptsetup.c
+++ b/src/cryptsetup/cryptsetup.c
@@ -52,6 +52,7 @@ static bool arg_verify = false;
static bool arg_discards = false;
static bool arg_tcrypt_hidden = false;
static bool arg_tcrypt_system = false;
+static bool arg_tcrypt_veracrypt = false;
static char **arg_tcrypt_keyfiles = NULL;
static uint64_t arg_offset = 0;
static uint64_t arg_skip = 0;
@@ -179,6 +180,14 @@ static int parse_one_option(const char *option) {
} else if (streq(option, "tcrypt-system")) {
arg_type = CRYPT_TCRYPT;
arg_tcrypt_system = true;
+ } else if (streq(option, "tcrypt-veracrypt")) {
+#ifdef CRYPT_TCRYPT_VERA_MODES
+ arg_type = CRYPT_TCRYPT;
+ arg_tcrypt_veracrypt = true;
+#else
+ log_error("This version of cryptsetup does not support tcrypt-veracrypt; refusing.");
+ return -EINVAL;
+#endif
} else if (STR_IN_SET(option, "plain", "swap", "tmp"))
arg_type = CRYPT_PLAIN;
else if (startswith(option, "timeout=")) {
@@ -441,6 +450,11 @@ static int attach_tcrypt(
if (arg_tcrypt_system)
params.flags |= CRYPT_TCRYPT_SYSTEM_HEADER;
+#ifdef CRYPT_TCRYPT_VERA_MODES
+ if (arg_tcrypt_veracrypt)
+ params.flags |= CRYPT_TCRYPT_VERA_MODES;
+#endif
+
if (key_file) {
r = read_one_line_file(key_file, &passphrase);
if (r < 0) {
diff --git a/src/shared/seccomp-util.c b/src/shared/seccomp-util.c
index 6252cd16a6..c9b24f1065 100644
--- a/src/shared/seccomp-util.c
+++ b/src/shared/seccomp-util.c
@@ -29,23 +29,49 @@
#include "util.h"
const char* seccomp_arch_to_string(uint32_t c) {
+ /* Maintain order used in <seccomp.h>.
+ *
+ * Names used here should be the same as those used for ConditionArchitecture=,
+ * except for "subarchitectures" like x32. */
- if (c == SCMP_ARCH_NATIVE)
+ switch(c) {
+ case SCMP_ARCH_NATIVE:
return "native";
- if (c == SCMP_ARCH_X86)
+ case SCMP_ARCH_X86:
return "x86";
- if (c == SCMP_ARCH_X86_64)
+ case SCMP_ARCH_X86_64:
return "x86-64";
- if (c == SCMP_ARCH_X32)
+ case SCMP_ARCH_X32:
return "x32";
- if (c == SCMP_ARCH_ARM)
+ case SCMP_ARCH_ARM:
return "arm";
- if (c == SCMP_ARCH_S390)
+ case SCMP_ARCH_AARCH64:
+ return "arm64";
+ case SCMP_ARCH_MIPS:
+ return "mips";
+ case SCMP_ARCH_MIPS64:
+ return "mips64";
+ case SCMP_ARCH_MIPS64N32:
+ return "mips64-n32";
+ case SCMP_ARCH_MIPSEL:
+ return "mips-le";
+ case SCMP_ARCH_MIPSEL64:
+ return "mips64-le";
+ case SCMP_ARCH_MIPSEL64N32:
+ return "mips64-le-n32";
+ case SCMP_ARCH_PPC:
+ return "ppc";
+ case SCMP_ARCH_PPC64:
+ return "ppc64";
+ case SCMP_ARCH_PPC64LE:
+ return "ppc64-le";
+ case SCMP_ARCH_S390:
return "s390";
- if (c == SCMP_ARCH_S390X)
+ case SCMP_ARCH_S390X:
return "s390x";
-
- return NULL;
+ default:
+ return NULL;
+ }
}
int seccomp_arch_from_string(const char *n, uint32_t *ret) {
@@ -64,6 +90,26 @@ int seccomp_arch_from_string(const char *n, uint32_t *ret) {
*ret = SCMP_ARCH_X32;
else if (streq(n, "arm"))
*ret = SCMP_ARCH_ARM;
+ else if (streq(n, "arm64"))
+ *ret = SCMP_ARCH_AARCH64;
+ else if (streq(n, "mips"))
+ *ret = SCMP_ARCH_MIPS;
+ else if (streq(n, "mips64"))
+ *ret = SCMP_ARCH_MIPS64;
+ else if (streq(n, "mips64-n32"))
+ *ret = SCMP_ARCH_MIPS64N32;
+ else if (streq(n, "mips-le"))
+ *ret = SCMP_ARCH_MIPSEL;
+ else if (streq(n, "mips64-le"))
+ *ret = SCMP_ARCH_MIPSEL64;
+ else if (streq(n, "mips64-le-n32"))
+ *ret = SCMP_ARCH_MIPSEL64N32;
+ else if (streq(n, "ppc"))
+ *ret = SCMP_ARCH_PPC;
+ else if (streq(n, "ppc64"))
+ *ret = SCMP_ARCH_PPC64;
+ else if (streq(n, "ppc64-le"))
+ *ret = SCMP_ARCH_PPC64LE;
else if (streq(n, "s390"))
*ret = SCMP_ARCH_S390;
else if (streq(n, "s390x"))
@@ -101,41 +147,52 @@ finish:
return r;
}
-int seccomp_add_secondary_archs(scmp_filter_ctx c) {
-
-#if defined(__i386__) || defined(__x86_64__)
- int r;
+int seccomp_add_secondary_archs(scmp_filter_ctx ctx) {
/* Add in all possible secondary archs we are aware of that
* this kernel might support. */
- r = seccomp_arch_add(c, SCMP_ARCH_X86);
- if (r < 0 && r != -EEXIST)
- return r;
-
- r = seccomp_arch_add(c, SCMP_ARCH_X86_64);
- if (r < 0 && r != -EEXIST)
- return r;
-
- r = seccomp_arch_add(c, SCMP_ARCH_X32);
- if (r < 0 && r != -EEXIST)
- return r;
+ static const int seccomp_arches[] = {
+#if defined(__i386__) || defined(__x86_64__)
+ SCMP_ARCH_X86,
+ SCMP_ARCH_X86_64,
+ SCMP_ARCH_X32,
+
+#elif defined(__arm__) || defined(__aarch64__)
+ SCMP_ARCH_ARM,
+ SCMP_ARCH_AARCH64,
+
+#elif defined(__arm__) || defined(__aarch64__)
+ SCMP_ARCH_ARM,
+ SCMP_ARCH_AARCH64,
+
+#elif defined(__mips__) || defined(__mips64__)
+ SCMP_ARCH_MIPS,
+ SCMP_ARCH_MIPS64,
+ SCMP_ARCH_MIPS64N32,
+ SCMP_ARCH_MIPSEL,
+ SCMP_ARCH_MIPSEL64,
+ SCMP_ARCH_MIPSEL64N32,
+
+#elif defined(__powerpc__) || defined(__powerpc64__)
+ SCMP_ARCH_PPC,
+ SCMP_ARCH_PPC64,
+ SCMP_ARCH_PPC64LE,
#elif defined(__s390__) || defined(__s390x__)
- int r;
-
- /* Add in all possible secondary archs we are aware of that
- * this kernel might support. */
-
- r = seccomp_arch_add(c, SCMP_ARCH_S390);
- if (r < 0 && r != -EEXIST)
- return r;
+ SCMP_ARCH_S390,
+ SCMP_ARCH_S390X,
+#endif
+ };
- r = seccomp_arch_add(c, SCMP_ARCH_S390X);
- if (r < 0 && r != -EEXIST)
- return r;
+ unsigned i;
+ int r;
-#endif
+ for (i = 0; i < ELEMENTSOF(seccomp_arches); i++) {
+ r = seccomp_arch_add(ctx, seccomp_arches[i]);
+ if (r < 0 && r != -EEXIST)
+ return r;
+ }
return 0;
}
@@ -160,6 +217,24 @@ bool is_seccomp_available(void) {
}
const SyscallFilterSet syscall_filter_sets[_SYSCALL_FILTER_SET_MAX] = {
+ [SYSCALL_FILTER_SET_BASIC_IO] = {
+ /* Basic IO */
+ .name = "@basic-io",
+ .value =
+ "close\0"
+ "dup2\0"
+ "dup3\0"
+ "dup\0"
+ "lseek\0"
+ "pread64\0"
+ "preadv\0"
+ "pwrite64\0"
+ "pwritev\0"
+ "read\0"
+ "readv\0"
+ "write\0"
+ "writev\0"
+ },
[SYSCALL_FILTER_SET_CLOCK] = {
/* Clock */
.name = "@clock",
@@ -196,15 +271,22 @@ const SyscallFilterSet syscall_filter_sets[_SYSCALL_FILTER_SET_MAX] = {
"sys_debug_setcontext\0"
},
[SYSCALL_FILTER_SET_DEFAULT] = {
- /* Default list */
+ /* Default list: the most basic of operations */
.name = "@default",
.value =
+ "clock_getres\0"
+ "clock_gettime\0"
+ "clock_nanosleep\0"
"execve\0"
"exit\0"
"exit_group\0"
"getrlimit\0" /* make sure processes can query stack size and such */
+ "gettimeofday\0"
+ "nanosleep\0"
+ "pause\0"
"rt_sigreturn\0"
"sigreturn\0"
+ "time\0"
},
[SYSCALL_FILTER_SET_IO_EVENT] = {
/* Event loop use */
@@ -226,9 +308,10 @@ const SyscallFilterSet syscall_filter_sets[_SYSCALL_FILTER_SET_MAX] = {
"select\0"
},
[SYSCALL_FILTER_SET_IPC] = {
- /* Message queues, SYSV IPC or other IPC: unusual */
+ /* Message queues, SYSV IPC or other IPC */
.name = "@ipc",
.value = "ipc\0"
+ "memfd_create\0"
"mq_getsetattr\0"
"mq_notify\0"
"mq_open\0"
@@ -239,6 +322,8 @@ const SyscallFilterSet syscall_filter_sets[_SYSCALL_FILTER_SET_MAX] = {
"msgget\0"
"msgrcv\0"
"msgsnd\0"
+ "pipe2\0"
+ "pipe\0"
"process_vm_readv\0"
"process_vm_writev\0"
"semctl\0"
@@ -379,7 +464,6 @@ const SyscallFilterSet syscall_filter_sets[_SYSCALL_FILTER_SET_MAX] = {
.value =
"arch_prctl\0"
"clone\0"
- "execve\0"
"execveat\0"
"fork\0"
"kill\0"
@@ -406,6 +490,22 @@ const SyscallFilterSet syscall_filter_sets[_SYSCALL_FILTER_SET_MAX] = {
"s390_pci_mmio_write\0"
#endif
},
+ [SYSCALL_FILTER_SET_RESOURCES] = {
+ /* Alter resource settings */
+ .name = "@resources",
+ .value =
+ "sched_setparam\0"
+ "sched_setscheduler\0"
+ "sched_setaffinity\0"
+ "setpriority\0"
+ "setrlimit\0"
+ "set_mempolicy\0"
+ "migrate_pages\0"
+ "move_pages\0"
+ "mbind\0"
+ "sched_setattr\0"
+ "prlimit64\0"
+ },
};
const SyscallFilterSet *syscall_filter_set_find(const char *name) {
diff --git a/src/shared/seccomp-util.h b/src/shared/seccomp-util.h
index 8050fc6fbf..8e209efef2 100644
--- a/src/shared/seccomp-util.h
+++ b/src/shared/seccomp-util.h
@@ -38,6 +38,7 @@ typedef struct SyscallFilterSet {
} SyscallFilterSet;
enum {
+ SYSCALL_FILTER_SET_BASIC_IO,
SYSCALL_FILTER_SET_CLOCK,
SYSCALL_FILTER_SET_CPU_EMULATION,
SYSCALL_FILTER_SET_DEBUG,
@@ -52,6 +53,7 @@ enum {
SYSCALL_FILTER_SET_PRIVILEGED,
SYSCALL_FILTER_SET_PROCESS,
SYSCALL_FILTER_SET_RAW_IO,
+ SYSCALL_FILTER_SET_RESOURCES,
_SYSCALL_FILTER_SET_MAX
};
diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c
index d311bbec1a..b6d66aa363 100644
--- a/src/systemctl/systemctl.c
+++ b/src/systemctl/systemctl.c
@@ -5272,7 +5272,7 @@ static int cat(int argc, char *argv[], void *userdata) {
else
puts("");
- if (need_daemon_reload(bus, *name))
+ if (need_daemon_reload(bus, *name) > 0) /* ignore errors (<0), this is informational output */
fprintf(stderr,
"%s# Warning: %s changed on disk, the version systemd has loaded is outdated.\n"
"%s# This output shows the current version of the unit's original fragment and drop-in files.\n"
diff --git a/src/test/test-path-util.c b/src/test/test-path-util.c
index 0b10d8e25e..a6a09a0031 100644
--- a/src/test/test-path-util.c
+++ b/src/test/test-path-util.c
@@ -263,16 +263,37 @@ static void test_strv_resolve(void) {
}
static void test_path_startswith(void) {
- assert_se(path_startswith("/foo/bar/barfoo/", "/foo"));
- assert_se(path_startswith("/foo/bar/barfoo/", "/foo/"));
- assert_se(path_startswith("/foo/bar/barfoo/", "/"));
- assert_se(path_startswith("/foo/bar/barfoo/", "////"));
- assert_se(path_startswith("/foo/bar/barfoo/", "/foo//bar/////barfoo///"));
- assert_se(path_startswith("/foo/bar/barfoo/", "/foo/bar/barfoo////"));
- assert_se(path_startswith("/foo/bar/barfoo/", "/foo/bar///barfoo/"));
- assert_se(path_startswith("/foo/bar/barfoo/", "/foo////bar/barfoo/"));
- assert_se(path_startswith("/foo/bar/barfoo/", "////foo/bar/barfoo/"));
- assert_se(path_startswith("/foo/bar/barfoo/", "/foo/bar/barfoo"));
+ const char *p;
+
+ p = path_startswith("/foo/bar/barfoo/", "/foo");
+ assert_se(streq_ptr(p, "bar/barfoo/"));
+
+ p = path_startswith("/foo/bar/barfoo/", "/foo/");
+ assert_se(streq_ptr(p, "bar/barfoo/"));
+
+ p = path_startswith("/foo/bar/barfoo/", "/");
+ assert_se(streq_ptr(p, "foo/bar/barfoo/"));
+
+ p = path_startswith("/foo/bar/barfoo/", "////");
+ assert_se(streq_ptr(p, "foo/bar/barfoo/"));
+
+ p = path_startswith("/foo/bar/barfoo/", "/foo//bar/////barfoo///");
+ assert_se(streq_ptr(p, ""));
+
+ p = path_startswith("/foo/bar/barfoo/", "/foo/bar/barfoo////");
+ assert_se(streq_ptr(p, ""));
+
+ p = path_startswith("/foo/bar/barfoo/", "/foo/bar///barfoo/");
+ assert_se(streq_ptr(p, ""));
+
+ p = path_startswith("/foo/bar/barfoo/", "/foo////bar/barfoo/");
+ assert_se(streq_ptr(p, ""));
+
+ p = path_startswith("/foo/bar/barfoo/", "////foo/bar/barfoo/");
+ assert_se(streq_ptr(p, ""));
+
+ p = path_startswith("/foo/bar/barfoo/", "/foo/bar/barfoo");
+ assert_se(streq_ptr(p, ""));
assert_se(!path_startswith("/foo/bar/barfoo/", "/foo/bar/barfooa/"));
assert_se(!path_startswith("/foo/bar/barfoo/", "/foo/bar/barfooa"));
diff --git a/src/test/test-seccomp.c b/src/test/test-seccomp.c
index 0060ecdf02..43d1567288 100644
--- a/src/test/test-seccomp.c
+++ b/src/test/test-seccomp.c
@@ -25,6 +25,8 @@
#include "macro.h"
#include "process-util.h"
#include "seccomp-util.h"
+#include "string-util.h"
+#include "util.h"
static void test_seccomp_arch_to_string(void) {
uint32_t a, b;
@@ -38,6 +40,36 @@ static void test_seccomp_arch_to_string(void) {
assert_se(a == b);
}
+static void test_architecture_table(void) {
+ const char *n, *n2;
+
+ NULSTR_FOREACH(n,
+ "native\0"
+ "x86\0"
+ "x86-64\0"
+ "x32\0"
+ "arm\0"
+ "arm64\0"
+ "mips\0"
+ "mips64\0"
+ "mips64-n32\0"
+ "mips-le\0"
+ "mips64-le\0"
+ "mips64-le-n32\0"
+ "ppc\0"
+ "ppc64\0"
+ "ppc64-le\0"
+ "s390\0"
+ "s390x\0") {
+ uint32_t c;
+
+ assert_se(seccomp_arch_from_string(n, &c) >= 0);
+ n2 = seccomp_arch_to_string(c);
+ log_info("seccomp-arch: %s → 0x%"PRIx32" → %s", n, c, n2);
+ assert_se(streq_ptr(n, n2));
+ }
+}
+
static void test_syscall_filter_set_find(void) {
assert_se(!syscall_filter_set_find(NULL));
assert_se(!syscall_filter_set_find(""));
@@ -96,6 +128,7 @@ static void test_filter_sets(void) {
int main(int argc, char *argv[]) {
test_seccomp_arch_to_string();
+ test_architecture_table();
test_syscall_filter_set_find();
test_filter_sets();
diff --git a/src/test/test-unit-file.c b/src/test/test-unit-file.c
index 7ef087a2e3..12f48bf435 100644
--- a/src/test/test-unit-file.c
+++ b/src/test/test-unit-file.c
@@ -589,7 +589,7 @@ static void test_install_printf(void) {
assert_se(specifier_machine_id('m', NULL, NULL, &mid) >= 0 && mid);
assert_se(specifier_boot_id('b', NULL, NULL, &bid) >= 0 && bid);
assert_se((host = gethostname_malloc()));
- assert_se((user = getusername_malloc()));
+ assert_se((user = uid_to_name(getuid())));
assert_se(asprintf(&uid, UID_FMT, getuid()) >= 0);
#define expect(src, pattern, result) \
diff --git a/src/udev/udev-builtin-net_id.c b/src/udev/udev-builtin-net_id.c
index a7be2a4eed..0eb2500dd2 100644
--- a/src/udev/udev-builtin-net_id.c
+++ b/src/udev/udev-builtin-net_id.c
@@ -35,10 +35,12 @@
* Type of names:
* b<number> — BCMA bus core number
* c<bus_id> — CCW bus group name, without leading zeros [s390]
- * o<index>[d<dev_port>] — on-board device index number
- * s<slot>[f<function>][d<dev_port>] — hotplug slot index number
+ * o<index>[n<phys_port_name>|d<dev_port>]
+ * — on-board device index number
+ * s<slot>[f<function>][n<phys_port_name>|d<dev_port>]
+ * — hotplug slot index number
* x<MAC> — MAC address
- * [P<domain>]p<bus>s<slot>[f<function>][d<dev_port>]
+ * [P<domain>]p<bus>s<slot>[f<function>][n<phys_port_name>|d<dev_port>]
* — PCI geographical location
* [P<domain>]p<bus>s<slot>[f<function>][u<port>][..][c<config>][i<interface>]
* — USB port number chain
@@ -137,7 +139,7 @@ static int dev_pci_onboard(struct udev_device *dev, struct netnames *names) {
unsigned dev_port = 0;
size_t l;
char *s;
- const char *attr;
+ const char *attr, *port_name;
int idx;
/* ACPI _DSM — device specific method for naming a PCI or PCI Express device */
@@ -164,10 +166,15 @@ static int dev_pci_onboard(struct udev_device *dev, struct netnames *names) {
if (attr)
dev_port = strtol(attr, NULL, 10);
+ /* kernel provided front panel port name for multiple port PCI device */
+ port_name = udev_device_get_sysattr_value(dev, "phys_port_name");
+
s = names->pci_onboard;
l = sizeof(names->pci_onboard);
l = strpcpyf(&s, l, "o%d", idx);
- if (dev_port > 0)
+ if (port_name)
+ l = strpcpyf(&s, l, "n%s", port_name);
+ else if (dev_port > 0)
l = strpcpyf(&s, l, "d%d", dev_port);
if (l == 0)
names->pci_onboard[0] = '\0';
@@ -202,7 +209,7 @@ static int dev_pci_slot(struct udev_device *dev, struct netnames *names) {
unsigned domain, bus, slot, func, dev_port = 0;
size_t l;
char *s;
- const char *attr;
+ const char *attr, *port_name;
struct udev_device *pci = NULL;
char slots[256], str[256];
_cleanup_closedir_ DIR *dir = NULL;
@@ -217,6 +224,9 @@ static int dev_pci_slot(struct udev_device *dev, struct netnames *names) {
if (attr)
dev_port = strtol(attr, NULL, 10);
+ /* kernel provided front panel port name for multiple port PCI device */
+ port_name = udev_device_get_sysattr_value(dev, "phys_port_name");
+
/* compose a name based on the raw kernel's PCI bus, slot numbers */
s = names->pci_path;
l = sizeof(names->pci_path);
@@ -225,7 +235,9 @@ static int dev_pci_slot(struct udev_device *dev, struct netnames *names) {
l = strpcpyf(&s, l, "p%us%u", bus, slot);
if (func > 0 || is_pci_multifunction(names->pcidev))
l = strpcpyf(&s, l, "f%u", func);
- if (dev_port > 0)
+ if (port_name)
+ l = strpcpyf(&s, l, "n%s", port_name);
+ else if (dev_port > 0)
l = strpcpyf(&s, l, "d%u", dev_port);
if (l == 0)
names->pci_path[0] = '\0';
@@ -275,7 +287,9 @@ static int dev_pci_slot(struct udev_device *dev, struct netnames *names) {
l = strpcpyf(&s, l, "s%d", hotplug_slot);
if (func > 0 || is_pci_multifunction(names->pcidev))
l = strpcpyf(&s, l, "f%d", func);
- if (dev_port > 0)
+ if (port_name)
+ l = strpcpyf(&s, l, "n%s", port_name);
+ else if (dev_port > 0)
l = strpcpyf(&s, l, "d%d", dev_port);
if (l == 0)
names->pci_slot[0] = '\0';