mirror of
https://github.com/systemd/systemd.git
synced 2025-02-08 09:57:41 +03:00
mac: rework labelling code to be simpler, and less racy
This merges the various labelling calls into a single label_fix_full(), which can operate on paths, on inode fds, and in a dirfd/fname style (i.e. like openat()). It also systematically separates the path to look up in the db from the path we actually use to reference the inode to relabel. This then ports tmpfiles over to labelling by fd. This should make the code a bit less racy, as we'll try hard to always operate on the very same inode, pinning it via an fd. User-visibly the behaviour should not change.
This commit is contained in:
parent
05c4affe04
commit
03bc11d1c4
@ -3081,7 +3081,7 @@ static int setup_credentials_internal(
|
||||
assert(!must_mount || workspace_mounted > 0);
|
||||
where = workspace_mounted ? workspace : final;
|
||||
|
||||
(void) label_fix_container(where, final, 0);
|
||||
(void) label_fix_full(AT_FDCWD, where, final, 0);
|
||||
|
||||
r = acquire_credentials(context, params, unit, where, uid, workspace_mounted);
|
||||
if (r < 0)
|
||||
|
@ -928,7 +928,7 @@ static int mount_private_dev(MountEntry *m) {
|
||||
if (r < 0)
|
||||
goto fail;
|
||||
|
||||
r = label_fix_container(dev, "/dev", 0);
|
||||
r = label_fix_full(AT_FDCWD, dev, "/dev", 0);
|
||||
if (r < 0) {
|
||||
log_debug_errno(r, "Failed to fix label of '%s' as /dev: %m", dev);
|
||||
goto fail;
|
||||
@ -1158,7 +1158,7 @@ static int mount_tmpfs(const MountEntry *m) {
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = label_fix_container(entry_path, inner_path, 0);
|
||||
r = label_fix_full(AT_FDCWD, entry_path, inner_path, 0);
|
||||
if (r < 0)
|
||||
return log_debug_errno(r, "Failed to fix label of '%s' as '%s': %m", entry_path, inner_path);
|
||||
|
||||
@ -2758,7 +2758,7 @@ static int setup_one_tmp_dir(const char *id, const char *prefix, char **path, ch
|
||||
if (mkdir(y, 0777 | S_ISVTX) < 0)
|
||||
return -errno;
|
||||
|
||||
r = label_fix_container(y, prefix, 0);
|
||||
r = label_fix_full(AT_FDCWD, y, prefix, 0);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
|
@ -11,12 +11,29 @@
|
||||
#include "selinux-util.h"
|
||||
#include "smack-util.h"
|
||||
|
||||
int label_fix_container(const char *path, const char *inside_path, LabelFixFlags flags) {
|
||||
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) {
|
||||
|
||||
int r, q;
|
||||
|
||||
r = mac_selinux_fix_container(path, inside_path, flags);
|
||||
q = mac_smack_fix_container(path, inside_path, flags);
|
||||
if (atfd < 0 && atfd != AT_FDCWD)
|
||||
return -EBADF;
|
||||
|
||||
if (!inode_path && atfd < 0) /* We need at least one of atfd and an inode path */
|
||||
return -EINVAL;
|
||||
|
||||
/* If both atfd and inode_path are specified, we take the specified path relative to atfd which must be an fd to a dir.
|
||||
*
|
||||
* If only atfd is specified (and inode_path is NULL), we'll operated on the inode the atfd refers to.
|
||||
*
|
||||
* 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);
|
||||
q = mac_smack_fix_full(atfd, inode_path, label_path, flags);
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (q < 0)
|
||||
|
@ -10,9 +10,10 @@ typedef enum LabelFixFlags {
|
||||
LABEL_IGNORE_EROFS = 1 << 1,
|
||||
} LabelFixFlags;
|
||||
|
||||
int label_fix_container(const char *path, const char *inside_path, LabelFixFlags flags);
|
||||
int label_fix_full(int atfd, const char *inode_path, const char *label_path, LabelFixFlags flags);
|
||||
|
||||
static inline int label_fix(const char *path, LabelFixFlags flags) {
|
||||
return label_fix_container(path, path, flags);
|
||||
return label_fix_full(AT_FDCWD, path, path, flags);
|
||||
}
|
||||
|
||||
int symlink_label(const char *old_path, const char *new_path);
|
||||
|
@ -22,7 +22,7 @@ int mkdirat_label(int dirfd, const char *path, mode_t mode) {
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
return mac_smack_fix_at(dirfd, path, 0);
|
||||
return mac_smack_fix_full(dirfd, path, NULL, 0);
|
||||
}
|
||||
|
||||
int mkdir_safe_label(const char *path, mode_t mode, uid_t uid, gid_t gid, MkdirFlags flags) {
|
||||
|
@ -233,46 +233,19 @@ static int mac_selinux_reload(int seqno) {
|
||||
}
|
||||
#endif
|
||||
|
||||
int mac_selinux_fix_container(const char *path, const char *inside_path, LabelFixFlags flags) {
|
||||
|
||||
assert(path);
|
||||
assert(inside_path);
|
||||
|
||||
#if HAVE_SELINUX
|
||||
_cleanup_close_ int fd = -1;
|
||||
static int selinux_fix_fd(
|
||||
int fd,
|
||||
const char *label_path,
|
||||
LabelFixFlags flags) {
|
||||
|
||||
/* if mac_selinux_init() wasn't called before we are a NOOP */
|
||||
if (!label_hnd)
|
||||
return 0;
|
||||
|
||||
/* Open the file as O_PATH, to pin it while we determine and adjust the label */
|
||||
fd = open(path, O_NOFOLLOW|O_CLOEXEC|O_PATH);
|
||||
if (fd < 0) {
|
||||
if ((flags & LABEL_IGNORE_ENOENT) && errno == ENOENT)
|
||||
return 0;
|
||||
|
||||
return -errno;
|
||||
}
|
||||
|
||||
return mac_selinux_fix_container_fd(fd, path, inside_path, flags);
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int mac_selinux_fix_container_fd(int fd, const char *path, const char *inside_path, LabelFixFlags flags) {
|
||||
|
||||
assert(fd >= 0);
|
||||
assert(inside_path);
|
||||
|
||||
#if HAVE_SELINUX
|
||||
_cleanup_freecon_ char* fcon = NULL;
|
||||
struct stat st;
|
||||
int r;
|
||||
|
||||
/* if mac_selinux_init() wasn't called before we are a NOOP */
|
||||
if (!label_hnd)
|
||||
return 0;
|
||||
assert(fd >= 0);
|
||||
assert(label_path);
|
||||
assert(path_is_absolute(label_path));
|
||||
|
||||
if (fstat(fd, &st) < 0)
|
||||
return -errno;
|
||||
@ -282,42 +255,85 @@ int mac_selinux_fix_container_fd(int fd, const char *path, const char *inside_pa
|
||||
if (!label_hnd)
|
||||
return 0;
|
||||
|
||||
if (selabel_lookup_raw(label_hnd, &fcon, inside_path, st.st_mode) < 0) {
|
||||
if (selabel_lookup_raw(label_hnd, &fcon, label_path, st.st_mode) < 0) {
|
||||
/* If there's no label to set, then exit without warning */
|
||||
if (errno == ENOENT)
|
||||
return 0;
|
||||
|
||||
r = -errno;
|
||||
goto fail;
|
||||
return log_enforcing_errno(errno, "Unable to lookup intended SELinux security context of %s: %m", label_path);
|
||||
}
|
||||
|
||||
if (setfilecon_raw(FORMAT_PROC_FD_PATH(fd), fcon) < 0) {
|
||||
_cleanup_freecon_ char *oldcon = NULL;
|
||||
|
||||
r = -errno;
|
||||
|
||||
/* If the FS doesn't support labels, then exit without warning */
|
||||
if (ERRNO_IS_NOT_SUPPORTED(errno))
|
||||
if (ERRNO_IS_NOT_SUPPORTED(r))
|
||||
return 0;
|
||||
|
||||
/* It the FS is read-only and we were told to ignore failures caused by that, suppress error */
|
||||
if (errno == EROFS && (flags & LABEL_IGNORE_EROFS))
|
||||
if (r == -EROFS && (flags & LABEL_IGNORE_EROFS))
|
||||
return 0;
|
||||
|
||||
r = -errno;
|
||||
|
||||
/* If the old label is identical to the new one, suppress any kind of error */
|
||||
if (getfilecon_raw(FORMAT_PROC_FD_PATH(fd), &oldcon) >= 0 && streq(fcon, oldcon))
|
||||
return 0;
|
||||
|
||||
goto fail;
|
||||
return log_enforcing_errno(r, "Unable to fix SELinux security context of %s: %m", label_path);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
return log_enforcing_errno(r, "Unable to fix SELinux security context of %s (%s): %m", strna(path), strna(inside_path));
|
||||
}
|
||||
#endif
|
||||
|
||||
int mac_selinux_fix_full(
|
||||
int atfd,
|
||||
const char *inode_path,
|
||||
const char *label_path,
|
||||
LabelFixFlags flags) {
|
||||
|
||||
assert(atfd >= 0 || atfd == AT_FDCWD);
|
||||
assert(atfd >= 0 || inode_path);
|
||||
|
||||
#if HAVE_SELINUX
|
||||
_cleanup_close_ int opened_fd = -1;
|
||||
_cleanup_free_ char *p = NULL;
|
||||
int inode_fd, r;
|
||||
|
||||
/* if mac_selinux_init() wasn't called before we are a NOOP */
|
||||
if (!label_hnd)
|
||||
return 0;
|
||||
|
||||
if (inode_path) {
|
||||
opened_fd = openat(atfd, inode_path, O_NOFOLLOW|O_CLOEXEC|O_PATH);
|
||||
if (opened_fd < 0) {
|
||||
if ((flags & LABEL_IGNORE_ENOENT) && errno == ENOENT)
|
||||
return 0;
|
||||
|
||||
return -errno;
|
||||
}
|
||||
|
||||
inode_fd = opened_fd;
|
||||
} else
|
||||
inode_fd = atfd;
|
||||
|
||||
if (!label_path) {
|
||||
if (path_is_absolute(inode_path))
|
||||
label_path = inode_path;
|
||||
else {
|
||||
r = fd_get_path(inode_fd, &p);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
label_path = p;
|
||||
}
|
||||
}
|
||||
|
||||
return selinux_fix_fd(inode_fd, label_path, flags);
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
int mac_selinux_apply(const char *path, const char *label) {
|
||||
|
@ -24,15 +24,7 @@ int mac_selinux_init(void);
|
||||
void mac_selinux_maybe_reload(void);
|
||||
void mac_selinux_finish(void);
|
||||
|
||||
int mac_selinux_fix_container(const char *path, const char *inside_path, LabelFixFlags flags);
|
||||
static inline int mac_selinux_fix(const char *path, LabelFixFlags flags) {
|
||||
return mac_selinux_fix_container(path, path, flags);
|
||||
}
|
||||
|
||||
int mac_selinux_fix_container_fd(int fd, const char *path, const char *inside_path, LabelFixFlags flags);
|
||||
static inline int mac_selinux_fix_fd(int fd, const char *path, LabelFixFlags flags) {
|
||||
return mac_selinux_fix_container_fd(fd, path, path, flags);
|
||||
}
|
||||
int mac_selinux_fix_full(int atfd, const char *inode_path, const char *label_path, LabelFixFlags flags);
|
||||
|
||||
int mac_selinux_apply(const char *path, const char *label);
|
||||
int mac_selinux_apply_fd(int fd, const char *path, const char *label);
|
||||
|
@ -122,17 +122,22 @@ int mac_smack_apply_pid(pid_t pid, const char *label) {
|
||||
return r;
|
||||
}
|
||||
|
||||
static int smack_fix_fd(int fd, const char *abspath, LabelFixFlags flags) {
|
||||
static int smack_fix_fd(
|
||||
int fd,
|
||||
const char *label_path,
|
||||
LabelFixFlags flags) {
|
||||
|
||||
const char *label;
|
||||
struct stat st;
|
||||
int r;
|
||||
|
||||
/* The caller should have done the sanity checks. */
|
||||
assert(abspath);
|
||||
assert(path_is_absolute(abspath));
|
||||
assert(fd >= 0);
|
||||
assert(label_path);
|
||||
assert(path_is_absolute(label_path));
|
||||
|
||||
/* Path must be in /dev. */
|
||||
if (!path_startswith(abspath, "/dev"))
|
||||
if (!path_startswith(label_path, "/dev"))
|
||||
return 0;
|
||||
|
||||
if (fstat(fd, &st) < 0)
|
||||
@ -171,70 +176,53 @@ static int smack_fix_fd(int fd, const char *abspath, LabelFixFlags flags) {
|
||||
streq(old_label, label))
|
||||
return 0;
|
||||
|
||||
return log_debug_errno(r, "Unable to fix SMACK label of %s: %m", abspath);
|
||||
return log_debug_errno(r, "Unable to fix SMACK label of %s: %m", label_path);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int mac_smack_fix_at(int dir_fd, const char *path, LabelFixFlags flags) {
|
||||
int mac_smack_fix_full(
|
||||
int atfd,
|
||||
const char *inode_path,
|
||||
const char *label_path,
|
||||
LabelFixFlags flags) {
|
||||
|
||||
_cleanup_close_ int opened_fd = -1;
|
||||
_cleanup_free_ char *p = NULL;
|
||||
_cleanup_close_ int fd = -1;
|
||||
int r;
|
||||
int r, inode_fd;
|
||||
|
||||
assert(path);
|
||||
assert(atfd >= 0 || atfd == AT_FDCWD);
|
||||
assert(atfd >= 0 || inode_path);
|
||||
|
||||
if (!mac_smack_use())
|
||||
return 0;
|
||||
|
||||
if (dir_fd < 0) {
|
||||
if (dir_fd != AT_FDCWD)
|
||||
return -EBADF;
|
||||
if (inode_path) {
|
||||
opened_fd = openat(atfd, inode_path, O_NOFOLLOW|O_CLOEXEC|O_PATH);
|
||||
if (opened_fd < 0) {
|
||||
if ((flags & LABEL_IGNORE_ENOENT) && errno == ENOENT)
|
||||
return 0;
|
||||
|
||||
return mac_smack_fix(path, flags);
|
||||
return -errno;
|
||||
}
|
||||
inode_fd = opened_fd;
|
||||
} else
|
||||
inode_fd = atfd;
|
||||
|
||||
if (!label_path) {
|
||||
if (path_is_absolute(inode_path))
|
||||
label_path = inode_path;
|
||||
else {
|
||||
r = fd_get_path(inode_fd, &p);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
label_path = p;
|
||||
}
|
||||
}
|
||||
|
||||
fd = openat(dir_fd, path, O_NOFOLLOW|O_CLOEXEC|O_PATH);
|
||||
if (fd < 0) {
|
||||
if ((flags & LABEL_IGNORE_ENOENT) && errno == ENOENT)
|
||||
return 0;
|
||||
|
||||
return -errno;
|
||||
}
|
||||
|
||||
if (!path_is_absolute(path)) {
|
||||
r = fd_get_path(fd, &p);
|
||||
if (r < 0)
|
||||
return r;
|
||||
path = p;
|
||||
}
|
||||
|
||||
return smack_fix_fd(fd, path, flags);
|
||||
}
|
||||
|
||||
int mac_smack_fix_container(const char *path, const char *inside_path, LabelFixFlags flags) {
|
||||
_cleanup_free_ char *abspath = NULL;
|
||||
_cleanup_close_ int fd = -1;
|
||||
int r;
|
||||
|
||||
assert(path);
|
||||
|
||||
if (!mac_smack_use())
|
||||
return 0;
|
||||
|
||||
r = path_make_absolute_cwd(path, &abspath);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
fd = open(abspath, O_NOFOLLOW|O_CLOEXEC|O_PATH);
|
||||
if (fd < 0) {
|
||||
if ((flags & LABEL_IGNORE_ENOENT) && errno == ENOENT)
|
||||
return 0;
|
||||
|
||||
return -errno;
|
||||
}
|
||||
|
||||
return smack_fix_fd(fd, inside_path, flags);
|
||||
return smack_fix_fd(inode_fd, label_path, flags);
|
||||
}
|
||||
|
||||
int mac_smack_copy(const char *dest, const char *src) {
|
||||
|
@ -29,13 +29,11 @@ typedef enum SmackAttr {
|
||||
|
||||
bool mac_smack_use(void);
|
||||
|
||||
int mac_smack_fix_container(const char *path, const char *inside_path, LabelFixFlags flags);
|
||||
int mac_smack_fix_full(int atfd, const char *inode_path, const char *label_path, LabelFixFlags flags);
|
||||
static inline int mac_smack_fix(const char *path, LabelFixFlags flags) {
|
||||
return mac_smack_fix_container(path, path, flags);
|
||||
return mac_smack_fix_full(AT_FDCWD, path, path, flags);
|
||||
}
|
||||
|
||||
int mac_smack_fix_at(int dirfd, const char *path, LabelFixFlags flags);
|
||||
|
||||
const char* smack_attr_to_string(SmackAttr i) _const_;
|
||||
SmackAttr smack_attr_from_string(const char *s) _pure_;
|
||||
int mac_smack_read(const char *path, SmackAttr attr, char **label);
|
||||
|
@ -923,7 +923,7 @@ static int fd_set_perms(Item *i, int fd, const char *path, const struct stat *st
|
||||
}
|
||||
|
||||
shortcut:
|
||||
return label_fix(path, 0);
|
||||
return label_fix_full(fd, /* inode_path= */ NULL, /* label_path= */ path, 0);
|
||||
}
|
||||
|
||||
static int path_open_parent_safe(const char *path) {
|
||||
|
@ -677,7 +677,7 @@ static int udev_node_apply_permissions_impl(
|
||||
|
||||
/* set the defaults */
|
||||
if (!selinux)
|
||||
(void) mac_selinux_fix_fd(node_fd, devnode, LABEL_IGNORE_ENOENT);
|
||||
(void) mac_selinux_fix_full(node_fd, NULL, devnode, LABEL_IGNORE_ENOENT);
|
||||
if (!smack)
|
||||
(void) mac_smack_apply_fd(node_fd, SMACK_ATTR_ACCESS, NULL);
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user