1
0
mirror of https://github.com/systemd/systemd.git synced 2025-01-26 14:04:03 +03:00

chase-symlinks: Add CHASE_MKDIR_0755

This commit is contained in:
Daan De Meyer 2023-01-09 12:29:12 +01:00
parent 28aa650eb7
commit e864dfa671
3 changed files with 38 additions and 15 deletions

View File

@ -98,6 +98,9 @@ int chase_symlinks_at(
if ((flags & CHASE_STEP) && ret_fd)
return -EINVAL;
if (FLAGS_SET(flags, CHASE_MKDIR_0755|CHASE_NONEXISTENT))
return -EINVAL;
if (isempty(path))
path = ".";
@ -172,7 +175,7 @@ int chase_symlinks_at(
if (!(flags &
(CHASE_AT_RESOLVE_IN_ROOT|CHASE_NONEXISTENT|CHASE_NO_AUTOFS|CHASE_SAFE|CHASE_STEP|
CHASE_PROHIBIT_SYMLINKS)) &&
CHASE_PROHIBIT_SYMLINKS|CHASE_MKDIR_0755)) &&
!ret_path && ret_fd) {
/* Shortcut the ret_fd case if the caller isn't interested in the actual path and has no root
@ -295,15 +298,15 @@ int chase_symlinks_at(
}
/* Otherwise let's see what this is. */
child = openat(fd, first, O_CLOEXEC|O_NOFOLLOW|O_PATH);
if (child < 0) {
if (errno == ENOENT &&
(flags & CHASE_NONEXISTENT) &&
(isempty(todo) || path_is_safe(todo))) {
/* If CHASE_NONEXISTENT is set, and the path does not exist, then
* that's OK, return what we got so far. But don't allow this if the
* remaining path contains "../" or something else weird. */
child = r = RET_NERRNO(openat(fd, first, O_CLOEXEC|O_NOFOLLOW|O_PATH));
if (r < 0) {
if (r != -ENOENT)
return r;
if (!isempty(todo) && !path_is_safe(todo))
return r;
if (flags & CHASE_NONEXISTENT) {
if (!path_extend(&done, first, todo))
return -ENOMEM;
@ -311,7 +314,12 @@ int chase_symlinks_at(
break;
}
return -errno;
if (!(flags & CHASE_MKDIR_0755))
return r;
child = open_mkdir_at(fd, first, O_CLOEXEC|O_PATH|O_EXCL, 0755);
if (child < 0)
return child;
}
if (fstat(child, &st) < 0)
@ -390,7 +398,7 @@ int chase_symlinks_at(
close_and_replace(fd, child);
}
if (flags & CHASE_PARENT) {
if (flags & (CHASE_PARENT|CHASE_MKDIR_0755)) {
r = fd_verify_directory(fd);
if (r < 0)
return r;
@ -548,7 +556,7 @@ int chase_symlinks_and_open(
return -EINVAL;
if (empty_or_root(root) && !ret_path &&
(chase_flags & (CHASE_NO_AUTOFS|CHASE_SAFE|CHASE_PROHIBIT_SYMLINKS|CHASE_PARENT)) == 0) {
(chase_flags & (CHASE_NO_AUTOFS|CHASE_SAFE|CHASE_PROHIBIT_SYMLINKS|CHASE_PARENT|CHASE_MKDIR_0755)) == 0) {
/* Shortcut this call if none of the special features of this call are requested */
r = open(path, open_flags | (FLAGS_SET(chase_flags, CHASE_NOFOLLOW) ? O_NOFOLLOW : 0));
if (r < 0)
@ -590,7 +598,7 @@ int chase_symlinks_and_opendir(
return -EINVAL;
if (empty_or_root(root) && !ret_path &&
(chase_flags & (CHASE_NO_AUTOFS|CHASE_SAFE|CHASE_PROHIBIT_SYMLINKS|CHASE_PARENT)) == 0) {
(chase_flags & (CHASE_NO_AUTOFS|CHASE_SAFE|CHASE_PROHIBIT_SYMLINKS|CHASE_PARENT|CHASE_MKDIR_0755)) == 0) {
/* Shortcut this call if none of the special features of this call are requested */
d = opendir(path);
if (!d)
@ -635,7 +643,7 @@ int chase_symlinks_and_stat(
return -EINVAL;
if (empty_or_root(root) && !ret_path &&
(chase_flags & (CHASE_NO_AUTOFS|CHASE_SAFE|CHASE_PROHIBIT_SYMLINKS|CHASE_PARENT)) == 0 && !ret_fd) {
(chase_flags & (CHASE_NO_AUTOFS|CHASE_SAFE|CHASE_PROHIBIT_SYMLINKS|CHASE_PARENT|CHASE_MKDIR_0755)) == 0 && !ret_fd) {
/* Shortcut this call if none of the special features of this call are requested */
if (fstatat(AT_FDCWD, path, ret_stat, FLAGS_SET(chase_flags, CHASE_NOFOLLOW) ? AT_SYMLINK_NOFOLLOW : 0) < 0)
@ -678,7 +686,7 @@ int chase_symlinks_and_access(
return -EINVAL;
if (empty_or_root(root) && !ret_path &&
(chase_flags & (CHASE_NO_AUTOFS|CHASE_SAFE|CHASE_PROHIBIT_SYMLINKS|CHASE_PARENT)) == 0 && !ret_fd) {
(chase_flags & (CHASE_NO_AUTOFS|CHASE_SAFE|CHASE_PROHIBIT_SYMLINKS|CHASE_PARENT|CHASE_MKDIR_0755)) == 0 && !ret_fd) {
/* Shortcut this call if none of the special features of this call are requested */
if (faccessat(AT_FDCWD, path, access_mode, FLAGS_SET(chase_flags, CHASE_NOFOLLOW) ? AT_SYMLINK_NOFOLLOW : 0) < 0)

View File

@ -21,6 +21,7 @@ typedef enum ChaseSymlinksFlags {
* relative to the given directory fd instead of root. */
CHASE_PROHIBIT_SYMLINKS = 1 << 9, /* Refuse all symlinks */
CHASE_PARENT = 1 << 10, /* Chase the parent directory of the given path. */
CHASE_MKDIR_0755 = 1 << 11, /* Create any missing directories in the given path. */
} ChaseSymlinksFlags;
bool unsafe_transition(const struct stat *a, const struct stat *b);

View File

@ -486,6 +486,20 @@ TEST(chase_symlinks_at) {
assert_se(chase_symlinks_at(tfd, "chase", CHASE_NONEXISTENT|CHASE_PARENT, &result, NULL) >= 0);
assert_se(streq(result, "."));
result = mfree(result);
/* Test CHASE_MKDIR_0755 */
assert_se(chase_symlinks_at(tfd, "m/k/d/i/r", CHASE_MKDIR_0755, &result, NULL) >= 0);
assert_se(faccessat(tfd, "m/k/d/i/r", F_OK, 0) >= 0);
assert_se(streq(result, "m/k/d/i/r"));
result = mfree(result);
assert_se(chase_symlinks_at(tfd, "m/../q", CHASE_MKDIR_0755, &result, NULL) >= 0);
assert_se(faccessat(tfd, "q", F_OK, 0) >= 0);
assert_se(streq(result, "q"));
result = mfree(result);
assert_se(chase_symlinks_at(tfd, "i/../p", CHASE_MKDIR_0755, NULL, NULL) == -ENOENT);
}
TEST(unlink_noerrno) {