7#include <sys/sendfile.h>
9static int combinations(
int kind) {
10 int failed = 0, alias = -1;
11 struct tf_file input = {.fd = -1}, output = {.fd = -1};
12 CHECK(!tf_create(&input,
"/tmp", 128, 31) && !tf_create(&output,
"/tmp", 128, 73));
13 CHECK((alias = dup(input.fd)) >= 0);
14 for (
int explicit_input = 0; explicit_input < 2; ++explicit_input) {
15 for (
int explicit_output = 0; explicit_output < (kind == TF_COPY_RANGE ? 2 : 1);
17 off_t from = 3, to = 11;
18 const off_t source = explicit_input ? from : 9, destination = explicit_output ? to : 17;
19 CHECK(lseek(input.fd, 9, SEEK_SET) == 9 && lseek(output.fd, 17, SEEK_SET) == 17);
20 CHECK(tf_copy(kind, alias, explicit_input ? &from : NULL, output.fd,
21 explicit_output ? &to : NULL, 25) == 25);
22 CHECK(from == (explicit_input ? 28 : 3) && to == (explicit_output ? 36 : 11));
23 CHECK(lseek(input.fd, 0, SEEK_CUR) == (explicit_input ? 9 : 34));
24 CHECK(lseek(output.fd, 0, SEEK_CUR) == (explicit_output ? 17 : 42));
25 CHECK(!tf_verify(output.fd, destination, 25, source, 31));
35static int same_file(
void) {
36 int failed = 0, alias = -1, separate = -1;
37 struct tf_file file = {.fd = -1};
38 unsigned char before[64], after[64];
39 CHECK(!tf_create(&file,
"/tmp", 64, 43));
40 CHECK((alias = dup(file.fd)) >= 0 && (separate = open(file.path, O_RDWR)) >= 0);
41 CHECK(lseek(file.fd, 7, SEEK_SET) == 7);
42 CHECK(sendfile(alias, file.fd, NULL, 9) == 9);
43 CHECK(lseek(file.fd, 0, SEEK_CUR) == 16 && lseek(alias, 0, SEEK_CUR) == 16);
44 CHECK(!tf_verify(file.fd, 0, 64, 0, 43));
45 CHECK(copy_file_range(file.fd, NULL, alias, NULL, 9, 0) == -1 && errno == EINVAL);
46 CHECK(lseek(alias, 0, SEEK_CUR) == 16);
47 CHECK(copy_file_range(file.fd, NULL, alias, NULL, 0, 0) == 0);
48 off_t from = 0, to = 32;
49 CHECK(copy_file_range(file.fd, &from, separate, &to, 16, 0) == 16);
50 CHECK(from == 16 && to == 48 && !tf_verify(file.fd, 32, 16, 0, 43));
51 CHECK(lseek(file.fd, 0, SEEK_CUR) == 16 && lseek(separate, 0, SEEK_CUR) == 0);
52 CHECK(pread(file.fd, before,
sizeof(before), 0) ==
sizeof(before));
55 CHECK(copy_file_range(file.fd, &from, separate, &to, 16, 0) == -1 && errno == EINVAL);
56 CHECK(from == 0 && to == 8);
57 CHECK(pread(file.fd, after,
sizeof(after), 0) ==
sizeof(after) &&
58 !memcmp(before, after,
sizeof(before)));
62 CHECK(copy_file_range(file.fd, &from, alias, &to, 40, 0) == 16);
63 CHECK(from == 64 && to == 48 && !tf_verify(file.fd, 32, 16, 48, 43));
64 CHECK(lseek(file.fd, 0, SEEK_CUR) == 16);
65 CHECK(lseek(file.fd, 64, SEEK_SET) == 64);
66 CHECK(copy_file_range(file.fd, NULL, alias, NULL, 4, 0) == 0);
75static int invalid_ranges(
void) {
77 struct tf_file input = {.fd = -1}, output = {.fd = -1};
78 const size_t page = sysconf(_SC_PAGESIZE);
79 void* denied = MAP_FAILED;
80 CHECK(!tf_create(&input,
"/tmp", 64, 19) && !tf_create(&output,
"/tmp", 64, 61));
81 denied = mmap(NULL, page, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
82 CHECK(denied != MAP_FAILED);
83 for (
int kind = 0; kind < 2; ++kind) {
85 CHECK(tf_copy(kind, input.fd, &offset, output.fd, NULL, 1) == -1 && errno == EINVAL);
87 CHECK(tf_copy(kind, input.fd, denied, output.fd, NULL, 1) == -1 && errno == EFAULT);
90 CHECK(copy_file_range(input.fd, &from, output.fd, denied, 1, 0) == -1 && errno == EFAULT);
93 CHECK(copy_file_range(input.fd, NULL, output.fd, &to, 1, 0) == -1 && errno == EINVAL);
96 CHECK(copy_file_range(input.fd, NULL, output.fd, &to, SIZE_MAX, 0) == -1 && errno == EOVERFLOW);
99 CHECK(copy_file_range(input.fd, &from, output.fd, NULL, SIZE_MAX, 0) == -1 && errno == EOVERFLOW);
101 from = INT64_MAX - 7;
102 CHECK(sendfile(output.fd, input.fd, &from, 16) == -1 && errno == EINVAL);
103 CHECK(from == INT64_MAX - 7);
104 CHECK(copy_file_range(input.fd, &from, output.fd, NULL, 16, 0) == 0);
105 CHECK(from == INT64_MAX - 7);
106 CHECK(copy_file_range(input.fd, NULL, output.fd, NULL, 1, 1) == -1 && errno == EINVAL);
107 CHECK(copy_file_range(input.fd, NULL, output.fd, NULL, 0, 1) == -1 && errno == EINVAL);
108 CHECK(!tf_verify(output.fd, 0, 64, 0, 61));
109 CHECK(lseek(input.fd, 0, SEEK_CUR) == 0 && lseek(output.fd, 0, SEEK_CUR) == 0);
111 if (denied != MAP_FAILED)
112 munmap(denied, page);
117static int late_copyout(
void) {
119 struct tf_file input = {.fd = -1}, output = {.fd = -1};
120 const size_t page = sysconf(_SC_PAGESIZE);
121 off_t* readonly = MAP_FAILED;
122 CHECK(!tf_create(&input,
"/tmp", 64, 17) && !tf_create(&output,
"/tmp", 128, 91));
123 readonly = mmap(NULL, page, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
124 CHECK(readonly != MAP_FAILED);
126 CHECK(!mprotect(readonly, page, PROT_READ));
127 CHECK(lseek(input.fd, 13, SEEK_SET) == 13);
128 CHECK(sendfile(output.fd, input.fd, readonly, 4) == -1 && errno == EFAULT);
129 CHECK(*readonly == 8 && lseek(input.fd, 0, SEEK_CUR) == 13 && lseek(output.fd, 0, SEEK_CUR) == 4);
130 CHECK(!tf_verify(output.fd, 0, 4, 8, 17));
132 CHECK(copy_file_range(input.fd, readonly, output.fd, &to, 4, 0) == -1 && errno == EFAULT);
133 CHECK(to == 28 && *readonly == 8 && !tf_verify(output.fd, 24, 4, 8, 17));
134 CHECK(lseek(output.fd, 0, SEEK_CUR) == 4);
136 CHECK(copy_file_range(input.fd, &from, output.fd, readonly, 4, 0) == -1 && errno == EFAULT);
137 CHECK(from == 7 && *readonly == 8 && !tf_verify(output.fd, 8, 4, 3, 17));
138 CHECK(copy_file_range(input.fd, readonly, output.fd, NULL, 4, 0) == -1 && errno == EFAULT);
139 CHECK(lseek(output.fd, 0, SEEK_CUR) == 8 && !tf_verify(output.fd, 4, 4, 8, 17));
140 CHECK(copy_file_range(input.fd, NULL, output.fd, readonly, 4, 0) == -1 && errno == EFAULT);
141 CHECK(lseek(input.fd, 0, SEEK_CUR) == 17 && !tf_verify(output.fd, 8, 4, 13, 17));
142 CHECK(copy_file_range(input.fd, readonly, output.fd, NULL, 0, 0) == 0);
143 CHECK(sendfile(output.fd, input.fd, readonly, 0) == -1 && errno == EFAULT);
144 CHECK(sendfile(-1, input.fd, readonly, 1) == -1 && errno == EFAULT);
145 CHECK(copy_file_range(input.fd, readonly, output.fd, NULL, 0, 1) == -1 && errno == EINVAL);
146 CHECK(!mprotect(readonly, page, PROT_READ | PROT_WRITE));
148 CHECK(!mprotect(readonly, page, PROT_READ));
149 CHECK(copy_file_range(input.fd, readonly, output.fd, NULL, 4, 0) == 0);
150 CHECK(sendfile(output.fd, input.fd, readonly, 4) == -1 && errno == EFAULT);
151 CHECK(*readonly == 64 && lseek(input.fd, 0, SEEK_CUR) == 17 &&
152 lseek(output.fd, 0, SEEK_CUR) == 8);
154 if (readonly != MAP_FAILED)
155 munmap(readonly, page);
160int transfer_offsets(
void) {
161 return combinations(TF_SENDFILE) || combinations(TF_COPY_RANGE) || same_file() ||
162 invalid_ranges() || late_copyout();