diff options
author | Lennart Poettering <lennart@poettering.net> | 2021-02-01 17:45:25 +0100 |
---|---|---|
committer | Lennart Poettering <lennart@poettering.net> | 2021-08-02 17:23:58 +0200 |
commit | 2f782044986a30bf73f1fe00209dbd204b3efe33 (patch) | |
tree | c0735c56c7da2738cb6e298c1ea048983670eb90 /src/shared/copy.c | |
parent | copy: move to single clean-up path (diff) | |
download | systemd-2f782044986a30bf73f1fe00209dbd204b3efe33.tar.xz systemd-2f782044986a30bf73f1fe00209dbd204b3efe33.zip |
copy: tighten destination checks when copying files
let's make sure we only operate on regular files when copying files.
Also, make sure to copy file attributes only over if target is a regular
file (so that copying a file to /dev/null won't alter the access
mode/ownership of that device node...)
Diffstat (limited to '')
-rw-r--r-- | src/shared/copy.c | 33 |
1 files changed, 27 insertions, 6 deletions
diff --git a/src/shared/copy.c b/src/shared/copy.c index 27aa3b2938..bf02a89b51 100644 --- a/src/shared/copy.c +++ b/src/shared/copy.c @@ -1026,6 +1026,7 @@ int copy_file_fd_full( void *userdata) { _cleanup_close_ int fdf = -1; + struct stat st; int r; assert(from); @@ -1035,12 +1036,23 @@ int copy_file_fd_full( if (fdf < 0) return -errno; + r = fd_verify_regular(fdf); + if (r < 0) + return r; + + if (fstat(fdt, &st) < 0) + return -errno; + r = copy_bytes_full(fdf, fdt, UINT64_MAX, copy_flags, NULL, NULL, progress_bytes, userdata); + if (r < 0) + return r; - (void) copy_times(fdf, fdt, copy_flags); - (void) copy_xattr(fdf, fdt); + if (S_ISREG(fdt)) { + (void) copy_times(fdf, fdt, copy_flags); + (void) copy_xattr(fdf, fdt); + } - return r; + return 0; } int copy_file_full( @@ -1065,9 +1077,12 @@ int copy_file_full( if (fdf < 0) return -errno; - if (mode == MODE_INVALID) - if (fstat(fdf, &st) < 0) - return -errno; + if (fstat(fdf, &st) < 0) + return -errno; + + r = stat_verify_regular(&st); + if (r < 0) + return r; RUN_WITH_UMASK(0000) { if (copy_flags & COPY_MAC_CREATE) { @@ -1083,6 +1098,12 @@ int copy_file_full( return -errno; } + if (!FLAGS_SET(flags, O_EXCL)) { /* if O_EXCL was used we created the thing as regular file, no need to check again */ + r = fd_verify_regular(fdt); + if (r < 0) + goto fail; + } + if (chattr_mask != 0) (void) chattr_fd(fdt, chattr_flags, chattr_mask & CHATTR_EARLY_FL, NULL); |