summaryrefslogtreecommitdiff
path: root/src/shared/copy.c
diff options
context:
space:
mode:
authorLennart Poettering <lennart@poettering.net>2021-02-01 17:45:25 +0100
committerLennart Poettering <lennart@poettering.net>2021-08-02 17:23:58 +0200
commit2f782044986a30bf73f1fe00209dbd204b3efe33 (patch)
treec0735c56c7da2738cb6e298c1ea048983670eb90 /src/shared/copy.c
parent5c9d961e79adaa0f4dc2e3b1e5deac0f29633723 (diff)
downloadsystemd-2f782044986a30bf73f1fe00209dbd204b3efe33.tar.gz
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 'src/shared/copy.c')
-rw-r--r--src/shared/copy.c33
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);