From: Rick Payne <[email protected]>
Committer: Nadav Har'El <[email protected]>
Branch: master

sendfile: don't try to send beyond the end of file

Ensure that sendfile doesn't try to send beyond the end of the source
file. Added some tests, and ensured that the same result is observed under
both Linux and OSv.

Fixes #815

Signed-off-by: Rick Payne <[email protected]>
Message-Id: <[email protected]>

---
diff --git a/fs/vfs/main.cc b/fs/vfs/main.cc
--- a/fs/vfs/main.cc
+++ b/fs/vfs/main.cc
@@ -2039,6 +2039,21 @@ int sendfile(int out_fd, int in_fd, off_t *_offset, size_t count)
         offset = lseek(in_fd, 0, SEEK_CUR);
     }

+    // Constrain count to the extent of the file...
+    struct stat st;
+    if (fstat(in_fd, &st) < 0) {
+        return -1;
+    } else {
+        if (offset >= st.st_size) {
+            return 0;
+        } else if ((offset + count) >= st.st_size) {
+            count = st.st_size - offset;
+            if (count == 0) {
+                return 0;
+            }
+        }
+    }
+
     size_t bytes_to_mmap = count + (offset % mmu::page_size);
     off_t offset_for_mmap =  align_down(offset, (off_t)mmu::page_size);

diff --git a/tests/tst-sendfile.cc b/tests/tst-sendfile.cc
--- a/tests/tst-sendfile.cc
+++ b/tests/tst-sendfile.cc
@@ -163,6 +163,22 @@ int test_sendfile_on_socket(off_t *offset, size_t count)
     return listener_result == 0 ? ret : -1;
 }

+int test_extents(int testfile_readfd, size_t offset, size_t count)
+{
+    const char *out_file = "testdata_sendfile_output";
+    off_t off;
+    int write_fd = open(out_file, O_RDWR | O_TRUNC | O_CREAT, S_IRWXU);
+    if (write_fd == -1) {
+ printf("\topen() failed with error message = %s\n",strerror(errno));
+        return -1;
+    }
+    lseek(testfile_readfd, 0 , SEEK_CUR);
+    off = offset;
+    int ret  = sendfile(write_fd, testfile_readfd, &off, count);
+    close(write_fd);
+    return ret;
+}
+
 int main()
 {
     int ret;
@@ -200,12 +216,22 @@ int main()
report(test_functions[i](offset_p[j], count_array[k]) == count_array[k], message.c_str());
             }
             offset = 0;
- report(lseek(testfile_readfd, 0, SEEK_SET) == 0, "set readfd to beginning of file"); + report(lseek(testfile_readfd, 0, SEEK_SET) == 0, "set readfd to beginning of file"); report(test_functions[i](offset_p[j], size_test_file) == size_test_file, "copy entire file");
             printf("\n\n");
         }
     }

+    // Test extents...
+ report(lseek(testfile_readfd, 0, SEEK_SET) == 0, "set readfd to beginning of file"); + report(test_extents(testfile_readfd, 0, size_test_file + 1) == size_test_file, "file size extent"); + report(lseek(testfile_readfd, 0, SEEK_SET) == 0, "set readfd to beginning of file"); + report(test_extents(testfile_readfd, 10, size_test_file) == (size_test_file - 10), "file size extent with offset"); + report(lseek(testfile_readfd, 0, SEEK_SET) == 0, "set readfd to beginning of file"); + report(test_extents(testfile_readfd, size_test_file - 1, 1) == 1, "file size extent with offset (tail)"); + report(lseek(testfile_readfd, 0, SEEK_SET) == 0, "set readfd to beginning of file"); + report(test_extents(testfile_readfd, size_test_file, 1) == 0, "file size extent with offset (tail, no bytes)");
+
     /* force sendfile to fail in rest of test cases */
     ret = sendfile(100, testfile_readfd, NULL, 10);
     report(ret == -1 && errno == EBADF, "test for bad out_fd");

--
You received this message because you are subscribed to the Google Groups "OSv 
Development" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
For more options, visit https://groups.google.com/d/optout.

Reply via email to