summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--devices/src/virtio/fs/passthrough.rs54
-rw-r--r--seccomp/aarch64/fs_device.policy1
-rw-r--r--seccomp/arm/fs_device.policy1
-rw-r--r--seccomp/x86_64/fs_device.policy1
4 files changed, 57 insertions, 0 deletions
diff --git a/devices/src/virtio/fs/passthrough.rs b/devices/src/virtio/fs/passthrough.rs
index aab1403..419d466 100644
--- a/devices/src/virtio/fs/passthrough.rs
+++ b/devices/src/virtio/fs/passthrough.rs
@@ -1696,4 +1696,58 @@ impl FileSystem for PassthroughFs {
             Err(io::Error::from_raw_os_error(libc::ENOTTY))
         }
     }
+
+    fn copy_file_range(
+        &self,
+        ctx: Context,
+        inode_src: Inode,
+        handle_src: Handle,
+        offset_src: u64,
+        inode_dst: Inode,
+        handle_dst: Handle,
+        offset_dst: u64,
+        length: u64,
+        flags: u64,
+    ) -> io::Result<usize> {
+        // We need to change credentials during a write so that the kernel will remove setuid or
+        // setgid bits from the file if it was written to by someone other than the owner.
+        let (_uid, _gid) = set_creds(ctx.uid, ctx.gid)?;
+        let src_data = self
+            .handles
+            .read()
+            .unwrap()
+            .get(&handle_src)
+            .filter(|hd| hd.inode == inode_src)
+            .map(Arc::clone)
+            .ok_or_else(ebadf)?;
+        let dst_data = self
+            .handles
+            .read()
+            .unwrap()
+            .get(&handle_dst)
+            .filter(|hd| hd.inode == inode_dst)
+            .map(Arc::clone)
+            .ok_or_else(ebadf)?;
+
+        let src = src_data.file.lock().as_raw_fd();
+        let dst = dst_data.file.lock().as_raw_fd();
+
+        let res = unsafe {
+            libc::syscall(
+                libc::SYS_copy_file_range,
+                src,
+                &offset_src,
+                dst,
+                offset_dst,
+                length,
+                flags,
+            )
+        };
+
+        if res >= 0 {
+            Ok(res as usize)
+        } else {
+            Err(io::Error::last_os_error())
+        }
+    }
 }
diff --git a/seccomp/aarch64/fs_device.policy b/seccomp/aarch64/fs_device.policy
index 9fd4c8b..ec9d155 100644
--- a/seccomp/aarch64/fs_device.policy
+++ b/seccomp/aarch64/fs_device.policy
@@ -4,6 +4,7 @@
 
 @include /usr/share/policy/crosvm/common_device.policy
 
+copy_file_range: 1
 fallocate: 1
 fchmodat: 1
 fchownat: 1
diff --git a/seccomp/arm/fs_device.policy b/seccomp/arm/fs_device.policy
index eb9df16..4078f41 100644
--- a/seccomp/arm/fs_device.policy
+++ b/seccomp/arm/fs_device.policy
@@ -4,6 +4,7 @@
 
 @include /usr/share/policy/crosvm/common_device.policy
 
+copy_file_range: 1
 fallocate: 1
 fchmodat: 1
 fchownat: 1
diff --git a/seccomp/x86_64/fs_device.policy b/seccomp/x86_64/fs_device.policy
index ddb2a51..eb5a1c4 100644
--- a/seccomp/x86_64/fs_device.policy
+++ b/seccomp/x86_64/fs_device.policy
@@ -4,6 +4,7 @@
 
 @include /usr/share/policy/crosvm/common_device.policy
 
+copy_file_range: 1
 fallocate: 1
 fchmodat: 1
 fchownat: 1