Line data Source code
1 : /*
2 : Unix SMB/CIFS implementation.
3 : SMB read/write torture tester
4 : Copyright (C) Andrew Tridgell 1997-2003
5 : Copyright (C) Jelmer Vernooij 2006
6 : Copyright (C) David Mulder 2019
7 :
8 : This program is free software; you can redistribute it and/or modify
9 : it under the terms of the GNU General Public License as published by
10 : the Free Software Foundation; either version 3 of the License, or
11 : (at your option) any later version.
12 :
13 : This program is distributed in the hope that it will be useful,
14 : but WITHOUT ANY WARRANTY; without even the implied warranty of
15 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 : GNU General Public License for more details.
17 :
18 : You should have received a copy of the GNU General Public License
19 : along with this program. If not, see <http://www.gnu.org/licenses/>.
20 : */
21 : #include "includes.h"
22 : #include "torture/smbtorture.h"
23 : #include "libcli/smb2/smb2.h"
24 : #include "libcli/smb2/smb2_calls.h"
25 : #include "torture/torture.h"
26 : #include "torture/util.h"
27 : #include "torture/smb2/proto.h"
28 :
29 : #define CHECK_STATUS(_status, _expected) \
30 : torture_assert_ntstatus_equal_goto(torture, _status, _expected, \
31 : ret, done, "Incorrect status")
32 :
33 : #define CHECK_VALUE(v, correct) \
34 : torture_assert_int_equal_goto(torture, v, correct, \
35 : ret, done, "Incorrect value")
36 :
37 : #define FNAME "smb2_writetest.dat"
38 :
39 10 : static bool run_smb2_readwritetest(struct torture_context *tctx,
40 : struct smb2_tree *t1, struct smb2_tree *t2)
41 : {
42 10 : const char *lockfname = "torture2.lck";
43 10 : struct smb2_create f1 = {0};
44 10 : struct smb2_create f2 = {0};
45 10 : struct smb2_handle h1 = {{0}};
46 10 : struct smb2_handle h2 = {{0}};
47 : int i;
48 : uint8_t buf[131072];
49 10 : bool correct = true;
50 : NTSTATUS status;
51 10 : int ret = 0;
52 :
53 10 : ret = smb2_deltree(t1, lockfname);
54 10 : torture_assert(tctx, ret != -1, "unlink failed");
55 :
56 10 : f1.in.desired_access = SEC_FILE_ALL;
57 10 : f1.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
58 : NTCREATEX_SHARE_ACCESS_WRITE;
59 10 : f1.in.create_disposition = FILE_CREATE;
60 10 : f1.in.fname = lockfname;
61 :
62 10 : status = smb2_create(t1, tctx, &f1);
63 10 : torture_assert_ntstatus_ok_goto(tctx, status, correct, done,
64 : talloc_asprintf(tctx, "first open read/write of %s failed (%s)",
65 : lockfname, nt_errstr(status)));
66 10 : h1 = f1.out.file.handle;
67 :
68 10 : f2.in.desired_access = SEC_FILE_READ_DATA;
69 10 : f2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
70 : NTCREATEX_SHARE_ACCESS_WRITE;
71 10 : f2.in.create_disposition = FILE_OPEN;
72 10 : f2.in.fname = lockfname;
73 :
74 10 : status = smb2_create(t2, tctx, &f2);
75 10 : torture_assert_ntstatus_ok_goto(tctx, status, correct, done,
76 : talloc_asprintf(tctx, "second open read-only of %s failed (%s)",
77 : lockfname, nt_errstr(status)));
78 10 : h2 = f2.out.file.handle;
79 :
80 10 : torture_comment(tctx, "Checking data integrity over %d ops\n",
81 : torture_numops);
82 :
83 198 : for (i = 0; i < torture_numops; i++) {
84 100 : struct smb2_write w = {0};
85 100 : struct smb2_read r = {0};
86 100 : size_t buf_size = ((unsigned int)random()%(sizeof(buf)-1))+ 1;
87 :
88 100 : if (i % 10 == 0) {
89 10 : if (torture_setting_bool(tctx, "progress", true)) {
90 0 : torture_comment(tctx, "%d\r", i); fflush(stdout);
91 : }
92 : }
93 :
94 100 : generate_random_buffer(buf, buf_size);
95 :
96 100 : w.in.file.handle = h1;
97 100 : w.in.offset = 0;
98 100 : w.in.data.data = buf;
99 100 : w.in.data.length = buf_size;
100 :
101 100 : status = smb2_write(t1, &w);
102 100 : if (!NT_STATUS_IS_OK(status) || w.out.nwritten != buf_size) {
103 0 : torture_comment(tctx, "write failed (%s)\n",
104 : nt_errstr(status));
105 0 : torture_result(tctx, TORTURE_FAIL,
106 : "wrote %d, expected %d\n",
107 0 : (int)w.out.nwritten, (int)buf_size);
108 0 : correct = false;
109 0 : goto done;
110 : }
111 :
112 100 : r.in.file.handle = h2;
113 100 : r.in.offset = 0;
114 100 : r.in.length = buf_size;
115 100 : status = smb2_read(t2, tctx, &r);
116 100 : if (!NT_STATUS_IS_OK(status) || r.out.data.length != buf_size) {
117 0 : torture_comment(tctx, "read failed (%s)\n",
118 : nt_errstr(status));
119 0 : torture_result(tctx, TORTURE_FAIL,
120 : "read %d, expected %d\n",
121 0 : (int)r.out.data.length, (int)buf_size);
122 0 : correct = false;
123 0 : goto done;
124 : }
125 :
126 100 : torture_assert_mem_equal_goto(tctx, r.out.data.data, buf,
127 : buf_size, correct, done, "read/write compare failed\n");
128 : }
129 :
130 10 : status = smb2_util_close(t2, h2);
131 10 : torture_assert_ntstatus_ok_goto(tctx, status, correct, done,
132 : talloc_asprintf(tctx, "close failed (%s)", nt_errstr(status)));
133 10 : ZERO_STRUCT(h2);
134 :
135 10 : status = smb2_util_close(t1, h1);
136 10 : torture_assert_ntstatus_ok_goto(tctx, status, correct, done,
137 : talloc_asprintf(tctx, "close failed (%s)", nt_errstr(status)));
138 10 : ZERO_STRUCT(h1);
139 :
140 10 : done:
141 10 : if (!smb2_util_handle_empty(h2)) {
142 0 : smb2_util_close(t2, h2);
143 : }
144 10 : if (!smb2_util_handle_empty(h1)) {
145 0 : smb2_util_close(t1, h1);
146 : }
147 :
148 10 : status = smb2_util_unlink(t1, lockfname);
149 10 : if (!NT_STATUS_IS_OK(status)) {
150 0 : torture_comment(tctx, "unlink failed (%s)", nt_errstr(status));
151 : }
152 :
153 10 : return correct;
154 : }
155 :
156 :
157 5 : static bool run_smb2_wrap_readwritetest(struct torture_context *tctx,
158 : struct smb2_tree *tree1,
159 : struct smb2_tree *tree2)
160 : {
161 5 : return run_smb2_readwritetest(tctx, tree1, tree1);
162 : }
163 :
164 5 : static bool test_rw_invalid(struct torture_context *torture, struct smb2_tree *tree)
165 : {
166 5 : bool ret = true;
167 : NTSTATUS status;
168 : struct smb2_handle h;
169 : uint8_t buf[64*1024];
170 : struct smb2_read rd;
171 5 : struct smb2_write w = {0};
172 : union smb_setfileinfo sfinfo;
173 5 : TALLOC_CTX *tmp_ctx = talloc_new(tree);
174 :
175 5 : ZERO_STRUCT(buf);
176 :
177 5 : smb2_util_unlink(tree, FNAME);
178 :
179 5 : status = torture_smb2_testfile(tree, FNAME, &h);
180 5 : CHECK_STATUS(status, NT_STATUS_OK);
181 :
182 : /* set delete-on-close */
183 5 : ZERO_STRUCT(sfinfo);
184 5 : sfinfo.generic.level = RAW_SFILEINFO_DISPOSITION_INFORMATION;
185 5 : sfinfo.disposition_info.in.delete_on_close = 1;
186 5 : sfinfo.generic.in.file.handle = h;
187 5 : status = smb2_setinfo_file(tree, &sfinfo);
188 5 : CHECK_STATUS(status, NT_STATUS_OK);
189 :
190 5 : status = smb2_util_write(tree, h, buf, 0, ARRAY_SIZE(buf));
191 5 : CHECK_STATUS(status, NT_STATUS_OK);
192 :
193 5 : ZERO_STRUCT(rd);
194 5 : rd.in.file.handle = h;
195 5 : rd.in.length = 10;
196 5 : rd.in.offset = 0;
197 5 : rd.in.min_count = 1;
198 :
199 5 : status = smb2_read(tree, tmp_ctx, &rd);
200 5 : CHECK_STATUS(status, NT_STATUS_OK);
201 5 : CHECK_VALUE(rd.out.data.length, 10);
202 :
203 5 : rd.in.min_count = 0;
204 5 : rd.in.length = 10;
205 5 : rd.in.offset = sizeof(buf);
206 5 : status = smb2_read(tree, tmp_ctx, &rd);
207 5 : CHECK_STATUS(status, NT_STATUS_END_OF_FILE);
208 :
209 5 : rd.in.min_count = 0;
210 5 : rd.in.length = 0;
211 5 : rd.in.offset = sizeof(buf);
212 5 : status = smb2_read(tree, tmp_ctx, &rd);
213 5 : CHECK_STATUS(status, NT_STATUS_OK);
214 5 : CHECK_VALUE(rd.out.data.length, 0);
215 :
216 5 : rd.in.min_count = 0;
217 5 : rd.in.length = 1;
218 5 : rd.in.offset = INT64_MAX - 1;
219 5 : status = smb2_read(tree, tmp_ctx, &rd);
220 5 : CHECK_STATUS(status, NT_STATUS_END_OF_FILE);
221 :
222 5 : rd.in.min_count = 0;
223 5 : rd.in.length = 0;
224 5 : rd.in.offset = INT64_MAX;
225 5 : status = smb2_read(tree, tmp_ctx, &rd);
226 5 : CHECK_STATUS(status, NT_STATUS_OK);
227 5 : CHECK_VALUE(rd.out.data.length, 0);
228 :
229 5 : rd.in.min_count = 0;
230 5 : rd.in.length = 1;
231 5 : rd.in.offset = INT64_MAX;
232 5 : status = smb2_read(tree, tmp_ctx, &rd);
233 5 : CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
234 :
235 5 : rd.in.min_count = 0;
236 5 : rd.in.length = 0;
237 5 : rd.in.offset = (uint64_t)INT64_MAX + 1;
238 5 : status = smb2_read(tree, tmp_ctx, &rd);
239 5 : CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
240 :
241 5 : rd.in.min_count = 0;
242 5 : rd.in.length = 0;
243 5 : rd.in.offset = (uint64_t)INT64_MIN;
244 5 : status = smb2_read(tree, tmp_ctx, &rd);
245 5 : CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
246 :
247 5 : rd.in.min_count = 0;
248 5 : rd.in.length = 0;
249 5 : rd.in.offset = (uint64_t)(int64_t)-1;
250 5 : status = smb2_read(tree, tmp_ctx, &rd);
251 5 : CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
252 :
253 5 : rd.in.min_count = 0;
254 5 : rd.in.length = 0;
255 5 : rd.in.offset = (uint64_t)(int64_t)-2;
256 5 : status = smb2_read(tree, tmp_ctx, &rd);
257 5 : CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
258 :
259 5 : rd.in.min_count = 0;
260 5 : rd.in.length = 0;
261 5 : rd.in.offset = (uint64_t)(int64_t)-3;
262 5 : status = smb2_read(tree, tmp_ctx, &rd);
263 5 : CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
264 :
265 5 : w.in.file.handle = h;
266 5 : w.in.offset = (int64_t)-1;
267 5 : w.in.data.data = buf;
268 5 : w.in.data.length = ARRAY_SIZE(buf);
269 :
270 5 : status = smb2_write(tree, &w);
271 5 : CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
272 :
273 4 : w.in.file.handle = h;
274 4 : w.in.offset = (int64_t)-2;
275 4 : w.in.data.data = buf;
276 4 : w.in.data.length = ARRAY_SIZE(buf);
277 :
278 4 : status = smb2_write(tree, &w);
279 4 : CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
280 :
281 4 : w.in.file.handle = h;
282 4 : w.in.offset = INT64_MIN;
283 4 : w.in.data.data = buf;
284 4 : w.in.data.length = 1;
285 :
286 4 : status = smb2_write(tree, &w);
287 4 : CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
288 :
289 4 : w.in.file.handle = h;
290 4 : w.in.offset = INT64_MIN;
291 4 : w.in.data.data = buf;
292 4 : w.in.data.length = 0;
293 4 : status = smb2_write(tree, &w);
294 4 : CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
295 :
296 4 : w.in.file.handle = h;
297 4 : w.in.offset = INT64_MAX;
298 4 : w.in.data.data = buf;
299 4 : w.in.data.length = 0;
300 4 : status = smb2_write(tree, &w);
301 4 : CHECK_STATUS(status, NT_STATUS_OK);
302 4 : CHECK_VALUE(w.out.nwritten, 0);
303 :
304 4 : w.in.file.handle = h;
305 4 : w.in.offset = INT64_MAX;
306 4 : w.in.data.data = buf;
307 4 : w.in.data.length = 1;
308 4 : status = smb2_write(tree, &w);
309 4 : CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
310 :
311 4 : w.in.file.handle = h;
312 4 : w.in.offset = (uint64_t)INT64_MAX + 1;
313 4 : w.in.data.data = buf;
314 4 : w.in.data.length = 0;
315 4 : status = smb2_write(tree, &w);
316 4 : CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
317 :
318 4 : w.in.file.handle = h;
319 4 : w.in.offset = 0xfffffff0000; /* MAXFILESIZE */
320 4 : w.in.data.data = buf;
321 4 : w.in.data.length = 1;
322 4 : status = smb2_write(tree, &w);
323 4 : CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
324 :
325 4 : w.in.file.handle = h;
326 4 : w.in.offset = 0xfffffff0000 - 1; /* MAXFILESIZE - 1 */
327 4 : w.in.data.data = buf;
328 4 : w.in.data.length = 1;
329 4 : status = smb2_write(tree, &w);
330 4 : if (TARGET_IS_SAMBA3(torture) || TARGET_IS_SAMBA4(torture)) {
331 4 : CHECK_STATUS(status, NT_STATUS_OK);
332 4 : CHECK_VALUE(w.out.nwritten, 1);
333 : } else {
334 0 : CHECK_STATUS(status, NT_STATUS_DISK_FULL);
335 : }
336 :
337 4 : w.in.file.handle = h;
338 4 : w.in.offset = 0xfffffff0000; /* MAXFILESIZE */
339 4 : w.in.data.data = buf;
340 4 : w.in.data.length = 0;
341 4 : status = smb2_write(tree, &w);
342 4 : CHECK_STATUS(status, NT_STATUS_OK);
343 4 : CHECK_VALUE(w.out.nwritten, 0);
344 :
345 8 : done:
346 5 : talloc_free(tmp_ctx);
347 5 : return ret;
348 : }
349 :
350 2355 : struct torture_suite *torture_smb2_readwrite_init(TALLOC_CTX *ctx)
351 : {
352 2355 : struct torture_suite *suite = torture_suite_create(ctx, "rw");
353 :
354 2355 : torture_suite_add_2smb2_test(suite, "rw1", run_smb2_readwritetest);
355 2355 : torture_suite_add_2smb2_test(suite, "rw2", run_smb2_wrap_readwritetest);
356 2355 : torture_suite_add_1smb2_test(suite, "invalid", test_rw_invalid);
357 :
358 2355 : suite->description = talloc_strdup(suite, "SMB2 Samba4 Read/Write");
359 :
360 2355 : return suite;
361 : }
|