summaryrefslogtreecommitdiffstats
path: root/src/basic
diff options
context:
space:
mode:
authorLennart Poettering <lennart@poettering.net>2018-08-03 18:11:36 +0200
committerGitHub <noreply@github.com>2018-08-03 18:11:36 +0200
commit685499007fc536f5e78ebb49cb67561e186f665e (patch)
treefe4c039d8042ec21f1d312e5b7f1c689b5ef21e0 /src/basic
parentMerge pull request #9791 from poettering/user-runtime-dir-fixes (diff)
parentpath-util: make use of path_join() in path_make_absolute_cwd() (diff)
downloadsystemd-685499007fc536f5e78ebb49cb67561e186f665e.tar.xz
systemd-685499007fc536f5e78ebb49cb67561e186f665e.zip
Merge pull request #8822 from fbuihuu/rfc-tmpfiles-safe-upstream
Make tmpfiles safe
Diffstat (limited to 'src/basic')
-rw-r--r--src/basic/btrfs-util.c26
-rw-r--r--src/basic/btrfs-util.h1
-rw-r--r--src/basic/fileio.c8
-rw-r--r--src/basic/fs-util.c29
-rw-r--r--src/basic/fs-util.h2
-rw-r--r--src/basic/label.h1
-rw-r--r--src/basic/mkdir-label.c17
-rw-r--r--src/basic/mkdir.c6
-rw-r--r--src/basic/mkdir.h1
-rw-r--r--src/basic/path-util.c5
-rw-r--r--src/basic/selinux-util.c83
-rw-r--r--src/basic/selinux-util.h1
-rw-r--r--src/basic/smack-util.c91
-rw-r--r--src/basic/smack-util.h1
-rw-r--r--src/basic/stat-util.c11
-rw-r--r--src/basic/stat-util.h1
16 files changed, 217 insertions, 67 deletions
diff --git a/src/basic/btrfs-util.c b/src/basic/btrfs-util.c
index efac0b9420..abd34824e7 100644
--- a/src/basic/btrfs-util.c
+++ b/src/basic/btrfs-util.c
@@ -116,8 +116,25 @@ int btrfs_is_subvol(const char *path) {
return btrfs_is_subvol_fd(fd);
}
-int btrfs_subvol_make(const char *path) {
+int btrfs_subvol_make_fd(int fd, const char *subvolume) {
struct btrfs_ioctl_vol_args args = {};
+ int r;
+
+ assert(subvolume);
+
+ r = validate_subvolume_name(subvolume);
+ if (r < 0)
+ return r;
+
+ strncpy(args.name, subvolume, sizeof(args.name)-1);
+
+ if (ioctl(fd, BTRFS_IOC_SUBVOL_CREATE, &args) < 0)
+ return -errno;
+
+ return 0;
+}
+
+int btrfs_subvol_make(const char *path) {
_cleanup_close_ int fd = -1;
const char *subvolume;
int r;
@@ -132,12 +149,7 @@ int btrfs_subvol_make(const char *path) {
if (fd < 0)
return fd;
- strncpy(args.name, subvolume, sizeof(args.name)-1);
-
- if (ioctl(fd, BTRFS_IOC_SUBVOL_CREATE, &args) < 0)
- return -errno;
-
- return 0;
+ return btrfs_subvol_make_fd(fd, subvolume);
}
int btrfs_subvol_set_read_only_fd(int fd, bool b) {
diff --git a/src/basic/btrfs-util.h b/src/basic/btrfs-util.h
index a594387b5a..b0cf6739f7 100644
--- a/src/basic/btrfs-util.h
+++ b/src/basic/btrfs-util.h
@@ -65,6 +65,7 @@ int btrfs_resize_loopback_fd(int fd, uint64_t size, bool grow_only);
int btrfs_resize_loopback(const char *path, uint64_t size, bool grow_only);
int btrfs_subvol_make(const char *path);
+int btrfs_subvol_make_fd(int fd, const char *subvolume);
int btrfs_subvol_snapshot_fd(int old_fd, const char *new_path, BtrfsSnapshotFlags flags);
int btrfs_subvol_snapshot(const char *old_path, const char *new_path, BtrfsSnapshotFlags flags);
diff --git a/src/basic/fileio.c b/src/basic/fileio.c
index 20d3f567c9..ea607f8cfb 100644
--- a/src/basic/fileio.c
+++ b/src/basic/fileio.c
@@ -1319,8 +1319,7 @@ int tempfn_random_child(const char *p, const char *extra, char **ret) {
r = tmp_dir(&p);
if (r < 0)
return r;
- } else if (isempty(p))
- return -EINVAL;
+ }
extra = strempty(extra);
@@ -1328,7 +1327,10 @@ int tempfn_random_child(const char *p, const char *extra, char **ret) {
if (!t)
return -ENOMEM;
- x = stpcpy(stpcpy(stpcpy(t, p), "/.#"), extra);
+ if (isempty(p))
+ x = stpcpy(stpcpy(t, ".#"), extra);
+ else
+ x = stpcpy(stpcpy(stpcpy(t, p), "/.#"), extra);
u = random_u64();
for (i = 0; i < 16; i++) {
diff --git a/src/basic/fs-util.c b/src/basic/fs-util.c
index aca9921de7..09fcc32e0e 100644
--- a/src/basic/fs-util.c
+++ b/src/basic/fs-util.c
@@ -435,6 +435,31 @@ int mkfifo_atomic(const char *path, mode_t mode) {
return 0;
}
+int mkfifoat_atomic(int dirfd, const char *path, mode_t mode) {
+ _cleanup_free_ char *t = NULL;
+ int r;
+
+ assert(path);
+
+ if (path_is_absolute(path))
+ return mkfifo_atomic(path, mode);
+
+ /* We're only interested in the (random) filename. */
+ r = tempfn_random_child("", NULL, &t);
+ if (r < 0)
+ return r;
+
+ if (mkfifoat(dirfd, t, mode) < 0)
+ return -errno;
+
+ if (renameat(dirfd, t, dirfd, path) < 0) {
+ unlink_noerrno(t);
+ return -errno;
+ }
+
+ return 0;
+}
+
int get_files_in_directory(const char *path, char ***list) {
_cleanup_closedir_ DIR *d = NULL;
struct dirent *de;
@@ -670,7 +695,7 @@ int chase_symlinks(const char *path, const char *original_root, unsigned flags,
if (!original_root && !ret && (flags & (CHASE_NONEXISTENT|CHASE_NO_AUTOFS|CHASE_SAFE|CHASE_OPEN|CHASE_STEP)) == CHASE_OPEN) {
/* Shortcut the CHASE_OPEN case if the caller isn't interested in the actual path and has no root set
* and doesn't care about any of the other special features we provide either. */
- r = open(path, O_PATH|O_CLOEXEC);
+ r = open(path, O_PATH|O_CLOEXEC|((flags & CHASE_NOFOLLOW) ? O_NOFOLLOW : 0));
if (r < 0)
return -errno;
@@ -825,7 +850,7 @@ int chase_symlinks(const char *path, const char *original_root, unsigned flags,
fd_is_fs_type(child, AUTOFS_SUPER_MAGIC) > 0)
return -EREMOTE;
- if (S_ISLNK(st.st_mode)) {
+ if (S_ISLNK(st.st_mode) && !((flags & CHASE_NOFOLLOW) && isempty(todo))) {
char *joined;
_cleanup_free_ char *destination = NULL;
diff --git a/src/basic/fs-util.h b/src/basic/fs-util.h
index 754163defd..4b65625861 100644
--- a/src/basic/fs-util.h
+++ b/src/basic/fs-util.h
@@ -42,6 +42,7 @@ int symlink_idempotent(const char *from, const char *to);
int symlink_atomic(const char *from, const char *to);
int mknod_atomic(const char *path, mode_t mode, dev_t dev);
int mkfifo_atomic(const char *path, mode_t mode);
+int mkfifoat_atomic(int dir_fd, const char *path, mode_t mode);
int get_files_in_directory(const char *path, char ***list);
@@ -72,6 +73,7 @@ enum {
CHASE_OPEN = 1 << 4, /* If set, return an O_PATH object to the final component */
CHASE_TRAIL_SLASH = 1 << 5, /* If set, any trailing slash will be preserved */
CHASE_STEP = 1 << 6, /* If set, just execute a single step of the normalization */
+ CHASE_NOFOLLOW = 1 << 7, /* Only valid with CHASE_OPEN: when the path's right-most component refers to symlink return O_PATH fd of the symlink, rather than following it. */
};
/* How many iterations to execute before returning -ELOOP */
diff --git a/src/basic/label.h b/src/basic/label.h
index 08fd109bcf..594fd65974 100644
--- a/src/basic/label.h
+++ b/src/basic/label.h
@@ -12,6 +12,7 @@ typedef enum LabelFixFlags {
int label_fix(const char *path, LabelFixFlags flags);
int mkdir_label(const char *path, mode_t mode);
+int mkdirat_label(int dirfd, const char *path, mode_t mode);
int symlink_label(const char *old_path, const char *new_path);
int btrfs_subvol_make_label(const char *path);
diff --git a/src/basic/mkdir-label.c b/src/basic/mkdir-label.c
index 1d51e92e9a..0eba7fc514 100644
--- a/src/basic/mkdir-label.c
+++ b/src/basic/mkdir-label.c
@@ -28,6 +28,23 @@ int mkdir_label(const char *path, mode_t mode) {
return mac_smack_fix(path, 0);
}
+int mkdirat_label(int dirfd, const char *path, mode_t mode) {
+ int r;
+
+ assert(path);
+
+ r = mac_selinux_create_file_prepare_at(dirfd, path, S_IFDIR);
+ if (r < 0)
+ return r;
+
+ r = mkdirat_errno_wrapper(dirfd, path, mode);
+ mac_selinux_create_file_clear();
+ if (r < 0)
+ return r;
+
+ return mac_smack_fix_at(dirfd, path, 0);
+}
+
int mkdir_safe_label(const char *path, mode_t mode, uid_t uid, gid_t gid, MkdirFlags flags) {
return mkdir_safe_internal(path, mode, uid, gid, flags, mkdir_label);
}
diff --git a/src/basic/mkdir.c b/src/basic/mkdir.c
index 6ab1b4422b..4bb65d5838 100644
--- a/src/basic/mkdir.c
+++ b/src/basic/mkdir.c
@@ -80,6 +80,12 @@ int mkdir_errno_wrapper(const char *pathname, mode_t mode) {
return 0;
}
+int mkdirat_errno_wrapper(int dirfd, const char *pathname, mode_t mode) {
+ if (mkdirat(dirfd, pathname, mode) < 0)
+ return -errno;
+ return 0;
+}
+
int mkdir_safe(const char *path, mode_t mode, uid_t uid, gid_t gid, MkdirFlags flags) {
return mkdir_safe_internal(path, mode, uid, gid, flags, mkdir_errno_wrapper);
}
diff --git a/src/basic/mkdir.h b/src/basic/mkdir.h
index bdca15460e..eb54853ea7 100644
--- a/src/basic/mkdir.h
+++ b/src/basic/mkdir.h
@@ -9,6 +9,7 @@ typedef enum MkdirFlags {
} MkdirFlags;
int mkdir_errno_wrapper(const char *pathname, mode_t mode);
+int mkdirat_errno_wrapper(int dirfd, const char *pathname, mode_t mode);
int mkdir_safe(const char *path, mode_t mode, uid_t uid, gid_t gid, MkdirFlags flags);
int mkdir_parents(const char *path, mode_t mode);
int mkdir_p(const char *path, mode_t mode);
diff --git a/src/basic/path-util.c b/src/basic/path-util.c
index d214c72916..b62786f27e 100644
--- a/src/basic/path-util.c
+++ b/src/basic/path-util.c
@@ -110,10 +110,7 @@ int path_make_absolute_cwd(const char *p, char **ret) {
if (r < 0)
return r;
- if (endswith(cwd, "/"))
- c = strjoin(cwd, p);
- else
- c = strjoin(cwd, "/", p);
+ c = path_join(NULL, cwd, p);
}
if (!c)
return -ENOMEM;
diff --git a/src/basic/selinux-util.c b/src/basic/selinux-util.c
index e15bd7e1fa..238b1d95e2 100644
--- a/src/basic/selinux-util.c
+++ b/src/basic/selinux-util.c
@@ -316,48 +316,89 @@ char* mac_selinux_free(char *label) {
return NULL;
}
-int mac_selinux_create_file_prepare(const char *path, mode_t mode) {
-
#if HAVE_SELINUX
+static int selinux_create_file_prepare_abspath(const char *abspath, mode_t mode) {
_cleanup_freecon_ char *filecon = NULL;
+ _cleanup_free_ char *path = NULL;
int r;
- assert(path);
-
- if (!label_hnd)
- return 0;
-
- if (path_is_absolute(path))
- r = selabel_lookup_raw(label_hnd, &filecon, path, mode);
- else {
- _cleanup_free_ char *newpath = NULL;
-
- r = path_make_absolute_cwd(path, &newpath);
- if (r < 0)
- return r;
-
- r = selabel_lookup_raw(label_hnd, &filecon, newpath, mode);
- }
+ assert(abspath);
+ assert(path_is_absolute(abspath));
+ r = selabel_lookup_raw(label_hnd, &filecon, abspath, mode);
if (r < 0) {
/* No context specified by the policy? Proceed without setting it. */
if (errno == ENOENT)
return 0;
- log_enforcing_errno(errno, "Failed to determine SELinux security context for %s: %m", path);
+ log_enforcing_errno(errno, "Failed to determine SELinux security context for %s: %m", abspath);
} else {
if (setfscreatecon_raw(filecon) >= 0)
return 0; /* Success! */
- log_enforcing_errno(errno, "Failed to set SELinux security context %s for %s: %m", filecon, path);
+ log_enforcing_errno(errno, "Failed to set SELinux security context %s for %s: %m", filecon, abspath);
}
if (security_getenforce() > 0)
return -errno;
-#endif
return 0;
}
+#endif
+
+int mac_selinux_create_file_prepare_at(int dirfd, const char *path, mode_t mode) {
+ int r = 0;
+
+#if HAVE_SELINUX
+ _cleanup_free_ char *abspath = NULL;
+ _cleanup_close_ int fd = -1;
+
+ assert(path);
+
+ if (!label_hnd)
+ return 0;
+
+ if (!path_is_absolute(path)) {
+ _cleanup_free_ char *p = NULL;
+
+ if (dirfd == AT_FDCWD)
+ r = safe_getcwd(&p);
+ else
+ r = fd_get_path(dirfd, &p);
+ if (r < 0)
+ return r;
+
+ abspath = path_join(NULL, p, path);
+ if (!abspath)
+ return -ENOMEM;
+
+ path = abspath;
+ }
+
+ r = selinux_create_file_prepare_abspath(path, mode);
+#endif
+ return r;
+}
+
+int mac_selinux_create_file_prepare(const char *path, mode_t mode) {
+ int r = 0;
+
+#if HAVE_SELINUX
+ _cleanup_free_ char *abspath = NULL;
+
+ assert(path);
+
+ if (!label_hnd)
+ return 0;
+
+ r = path_make_absolute_cwd(path, &abspath);
+ if (r < 0)
+ return r;
+
+ r = selinux_create_file_prepare_abspath(abspath, mode);
+#endif
+ return r;
+}
void mac_selinux_create_file_clear(void) {
diff --git a/src/basic/selinux-util.h b/src/basic/selinux-util.h
index 08314057fb..bd5207c318 100644
--- a/src/basic/selinux-util.h
+++ b/src/basic/selinux-util.h
@@ -23,6 +23,7 @@ int mac_selinux_get_child_mls_label(int socket_fd, const char *exe, const char *
char* mac_selinux_free(char *label);
int mac_selinux_create_file_prepare(const char *path, mode_t mode);
+int mac_selinux_create_file_prepare_at(int dirfd, const char *path, mode_t mode);
void mac_selinux_create_file_clear(void);
int mac_selinux_create_socket_prepare(const char *label);
diff --git a/src/basic/smack-util.c b/src/basic/smack-util.c
index 9d31b7717f..5d7be1f1d5 100644
--- a/src/basic/smack-util.c
+++ b/src/basic/smack-util.c
@@ -122,43 +122,20 @@ int mac_smack_apply_pid(pid_t pid, const char *label) {
return r;
}
-int mac_smack_fix(const char *path, LabelFixFlags flags) {
+static int smack_fix_fd(int fd , const char *abspath, LabelFixFlags flags) {
char procfs_path[STRLEN("/proc/self/fd/") + DECIMAL_STR_MAX(int)];
- _cleanup_close_ int fd = -1;
const char *label;
struct stat st;
int r;
- assert(path);
+ /* The caller should have done the sanity checks. */
+ assert(abspath);
+ assert(path_is_absolute(abspath));
- if (!mac_smack_use())
+ /* Path must be in /dev. */
+ if (!path_startswith(abspath, "/dev"))
return 0;
- /* Path must be in /dev. Note that this check is pretty sloppy, as we might be called with non-normalized paths
- * and hence not detect all cases of /dev. */
-
- if (path_is_absolute(path)) {
- if (!path_startswith(path, "/dev"))
- return 0;
- } else {
- _cleanup_free_ char *cwd = NULL;
-
- r = safe_getcwd(&cwd);
- if (r < 0)
- return r;
-
- if (!path_startswith(cwd, "/dev"))
- return 0;
- }
-
- fd = open(path, O_NOFOLLOW|O_CLOEXEC|O_PATH);
- if (fd < 0) {
- if ((flags & LABEL_IGNORE_ENOENT) && errno == ENOENT)
- return 0;
-
- return -errno;
- }
-
if (fstat(fd, &st) < 0)
return -errno;
@@ -196,12 +173,62 @@ int mac_smack_fix(const char *path, LabelFixFlags flags) {
streq(old_label, label))
return 0;
- return log_debug_errno(r, "Unable to fix SMACK label of %s: %m", path);
+ return log_debug_errno(r, "Unable to fix SMACK label of %s: %m", abspath);
}
return 0;
}
+int mac_smack_fix_at(int dirfd, const char *path, LabelFixFlags flags) {
+ _cleanup_free_ char *p = NULL;
+ _cleanup_close_ int fd = -1;
+ int r;
+
+ assert(path);
+
+ if (!mac_smack_use())
+ return 0;
+
+ fd = openat(dirfd, path, O_NOFOLLOW|O_CLOEXEC|O_PATH);
+ if (fd < 0) {
+ if ((flags & LABEL_IGNORE_ENOENT) && errno == ENOENT)
+ return 0;
+
+ return -errno;
+ }
+
+ r = fd_get_path(fd, &p);
+ if (r < 0)
+ return r;
+
+ return smack_fix_fd(fd, p, flags);
+}
+
+int mac_smack_fix(const char *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, abspath, flags);
+}
+
int mac_smack_copy(const char *dest, const char *src) {
int r = 0;
_cleanup_free_ char *label = NULL;
@@ -249,6 +276,10 @@ int mac_smack_fix(const char *path, LabelFixFlags flags) {
return 0;
}
+int mac_smack_fix_at(int dirfd, const char *path, LabelFixFlags flags) {
+ return 0;
+}
+
int mac_smack_copy(const char *dest, const char *src) {
return 0;
}
diff --git a/src/basic/smack-util.h b/src/basic/smack-util.h
index fd59787ecb..395ec07b57 100644
--- a/src/basic/smack-util.h
+++ b/src/basic/smack-util.h
@@ -30,6 +30,7 @@ typedef enum SmackAttr {
bool mac_smack_use(void);
int mac_smack_fix(const char *path, LabelFixFlags 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_;
diff --git a/src/basic/stat-util.c b/src/basic/stat-util.c
index 07154e25bb..762777e94f 100644
--- a/src/basic/stat-util.c
+++ b/src/basic/stat-util.c
@@ -45,6 +45,17 @@ int is_dir(const char* path, bool follow) {
return !!S_ISDIR(st.st_mode);
}
+int is_dir_fd(int fd) {
+ struct stat st;
+ int r;
+
+ r = fstat(fd, &st);
+ if (r < 0)
+ return -errno;
+
+ return !!S_ISDIR(st.st_mode);
+}
+
int is_device_node(const char *path) {
struct stat info;
diff --git a/src/basic/stat-util.h b/src/basic/stat-util.h
index f8014ed30b..1a725f1da0 100644
--- a/src/basic/stat-util.h
+++ b/src/basic/stat-util.h
@@ -12,6 +12,7 @@
int is_symlink(const char *path);
int is_dir(const char *path, bool follow);
+int is_dir_fd(int fd);
int is_device_node(const char *path);
int dir_is_empty(const char *path);