1
0
mirror of https://github.com/systemd/systemd.git synced 2025-01-13 17:18:18 +03:00

Merge pull request #25355 from poettering/chase-symlinks-no-symlink

chase_symlinks(): add CHASE_PROHIBIT_SYMLINKS
This commit is contained in:
Yu Watanabe 2022-11-13 20:16:34 +09:00 committed by GitHub
commit 8ce056c171
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 41 additions and 13 deletions

View File

@ -57,6 +57,21 @@ static int log_autofs_mount_point(int fd, const char *path, ChaseSymlinksFlags f
strna(n1), path);
}
static int log_prohibited_symlink(int fd, ChaseSymlinksFlags flags) {
_cleanup_free_ char *n1 = NULL;
assert(fd >= 0);
if (!FLAGS_SET(flags, CHASE_WARN))
return -EREMCHG;
(void) fd_get_path(fd, &n1);
return log_warning_errno(SYNTHETIC_ERRNO(EREMCHG),
"Detected symlink where not symlink is allowed at %s, refusing.",
strna(n1));
}
int chase_symlinks_at(
int dir_fd,
const char *path,
@ -291,6 +306,9 @@ int chase_symlinks_at(
if (S_ISLNK(st.st_mode) && !((flags & CHASE_NOFOLLOW) && isempty(todo))) {
_cleanup_free_ char *destination = NULL;
if (flags & CHASE_PROHIBIT_SYMLINKS)
return log_prohibited_symlink(child, flags);
/* This is a symlink, in this case read the destination. But let's make sure we
* don't follow symlinks without bounds. */
if (--max_follow <= 0)

View File

@ -19,6 +19,7 @@ typedef enum ChaseSymlinksFlags {
* Note: this may do an NSS lookup, hence this flag cannot be used in PID 1. */
CHASE_AT_RESOLVE_IN_ROOT = 1 << 8, /* Same as openat2()'s RESOLVE_IN_ROOT flag, symlinks are resolved
* relative to the given directory fd instead of root. */
CHASE_PROHIBIT_SYMLINKS = 1 << 9, /* Refuse all symlinks */
} ChaseSymlinksFlags;
bool unsafe_transition(const struct stat *a, const struct stat *b);

View File

@ -484,7 +484,7 @@ static int enumerate_binaries(
assert(previous);
assert(is_first);
r = chase_symlinks_and_opendir(path, esp_path, CHASE_PREFIX_ROOT, &p, &d);
r = chase_symlinks_and_opendir(path, esp_path, CHASE_PREFIX_ROOT|CHASE_PROHIBIT_SYMLINKS, &p, &d);
if (r == -ENOENT)
return 0;
if (r < 0)
@ -913,10 +913,10 @@ static int copy_one_file(const char *esp_path, const char *name, bool force) {
if (!p)
return log_oom();
r = chase_symlinks(p, root, CHASE_PREFIX_ROOT, &source_path, NULL);
r = chase_symlinks(p, root, CHASE_PREFIX_ROOT|CHASE_PROHIBIT_SYMLINKS, &source_path, NULL);
/* If we had a root directory to try, we didn't find it and we are in auto mode, retry on the host */
if (r == -ENOENT && root && arg_install_source == ARG_INSTALL_SOURCE_AUTO)
r = chase_symlinks(p, NULL, CHASE_PREFIX_ROOT, &source_path, NULL);
r = chase_symlinks(p, NULL, CHASE_PREFIX_ROOT|CHASE_PROHIBIT_SYMLINKS, &source_path, NULL);
if (r < 0)
return log_error_errno(r,
"Failed to resolve path %s%s%s: %m",
@ -928,7 +928,7 @@ static int copy_one_file(const char *esp_path, const char *name, bool force) {
if (!q)
return log_oom();
r = chase_symlinks(q, esp_path, CHASE_PREFIX_ROOT | CHASE_NONEXISTENT, &dest_path, NULL);
r = chase_symlinks(q, esp_path, CHASE_PREFIX_ROOT|CHASE_PROHIBIT_SYMLINKS|CHASE_NONEXISTENT, &dest_path, NULL);
if (r < 0)
return log_error_errno(r, "Failed to resolve path %s under directory %s: %m", q, esp_path);
@ -945,7 +945,7 @@ static int copy_one_file(const char *esp_path, const char *name, bool force) {
v = strjoina("/EFI/BOOT/BOOT", e);
ascii_strupper(strrchr(v, '/') + 1);
r = chase_symlinks(v, esp_path, CHASE_PREFIX_ROOT | CHASE_NONEXISTENT, &default_dest_path, NULL);
r = chase_symlinks(v, esp_path, CHASE_PREFIX_ROOT|CHASE_PROHIBIT_SYMLINKS|CHASE_NONEXISTENT, &default_dest_path, NULL);
if (r < 0)
return log_error_errno(r, "Failed to resolve path %s under directory %s: %m", v, esp_path);
@ -963,10 +963,10 @@ static int install_binaries(const char *esp_path, const char *arch, bool force)
_cleanup_free_ char *path = NULL;
int r;
r = chase_symlinks_and_opendir(BOOTLIBDIR, root, CHASE_PREFIX_ROOT, &path, &d);
r = chase_symlinks_and_opendir(BOOTLIBDIR, root, CHASE_PREFIX_ROOT|CHASE_PROHIBIT_SYMLINKS, &path, &d);
/* If we had a root directory to try, we didn't find it and we are in auto mode, retry on the host */
if (r == -ENOENT && root && arg_install_source == ARG_INSTALL_SOURCE_AUTO)
r = chase_symlinks_and_opendir(BOOTLIBDIR, NULL, CHASE_PREFIX_ROOT, &path, &d);
r = chase_symlinks_and_opendir(BOOTLIBDIR, NULL, CHASE_PREFIX_ROOT|CHASE_PROHIBIT_SYMLINKS, &path, &d);
if (r < 0)
return log_error_errno(r, "Failed to open boot loader directory %s%s: %m", strempty(root), BOOTLIBDIR);
@ -1136,7 +1136,7 @@ static int install_variables(
return 0;
}
r = chase_symlinks_and_access(path, esp_path, CHASE_PREFIX_ROOT, F_OK, NULL, NULL);
r = chase_symlinks_and_access(path, esp_path, CHASE_PREFIX_ROOT|CHASE_PROHIBIT_SYMLINKS, F_OK, NULL, NULL);
if (r == -ENOENT)
return 0;
if (r < 0)
@ -1167,7 +1167,7 @@ static int remove_boot_efi(const char *esp_path) {
_cleanup_free_ char *p = NULL;
int r, c = 0;
r = chase_symlinks_and_opendir("/EFI/BOOT", esp_path, CHASE_PREFIX_ROOT, &p, &d);
r = chase_symlinks_and_opendir("/EFI/BOOT", esp_path, CHASE_PREFIX_ROOT|CHASE_PROHIBIT_SYMLINKS, &p, &d);
if (r == -ENOENT)
return 0;
if (r < 0)

View File

@ -508,7 +508,7 @@ static int boot_loader_read_conf_path(BootConfig *config, const char *root, cons
assert(config);
assert(path);
r = chase_symlinks_and_fopen_unlocked(path, root, CHASE_PREFIX_ROOT, "re", &full, &f);
r = chase_symlinks_and_fopen_unlocked(path, root, CHASE_PREFIX_ROOT|CHASE_PROHIBIT_SYMLINKS, "re", &full, &f);
if (r == -ENOENT)
return 0;
if (r < 0)
@ -593,7 +593,7 @@ static int boot_entries_find_type1(
assert(root);
assert(dir);
dir_fd = chase_symlinks_and_open(dir, root, CHASE_PREFIX_ROOT, O_DIRECTORY|O_CLOEXEC, &full);
dir_fd = chase_symlinks_and_open(dir, root, CHASE_PREFIX_ROOT|CHASE_PROHIBIT_SYMLINKS, O_DIRECTORY|O_CLOEXEC, &full);
if (dir_fd == -ENOENT)
return 0;
if (dir_fd < 0)
@ -853,7 +853,7 @@ static int boot_entries_find_unified(
assert(config);
assert(dir);
r = chase_symlinks_and_opendir(dir, root, CHASE_PREFIX_ROOT, &full, &d);
r = chase_symlinks_and_opendir(dir, root, CHASE_PREFIX_ROOT|CHASE_PROHIBIT_SYMLINKS, &full, &d);
if (r == -ENOENT)
return 0;
if (r < 0)
@ -1260,7 +1260,7 @@ static void boot_entry_file_list(
assert(p);
assert(ret_status);
int status = chase_symlinks_and_access(p, root, CHASE_PREFIX_ROOT, F_OK, NULL, NULL);
int status = chase_symlinks_and_access(p, root, CHASE_PREFIX_ROOT|CHASE_PROHIBIT_SYMLINKS, F_OK, NULL, NULL);
printf("%13s%s ", strempty(field), field ? ":" : " ");
if (status < 0) {

View File

@ -386,6 +386,15 @@ TEST(chase_symlinks) {
assert_se(path_equal(path_startswith(result, p), "usr"));
result = mfree(result);
/* Test CHASE_PROHIBIT_SYMLINKS */
assert_se(chase_symlinks("top/dot", temp, CHASE_PREFIX_ROOT|CHASE_PROHIBIT_SYMLINKS, NULL, NULL) == -EREMCHG);
assert_se(chase_symlinks("top/dot", temp, CHASE_PREFIX_ROOT|CHASE_PROHIBIT_SYMLINKS|CHASE_WARN, NULL, NULL) == -EREMCHG);
assert_se(chase_symlinks("top/dotdot", temp, CHASE_PREFIX_ROOT|CHASE_PROHIBIT_SYMLINKS, NULL, NULL) == -EREMCHG);
assert_se(chase_symlinks("top/dotdot", temp, CHASE_PREFIX_ROOT|CHASE_PROHIBIT_SYMLINKS|CHASE_WARN, NULL, NULL) == -EREMCHG);
assert_se(chase_symlinks("top/dot/dot", temp, CHASE_PREFIX_ROOT|CHASE_PROHIBIT_SYMLINKS, NULL, NULL) == -EREMCHG);
assert_se(chase_symlinks("top/dot/dot", temp, CHASE_PREFIX_ROOT|CHASE_PROHIBIT_SYMLINKS|CHASE_WARN, NULL, NULL) == -EREMCHG);
cleanup:
assert_se(rm_rf(temp, REMOVE_ROOT|REMOVE_PHYSICAL) >= 0);
}