]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
copy: tighten destination checks when copying files
authorLennart Poettering <lennart@poettering.net>
Mon, 1 Feb 2021 16:45:25 +0000 (17:45 +0100)
committerLennart Poettering <lennart@poettering.net>
Mon, 2 Aug 2021 15:23:58 +0000 (17:23 +0200)
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...)

src/shared/copy.c

index 27aa3b29387f3e3990f55cd767366eb59e1f20df..bf02a89b5149b48125ee25861d1e9e99b5c659be 100644 (file)
@@ -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);