selinux: alternate root support (#42768)
This PR changes some SELinux bits related to working with alternate roots (specifically when using `--root` or `--image` on a bunch of executables). It addresses bug #42643 and it's hopefully the more whole approach than the naive approach I PR'ed in #42644. Before this PR the 'wrong' labels get applied because the path lookups in the SELinux label database are prefixed with whatever the location of the alternate root is (explained in more detail below). Initially I had taken a very naive approach that did fix the issue by stripping the alternate root from the path; however this still looks up that path in the hosts' label database, which might differ from the one contained in the alternate root. So this expanded approach actually reads the label database from the alternate root, strips the prefix *if* an alternate root is used directly in `selinux-util.c` and then uses that to assign labels instead. See under the line for the behavior pre/post. I've tried builds of this PR on both enforcing/non-enforcing/non-enabled hosts *and* on enabled/non-enabled disk images and things seem to work or at least fall back to ignoring MAC when required bits aren't present. One thing is *if* an `/etc/selinux/config` is present that defines a `SELINUXTYPE=` we *do* require the policy given to be present in the image. This is the only new actual error in this code path that doesn't get ignored. We *could* verify that the path exists and also ignore it but I personally don't think that's the right approach since the actual system itself would likely also be broken anyhow. Let me know thoughts on that. There's a tight coupling here still with the *hosts* SELinux policy in that to set (potentially) unknown labels to the policy loaded in the host kernel these executables would need to execute in a domain that allows transitioning to `mac_admin`. I'd say that `install_t` is the most likely candidate for that. See the first comment on this PR for more explanation on it/request for input. --- When mounting `a.raw` before running any tooling against it and showing the `/etc/shadow` file labels we have: ``` € sudo systemd-dissect --mount test/a.raw test/mnt/a € ls -Zlart test/mnt/a/etc/shadow ----------. 1 root root system_u:object_r:shadow_t:s0 520 Jun 27 07:55 test/mnt/a/etc/shadow € sudo systemd-dissect ---umount test/mnt/a ``` After running `systemd-firstboot` against the image, then remounting, note the labels that have been changed to incorrect values: ``` € sudo systemd-firstboot --image test/a.raw --root-password test /home/user/src/github.com/teamsbc/artifacts/test/a.raw: /etc/passwd written. /home/user/src/github.com/teamsbc/artifacts/test/a.raw: /etc/shadow written. € sudo systemd-dissect --mount test/a.raw test/mnt/a € ls -Zlart test/mnt/a/etc/shadow ----------. 1 root root system_u:object_r:init_var_run_t:s0 579 Jun 27 08:01 test/mnt/a/etc/shadow ``` The behavior before this PR looks up the labels in the label database of the host, but the path that gets looked up is the path where the image is temporarily mounted, or in the case of `--root` where the root is on the host. Since that path doesn't define any labels we get the labels of the location where the file was created on the host. In this case since `--image` was used, which mounted things in a temporary location we end up with `var_run_t`. If this image is booted things that want to read `/etc/shadow` might not be allowed to read files labeled this way; thus services fail to start, and root can't login when SELinux is in enforcing mode. After this PR is applied there are two main differences in how things are handled. The first being that instead of reading the label database from the host (which might have none, or have a different one from the one contained inside an image or root) we read the label database from inside the alternate root. This tries to make sure we get the correct labels for given paths. Second, and most importantly, if we did init SELinux with an alternate root then any paths passed to the relevant label lookup functions strip that alternate root from the path. While previously we'd look up a path like `/run/dissect-XXXX/etc/shadow` we now look up a path like `/etc/shadow` *and* this path gets looked up in the label database in the alternate root. Together these things give in my opinion better handling of SELinux in alternate roots. To confirm things work here's the same operations on the second copy of our image: ``` € sudo systemd-dissect --mount test/b.raw test/mnt/b artifacts € ls -Zlart test/mnt/b/etc/shadow ----------. 1 root root system_u:object_r:shadow_t:s0 520 Jun 27 07:55 test/mnt/b/etc/shadow € sudo ~/src/github.com/systemd/systemd/build/systemd-firstboot --image test/b.raw --root-password test /home/user/src/github.com/teamsbc/artifacts/test/b.raw: /etc/passwd written. /home/user/src/github.com/teamsbc/artifacts/test/b.raw: /etc/shadow written. € sudo systemd-dissect --mount test/b.raw test/mnt/b € ls -Zlart test/mnt/b/etc/shadow ----------. 1 root root system_u:object_r:shadow_t:s0 579 Jun 27 08:44 test/mnt/b/etc/shadow ``` Showing that we now have the correct labels applied.
This commit is contained in:
@@ -665,7 +665,7 @@ static void write_env_var(FILE *f, const char *v) {
|
||||
fputc_unlocked('\n', f);
|
||||
}
|
||||
|
||||
int write_env_file(int dir_fd, const char *fname, char **headers, char **l, WriteEnvFileFlags flags) {
|
||||
int write_env_file_label(int dir_fd, const char *fname, char **headers, char **l, WriteEnvFileFlags flags, LabelContext *label_context) {
|
||||
_cleanup_fclose_ FILE *f = NULL;
|
||||
_cleanup_free_ char *p = NULL;
|
||||
int r;
|
||||
@@ -675,7 +675,7 @@ int write_env_file(int dir_fd, const char *fname, char **headers, char **l, Writ
|
||||
|
||||
bool call_label_ops_post = false;
|
||||
if (FLAGS_SET(flags, WRITE_ENV_FILE_LABEL)) {
|
||||
r = label_ops_pre(dir_fd, fname, S_IFREG);
|
||||
r = label_ops_pre(dir_fd, fname, S_IFREG, label_context);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
@@ -683,7 +683,7 @@ int write_env_file(int dir_fd, const char *fname, char **headers, char **l, Writ
|
||||
}
|
||||
|
||||
r = fopen_tmpfile_linkable_at(dir_fd, fname, O_WRONLY|O_CLOEXEC, &p, &f);
|
||||
int k = call_label_ops_post ? label_ops_post(f ? fileno(f) : dir_fd, f ? NULL : fname, /* created= */ !!f) : 0;
|
||||
int k = call_label_ops_post ? label_ops_post(f ? fileno(f) : dir_fd, f ? NULL : fname, /* created= */ !!f, label_context) : 0;
|
||||
if (r < 0)
|
||||
return r;
|
||||
CLEANUP_TMPFILE_AT(dir_fd, p);
|
||||
@@ -717,5 +717,5 @@ int write_vconsole_conf(int dir_fd, const char *fname, char **l) {
|
||||
"# Written by systemd-localed(8) or systemd-firstboot(1), read by systemd-localed",
|
||||
"# and systemd-vconsole-setup(8). Use localectl(1) to update this file.");
|
||||
|
||||
return write_env_file(dir_fd, fname, headers, l, WRITE_ENV_FILE_LABEL);
|
||||
return write_env_file_label(dir_fd, fname, headers, l, WRITE_ENV_FILE_LABEL, /* label_context= */ NULL);
|
||||
}
|
||||
|
||||
@@ -24,7 +24,10 @@ typedef enum WriteEnvFileFlags {
|
||||
WRITE_ENV_FILE_LABEL = 1 << 0,
|
||||
} WriteEnvFileFlags;
|
||||
|
||||
int write_env_file(int dir_fd, const char *fname, char **headers, char **l, WriteEnvFileFlags flags);
|
||||
int write_env_file_label(int dir_fd, const char *fname, char **headers, char **l, WriteEnvFileFlags flags, LabelContext *label_context);
|
||||
static inline int write_env_file(int dir_fd, const char *fname, char **headers, char **l, WriteEnvFileFlags flags) {
|
||||
return write_env_file_label(dir_fd, fname, headers, l, flags, /* label_context= */ NULL);
|
||||
}
|
||||
|
||||
int write_vconsole_conf(int dir_fd, const char *fname, char **l);
|
||||
|
||||
|
||||
+10
-8
@@ -219,7 +219,8 @@ static int write_string_file_atomic_at(
|
||||
const char *fn,
|
||||
const char *line,
|
||||
WriteStringFileFlags flags,
|
||||
const struct timespec *ts) {
|
||||
const struct timespec *ts,
|
||||
LabelContext *label_context) {
|
||||
|
||||
_cleanup_fclose_ FILE *f = NULL;
|
||||
_cleanup_free_ char *p = NULL;
|
||||
@@ -235,7 +236,7 @@ static int write_string_file_atomic_at(
|
||||
|
||||
bool call_label_ops_post = false;
|
||||
if (FLAGS_SET(flags, WRITE_STRING_FILE_LABEL)) {
|
||||
r = label_ops_pre(dir_fd, fn, mode);
|
||||
r = label_ops_pre(dir_fd, fn, mode, label_context);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
@@ -243,7 +244,7 @@ static int write_string_file_atomic_at(
|
||||
}
|
||||
|
||||
r = fopen_temporary_at(dir_fd, fn, &f, &p);
|
||||
int k = call_label_ops_post ? label_ops_post(f ? fileno(f) : dir_fd, f ? NULL : fn, /* created= */ !!f) : 0;
|
||||
int k = call_label_ops_post ? label_ops_post(f ? fileno(f) : dir_fd, f ? NULL : fn, /* created= */ !!f, label_context) : 0;
|
||||
/* If fopen_temporary_at() failed in the above, propagate the error code, and ignore failures in
|
||||
* label_ops_post(). */
|
||||
if (r < 0)
|
||||
@@ -276,13 +277,14 @@ static int write_string_file_atomic_at(
|
||||
return 0;
|
||||
}
|
||||
|
||||
int write_string_file_full(
|
||||
int write_string_file_full_label(
|
||||
int dir_fd,
|
||||
const char *fn,
|
||||
const char *line,
|
||||
WriteStringFileFlags flags,
|
||||
const struct timespec *ts,
|
||||
const char *label_fn) {
|
||||
const char *label_fn,
|
||||
LabelContext *label_context) {
|
||||
|
||||
bool made_file = false;
|
||||
_cleanup_fclose_ FILE *f = NULL;
|
||||
@@ -307,7 +309,7 @@ int write_string_file_full(
|
||||
assert(fn);
|
||||
assert(flags & WRITE_STRING_FILE_CREATE);
|
||||
|
||||
r = write_string_file_atomic_at(dir_fd, fn, line, flags, ts);
|
||||
r = write_string_file_atomic_at(dir_fd, fn, line, flags, ts, label_context);
|
||||
if (r < 0)
|
||||
goto fail;
|
||||
|
||||
@@ -326,7 +328,7 @@ int write_string_file_full(
|
||||
bool call_label_ops_post = false;
|
||||
|
||||
if (FLAGS_SET(flags, WRITE_STRING_FILE_LABEL|WRITE_STRING_FILE_CREATE)) {
|
||||
r = label_ops_pre(dir_fd, label_fn ?: fn, mode);
|
||||
r = label_ops_pre(dir_fd, label_fn ?: fn, mode, label_context);
|
||||
if (r < 0)
|
||||
goto fail;
|
||||
|
||||
@@ -345,7 +347,7 @@ int write_string_file_full(
|
||||
if (call_label_ops_post)
|
||||
/* If openat_report_new() failed in the above, propagate the error code, and ignore
|
||||
* failures in label_ops_post(). */
|
||||
RET_GATHER(r, label_ops_post(fd >= 0 ? fd : dir_fd, fd >= 0 ? NULL : fn, made_file));
|
||||
RET_GATHER(r, label_ops_post(fd >= 0 ? fd : dir_fd, fd >= 0 ? NULL : fn, made_file, label_context));
|
||||
}
|
||||
if (r < 0)
|
||||
goto fail;
|
||||
|
||||
+4
-1
@@ -45,7 +45,10 @@ static inline int write_string_stream(FILE *f, const char *line, WriteStringFile
|
||||
return write_string_stream_full(f, line, flags, NULL);
|
||||
}
|
||||
|
||||
int write_string_file_full(int dir_fd, const char *fn, const char *line, WriteStringFileFlags flags, const struct timespec *ts, const char *label_fn);
|
||||
int write_string_file_full_label(int dir_fd, const char *fn, const char *line, WriteStringFileFlags flags, const struct timespec *ts, const char *label_fn, LabelContext *label_context);
|
||||
static inline int write_string_file_full(int dir_fd, const char *fn, const char *line, WriteStringFileFlags flags, const struct timespec *ts, const char *label_fn) {
|
||||
return write_string_file_full_label(dir_fd, fn, line, flags, ts, label_fn, /* label_context= */ NULL);
|
||||
}
|
||||
static inline int write_string_file_at(int dir_fd, const char *fn, const char *line, WriteStringFileFlags flags) {
|
||||
return write_string_file_full(dir_fd, fn, line, flags, NULL, NULL);
|
||||
}
|
||||
|
||||
@@ -128,6 +128,7 @@ typedef struct dual_timestamp dual_timestamp;
|
||||
typedef struct triple_timestamp triple_timestamp;
|
||||
typedef struct Compressor Compressor;
|
||||
typedef struct ConfFile ConfFile;
|
||||
typedef struct LabelContext LabelContext;
|
||||
typedef struct LockFile LockFile;
|
||||
typedef struct PidRef PidRef;
|
||||
typedef struct Prioq Prioq;
|
||||
|
||||
+13
-12
@@ -461,7 +461,7 @@ int symlinkat_idempotent(const char *target, int atfd, const char *linkpath, boo
|
||||
return 0;
|
||||
}
|
||||
|
||||
int symlinkat_atomic_full(const char *target, int atfd, const char *linkpath, SymlinkFlags flags) {
|
||||
int symlinkat_atomic_full_label(const char *target, int atfd, const char *linkpath, SymlinkFlags flags, LabelContext *label_context) {
|
||||
int r;
|
||||
|
||||
assert(target);
|
||||
@@ -483,7 +483,7 @@ int symlinkat_atomic_full(const char *target, int atfd, const char *linkpath, Sy
|
||||
|
||||
bool call_label_ops_post = false;
|
||||
if (FLAGS_SET(flags, SYMLINK_LABEL)) {
|
||||
r = label_ops_pre(atfd, linkpath, S_IFLNK);
|
||||
r = label_ops_pre(atfd, linkpath, S_IFLNK, label_context);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
@@ -492,7 +492,7 @@ int symlinkat_atomic_full(const char *target, int atfd, const char *linkpath, Sy
|
||||
|
||||
r = RET_NERRNO(symlinkat(target, atfd, t));
|
||||
if (call_label_ops_post)
|
||||
RET_GATHER(r, label_ops_post(atfd, t, /* created= */ r >= 0));
|
||||
RET_GATHER(r, label_ops_post(atfd, t, /* created= */ r >= 0, label_context));
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
@@ -1035,7 +1035,7 @@ int parse_cifs_service(
|
||||
return 0;
|
||||
}
|
||||
|
||||
int open_mkdir_at_full(int dirfd, const char *path, int flags, XOpenFlags xopen_flags, mode_t mode) {
|
||||
int open_mkdir_at_full_label(int dirfd, const char *path, int flags, XOpenFlags xopen_flags, mode_t mode, LabelContext *label_context) {
|
||||
_cleanup_close_ int fd = -EBADF, parent_fd = -EBADF;
|
||||
_cleanup_free_ char *fname = NULL, *parent = NULL;
|
||||
int r;
|
||||
@@ -1071,7 +1071,7 @@ int open_mkdir_at_full(int dirfd, const char *path, int flags, XOpenFlags xopen_
|
||||
path = fname;
|
||||
}
|
||||
|
||||
fd = xopenat_full(dirfd, path, flags|O_CREAT|O_DIRECTORY|O_NOFOLLOW, xopen_flags, mode);
|
||||
fd = xopenat_full_label(dirfd, path, flags|O_CREAT|O_DIRECTORY|O_NOFOLLOW, xopen_flags, mode, label_context);
|
||||
if (IN_SET(fd, -ELOOP, -ENOTDIR))
|
||||
return -EEXIST;
|
||||
if (fd < 0)
|
||||
@@ -1171,7 +1171,7 @@ static int openat_with_automount(int dir_fd, const char *path, int open_flags, m
|
||||
return RET_NERRNO(openat(dir_fd, path, open_flags, mode));
|
||||
}
|
||||
|
||||
int xopenat_full(int dir_fd, const char *path, int open_flags, XOpenFlags xopen_flags, mode_t mode) {
|
||||
int xopenat_full_label(int dir_fd, const char *path, int open_flags, XOpenFlags xopen_flags, mode_t mode, LabelContext *label_context) {
|
||||
_cleanup_close_ int fd = -EBADF;
|
||||
bool made_dir = false, made_file = false;
|
||||
int r;
|
||||
@@ -1276,7 +1276,7 @@ int xopenat_full(int dir_fd, const char *path, int open_flags, XOpenFlags xopen_
|
||||
bool call_label_ops_post = false;
|
||||
|
||||
if (FLAGS_SET(open_flags, O_CREAT) && FLAGS_SET(xopen_flags, XO_LABEL)) {
|
||||
r = label_ops_pre(dir_fd, path, FLAGS_SET(open_flags, O_DIRECTORY) ? S_IFDIR : S_IFREG);
|
||||
r = label_ops_pre(dir_fd, path, FLAGS_SET(open_flags, O_DIRECTORY) ? S_IFDIR : S_IFREG, label_context);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
@@ -1433,7 +1433,7 @@ int xopenat_full(int dir_fd, const char *path, int open_flags, XOpenFlags xopen_
|
||||
if (call_label_ops_post) {
|
||||
call_label_ops_post = false;
|
||||
|
||||
r = label_ops_post(fd, /* path= */ NULL, made_file || made_dir);
|
||||
r = label_ops_post(fd, /* path= */ NULL, made_file || made_dir, label_context);
|
||||
if (r < 0)
|
||||
goto error;
|
||||
}
|
||||
@@ -1448,7 +1448,7 @@ int xopenat_full(int dir_fd, const char *path, int open_flags, XOpenFlags xopen_
|
||||
|
||||
error:
|
||||
if (call_label_ops_post)
|
||||
(void) label_ops_post(fd >= 0 ? fd : dir_fd, fd >= 0 ? NULL : path, made_dir || made_file);
|
||||
(void) label_ops_post(fd >= 0 ? fd : dir_fd, fd >= 0 ? NULL : path, made_dir || made_file, label_context);
|
||||
|
||||
if (made_dir || made_file)
|
||||
(void) unlinkat(dir_fd, path, made_dir ? AT_REMOVEDIR : 0);
|
||||
@@ -1456,14 +1456,15 @@ error:
|
||||
return r;
|
||||
}
|
||||
|
||||
int xopenat_lock_full(
|
||||
int xopenat_lock_full_label(
|
||||
int dir_fd,
|
||||
const char *path,
|
||||
int open_flags,
|
||||
XOpenFlags xopen_flags,
|
||||
mode_t mode,
|
||||
LockType locktype,
|
||||
int operation) {
|
||||
int operation,
|
||||
LabelContext *label_context) {
|
||||
|
||||
_cleanup_close_ int fd = -EBADF;
|
||||
int r;
|
||||
@@ -1479,7 +1480,7 @@ int xopenat_lock_full(
|
||||
for (;;) {
|
||||
struct stat st;
|
||||
|
||||
fd = xopenat_full(dir_fd, path, open_flags, xopen_flags, mode);
|
||||
fd = xopenat_full_label(dir_fd, path, open_flags, xopen_flags, mode, label_context);
|
||||
if (fd < 0)
|
||||
return fd;
|
||||
|
||||
|
||||
+16
-4
@@ -58,7 +58,10 @@ typedef enum SymlinkFlags {
|
||||
SYMLINK_LABEL = 1 << 1,
|
||||
} SymlinkFlags;
|
||||
|
||||
int symlinkat_atomic_full(const char *target, int atfd, const char *linkpath, SymlinkFlags flags);
|
||||
int symlinkat_atomic_full_label(const char *target, int atfd, const char *linkpath, SymlinkFlags flags, LabelContext *label_context);
|
||||
static inline int symlinkat_atomic_full(const char *target, int atfd, const char *linkpath, SymlinkFlags flags) {
|
||||
return symlinkat_atomic_full_label(target, atfd, linkpath, flags, /* label_context= */ NULL);
|
||||
}
|
||||
static inline int symlink_atomic(const char *target, const char *linkpath) {
|
||||
return symlinkat_atomic_full(target, AT_FDCWD, linkpath, 0);
|
||||
}
|
||||
@@ -119,7 +122,10 @@ typedef enum XOpenFlags {
|
||||
XO_AUTO_RW_RO = 1 << 7, /* Open in O_RDWR mode if possible, O_RDONLY if not */
|
||||
} XOpenFlags;
|
||||
|
||||
int open_mkdir_at_full(int dirfd, const char *path, int flags, XOpenFlags xopen_flags, mode_t mode);
|
||||
int open_mkdir_at_full_label(int dirfd, const char *path, int flags, XOpenFlags xopen_flags, mode_t mode, LabelContext *label_context);
|
||||
static inline int open_mkdir_at_full(int dirfd, const char *path, int flags, XOpenFlags xopen_flags, mode_t mode) {
|
||||
return open_mkdir_at_full_label(dirfd, path, flags, xopen_flags, mode, /* label_context= */ NULL);
|
||||
}
|
||||
static inline int open_mkdir_at(int dirfd, const char *path, int flags, mode_t mode) {
|
||||
return open_mkdir_at_full(dirfd, path, flags, 0, mode);
|
||||
}
|
||||
@@ -129,12 +135,18 @@ static inline int open_mkdir(const char *path, int flags, mode_t mode) {
|
||||
|
||||
int openat_report_new(int dirfd, const char *pathname, int flags, mode_t mode, bool *ret_newly_created);
|
||||
|
||||
int xopenat_full(int dir_fd, const char *path, int open_flags, XOpenFlags xopen_flags, mode_t mode);
|
||||
int xopenat_full_label(int dir_fd, const char *path, int open_flags, XOpenFlags xopen_flags, mode_t mode, LabelContext *label_context);
|
||||
static inline int xopenat_full(int dir_fd, const char *path, int open_flags, XOpenFlags xopen_flags, mode_t mode) {
|
||||
return xopenat_full_label(dir_fd, path, open_flags, xopen_flags, mode, /* label_context= */ NULL);
|
||||
}
|
||||
static inline int xopenat(int dir_fd, const char *path, int open_flags) {
|
||||
return xopenat_full(dir_fd, path, open_flags, 0, MODE_INVALID);
|
||||
}
|
||||
|
||||
int xopenat_lock_full(int dir_fd, const char *path, int open_flags, XOpenFlags xopen_flags, mode_t mode, LockType locktype, int operation);
|
||||
int xopenat_lock_full_label(int dir_fd, const char *path, int open_flags, XOpenFlags xopen_flags, mode_t mode, LockType locktype, int operation, LabelContext *label_context);
|
||||
static inline int xopenat_lock_full(int dir_fd, const char *path, int open_flags, XOpenFlags xopen_flags, mode_t mode, LockType locktype, int operation) {
|
||||
return xopenat_lock_full_label(dir_fd, path, open_flags, xopen_flags, mode, locktype, operation, /* label_context= */ NULL);
|
||||
}
|
||||
static inline int xopenat_lock(int dir_fd, const char *path, int open_flags, LockType locktype, int operation) {
|
||||
return xopenat_lock_full(dir_fd, path, open_flags, 0, 0, locktype, operation);
|
||||
}
|
||||
|
||||
@@ -18,16 +18,16 @@ void label_ops_reset(void) {
|
||||
label_ops = NULL;
|
||||
}
|
||||
|
||||
int label_ops_pre(int dir_fd, const char *path, mode_t mode) {
|
||||
int label_ops_pre(int dir_fd, const char *path, mode_t mode, LabelContext *label_context) {
|
||||
if (!label_ops || !label_ops->pre)
|
||||
return 0;
|
||||
|
||||
return label_ops->pre(dir_fd, path, mode);
|
||||
return label_ops->pre(dir_fd, path, mode, label_context);
|
||||
}
|
||||
|
||||
int label_ops_post(int dir_fd, const char *path, bool created) {
|
||||
int label_ops_post(int dir_fd, const char *path, bool created, LabelContext *label_context) {
|
||||
if (!label_ops || !label_ops->post)
|
||||
return 0;
|
||||
|
||||
return label_ops->post(dir_fd, path, created);
|
||||
return label_ops->post(dir_fd, path, created, label_context);
|
||||
}
|
||||
|
||||
@@ -4,12 +4,12 @@
|
||||
#include "forward.h"
|
||||
|
||||
typedef struct LabelOps {
|
||||
int (*pre)(int dir_fd, const char *path, mode_t mode);
|
||||
int (*post)(int dir_fd, const char *path, bool created);
|
||||
int (*pre)(int dir_fd, const char *path, mode_t mode, LabelContext *label_context);
|
||||
int (*post)(int dir_fd, const char *path, bool created, LabelContext *label_context);
|
||||
} LabelOps;
|
||||
|
||||
int label_ops_set(const LabelOps *label_ops);
|
||||
void label_ops_reset(void);
|
||||
|
||||
int label_ops_pre(int dir_fd, const char *path, mode_t mode);
|
||||
int label_ops_post(int dir_fd, const char *path, bool created);
|
||||
int label_ops_pre(int dir_fd, const char *path, mode_t mode, LabelContext *label_context);
|
||||
int label_ops_post(int dir_fd, const char *path, bool created, LabelContext *label_context);
|
||||
|
||||
+22
-21
@@ -25,16 +25,17 @@ int mkdirat_safe_internal(
|
||||
uid_t uid,
|
||||
gid_t gid,
|
||||
MkdirFlags flags,
|
||||
mkdirat_func_t _mkdirat) {
|
||||
mkdirat_func_t _mkdirat,
|
||||
LabelContext *label_context) {
|
||||
|
||||
struct stat st;
|
||||
int r;
|
||||
|
||||
assert(path);
|
||||
assert(mode != MODE_INVALID);
|
||||
assert(_mkdirat && _mkdirat != mkdirat);
|
||||
assert(_mkdirat);
|
||||
|
||||
r = _mkdirat(dir_fd, path, mode);
|
||||
r = _mkdirat(dir_fd, path, mode, label_context);
|
||||
if (r >= 0)
|
||||
return chmod_and_chown_at(dir_fd, path, mode, uid, gid);
|
||||
if (r != -EEXIST)
|
||||
@@ -52,7 +53,7 @@ int mkdirat_safe_internal(
|
||||
if (r == 0)
|
||||
return mkdirat_safe_internal(dir_fd, p, mode, uid, gid,
|
||||
flags & ~MKDIR_FOLLOW_SYMLINK,
|
||||
_mkdirat);
|
||||
_mkdirat, label_context);
|
||||
|
||||
if (fstatat(dir_fd, p, &st, AT_SYMLINK_NOFOLLOW) < 0)
|
||||
return -errno;
|
||||
@@ -80,20 +81,20 @@ int mkdirat_safe_internal(
|
||||
return 0;
|
||||
}
|
||||
|
||||
int mkdirat_errno_wrapper(int dirfd, const char *pathname, mode_t mode) {
|
||||
int mkdirat_errno_wrapper(int dirfd, const char *pathname, mode_t mode, LabelContext *label_context) {
|
||||
return RET_NERRNO(mkdirat(dirfd, pathname, mode));
|
||||
}
|
||||
|
||||
int mkdirat_safe(int dir_fd, const char *path, mode_t mode, uid_t uid, gid_t gid, MkdirFlags flags) {
|
||||
return mkdirat_safe_internal(dir_fd, path, mode, uid, gid, flags, mkdirat_errno_wrapper);
|
||||
return mkdirat_safe_internal(dir_fd, path, mode, uid, gid, flags, mkdirat_errno_wrapper, /* label_context= */ NULL);
|
||||
}
|
||||
|
||||
int mkdirat_parents_internal(int dir_fd, const char *path, mode_t mode, uid_t uid, gid_t gid, MkdirFlags flags, mkdirat_func_t _mkdirat) {
|
||||
int mkdirat_parents_internal(int dir_fd, const char *path, mode_t mode, uid_t uid, gid_t gid, MkdirFlags flags, mkdirat_func_t _mkdirat, LabelContext *label_context) {
|
||||
const char *e = NULL;
|
||||
int r;
|
||||
|
||||
assert(path);
|
||||
assert(_mkdirat != mkdirat);
|
||||
assert(_mkdirat);
|
||||
|
||||
if (isempty(path))
|
||||
return 0;
|
||||
@@ -134,7 +135,7 @@ int mkdirat_parents_internal(int dir_fd, const char *path, mode_t mode, uid_t ui
|
||||
|
||||
s[n] = '\0';
|
||||
|
||||
r = mkdirat_safe_internal(dir_fd, path, mode, uid, gid, flags | MKDIR_IGNORE_EXISTING, _mkdirat);
|
||||
r = mkdirat_safe_internal(dir_fd, path, mode, uid, gid, flags | MKDIR_IGNORE_EXISTING, _mkdirat, label_context);
|
||||
if (r < 0 && r != -EEXIST)
|
||||
return r;
|
||||
|
||||
@@ -142,12 +143,12 @@ int mkdirat_parents_internal(int dir_fd, const char *path, mode_t mode, uid_t ui
|
||||
}
|
||||
}
|
||||
|
||||
int mkdir_parents_internal(const char *prefix, const char *path, mode_t mode, uid_t uid, gid_t gid, MkdirFlags flags, mkdirat_func_t _mkdirat) {
|
||||
int mkdir_parents_internal(const char *prefix, const char *path, mode_t mode, uid_t uid, gid_t gid, MkdirFlags flags, mkdirat_func_t _mkdirat, LabelContext *label_context) {
|
||||
_cleanup_close_ int fd = AT_FDCWD;
|
||||
const char *p;
|
||||
|
||||
assert(path);
|
||||
assert(_mkdirat != mkdirat);
|
||||
assert(_mkdirat);
|
||||
|
||||
if (prefix) {
|
||||
p = path_startswith_full(path, prefix, PATH_STARTSWITH_REFUSE_DOT_DOT);
|
||||
@@ -160,34 +161,34 @@ int mkdir_parents_internal(const char *prefix, const char *path, mode_t mode, ui
|
||||
} else
|
||||
p = path;
|
||||
|
||||
return mkdirat_parents_internal(fd, p, mode, uid, gid, flags, _mkdirat);
|
||||
return mkdirat_parents_internal(fd, p, mode, uid, gid, flags, _mkdirat, label_context);
|
||||
}
|
||||
|
||||
int mkdirat_parents(int dir_fd, const char *path, mode_t mode) {
|
||||
return mkdirat_parents_internal(dir_fd, path, mode, UID_INVALID, UID_INVALID, 0, mkdirat_errno_wrapper);
|
||||
return mkdirat_parents_internal(dir_fd, path, mode, UID_INVALID, UID_INVALID, 0, mkdirat_errno_wrapper, /* label_context= */ NULL);
|
||||
}
|
||||
|
||||
int mkdir_parents_safe(const char *prefix, const char *path, mode_t mode, uid_t uid, gid_t gid, MkdirFlags flags) {
|
||||
return mkdir_parents_internal(prefix, path, mode, uid, gid, flags, mkdirat_errno_wrapper);
|
||||
return mkdir_parents_internal(prefix, path, mode, uid, gid, flags, mkdirat_errno_wrapper, /* label_context= */ NULL);
|
||||
}
|
||||
|
||||
int mkdir_p_internal(const char *prefix, const char *path, mode_t mode, uid_t uid, gid_t gid, MkdirFlags flags, mkdirat_func_t _mkdirat) {
|
||||
int mkdir_p_internal(const char *prefix, const char *path, mode_t mode, uid_t uid, gid_t gid, MkdirFlags flags, mkdirat_func_t _mkdirat, LabelContext *label_context) {
|
||||
int r;
|
||||
|
||||
/* Like mkdir -p */
|
||||
|
||||
assert(_mkdirat != mkdirat);
|
||||
assert(_mkdirat);
|
||||
|
||||
r = mkdir_parents_internal(prefix, path, mode, uid, gid, flags | MKDIR_FOLLOW_SYMLINK, _mkdirat);
|
||||
r = mkdir_parents_internal(prefix, path, mode, uid, gid, flags | MKDIR_FOLLOW_SYMLINK, _mkdirat, label_context);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (!uid_is_valid(uid) && !gid_is_valid(gid) && flags == 0) {
|
||||
r = _mkdirat(AT_FDCWD, path, mode);
|
||||
r = _mkdirat(AT_FDCWD, path, mode, label_context);
|
||||
if (r < 0 && (r != -EEXIST || is_dir(path, true) <= 0))
|
||||
return r;
|
||||
} else {
|
||||
r = mkdir_safe_internal(path, mode, uid, gid, flags, _mkdirat);
|
||||
r = mkdir_safe_internal(path, mode, uid, gid, flags, _mkdirat, label_context);
|
||||
if (r < 0 && r != -EEXIST)
|
||||
return r;
|
||||
}
|
||||
@@ -196,11 +197,11 @@ int mkdir_p_internal(const char *prefix, const char *path, mode_t mode, uid_t ui
|
||||
}
|
||||
|
||||
int mkdir_p(const char *path, mode_t mode) {
|
||||
return mkdir_p_internal(NULL, path, mode, UID_INVALID, UID_INVALID, 0, mkdirat_errno_wrapper);
|
||||
return mkdir_p_internal(/* prefix= */ NULL, path, mode, UID_INVALID, UID_INVALID, 0, mkdirat_errno_wrapper, /* label_context= */ NULL);
|
||||
}
|
||||
|
||||
int mkdir_p_safe(const char *prefix, const char *path, mode_t mode, uid_t uid, gid_t gid, MkdirFlags flags) {
|
||||
return mkdir_p_internal(prefix, path, mode, uid, gid, flags, mkdirat_errno_wrapper);
|
||||
return mkdir_p_internal(prefix, path, mode, uid, gid, flags, mkdirat_errno_wrapper, /* label_context= */ NULL);
|
||||
}
|
||||
|
||||
int mkdir_p_root_full(const char *root, const char *p, uid_t uid, gid_t gid, mode_t m, usec_t ts, Hashmap *subvolumes) {
|
||||
|
||||
+8
-8
@@ -9,7 +9,7 @@ typedef enum MkdirFlags {
|
||||
MKDIR_WARN_MODE = 1 << 2, /* Log at LOG_WARNING when mode doesn't match */
|
||||
} MkdirFlags;
|
||||
|
||||
int mkdirat_errno_wrapper(int dirfd, const char *pathname, mode_t mode);
|
||||
int mkdirat_errno_wrapper(int dirfd, const char *pathname, mode_t mode, LabelContext *label_context);
|
||||
|
||||
int mkdirat_safe(int dir_fd, const char *path, mode_t mode, uid_t uid, gid_t gid, MkdirFlags flags);
|
||||
static inline int mkdir_safe(const char *path, mode_t mode, uid_t uid, gid_t gid, MkdirFlags flags) {
|
||||
@@ -28,11 +28,11 @@ static inline int mkdir_p_root(const char *root, const char *p, uid_t uid, gid_t
|
||||
}
|
||||
|
||||
/* The following are used to implement the mkdir_xyz_label() calls, don't use otherwise. */
|
||||
typedef int (*mkdirat_func_t)(int dir_fd, const char *pathname, mode_t mode);
|
||||
int mkdirat_safe_internal(int dir_fd, const char *path, mode_t mode, uid_t uid, gid_t gid, MkdirFlags flags, mkdirat_func_t _mkdir);
|
||||
static inline int mkdir_safe_internal(const char *path, mode_t mode, uid_t uid, gid_t gid, MkdirFlags flags, mkdirat_func_t _mkdir) {
|
||||
return mkdirat_safe_internal(AT_FDCWD, path, mode, uid, gid, flags, _mkdir);
|
||||
typedef int (*mkdirat_func_t)(int dir_fd, const char *pathname, mode_t mode, LabelContext *label_context);
|
||||
int mkdirat_safe_internal(int dir_fd, const char *path, mode_t mode, uid_t uid, gid_t gid, MkdirFlags flags, mkdirat_func_t _mkdir, LabelContext *label_context);
|
||||
static inline int mkdir_safe_internal(const char *path, mode_t mode, uid_t uid, gid_t gid, MkdirFlags flags, mkdirat_func_t _mkdir, LabelContext *label_context) {
|
||||
return mkdirat_safe_internal(AT_FDCWD, path, mode, uid, gid, flags, _mkdir, label_context);
|
||||
}
|
||||
int mkdirat_parents_internal(int dir_fd, const char *path, mode_t mode, uid_t uid, gid_t gid, MkdirFlags flags, mkdirat_func_t _mkdirat);
|
||||
int mkdir_parents_internal(const char *prefix, const char *path, mode_t mode, uid_t uid, gid_t gid, MkdirFlags flags, mkdirat_func_t _mkdir);
|
||||
int mkdir_p_internal(const char *prefix, const char *path, mode_t mode, uid_t uid, gid_t gid, MkdirFlags flags, mkdirat_func_t _mkdir);
|
||||
int mkdirat_parents_internal(int dir_fd, const char *path, mode_t mode, uid_t uid, gid_t gid, MkdirFlags flags, mkdirat_func_t _mkdirat, LabelContext *label_context);
|
||||
int mkdir_parents_internal(const char *prefix, const char *path, mode_t mode, uid_t uid, gid_t gid, MkdirFlags flags, mkdirat_func_t _mkdir, LabelContext *label_context);
|
||||
int mkdir_p_internal(const char *prefix, const char *path, mode_t mode, uid_t uid, gid_t gid, MkdirFlags flags, mkdirat_func_t _mkdir, LabelContext *label_context);
|
||||
|
||||
@@ -982,7 +982,7 @@ static int setup_credentials_plain_dir(
|
||||
return log_debug_errno(dfd, "Failed to create workspace for credentials: %m");
|
||||
workspace_rm = workspace;
|
||||
|
||||
(void) label_fix_full(dfd, /* inode_path= */ NULL, cred_dir, /* flags= */ 0);
|
||||
(void) label_fix_full(dfd, /* inode_path= */ NULL, cred_dir, /* flags= */ 0, /* label_context= */ NULL);
|
||||
|
||||
r = acquire_credentials(context, dfd, /* ownership_ok= */ false);
|
||||
if (r < 0)
|
||||
@@ -1063,7 +1063,7 @@ static int setup_credentials_internal(
|
||||
if (dfd < 0)
|
||||
return dfd;
|
||||
|
||||
(void) label_fix_full(dfd, /* inode_path= */ NULL, cred_dir, /* flags= */ 0);
|
||||
(void) label_fix_full(dfd, /* inode_path= */ NULL, cred_dir, /* flags= */ 0, /* label_context= */ NULL);
|
||||
|
||||
r = acquire_credentials(context, dfd, /* ownership_ok= */ true);
|
||||
if (r < 0)
|
||||
|
||||
@@ -1220,7 +1220,7 @@ static int clone_device_node(const char *node, const char *temporary_mount, bool
|
||||
|
||||
/* First, try to create device node properly */
|
||||
if (*make_devnode) {
|
||||
mac_selinux_create_file_prepare(node, st.st_mode);
|
||||
mac_selinux_create_file_prepare(node, st.st_mode, /* label_context= */ NULL);
|
||||
r = mknod(dn, st.st_mode, st.st_rdev);
|
||||
mac_selinux_create_file_clear();
|
||||
if (r >= 0)
|
||||
@@ -1341,7 +1341,7 @@ static int mount_private_dev(const MountEntry *m, const NamespaceParameters *p)
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = label_fix_full(AT_FDCWD, dev, "/dev", 0);
|
||||
r = label_fix_full(AT_FDCWD, dev, "/dev", /* flags= */ 0, /* label_context= */ NULL);
|
||||
if (r < 0)
|
||||
return log_debug_errno(r, "Failed to fix label of '%s' as /dev/: %m", dev);
|
||||
|
||||
@@ -1610,7 +1610,7 @@ static int mount_tmpfs(const MountEntry *m) {
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = label_fix_full(AT_FDCWD, entry_path, inner_path, 0);
|
||||
r = label_fix_full(AT_FDCWD, entry_path, inner_path, /* flags= */ 0, /* label_context= */ NULL);
|
||||
if (r < 0)
|
||||
return log_debug_errno(r, "Failed to fix label of '%s' as '%s': %m", entry_path, inner_path);
|
||||
|
||||
@@ -2067,7 +2067,7 @@ static int apply_one_mount(
|
||||
if (r < 0)
|
||||
return log_debug_errno(r, "Failed to create source directory %s: %m", mount_entry_source(m));
|
||||
|
||||
r = label_fix_full(AT_FDCWD, mount_entry_source(m), mount_entry_unprefixed_path(m), /* flags= */ 0);
|
||||
r = label_fix_full(AT_FDCWD, mount_entry_source(m), mount_entry_unprefixed_path(m), /* flags= */ 0, /* label_context= */ NULL);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to set label of the source directory %s: %m", mount_entry_source(m));
|
||||
}
|
||||
@@ -3474,7 +3474,7 @@ int setup_tmp_dir_one(const char *id, const char *prefix, char **ret_path) {
|
||||
return r;
|
||||
}
|
||||
|
||||
r = label_fix_full(AT_FDCWD, inner_dir, prefix, 0);
|
||||
r = label_fix_full(AT_FDCWD, inner_dir, prefix, /* flags= */ 0, /* label_context= */ NULL);
|
||||
if (r < 0) {
|
||||
(void) rmdir(inner_dir);
|
||||
(void) rmdir(d);
|
||||
|
||||
+1
-1
@@ -1209,7 +1209,7 @@ static int fifo_address_create(
|
||||
|
||||
(void) mkdir_parents_label(path, directory_mode);
|
||||
|
||||
r = mac_selinux_create_file_prepare(path, S_IFIFO);
|
||||
r = mac_selinux_create_file_prepare(path, S_IFIFO, /* label_context= */ NULL);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
|
||||
+25
-14
@@ -94,6 +94,7 @@ static bool arg_reset = false;
|
||||
static ImagePolicy *arg_image_policy = NULL;
|
||||
static bool arg_chrome = true;
|
||||
static bool arg_mute_console = false;
|
||||
static LabelContext *arg_label_context = NULL;
|
||||
|
||||
STATIC_DESTRUCTOR_REGISTER(arg_root, freep);
|
||||
STATIC_DESTRUCTOR_REGISTER(arg_image, freep);
|
||||
@@ -107,6 +108,7 @@ STATIC_DESTRUCTOR_REGISTER(arg_root_password, erase_and_freep);
|
||||
STATIC_DESTRUCTOR_REGISTER(arg_root_shell, freep);
|
||||
STATIC_DESTRUCTOR_REGISTER(arg_kernel_cmdline, freep);
|
||||
STATIC_DESTRUCTOR_REGISTER(arg_image_policy, image_policy_freep);
|
||||
STATIC_DESTRUCTOR_REGISTER(arg_label_context, mac_label_context_freep);
|
||||
|
||||
static bool welcome_done = false;
|
||||
|
||||
@@ -408,12 +410,13 @@ static int process_locale(int rfd, sd_varlink **mute_console_link) {
|
||||
|
||||
locales[i] = NULL;
|
||||
|
||||
r = write_env_file(
|
||||
r = write_env_file_label(
|
||||
pfd,
|
||||
f,
|
||||
/* headers= */ NULL,
|
||||
locales,
|
||||
WRITE_ENV_FILE_LABEL);
|
||||
WRITE_ENV_FILE_LABEL,
|
||||
arg_label_context);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to write /etc/locale.conf: %m");
|
||||
|
||||
@@ -653,7 +656,7 @@ static int process_timezone(int rfd, sd_varlink **mute_console_link) {
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to read host's /etc/localtime: %m");
|
||||
|
||||
r = symlinkat_atomic_full(s, pfd, f, SYMLINK_LABEL);
|
||||
r = symlinkat_atomic_full_label(s, pfd, f, SYMLINK_LABEL, arg_label_context);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to create /etc/localtime symlink: %m");
|
||||
|
||||
@@ -674,7 +677,7 @@ static int process_timezone(int rfd, sd_varlink **mute_console_link) {
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = symlinkat_atomic_full(relpath, pfd, f, SYMLINK_LABEL);
|
||||
r = symlinkat_atomic_full_label(relpath, pfd, f, SYMLINK_LABEL, arg_label_context);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to create /etc/localtime symlink: %m");
|
||||
|
||||
@@ -779,8 +782,9 @@ static int process_hostname(int rfd, sd_varlink **mute_console_link) {
|
||||
hostname = resolved;
|
||||
}
|
||||
|
||||
r = write_string_file_at(pfd, f, hostname,
|
||||
WRITE_STRING_FILE_CREATE|WRITE_STRING_FILE_SYNC|WRITE_STRING_FILE_ATOMIC|WRITE_STRING_FILE_LABEL);
|
||||
r = write_string_file_full_label(pfd, f, hostname,
|
||||
WRITE_STRING_FILE_CREATE|WRITE_STRING_FILE_SYNC|WRITE_STRING_FILE_ATOMIC|WRITE_STRING_FILE_LABEL,
|
||||
/* ts= */ NULL, /* label_fn= */ NULL, arg_label_context);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to write /etc/hostname: %m");
|
||||
|
||||
@@ -812,8 +816,9 @@ static int process_machine_id(int rfd) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
r = write_string_file_at(pfd, "machine-id", SD_ID128_TO_STRING(arg_machine_id),
|
||||
WRITE_STRING_FILE_CREATE|WRITE_STRING_FILE_SYNC|WRITE_STRING_FILE_ATOMIC|WRITE_STRING_FILE_LABEL);
|
||||
r = write_string_file_full_label(pfd, "machine-id", SD_ID128_TO_STRING(arg_machine_id),
|
||||
WRITE_STRING_FILE_CREATE|WRITE_STRING_FILE_SYNC|WRITE_STRING_FILE_ATOMIC|WRITE_STRING_FILE_LABEL,
|
||||
/* ts= */ NULL, /* label_fn= */ NULL, arg_label_context);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to write /etc/machine-id: %m");
|
||||
|
||||
@@ -874,11 +879,12 @@ static int process_machine_tags(int rfd) {
|
||||
if (!c)
|
||||
return log_oom();
|
||||
|
||||
r = write_string_file_at(
|
||||
r = write_string_file_full_label(
|
||||
pfd,
|
||||
"machine-info",
|
||||
c,
|
||||
WRITE_STRING_FILE_CREATE|WRITE_STRING_FILE_SYNC|WRITE_STRING_FILE_ATOMIC|WRITE_STRING_FILE_LABEL);
|
||||
WRITE_STRING_FILE_CREATE|WRITE_STRING_FILE_SYNC|WRITE_STRING_FILE_ATOMIC|WRITE_STRING_FILE_LABEL,
|
||||
/* ts= */ NULL, /* label_fn= */ NULL, arg_label_context);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to write /etc/machine-info: %m");
|
||||
|
||||
@@ -1038,7 +1044,7 @@ static int write_root_passwd(int rfd, int etc_fd, const char *password, const ch
|
||||
int r;
|
||||
bool found = false;
|
||||
|
||||
r = fopen_temporary_at_label(etc_fd, "passwd", "passwd", &passwd, &passwd_tmp);
|
||||
r = fopen_temporary_at_label(etc_fd, "passwd", "passwd", &passwd, &passwd_tmp, arg_label_context);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
@@ -1109,7 +1115,7 @@ static int write_root_shadow(int etc_fd, const char *hashed_password) {
|
||||
int r;
|
||||
bool found = false;
|
||||
|
||||
r = fopen_temporary_at_label(etc_fd, "shadow", "shadow", &shadow, &shadow_tmp);
|
||||
r = fopen_temporary_at_label(etc_fd, "shadow", "shadow", &shadow, &shadow_tmp, arg_label_context);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
@@ -1319,8 +1325,9 @@ static int process_kernel_cmdline(int rfd) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
r = write_string_file_at(pfd, "cmdline", arg_kernel_cmdline,
|
||||
WRITE_STRING_FILE_CREATE|WRITE_STRING_FILE_SYNC|WRITE_STRING_FILE_ATOMIC|WRITE_STRING_FILE_LABEL);
|
||||
r = write_string_file_full_label(pfd, "cmdline", arg_kernel_cmdline,
|
||||
WRITE_STRING_FILE_CREATE|WRITE_STRING_FILE_SYNC|WRITE_STRING_FILE_ATOMIC|WRITE_STRING_FILE_LABEL,
|
||||
/* ts= */ NULL, /* label_fn= */ NULL, arg_label_context);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to write /etc/kernel/cmdline: %m");
|
||||
|
||||
@@ -1777,6 +1784,10 @@ static int run(int argc, char *argv[]) {
|
||||
return log_error_errno(errno, "Failed to open %s: %m", empty_to_root(arg_root));
|
||||
}
|
||||
|
||||
r = mac_label_context_new(arg_root, &arg_label_context);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to initialize label context for root '%s': %m", arg_root);
|
||||
|
||||
LOG_SET_PREFIX(arg_image ?: arg_root);
|
||||
DEFER_VOID_CALL(end_marker);
|
||||
DEFER_VOID_CALL(chrome_hide);
|
||||
|
||||
+5
-5
@@ -480,7 +480,7 @@ static int fd_copy_symlink(
|
||||
return r;
|
||||
|
||||
if (copy_flags & COPY_MAC_CREATE) {
|
||||
r = mac_selinux_create_file_prepare_at(dt, to, S_IFLNK);
|
||||
r = mac_selinux_create_file_prepare_at(dt, to, S_IFLNK, /* label_context= */ NULL);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
@@ -836,7 +836,7 @@ static int fd_copy_regular(
|
||||
return fdf;
|
||||
|
||||
if (copy_flags & COPY_MAC_CREATE) {
|
||||
r = mac_selinux_create_file_prepare_at(dt, to, S_IFREG);
|
||||
r = mac_selinux_create_file_prepare_at(dt, to, S_IFREG, /* label_context= */ NULL);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
@@ -923,7 +923,7 @@ static int fd_copy_fifo(
|
||||
return 0;
|
||||
|
||||
if (copy_flags & COPY_MAC_CREATE) {
|
||||
r = mac_selinux_create_file_prepare_at(dt, to, S_IFIFO);
|
||||
r = mac_selinux_create_file_prepare_at(dt, to, S_IFIFO, /* label_context= */ NULL);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
@@ -976,7 +976,7 @@ static int fd_copy_node(
|
||||
return 0;
|
||||
|
||||
if (copy_flags & COPY_MAC_CREATE) {
|
||||
r = mac_selinux_create_file_prepare_at(dt, to, st->st_mode & S_IFMT);
|
||||
r = mac_selinux_create_file_prepare_at(dt, to, st->st_mode & S_IFMT, /* label_context= */ NULL);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
@@ -1577,7 +1577,7 @@ int copy_file_atomic_at_full(
|
||||
assert(!FLAGS_SET(copy_flags, COPY_LOCK_BSD));
|
||||
|
||||
if (copy_flags & COPY_MAC_CREATE) {
|
||||
r = mac_selinux_create_file_prepare_at(dir_fdt, to, S_IFREG);
|
||||
r = mac_selinux_create_file_prepare_at(dir_fdt, to, S_IFREG, /* label_context= */ NULL);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
@@ -46,7 +46,7 @@ int dev_setup(const char *prefix, uid_t uid, gid_t gid) {
|
||||
} else
|
||||
n = k;
|
||||
|
||||
r = symlink_label(j, n);
|
||||
r = symlink_label(j, n, /* label_context= */ NULL);
|
||||
if (r < 0)
|
||||
log_debug_errno(r, "Failed to symlink %s to %s: %m", j, n);
|
||||
|
||||
@@ -113,9 +113,9 @@ int make_inaccessible_nodes(
|
||||
return log_oom();
|
||||
|
||||
if (S_ISDIR(inode_type))
|
||||
r = mkdirat_label(inaccessible_fd, fn, 0000);
|
||||
r = mkdirat_label(inaccessible_fd, fn, 0000, /* label_context= */ NULL);
|
||||
else
|
||||
r = mknodat_label(inaccessible_fd, fn, inode_type | 0000, makedev(0, 0));
|
||||
r = mknodat_label(inaccessible_fd, fn, inode_type | 0000, makedev(0, 0), /* label_context= */ NULL);
|
||||
if (r == -EEXIST) {
|
||||
if (fchmodat(inaccessible_fd, fn, 0000, AT_SYMLINK_NOFOLLOW) < 0)
|
||||
log_debug_errno(errno, "Failed to adjust access mode of existing inode '%s', ignoring: %m", path);
|
||||
|
||||
@@ -2199,7 +2199,7 @@ int image_setup_pool(RuntimeScope scope, ImageClass class, bool use_btrfs_subvol
|
||||
if (!use_btrfs_subvol)
|
||||
return 0;
|
||||
|
||||
(void) btrfs_subvol_make_label(pool);
|
||||
(void) btrfs_subvol_make_label(pool, /* label_context= */ NULL);
|
||||
|
||||
if (!use_btrfs_quota)
|
||||
return 0;
|
||||
|
||||
+25
-8
@@ -6,6 +6,7 @@
|
||||
#include "btrfs-util.h"
|
||||
#include "errno-util.h"
|
||||
#include "label-util.h"
|
||||
#include "path-util.h"
|
||||
#include "selinux-util.h"
|
||||
#include "smack-util.h"
|
||||
|
||||
@@ -13,7 +14,8 @@ int label_fix_full(
|
||||
int atfd,
|
||||
const char *inode_path, /* path of inode to apply label to */
|
||||
const char *label_path, /* path to use as database lookup key in label database (typically same as inode_path, but not always) */
|
||||
LabelFixFlags flags) {
|
||||
LabelFixFlags flags,
|
||||
LabelContext *label_context) {
|
||||
|
||||
int r, q;
|
||||
|
||||
@@ -30,7 +32,7 @@ int label_fix_full(
|
||||
* If atfd is AT_FDCWD then we'll operate on the inode the path refers to.
|
||||
*/
|
||||
|
||||
r = mac_selinux_fix_full(atfd, inode_path, label_path, flags);
|
||||
r = mac_selinux_fix_full(atfd, inode_path, label_path, flags, label_context);
|
||||
q = mac_smack_fix_full(atfd, inode_path, label_path, flags);
|
||||
if (r < 0)
|
||||
return r;
|
||||
@@ -40,13 +42,13 @@ int label_fix_full(
|
||||
return 0;
|
||||
}
|
||||
|
||||
int symlink_label(const char *old_path, const char *new_path) {
|
||||
int symlink_label(const char *old_path, const char *new_path, LabelContext *label_context) {
|
||||
int r;
|
||||
|
||||
assert(old_path);
|
||||
assert(new_path);
|
||||
|
||||
r = mac_selinux_create_file_prepare(new_path, S_IFLNK);
|
||||
r = mac_selinux_create_file_prepare(new_path, S_IFLNK, label_context);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
@@ -59,13 +61,13 @@ int symlink_label(const char *old_path, const char *new_path) {
|
||||
return mac_smack_fix(new_path, 0);
|
||||
}
|
||||
|
||||
int mknodat_label(int dirfd, const char *pathname, mode_t mode, dev_t dev) {
|
||||
int mknodat_label(int dirfd, const char *pathname, mode_t mode, dev_t dev, LabelContext *label_context) {
|
||||
int r;
|
||||
|
||||
assert(dirfd >= 0 || dirfd == AT_FDCWD);
|
||||
assert(pathname);
|
||||
|
||||
r = mac_selinux_create_file_prepare_at(dirfd, pathname, mode);
|
||||
r = mac_selinux_create_file_prepare_at(dirfd, pathname, mode, label_context);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
@@ -78,12 +80,12 @@ int mknodat_label(int dirfd, const char *pathname, mode_t mode, dev_t dev) {
|
||||
return mac_smack_fix_full(dirfd, pathname, NULL, 0);
|
||||
}
|
||||
|
||||
int btrfs_subvol_make_label(const char *path) {
|
||||
int btrfs_subvol_make_label(const char *path, LabelContext *label_context) {
|
||||
int r;
|
||||
|
||||
assert(path);
|
||||
|
||||
r = mac_selinux_create_file_prepare(path, S_IFDIR);
|
||||
r = mac_selinux_create_file_prepare(path, S_IFDIR, label_context);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
@@ -96,6 +98,21 @@ int btrfs_subvol_make_label(const char *path) {
|
||||
return mac_smack_fix(path, 0);
|
||||
}
|
||||
|
||||
int mac_label_context_new(const char *root, LabelContext **ret) {
|
||||
assert(ret);
|
||||
|
||||
if (empty_or_root(root)) {
|
||||
*ret = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return mac_selinux_label_context_new(root, ret);
|
||||
}
|
||||
|
||||
LabelContext* mac_label_context_free(LabelContext *c) {
|
||||
return mac_selinux_label_context_free(c);
|
||||
}
|
||||
|
||||
static int init_internal(bool lazy) {
|
||||
int r;
|
||||
|
||||
|
||||
+10
-6
@@ -10,20 +10,24 @@ typedef enum LabelFixFlags {
|
||||
LABEL_IGNORE_EROFS = 1 << 1,
|
||||
} LabelFixFlags;
|
||||
|
||||
int label_fix_full(int atfd, const char *inode_path, const char *label_path, LabelFixFlags flags);
|
||||
int label_fix_full(int atfd, const char *inode_path, const char *label_path, LabelFixFlags flags, LabelContext *label_context);
|
||||
|
||||
static inline int label_fix(const char *path, LabelFixFlags flags) {
|
||||
return label_fix_full(AT_FDCWD, path, path, flags);
|
||||
return label_fix_full(AT_FDCWD, path, path, flags, /* label_context= */ NULL);
|
||||
}
|
||||
|
||||
int symlink_label(const char *old_path, const char *new_path);
|
||||
int symlink_label(const char *old_path, const char *new_path, LabelContext *label_context);
|
||||
|
||||
int mknodat_label(int dirfd, const char *pathname, mode_t mode, dev_t dev);
|
||||
int mknodat_label(int dirfd, const char *pathname, mode_t mode, dev_t dev, LabelContext *label_context);
|
||||
static inline int mknod_label(const char *pathname, mode_t mode, dev_t dev) {
|
||||
return mknodat_label(AT_FDCWD, pathname, mode, dev);
|
||||
return mknodat_label(AT_FDCWD, pathname, mode, dev, /* label_context= */ NULL);
|
||||
}
|
||||
|
||||
int btrfs_subvol_make_label(const char *path);
|
||||
int btrfs_subvol_make_label(const char *path, LabelContext *label_context);
|
||||
|
||||
int mac_init(void);
|
||||
int mac_init_lazy(void);
|
||||
|
||||
int mac_label_context_new(const char *root, LabelContext **ret);
|
||||
LabelContext* mac_label_context_free(LabelContext *c);
|
||||
DEFINE_TRIVIAL_CLEANUP_FUNC(LabelContext*, mac_label_context_free);
|
||||
|
||||
+6
-14
@@ -8,12 +8,12 @@
|
||||
#include "selinux-util.h"
|
||||
#include "smack-util.h"
|
||||
|
||||
int mkdirat_label(int dirfd, const char *path, mode_t mode) {
|
||||
int mkdirat_label(int dirfd, const char *path, mode_t mode, LabelContext *label_context) {
|
||||
int r;
|
||||
|
||||
assert(path);
|
||||
|
||||
r = mac_selinux_create_file_prepare_at(dirfd, path, S_IFDIR);
|
||||
r = mac_selinux_create_file_prepare_at(dirfd, path, S_IFDIR, label_context);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
@@ -25,18 +25,10 @@ int mkdirat_label(int dirfd, const char *path, mode_t mode) {
|
||||
return mac_smack_fix_full(dirfd, path, NULL, 0);
|
||||
}
|
||||
|
||||
int mkdirat_safe_label(int dir_fd, const char *path, mode_t mode, uid_t uid, gid_t gid, MkdirFlags flags) {
|
||||
return mkdirat_safe_internal(dir_fd, path, mode, uid, gid, flags, mkdirat_label);
|
||||
int mkdirat_safe_label(int dir_fd, const char *path, mode_t mode, uid_t uid, gid_t gid, MkdirFlags flags, LabelContext *label_context) {
|
||||
return mkdirat_safe_internal(dir_fd, path, mode, uid, gid, flags, mkdirat_label, label_context);
|
||||
}
|
||||
|
||||
int mkdirat_parents_label(int dir_fd, const char *path, mode_t mode) {
|
||||
return mkdirat_parents_internal(dir_fd, path, mode, UID_INVALID, UID_INVALID, 0, mkdirat_label);
|
||||
}
|
||||
|
||||
int mkdir_parents_safe_label(const char *prefix, const char *path, mode_t mode, uid_t uid, gid_t gid, MkdirFlags flags) {
|
||||
return mkdir_parents_internal(prefix, path, mode, uid, gid, flags, mkdirat_label);
|
||||
}
|
||||
|
||||
int mkdir_p_label(const char *path, mode_t mode) {
|
||||
return mkdir_p_internal(NULL, path, mode, UID_INVALID, UID_INVALID, 0, mkdirat_label);
|
||||
int mkdirat_parents_label(int dir_fd, const char *path, mode_t mode, LabelContext *label_context) {
|
||||
return mkdirat_parents_internal(dir_fd, path, mode, UID_INVALID, UID_INVALID, 0, mkdirat_label, label_context);
|
||||
}
|
||||
|
||||
+12
-8
@@ -5,21 +5,25 @@
|
||||
|
||||
#include "../basic/mkdir.h" /* IWYU pragma: export */
|
||||
|
||||
int mkdirat_label(int dirfd, const char *path, mode_t mode);
|
||||
int mkdirat_label(int dirfd, const char *path, mode_t mode, LabelContext *label_context);
|
||||
|
||||
static inline int mkdir_label(const char *path, mode_t mode) {
|
||||
return mkdirat_label(AT_FDCWD, path, mode);
|
||||
return mkdirat_label(AT_FDCWD, path, mode, /* label_context= */ NULL);
|
||||
}
|
||||
|
||||
int mkdirat_safe_label(int dir_fd, const char *path, mode_t mode, uid_t uid, gid_t gid, MkdirFlags flags);
|
||||
int mkdirat_safe_label(int dir_fd, const char *path, mode_t mode, uid_t uid, gid_t gid, MkdirFlags flags, LabelContext *label_context);
|
||||
static inline int mkdir_safe_label(const char *path, mode_t mode, uid_t uid, gid_t gid, MkdirFlags flags) {
|
||||
return mkdirat_safe_label(AT_FDCWD, path, mode, uid, gid, flags);
|
||||
return mkdirat_safe_label(AT_FDCWD, path, mode, uid, gid, flags, /* label_context= */ NULL);
|
||||
}
|
||||
int mkdirat_parents_label(int dir_fd, const char *path, mode_t mod);
|
||||
int mkdirat_parents_label(int dir_fd, const char *path, mode_t mod, LabelContext *label_context);
|
||||
static inline int mkdir_parents_label(const char *path, mode_t mod) {
|
||||
return mkdirat_parents_label(AT_FDCWD, path, mod);
|
||||
return mkdirat_parents_label(AT_FDCWD, path, mod, /* label_context= */ NULL);
|
||||
}
|
||||
|
||||
int mkdir_parents_safe_label(const char *prefix, const char *path, mode_t mode, uid_t uid, gid_t gid, MkdirFlags flags);
|
||||
static inline int mkdir_parents_safe_label(const char *prefix, const char *path, mode_t mode, uid_t uid, gid_t gid, MkdirFlags flags) {
|
||||
return mkdir_parents_internal(prefix, path, mode, uid, gid, flags, mkdirat_label, /* label_context= */ NULL);
|
||||
}
|
||||
|
||||
int mkdir_p_label(const char *path, mode_t mode);
|
||||
static inline int mkdir_p_label(const char *path, mode_t mode) {
|
||||
return mkdir_p_internal(/* prefix= */ NULL, path, mode, UID_INVALID, UID_INVALID, 0, mkdirat_label, /* label_context= */ NULL);
|
||||
}
|
||||
|
||||
@@ -1946,7 +1946,7 @@ int make_mount_point_inode_from_mode(int dir_fd, const char *dest, mode_t source
|
||||
assert(dest);
|
||||
|
||||
if (S_ISDIR(source_mode))
|
||||
return mkdirat_label(dir_fd, dest, target_mode & 07777);
|
||||
return mkdirat_label(dir_fd, dest, target_mode & 07777, /* label_context= */ NULL);
|
||||
else
|
||||
return RET_NERRNO(mknodat(dir_fd, dest, S_IFREG|(target_mode & 07666), 0)); /* Mask off X bit */
|
||||
}
|
||||
|
||||
+333
-24
@@ -19,17 +19,22 @@
|
||||
|
||||
#include "alloc-util.h"
|
||||
#include "fd-util.h"
|
||||
#include "path-util.h"
|
||||
#include "string-util.h"
|
||||
#include "strv.h"
|
||||
#include "time-util.h"
|
||||
#endif
|
||||
|
||||
#include "chase.h"
|
||||
#include "env-file.h"
|
||||
#include "errno-util.h"
|
||||
#include "label-util.h"
|
||||
#include "path-util.h"
|
||||
#include "selinux-util.h"
|
||||
#include "smack-util.h"
|
||||
|
||||
#if HAVE_SELINUX
|
||||
DEFINE_TRIVIAL_CLEANUP_FUNC_FULL_RENAME(context_t, sym_context_free, context_freep, NULL);
|
||||
DEFINE_TRIVIAL_CLEANUP_FUNC_FULL_RENAME(struct selabel_handle *, sym_selabel_close, selabel_closep, NULL);
|
||||
|
||||
typedef enum Initialized {
|
||||
UNINITIALIZED,
|
||||
@@ -43,15 +48,38 @@ static int last_policyload = 0;
|
||||
static struct selabel_handle *label_hnd = NULL;
|
||||
static bool have_status_page = false;
|
||||
|
||||
static int mac_selinux_label_pre(int dir_fd, const char *path, mode_t mode) {
|
||||
return mac_selinux_create_file_prepare_at(dir_fd, path, mode);
|
||||
struct LabelContext {
|
||||
struct selabel_handle *label_hnd;
|
||||
int rfd;
|
||||
char *root;
|
||||
};
|
||||
|
||||
static void selinux_policy_root_reset_and_freep(char **s) {
|
||||
assert(s);
|
||||
if (!*s)
|
||||
return;
|
||||
(void) sym_selinux_set_policy_root(*s);
|
||||
*s = mfree(*s);
|
||||
}
|
||||
|
||||
static int mac_selinux_label_post(int dir_fd, const char *path, bool created) {
|
||||
mac_selinux_create_file_clear();
|
||||
static int mac_selinux_label_pre(int dir_fd, const char *path, mode_t mode, LabelContext *label_context) {
|
||||
return mac_selinux_create_file_prepare_at(dir_fd, path, mode, label_context);
|
||||
}
|
||||
|
||||
static int mac_selinux_label_post(int dir_fd, const char *path, bool created, LabelContext *label_context) {
|
||||
if (label_context) {
|
||||
PROTECT_ERRNO;
|
||||
(void) sym_setfscreatecon_raw(NULL);
|
||||
} else
|
||||
mac_selinux_create_file_clear();
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const LabelOps selinux_label_ops = {
|
||||
.pre = mac_selinux_label_pre,
|
||||
.post = mac_selinux_label_post,
|
||||
};
|
||||
|
||||
DLSYM_PROTOTYPE(avc_open) = NULL;
|
||||
DLSYM_PROTOTYPE(context_free) = NULL;
|
||||
DLSYM_PROTOTYPE(context_new) = NULL;
|
||||
@@ -75,7 +103,9 @@ DLSYM_PROTOTYPE(selinux_check_access) = NULL;
|
||||
DLSYM_PROTOTYPE(selinux_getenforcemode) = NULL;
|
||||
DLSYM_PROTOTYPE(selinux_init_load_policy) = NULL;
|
||||
DLSYM_PROTOTYPE(selinux_path) = NULL;
|
||||
DLSYM_PROTOTYPE(selinux_policy_root) = NULL;
|
||||
DLSYM_PROTOTYPE(selinux_set_callback) = NULL;
|
||||
DLSYM_PROTOTYPE(selinux_set_policy_root) = NULL;
|
||||
DLSYM_PROTOTYPE(selinux_status_close) = NULL;
|
||||
DLSYM_PROTOTYPE(selinux_status_getenforce) = NULL;
|
||||
DLSYM_PROTOTYPE(selinux_status_open) = NULL;
|
||||
@@ -121,7 +151,9 @@ int dlopen_libselinux(int log_level) {
|
||||
DLSYM_ARG(selinux_getenforcemode),
|
||||
DLSYM_ARG(selinux_init_load_policy),
|
||||
DLSYM_ARG(selinux_path),
|
||||
DLSYM_ARG(selinux_policy_root),
|
||||
DLSYM_ARG(selinux_set_callback),
|
||||
DLSYM_ARG(selinux_set_policy_root),
|
||||
DLSYM_ARG(selinux_status_close),
|
||||
DLSYM_ARG(selinux_status_getenforce),
|
||||
DLSYM_ARG(selinux_status_open),
|
||||
@@ -220,10 +252,6 @@ static int open_label_db(void) {
|
||||
|
||||
static int selinux_init(bool force) {
|
||||
#if HAVE_SELINUX
|
||||
static const LabelOps label_ops = {
|
||||
.pre = mac_selinux_label_pre,
|
||||
.post = mac_selinux_label_post,
|
||||
};
|
||||
int r;
|
||||
|
||||
if (!mac_selinux_use())
|
||||
@@ -256,7 +284,7 @@ static int selinux_init(bool force) {
|
||||
return r;
|
||||
}
|
||||
|
||||
r = label_ops_set(&label_ops);
|
||||
r = label_ops_set(&selinux_label_ops);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
@@ -372,12 +400,32 @@ static int setfilecon_idempotent(int fd, const char *context) {
|
||||
return RET_NERRNO(sym_setfilecon_raw(FORMAT_PROC_FD_PATH(fd), context));
|
||||
}
|
||||
|
||||
static const char* strip_root_path(const char *path, const char *root) {
|
||||
assert(path);
|
||||
assert(root);
|
||||
|
||||
const char *suffix = path_startswith(path, root);
|
||||
if (!suffix)
|
||||
return NULL;
|
||||
|
||||
if (isempty(suffix))
|
||||
return "/";
|
||||
|
||||
assert(suffix > path);
|
||||
assert(suffix[-1] == '/');
|
||||
|
||||
return suffix - 1; /* back up to include the leading / */
|
||||
}
|
||||
|
||||
static int selinux_fix_fd(
|
||||
int fd,
|
||||
const char *label_path,
|
||||
LabelFixFlags flags) {
|
||||
LabelFixFlags flags,
|
||||
LabelContext *c) {
|
||||
|
||||
_cleanup_freecon_ char* fcon = NULL;
|
||||
struct selabel_handle *hnd;
|
||||
const char *lookup_path;
|
||||
struct stat st;
|
||||
int r;
|
||||
|
||||
@@ -388,16 +436,30 @@ static int selinux_fix_fd(
|
||||
if (fstat(fd, &st) < 0)
|
||||
return -errno;
|
||||
|
||||
/* Check for policy reload so 'label_hnd' is kept up-to-date by callbacks */
|
||||
mac_selinux_maybe_reload();
|
||||
if (!label_hnd)
|
||||
return 0;
|
||||
if (c) {
|
||||
hnd = c->label_hnd;
|
||||
|
||||
if (sym_selabel_lookup_raw(label_hnd, &fcon, label_path, st.st_mode) < 0) {
|
||||
lookup_path = strip_root_path(label_path, c->root);
|
||||
if (!lookup_path)
|
||||
return log_debug_errno(SYNTHETIC_ERRNO(EINVAL),
|
||||
"Path '%s' is not under root '%s', refusing SELinux label fix.", label_path, c->root);
|
||||
} else {
|
||||
/* Check for policy reload so 'label_hnd' is kept up-to-date by callbacks */
|
||||
mac_selinux_maybe_reload();
|
||||
if (!label_hnd)
|
||||
return 0;
|
||||
hnd = label_hnd;
|
||||
lookup_path = label_path;
|
||||
}
|
||||
|
||||
if (sym_selabel_lookup_raw(hnd, &fcon, lookup_path, st.st_mode) < 0) {
|
||||
/* If there's no label to set, then exit without warning */
|
||||
if (errno == ENOENT)
|
||||
return 0;
|
||||
|
||||
if (c)
|
||||
return log_debug_errno(errno, "Unable to look up intended SELinux security context of %s (looked up as %s): %m", label_path, lookup_path);
|
||||
|
||||
return log_selinux_enforcing_errno(errno, "Unable to lookup intended SELinux security context of %s: %m", label_path);
|
||||
}
|
||||
|
||||
@@ -413,6 +475,16 @@ static int selinux_fix_fd(
|
||||
if (r == -EROFS && (flags & LABEL_IGNORE_EROFS))
|
||||
return 0;
|
||||
|
||||
if (c) {
|
||||
/* EINVAL means the host kernel doesn't know this context, degrade gracefully */
|
||||
if (r == -EINVAL) {
|
||||
log_debug_errno(r, "Unable to fix SELinux security context of %s, ignoring: %m", label_path);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return log_debug_errno(r, "Unable to fix SELinux security context of %s: %m", label_path);
|
||||
}
|
||||
|
||||
return log_selinux_enforcing_errno(r, "Unable to fix SELinux security context of %s: %m", label_path);
|
||||
}
|
||||
#endif
|
||||
@@ -421,7 +493,8 @@ int mac_selinux_fix_full(
|
||||
int atfd,
|
||||
const char *inode_path,
|
||||
const char *label_path,
|
||||
LabelFixFlags flags) {
|
||||
LabelFixFlags flags,
|
||||
LabelContext *label_context) {
|
||||
|
||||
assert(atfd >= 0 || atfd == AT_FDCWD);
|
||||
assert(atfd >= 0 || inode_path);
|
||||
@@ -431,12 +504,19 @@ int mac_selinux_fix_full(
|
||||
_cleanup_free_ char *p = NULL;
|
||||
int inode_fd, r;
|
||||
|
||||
r = selinux_init(/* force= */ false);
|
||||
if (r <= 0)
|
||||
return r;
|
||||
LabelContext *c = label_context;
|
||||
|
||||
if (!label_hnd)
|
||||
return 0;
|
||||
if (c) {
|
||||
if (!c->label_hnd)
|
||||
return 0;
|
||||
} else {
|
||||
r = selinux_init(/* force= */ false);
|
||||
if (r <= 0)
|
||||
return r;
|
||||
|
||||
if (!label_hnd)
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (inode_path) {
|
||||
opened_fd = openat(atfd, inode_path, O_NOFOLLOW|O_CLOEXEC|O_PATH);
|
||||
@@ -463,7 +543,7 @@ int mac_selinux_fix_full(
|
||||
}
|
||||
}
|
||||
|
||||
return selinux_fix_fd(inode_fd, label_path, flags);
|
||||
return selinux_fix_fd(inode_fd, label_path, flags, c);
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
@@ -689,12 +769,59 @@ static int selinux_create_file_prepare_abspath(const char *abspath, mode_t mode)
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int selinux_create_file_prepare_context(int dir_fd, const char *path, mode_t mode, LabelContext *c) {
|
||||
_cleanup_free_ char *abspath = NULL;
|
||||
_cleanup_freecon_ char *filecon = NULL;
|
||||
const char *lookup_path;
|
||||
int r;
|
||||
|
||||
assert(c);
|
||||
assert(c->label_hnd);
|
||||
|
||||
/* Resolve the path to absolute if needed */
|
||||
if (isempty(path) || !path_is_absolute(path)) {
|
||||
r = fd_get_path(dir_fd, &abspath);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (!isempty(path) && !path_extend(&abspath, path))
|
||||
return -ENOMEM;
|
||||
|
||||
path = abspath;
|
||||
}
|
||||
|
||||
/* Strip the root prefix so we look up the path as it would appear inside the image */
|
||||
lookup_path = strip_root_path(path, c->root);
|
||||
if (!lookup_path)
|
||||
return log_debug_errno(SYNTHETIC_ERRNO(EINVAL),
|
||||
"Path '%s' is not under root '%s', refusing SELinux labeling.", path, c->root);
|
||||
|
||||
r = RET_NERRNO(sym_selabel_lookup_raw(c->label_hnd, &filecon, lookup_path, mode));
|
||||
if (r == -ENOENT)
|
||||
return 0;
|
||||
if (r < 0)
|
||||
return log_debug_errno(r, "Failed to determine SELinux security context for %s (looked up as %s): %m", path, lookup_path);
|
||||
|
||||
if (sym_setfscreatecon_raw(filecon) < 0) {
|
||||
/* EINVAL means the host kernel doesn't know this context, degrade gracefully */
|
||||
if (errno == EINVAL) {
|
||||
log_debug_errno(errno, "Failed to set SELinux security context %s for %s, ignoring: %m", filecon, path);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return log_debug_errno(errno, "Failed to set SELinux security context %s for %s: %m", filecon, path);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
int mac_selinux_create_file_prepare_at(
|
||||
int dir_fd,
|
||||
const char *path,
|
||||
mode_t mode) {
|
||||
mode_t mode,
|
||||
LabelContext *label_context) {
|
||||
|
||||
#if HAVE_SELINUX
|
||||
_cleanup_free_ char *abspath = NULL;
|
||||
@@ -702,6 +829,9 @@ int mac_selinux_create_file_prepare_at(
|
||||
|
||||
assert(dir_fd >= 0 || dir_fd == AT_FDCWD);
|
||||
|
||||
if (label_context)
|
||||
return selinux_create_file_prepare_context(dir_fd, path, mode, label_context);
|
||||
|
||||
r = selinux_init(/* force= */ false);
|
||||
if (r <= 0)
|
||||
return r;
|
||||
@@ -870,3 +1000,182 @@ skipped:
|
||||
#endif
|
||||
return RET_NERRNO(bind(fd, addr, addrlen));
|
||||
}
|
||||
|
||||
#if HAVE_SELINUX
|
||||
static int get_selinux_policy_root(int rfd, const char *root, char **ret) {
|
||||
_cleanup_free_ char *policytype = NULL;
|
||||
int r;
|
||||
|
||||
assert(rfd >= 0);
|
||||
assert(root);
|
||||
assert(ret);
|
||||
|
||||
/* Read the SELinux config from the alternate root, trying /etc and /usr/lib */
|
||||
FOREACH_STRING(config_dir, "/etc/selinux/config", "/usr/lib/selinux/config") {
|
||||
_cleanup_close_ int fd = -EBADF;
|
||||
|
||||
r = chaseat(rfd, rfd, config_dir, CHASE_MUST_BE_REGULAR, /* ret_path= */ NULL, &fd);
|
||||
if (IN_SET(r, -ENOENT, -ENOTDIR, -EISDIR))
|
||||
continue;
|
||||
if (r < 0)
|
||||
return log_debug_errno(r, "Failed to resolve SELinux config path in root '%s': %m", root);
|
||||
|
||||
r = parse_env_file_fd(fd, config_dir, "SELINUXTYPE", &policytype);
|
||||
if (r == -ENOENT)
|
||||
continue;
|
||||
if (r < 0)
|
||||
return log_debug_errno(r, "Failed to parse SELinux config '%s' in root '%s': %m", config_dir, root);
|
||||
|
||||
if (!isempty(policytype))
|
||||
break;
|
||||
}
|
||||
|
||||
if (isempty(policytype)) {
|
||||
log_debug("No SELINUXTYPE configured in alternate root '%s', skipping label context setup.", root);
|
||||
*ret = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!filename_is_valid(policytype))
|
||||
return log_debug_errno(SYNTHETIC_ERRNO(EINVAL),
|
||||
"SELINUXTYPE '%s' in alternate root '%s' is not a valid filename.", policytype, root);
|
||||
|
||||
/* Look for the policy database under the alternate root */
|
||||
FOREACH_STRING(policy_dir, "/etc/selinux", "/usr/share/selinux") {
|
||||
_cleanup_free_ char *p = NULL, *policy_subdir = NULL;
|
||||
|
||||
policy_subdir = path_join(policy_dir, policytype);
|
||||
if (!policy_subdir)
|
||||
return log_oom();
|
||||
|
||||
r = chaseat(rfd, rfd, policy_subdir, CHASE_MUST_BE_DIRECTORY, &p, /* ret_fd= */ NULL);
|
||||
if (IN_SET(r, -ENOENT, -ENOTDIR))
|
||||
continue;
|
||||
if (r < 0) {
|
||||
log_debug_errno(r, "Failed to resolve policy directory '%s' in root '%s': %m", policy_subdir, root);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Validate that the file_contexts file resolves within the root, since libselinux
|
||||
* will open it with plain fopen() which follows symlinks without confinement */
|
||||
_cleanup_free_ char *fc_subpath = NULL;
|
||||
fc_subpath = path_join(policy_subdir, "contexts/files/file_contexts");
|
||||
if (!fc_subpath)
|
||||
return log_oom();
|
||||
|
||||
r = chaseat(rfd, rfd, fc_subpath, CHASE_MUST_BE_REGULAR, /* ret_path= */ NULL, /* ret_fd= */ NULL);
|
||||
if (IN_SET(r, -ENOENT, -ENOTDIR)) {
|
||||
log_debug_errno(r, "file_contexts not found at '%s' in root '%s', skipping.", fc_subpath, root);
|
||||
continue;
|
||||
}
|
||||
if (r < 0) {
|
||||
log_debug_errno(r, "Failed to resolve file_contexts '%s' in root '%s': %m", fc_subpath, root);
|
||||
continue;
|
||||
}
|
||||
|
||||
r = chaseat_prefix_root(p, root, ret);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
log_debug("SELinux policy directory for type '%s' not found in alternate root '%s', skipping.", policytype, root);
|
||||
*ret = NULL;
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
int mac_selinux_label_context_new(const char *root, LabelContext **ret) {
|
||||
assert(root);
|
||||
assert(!empty_or_root(root));
|
||||
assert(ret);
|
||||
|
||||
#if HAVE_SELINUX
|
||||
_cleanup_free_ char *policyroot = NULL, *canonical_root = NULL;
|
||||
_cleanup_close_ int rfd = -EBADF;
|
||||
int r;
|
||||
|
||||
if (mac_smack_use()) {
|
||||
*ret = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
r = dlopen_libselinux(LOG_ERR);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
mac_selinux_disable_logging();
|
||||
|
||||
r = chaseat(AT_FDCWD, AT_FDCWD, root, CHASE_MUST_BE_DIRECTORY, &canonical_root, &rfd);
|
||||
if (r < 0)
|
||||
return log_debug_errno(r, "Failed to open root directory '%s': %m", root);
|
||||
|
||||
r = get_selinux_policy_root(rfd, root, &policyroot);
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (r == 0) {
|
||||
*ret = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Temporarily switch the policy root so selabel_open() reads the image's file_contexts.
|
||||
* The handle bakes in the database at open time, so we can reset the root immediately after.
|
||||
* We must strdup the saved root because selinux_set_policy_root() frees the internal buffer. */
|
||||
_cleanup_(selinux_policy_root_reset_and_freep) char *saved_policy_root = NULL;
|
||||
const char *p = sym_selinux_policy_root();
|
||||
if (p) {
|
||||
saved_policy_root = strdup(p);
|
||||
if (!saved_policy_root)
|
||||
return log_oom();
|
||||
}
|
||||
|
||||
r = RET_NERRNO(sym_selinux_set_policy_root(policyroot));
|
||||
if (r < 0)
|
||||
return log_debug_errno(r, "Failed to set SELinux policy root to '%s': %m", policyroot);
|
||||
|
||||
_cleanup_(selabel_closep) struct selabel_handle *hnd = sym_selabel_open(SELABEL_CTX_FILE, /* opts= */ NULL, /* nopts= */ 0);
|
||||
int saved_errno = errno;
|
||||
|
||||
/* Reset immediately - the handle baked in the database at open time */
|
||||
selinux_policy_root_reset_and_freep(&saved_policy_root);
|
||||
|
||||
if (!hnd)
|
||||
return log_debug_errno(saved_errno, "Failed to open SELinux label database for alternate root '%s': %m", root);
|
||||
|
||||
r = label_ops_set(&selinux_label_ops);
|
||||
if (r < 0 && r != -EBUSY)
|
||||
return r;
|
||||
|
||||
_cleanup_free_ LabelContext *c = new(LabelContext, 1);
|
||||
if (!c)
|
||||
return log_oom();
|
||||
|
||||
*c = (LabelContext) {
|
||||
.label_hnd = TAKE_PTR(hnd),
|
||||
.rfd = TAKE_FD(rfd),
|
||||
.root = TAKE_PTR(canonical_root),
|
||||
};
|
||||
|
||||
*ret = TAKE_PTR(c);
|
||||
return 0;
|
||||
#else
|
||||
*ret = NULL;
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
LabelContext* mac_selinux_label_context_free(LabelContext *c) {
|
||||
if (!c)
|
||||
return NULL;
|
||||
|
||||
#if HAVE_SELINUX
|
||||
if (c->label_hnd)
|
||||
sym_selabel_close(c->label_hnd);
|
||||
|
||||
safe_close(c->rfd);
|
||||
free(c->root);
|
||||
#endif
|
||||
|
||||
return mfree(c);
|
||||
}
|
||||
|
||||
@@ -41,7 +41,9 @@ extern DLSYM_PROTOTYPE(selinux_check_access);
|
||||
extern DLSYM_PROTOTYPE(selinux_getenforcemode);
|
||||
extern DLSYM_PROTOTYPE(selinux_init_load_policy);
|
||||
extern DLSYM_PROTOTYPE(selinux_path);
|
||||
extern DLSYM_PROTOTYPE(selinux_policy_root);
|
||||
extern DLSYM_PROTOTYPE(selinux_set_callback);
|
||||
extern DLSYM_PROTOTYPE(selinux_set_policy_root);
|
||||
extern DLSYM_PROTOTYPE(selinux_status_close);
|
||||
extern DLSYM_PROTOTYPE(selinux_status_getenforce);
|
||||
extern DLSYM_PROTOTYPE(selinux_status_open);
|
||||
@@ -93,7 +95,7 @@ void mac_selinux_finish(void);
|
||||
|
||||
void mac_selinux_disable_logging(void);
|
||||
|
||||
int mac_selinux_fix_full(int atfd, const char *inode_path, const char *label_path, LabelFixFlags flags);
|
||||
int mac_selinux_fix_full(int atfd, const char *inode_path, const char *label_path, LabelFixFlags flags, LabelContext *label_context);
|
||||
|
||||
int mac_selinux_apply(const char *path, const char *label);
|
||||
int mac_selinux_apply_fd(int fd, const char *path, const char *label);
|
||||
@@ -103,9 +105,9 @@ int mac_selinux_get_our_label(char **ret_label);
|
||||
int mac_selinux_get_peer_label(int socket_fd, char **ret_label);
|
||||
int mac_selinux_get_child_mls_label(int socket_fd, const char *exe, const char *exec_label, char **ret_label);
|
||||
|
||||
int mac_selinux_create_file_prepare_at(int dir_fd, const char *path, mode_t mode);
|
||||
static inline int mac_selinux_create_file_prepare(const char *path, mode_t mode) {
|
||||
return mac_selinux_create_file_prepare_at(AT_FDCWD, path, mode);
|
||||
int mac_selinux_create_file_prepare_at(int dir_fd, const char *path, mode_t mode, LabelContext *label_context);
|
||||
static inline int mac_selinux_create_file_prepare(const char *path, mode_t mode, LabelContext *label_context) {
|
||||
return mac_selinux_create_file_prepare_at(AT_FDCWD, path, mode, label_context);
|
||||
}
|
||||
int mac_selinux_create_file_prepare_label(const char *path, const char *label);
|
||||
void mac_selinux_create_file_clear(void);
|
||||
@@ -114,3 +116,6 @@ int mac_selinux_create_socket_prepare(const char *label);
|
||||
void mac_selinux_create_socket_clear(void);
|
||||
|
||||
int mac_selinux_bind(int fd, const struct sockaddr *addr, socklen_t addrlen);
|
||||
|
||||
int mac_selinux_label_context_new(const char *root, LabelContext **ret);
|
||||
LabelContext* mac_selinux_label_context_free(LabelContext *c);
|
||||
|
||||
@@ -221,11 +221,11 @@ int renameat_and_apply_smack_floor_label(int fdf, const char *from, int fdt, con
|
||||
#endif
|
||||
}
|
||||
|
||||
static int mac_smack_label_pre(int dir_fd, const char *path, mode_t mode) {
|
||||
static int mac_smack_label_pre(int dir_fd, const char *path, mode_t mode, LabelContext *label_context) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mac_smack_label_post(int dir_fd, const char *path, bool created) {
|
||||
static int mac_smack_label_post(int dir_fd, const char *path, bool created, LabelContext *label_context) {
|
||||
if (!created)
|
||||
return 0;
|
||||
|
||||
|
||||
@@ -10,14 +10,15 @@ int fopen_temporary_at_label(
|
||||
const char *target,
|
||||
const char *path,
|
||||
FILE **f,
|
||||
char **temp_path) {
|
||||
char **temp_path,
|
||||
LabelContext *label_context) {
|
||||
|
||||
int r;
|
||||
|
||||
assert(dir_fd >= 0 || dir_fd == AT_FDCWD);
|
||||
assert(path);
|
||||
|
||||
r = mac_selinux_create_file_prepare_at(dir_fd, target, S_IFREG);
|
||||
r = mac_selinux_create_file_prepare_at(dir_fd, target, S_IFREG, label_context);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
* Targets that link libshared automatically pick up this version via -Isrc/shared; targets that only have
|
||||
* src/basic on their include path fall through to the basic header. */
|
||||
|
||||
int fopen_temporary_at_label(int dir_fd, const char *target, const char *path, FILE **f, char **temp_path);
|
||||
int fopen_temporary_at_label(int dir_fd, const char *target, const char *path, FILE **f, char **temp_path, LabelContext *label_context);
|
||||
static inline int fopen_temporary_label(const char *target, const char *path, FILE **f, char **temp_path) {
|
||||
return fopen_temporary_at_label(AT_FDCWD, target, path, f, temp_path);
|
||||
return fopen_temporary_at_label(AT_FDCWD, target, path, f, temp_path, /* label_context= */ NULL);
|
||||
}
|
||||
|
||||
+4
-4
@@ -998,7 +998,7 @@ static int resolve_mutable_directory(
|
||||
if (fchmod(chmod_fd, hierarchy_mode) < 0)
|
||||
return log_error_errno(errno, "Failed to chmod directory '%s/%s': %m", strempty(root), skip_leading_slash(path));
|
||||
|
||||
r = mac_selinux_fix_full(chmod_fd, /* inode_path= */ NULL, hierarchy, /* flags= */ 0);
|
||||
r = mac_selinux_fix_full(chmod_fd, /* inode_path= */ NULL, hierarchy, /* flags= */ 0, /* label_context= */ NULL);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to fix SELinux label for '%s/%s': %m", strempty(root), skip_leading_slash(path));
|
||||
}
|
||||
@@ -1376,7 +1376,7 @@ static int mount_overlayfs_with_op(
|
||||
if (atfd < 0)
|
||||
return log_error_errno(errno, "Failed to open directory '%s': %m", meta_path);
|
||||
|
||||
r = mac_selinux_fix_full(atfd, /* inode_path= */ NULL, op->hierarchy, /* flags= */ 0);
|
||||
r = mac_selinux_fix_full(atfd, /* inode_path= */ NULL, op->hierarchy, /* flags= */ 0, /* label_context= */ NULL);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to fix SELinux label for '%s': %m", meta_path);
|
||||
|
||||
@@ -1389,7 +1389,7 @@ static int mount_overlayfs_with_op(
|
||||
if (dfd < 0)
|
||||
return log_error_errno(errno, "Failed to open directory '%s': %m", op->work_dir);
|
||||
|
||||
r = mac_selinux_fix_full(dfd, /* inode_path= */ NULL, op->hierarchy, /* flags= */ 0);
|
||||
r = mac_selinux_fix_full(dfd, /* inode_path= */ NULL, op->hierarchy, /* flags= */ 0, /* label_context= */ NULL);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to fix SELinux label for '%s': %m", op->work_dir);
|
||||
|
||||
@@ -1601,7 +1601,7 @@ static int store_info_in_meta(
|
||||
if (atfd < 0)
|
||||
return log_error_errno(errno, "Failed to open directory '%s': %m", f);
|
||||
|
||||
r = mac_selinux_fix_full(atfd, /* inode_path= */ NULL, hierarchy, /* flags= */ 0);
|
||||
r = mac_selinux_fix_full(atfd, /* inode_path= */ NULL, hierarchy, /* flags= */ 0, /* label_context= */ NULL);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to fix SELinux label for '%s': %m", hierarchy);
|
||||
|
||||
|
||||
+20
-11
@@ -132,6 +132,8 @@ typedef struct Context {
|
||||
|
||||
UGIDAllocationRange login_defs;
|
||||
bool login_defs_need_warning;
|
||||
|
||||
LabelContext *label_context;
|
||||
} Context;
|
||||
|
||||
static void context_done(Context *c) {
|
||||
@@ -152,6 +154,7 @@ static void context_done(Context *c) {
|
||||
|
||||
set_free(c->names);
|
||||
uid_range_free(c->uid_range);
|
||||
mac_label_context_free(c->label_context);
|
||||
}
|
||||
|
||||
static void maybe_emit_login_defs_warning(Context *c) {
|
||||
@@ -303,7 +306,7 @@ static int load_group_database(Context *c) {
|
||||
return r;
|
||||
}
|
||||
|
||||
static int make_backup(const char *target, const char *x) {
|
||||
static int make_backup(const char *target, const char *x, LabelContext *label_context) {
|
||||
_cleanup_(unlink_and_freep) char *dst_tmp = NULL;
|
||||
_cleanup_fclose_ FILE *dst = NULL;
|
||||
_cleanup_close_ int src = -EBADF;
|
||||
@@ -325,11 +328,13 @@ static int make_backup(const char *target, const char *x) {
|
||||
if (fstat(src, &st) < 0)
|
||||
return -errno;
|
||||
|
||||
r = fopen_temporary_label(
|
||||
r = fopen_temporary_at_label(
|
||||
AT_FDCWD,
|
||||
target, /* The path for which to the look up the label */
|
||||
x, /* Where we want the file actually to end up */
|
||||
&dst, /* The temporary file we write to */
|
||||
&dst_tmp);
|
||||
&dst_tmp,
|
||||
label_context);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
@@ -527,7 +532,7 @@ static int write_temporary_passwd(
|
||||
goto done;
|
||||
}
|
||||
|
||||
r = fopen_temporary_label("/etc/passwd", passwd_path, &passwd, &passwd_tmp);
|
||||
r = fopen_temporary_at_label(AT_FDCWD, passwd_path, passwd_path, &passwd, &passwd_tmp, c->label_context);
|
||||
if (r < 0)
|
||||
return log_debug_errno(r, "Failed to open temporary copy of %s: %m", passwd_path);
|
||||
|
||||
@@ -655,7 +660,7 @@ static int write_temporary_shadow(
|
||||
goto done;
|
||||
}
|
||||
|
||||
r = fopen_temporary_label("/etc/shadow", shadow_path, &shadow, &shadow_tmp);
|
||||
r = fopen_temporary_at_label(AT_FDCWD, shadow_path, shadow_path, &shadow, &shadow_tmp, c->label_context);
|
||||
if (r < 0)
|
||||
return log_debug_errno(r, "Failed to open temporary copy of %s: %m", shadow_path);
|
||||
|
||||
@@ -792,7 +797,7 @@ static int write_temporary_group(
|
||||
goto done;
|
||||
}
|
||||
|
||||
r = fopen_temporary_label("/etc/group", group_path, &group, &group_tmp);
|
||||
r = fopen_temporary_at_label(AT_FDCWD, group_path, group_path, &group, &group_tmp, c->label_context);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to open temporary copy of %s: %m", group_path);
|
||||
|
||||
@@ -911,7 +916,7 @@ static int write_temporary_gshadow(
|
||||
goto done;
|
||||
}
|
||||
|
||||
r = fopen_temporary_label("/etc/gshadow", gshadow_path, &gshadow, &gshadow_tmp);
|
||||
r = fopen_temporary_at_label(AT_FDCWD, gshadow_path, gshadow_path, &gshadow, &gshadow_tmp, c->label_context);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to open temporary copy of %s: %m", gshadow_path);
|
||||
|
||||
@@ -1021,23 +1026,23 @@ static int write_files(Context *c) {
|
||||
|
||||
/* Make a backup of the old files */
|
||||
if (group) {
|
||||
r = make_backup("/etc/group", group_path);
|
||||
r = make_backup(group_path, group_path, c->label_context);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to backup %s: %m", group_path);
|
||||
}
|
||||
if (gshadow) {
|
||||
r = make_backup("/etc/gshadow", gshadow_path);
|
||||
r = make_backup(gshadow_path, gshadow_path, c->label_context);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to backup %s: %m", gshadow_path);
|
||||
}
|
||||
|
||||
if (passwd) {
|
||||
r = make_backup("/etc/passwd", passwd_path);
|
||||
r = make_backup(passwd_path, passwd_path, c->label_context);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to backup %s: %m", passwd_path);
|
||||
}
|
||||
if (shadow) {
|
||||
r = make_backup("/etc/shadow", shadow_path);
|
||||
r = make_backup(shadow_path, shadow_path, c->label_context);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to backup %s: %m", shadow_path);
|
||||
}
|
||||
@@ -2351,6 +2356,10 @@ static int run(int argc, char *argv[]) {
|
||||
return log_oom();
|
||||
}
|
||||
|
||||
r = mac_label_context_new(arg_root, &c.label_context);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to initialize label context for root '%s': %m", arg_root);
|
||||
|
||||
/* Prepare to emit audit events, but only if we're operating on the host system. */
|
||||
if (!arg_root)
|
||||
c.audit_fd = open_audit_fd_or_warn();
|
||||
|
||||
+13
-13
@@ -30,7 +30,7 @@ static int check_path(int dir_fd, const char *path) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int pre_labelling_func(int dir_fd, const char *path, mode_t mode) {
|
||||
static int pre_labelling_func(int dir_fd, const char *path, mode_t mode, LabelContext *label_context) {
|
||||
int r;
|
||||
|
||||
assert(mode != MODE_INVALID);
|
||||
@@ -41,7 +41,7 @@ static int pre_labelling_func(int dir_fd, const char *path, mode_t mode) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int post_labelling_func(int dir_fd, const char *path, bool created) {
|
||||
static int post_labelling_func(int dir_fd, const char *path, bool created, LabelContext *label_context) {
|
||||
int r;
|
||||
|
||||
/* assume label policies that restrict certain labels */
|
||||
@@ -115,11 +115,11 @@ TEST(label_ops_pre) {
|
||||
label_ops_reset();
|
||||
label_ops_set(&test_label_ops);
|
||||
fd = get_dir_fd("file1.txt", 0755);
|
||||
assert_se(label_ops_pre(fd, "file1.txt", 0644) == 0);
|
||||
assert_se(label_ops_pre(fd, "/restricted_directory", 0644) == -EACCES);
|
||||
assert_se(label_ops_pre(fd, "", 0700) == -EINVAL);
|
||||
assert_se(label_ops_pre(fd, "/tmp", 0700) == 0);
|
||||
assert_se(label_ops_pre(fd, "wekrgoierhgoierhqgherhgwklegnlweehgorwfkryrit", 0644) == -ENAMETOOLONG);
|
||||
assert_se(label_ops_pre(fd, "file1.txt", 0644, /* label_context= */ NULL) == 0);
|
||||
assert_se(label_ops_pre(fd, "/restricted_directory", 0644, /* label_context= */ NULL) == -EACCES);
|
||||
assert_se(label_ops_pre(fd, "", 0700, /* label_context= */ NULL) == -EINVAL);
|
||||
assert_se(label_ops_pre(fd, "/tmp", 0700, /* label_context= */ NULL) == 0);
|
||||
assert_se(label_ops_pre(fd, "wekrgoierhgoierhqgherhgwklegnlweehgorwfkryrit", 0644, /* label_context= */ NULL) == -ENAMETOOLONG);
|
||||
}
|
||||
|
||||
TEST(label_ops_post) {
|
||||
@@ -138,17 +138,17 @@ TEST(label_ops_post) {
|
||||
text1 = "Add initial texts to file for testing label operations to file1\n";
|
||||
|
||||
assert_se(labelling_op(fd, text1, "file1.txt", 0644) == 0);
|
||||
assert_se(label_ops_post(fd, "file1.txt", true) == 0);
|
||||
assert_se(label_ops_post(fd, "file1.txt", true, /* label_context= */ NULL) == 0);
|
||||
assert_se(strlen(text1) == (size_t)buf.st_size);
|
||||
text2 = "Add text2 data to file2\n";
|
||||
|
||||
assert_se(labelling_op(fd, text2, "file2.txt", 0644) == 0);
|
||||
assert_se(label_ops_post(fd, "file2.txt", true) == 0);
|
||||
assert_se(label_ops_post(fd, "file2.txt", true, /* label_context= */ NULL) == 0);
|
||||
assert_se(strlen(text2) == (size_t)buf.st_size);
|
||||
assert_se(label_ops_post(fd, "file3.txt", true) == -ENOENT);
|
||||
assert_se(label_ops_post(fd, "/abcd", true) == -ENOENT);
|
||||
assert_se(label_ops_post(fd, "/restricted_directory", true) == -EACCES);
|
||||
assert_se(label_ops_post(fd, "", true) == -EINVAL);
|
||||
assert_se(label_ops_post(fd, "file3.txt", true, /* label_context= */ NULL) == -ENOENT);
|
||||
assert_se(label_ops_post(fd, "/abcd", true, /* label_context= */ NULL) == -ENOENT);
|
||||
assert_se(label_ops_post(fd, "/restricted_directory", true, /* label_context= */ NULL) == -EACCES);
|
||||
assert_se(label_ops_post(fd, "", true, /* label_context= */ NULL) == -EINVAL);
|
||||
}
|
||||
|
||||
DEFINE_TEST_MAIN(LOG_INFO)
|
||||
|
||||
@@ -84,7 +84,7 @@ static void test_create_file_prepare(const char* fname) {
|
||||
|
||||
log_info("============ %s ==========", __func__);
|
||||
|
||||
r = mac_selinux_create_file_prepare(fname, S_IRWXU);
|
||||
r = mac_selinux_create_file_prepare(fname, S_IRWXU, /* label_context= */ NULL);
|
||||
log_info_errno(r, "mac_selinux_create_file_prepare → %d (%m)", r);
|
||||
|
||||
mac_selinux_create_file_clear();
|
||||
|
||||
+21
-15
@@ -232,6 +232,7 @@ static char *arg_root = NULL;
|
||||
static char *arg_image = NULL;
|
||||
static const char *arg_replace = NULL;
|
||||
static ImagePolicy *arg_image_policy = NULL;
|
||||
static LabelContext *arg_label_context = NULL;
|
||||
|
||||
#define MAX_DEPTH 256
|
||||
|
||||
@@ -248,6 +249,7 @@ STATIC_DESTRUCTOR_REGISTER(arg_exclude_prefixes, strv_freep);
|
||||
STATIC_DESTRUCTOR_REGISTER(arg_root, freep);
|
||||
STATIC_DESTRUCTOR_REGISTER(arg_image, freep);
|
||||
STATIC_DESTRUCTOR_REGISTER(arg_image_policy, image_policy_freep);
|
||||
STATIC_DESTRUCTOR_REGISTER(arg_label_context, mac_label_context_freep);
|
||||
|
||||
static const char *const creation_mode_verb_table[_CREATION_MODE_MAX] = {
|
||||
[CREATION_NORMAL] = "Created",
|
||||
@@ -1062,7 +1064,7 @@ shortcut:
|
||||
}
|
||||
|
||||
log_debug("Relabelling \"%s\"", path);
|
||||
return label_fix_full(fd, /* inode_path= */ NULL, /* label_path= */ path, 0);
|
||||
return label_fix_full(fd, /* inode_path= */ NULL, /* label_path= */ path, /* flags= */ 0, arg_label_context);
|
||||
}
|
||||
|
||||
static int path_open_parent_safe(const char *path, bool allow_failure) {
|
||||
@@ -2070,7 +2072,7 @@ static int create_file(
|
||||
return dir_fd;
|
||||
|
||||
WITH_UMASK(0000) {
|
||||
mac_selinux_create_file_prepare(path, S_IFREG);
|
||||
mac_selinux_create_file_prepare(path, S_IFREG, arg_label_context);
|
||||
fd = RET_NERRNO(openat(dir_fd, bn, O_CREAT|O_EXCL|O_NOFOLLOW|O_NONBLOCK|O_CLOEXEC|O_WRONLY|O_NOCTTY, i->mode));
|
||||
mac_selinux_create_file_clear();
|
||||
}
|
||||
@@ -2153,7 +2155,7 @@ static int truncate_file(
|
||||
creation = CREATION_NORMAL; /* Didn't work without O_CREATE, try again with */
|
||||
|
||||
WITH_UMASK(0000) {
|
||||
mac_selinux_create_file_prepare(path, S_IFREG);
|
||||
mac_selinux_create_file_prepare(path, S_IFREG, arg_label_context);
|
||||
fd = RET_NERRNO(openat(dir_fd, bn, O_CREAT|O_NOFOLLOW|O_NONBLOCK|O_CLOEXEC|O_WRONLY|O_NOCTTY, i->mode));
|
||||
mac_selinux_create_file_clear();
|
||||
}
|
||||
@@ -2314,7 +2316,7 @@ static int create_directory_or_subvolume(
|
||||
log_action("Would create", "Creating", "%s directory \"%s\"", path);
|
||||
if (!arg_dry_run)
|
||||
WITH_UMASK(0000)
|
||||
r = mkdirat_label(pfd, bn, mode);
|
||||
r = mkdirat_label(pfd, bn, mode, arg_label_context);
|
||||
}
|
||||
|
||||
if (arg_dry_run)
|
||||
@@ -2501,7 +2503,7 @@ static int create_device(
|
||||
return dfd;
|
||||
|
||||
WITH_UMASK(0000) {
|
||||
mac_selinux_create_file_prepare(i->path, file_type);
|
||||
mac_selinux_create_file_prepare(i->path, file_type, arg_label_context);
|
||||
r = RET_NERRNO(mknodat(dfd, bn, i->mode | file_type, i->major_minor));
|
||||
mac_selinux_create_file_clear();
|
||||
}
|
||||
@@ -2532,7 +2534,7 @@ static int create_device(
|
||||
fd = safe_close(fd);
|
||||
|
||||
WITH_UMASK(0000) {
|
||||
mac_selinux_create_file_prepare(i->path, file_type);
|
||||
mac_selinux_create_file_prepare(i->path, file_type, arg_label_context);
|
||||
r = mknodat_atomic(dfd, bn, i->mode | file_type, i->major_minor);
|
||||
mac_selinux_create_file_clear();
|
||||
}
|
||||
@@ -2543,7 +2545,7 @@ static int create_device(
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "rm -rf %s failed: %m", i->path);
|
||||
|
||||
mac_selinux_create_file_prepare(i->path, file_type);
|
||||
mac_selinux_create_file_prepare(i->path, file_type, arg_label_context);
|
||||
r = RET_NERRNO(mknodat(dfd, bn, i->mode | file_type, i->major_minor));
|
||||
mac_selinux_create_file_clear();
|
||||
}
|
||||
@@ -2611,7 +2613,7 @@ static int create_fifo(Context *c, Item *i) {
|
||||
return pfd;
|
||||
|
||||
WITH_UMASK(0000) {
|
||||
mac_selinux_create_file_prepare(i->path, S_IFIFO);
|
||||
mac_selinux_create_file_prepare(i->path, S_IFIFO, arg_label_context);
|
||||
r = RET_NERRNO(mkfifoat(pfd, bn, i->mode));
|
||||
mac_selinux_create_file_clear();
|
||||
}
|
||||
@@ -2636,7 +2638,7 @@ static int create_fifo(Context *c, Item *i) {
|
||||
fd = safe_close(fd);
|
||||
|
||||
WITH_UMASK(0000) {
|
||||
mac_selinux_create_file_prepare(i->path, S_IFIFO);
|
||||
mac_selinux_create_file_prepare(i->path, S_IFIFO, arg_label_context);
|
||||
r = mkfifoat_atomic(pfd, bn, i->mode);
|
||||
mac_selinux_create_file_clear();
|
||||
}
|
||||
@@ -2645,7 +2647,7 @@ static int create_fifo(Context *c, Item *i) {
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "rm -rf %s failed: %m", i->path);
|
||||
|
||||
mac_selinux_create_file_prepare(i->path, S_IFIFO);
|
||||
mac_selinux_create_file_prepare(i->path, S_IFIFO, arg_label_context);
|
||||
r = RET_NERRNO(mkfifoat(pfd, bn, i->mode));
|
||||
mac_selinux_create_file_clear();
|
||||
}
|
||||
@@ -2730,7 +2732,7 @@ static int create_symlink(Context *c, Item *i) {
|
||||
if (pfd < 0)
|
||||
return pfd;
|
||||
|
||||
mac_selinux_create_file_prepare(i->path, S_IFLNK);
|
||||
mac_selinux_create_file_prepare(i->path, S_IFLNK, arg_label_context);
|
||||
r = RET_NERRNO(symlinkat(i->argument, pfd, bn));
|
||||
mac_selinux_create_file_clear();
|
||||
|
||||
@@ -2766,13 +2768,13 @@ static int create_symlink(Context *c, Item *i) {
|
||||
|
||||
fd = safe_close(fd);
|
||||
|
||||
r = symlinkat_atomic_full(i->argument, pfd, bn, SYMLINK_LABEL);
|
||||
r = symlinkat_atomic_full_label(i->argument, pfd, bn, SYMLINK_LABEL, arg_label_context);
|
||||
if (IN_SET(r, -EISDIR, -EEXIST, -ENOTEMPTY)) {
|
||||
r = rm_rf_child(pfd, bn, REMOVE_PHYSICAL);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "rm -rf %s failed: %m", i->path);
|
||||
|
||||
r = symlinkat_atomic_full(i->argument, pfd, bn, SYMLINK_LABEL);
|
||||
r = symlinkat_atomic_full_label(i->argument, pfd, bn, SYMLINK_LABEL, arg_label_context);
|
||||
}
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "symlink(%s, %s) failed: %m", i->argument, i->path);
|
||||
@@ -3060,7 +3062,7 @@ static int mkdir_parents_rm_if_wrong_type(mode_t child_mode, const char *path) {
|
||||
if (r == -ENOENT) {
|
||||
if (!arg_dry_run) {
|
||||
WITH_UMASK(0000)
|
||||
r = mkdirat_label(parent_fd, t, 0755);
|
||||
r = mkdirat_label(parent_fd, t, 0755, arg_label_context);
|
||||
if (r < 0) {
|
||||
_cleanup_free_ char *parent_name = NULL;
|
||||
|
||||
@@ -3101,7 +3103,7 @@ static int mkdir_parents_item(Item *i, mode_t child_mode) {
|
||||
} else
|
||||
WITH_UMASK(0000)
|
||||
if (!arg_dry_run)
|
||||
(void) mkdir_parents_label(i->path, 0755);
|
||||
(void) mkdirat_parents_label(AT_FDCWD, i->path, 0755, arg_label_context);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -5406,6 +5408,10 @@ static int run(int argc, char *argv[]) {
|
||||
return log_oom();
|
||||
}
|
||||
|
||||
r = mac_label_context_new(arg_root, &arg_label_context);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to initialize label context for root '%s': %m", arg_root);
|
||||
|
||||
c.items = ordered_hashmap_new(&item_array_hash_ops);
|
||||
c.globs = ordered_hashmap_new(&item_array_hash_ops);
|
||||
if (!c.items || !c.globs)
|
||||
|
||||
@@ -683,7 +683,7 @@ static int udev_node_apply_permissions_impl(
|
||||
|
||||
/* set the defaults */
|
||||
if (!selinux)
|
||||
(void) mac_selinux_fix_full(node_fd, NULL, devnode, LABEL_IGNORE_ENOENT);
|
||||
(void) mac_selinux_fix_full(node_fd, NULL, devnode, LABEL_IGNORE_ENOENT, /* label_context= */ NULL);
|
||||
if (!smack)
|
||||
(void) mac_smack_apply_fd(node_fd, SMACK_ATTR_ACCESS, NULL);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user