about summary refs log tree commit diff
diff options
context:
space:
mode:
authorMatthias Krüger <matthias.krueger@famsik.de>2021-11-23 19:28:12 +0100
committerGitHub <noreply@github.com>2021-11-23 19:28:12 +0100
commit3dc00111f2e24e5afef0234360e26acb58bb6e4f (patch)
tree45a294f5bb9f9fd3f4faaded44fb619eb316574c
parente52e3a4bb3efa4c75350ba11e99ebbc93a982768 (diff)
parentb490ccc22746375e154352466fb0d0deafb50194 (diff)
downloadrust-3dc00111f2e24e5afef0234360e26acb58bb6e4f.tar.gz
rust-3dc00111f2e24e5afef0234360e26acb58bb6e4f.zip
Rollup merge of #91153 - birkenfeld:kernel_copy_fallback, r=the8472
kernel_copy: avoid panic on unexpected OS error

According to documentation, the listed errnos should only occur
if the `copy_file_range` call cannot be made at all, so the
assert be correct.  However, since in practice file system
drivers (incl. FUSE etc.) can return any errno they want, we
should not panic here.

Fixes #91152
-rw-r--r--library/std/src/sys/unix/kernel_copy.rs6
1 files changed, 4 insertions, 2 deletions
diff --git a/library/std/src/sys/unix/kernel_copy.rs b/library/std/src/sys/unix/kernel_copy.rs
index a6b43229ba6..f3155fbc062 100644
--- a/library/std/src/sys/unix/kernel_copy.rs
+++ b/library/std/src/sys/unix/kernel_copy.rs
@@ -576,7 +576,7 @@ pub(super) fn copy_regular_files(reader: RawFd, writer: RawFd, max_len: u64) ->
                 return match err.raw_os_error() {
                     // when file offset + max_length > u64::MAX
                     Some(EOVERFLOW) => CopyResult::Fallback(written),
-                    Some(ENOSYS | EXDEV | EINVAL | EPERM | EOPNOTSUPP | EBADF) => {
+                    Some(ENOSYS | EXDEV | EINVAL | EPERM | EOPNOTSUPP | EBADF) if written == 0 => {
                         // Try fallback io::copy if either:
                         // - Kernel version is < 4.5 (ENOSYS¹)
                         // - Files are mounted on different fs (EXDEV)
@@ -584,12 +584,14 @@ pub(super) fn copy_regular_files(reader: RawFd, writer: RawFd, max_len: u64) ->
                         // - copy_file_range file is immutable or syscall is blocked by seccomp¹ (EPERM)
                         // - copy_file_range cannot be used with pipes or device nodes (EINVAL)
                         // - the writer fd was opened with O_APPEND (EBADF²)
+                        // and no bytes were written successfully yet.  (All these errnos should
+                        // not be returned if something was already written, but they happen in
+                        // the wild, see #91152.)
                         //
                         // ¹ these cases should be detected by the initial probe but we handle them here
                         //   anyway in case syscall interception changes during runtime
                         // ² actually invalid file descriptors would cause this too, but in that case
                         //   the fallback code path is expected to encounter the same error again
-                        assert_eq!(written, 0);
                         CopyResult::Fallback(0)
                     }
                     _ => CopyResult::Error(err, written),