LCOV - code coverage report
Current view: top level - source4/torture/smb2 - read_write.c (source / functions) Hit Total Coverage
Test: coverage report for v4-17-test 1498b464 Lines: 150 223 67.3 %
Date: 2024-06-13 04:01:37 Functions: 4 4 100.0 %

          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           2 : static bool run_smb2_readwritetest(struct torture_context *tctx,
      40             :                                    struct smb2_tree *t1, struct smb2_tree *t2)
      41             : {
      42           2 :         const char *lockfname = "torture2.lck";
      43           2 :         struct smb2_create f1 = {0};
      44           2 :         struct smb2_create f2 = {0};
      45           2 :         struct smb2_handle h1 = {{0}};
      46           2 :         struct smb2_handle h2 = {{0}};
      47             :         int i;
      48             :         uint8_t buf[131072];
      49           2 :         bool correct = true;
      50             :         NTSTATUS status;
      51           2 :         int ret = 0;
      52             : 
      53           2 :         ret = smb2_deltree(t1, lockfname);
      54           2 :         torture_assert(tctx, ret != -1, "unlink failed");
      55             : 
      56           2 :         f1.in.desired_access = SEC_FILE_ALL;
      57           2 :         f1.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
      58             :                              NTCREATEX_SHARE_ACCESS_WRITE;
      59           2 :         f1.in.create_disposition = FILE_CREATE;
      60           2 :         f1.in.fname = lockfname;
      61             : 
      62           2 :         status = smb2_create(t1, tctx, &f1);
      63           2 :         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           2 :         h1 = f1.out.file.handle;
      67             : 
      68           2 :         f2.in.desired_access = SEC_FILE_READ_DATA;
      69           2 :         f2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
      70             :                              NTCREATEX_SHARE_ACCESS_WRITE;
      71           2 :         f2.in.create_disposition = FILE_OPEN;
      72           2 :         f2.in.fname = lockfname;
      73             : 
      74           2 :         status = smb2_create(t2, tctx, &f2);
      75           2 :         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           2 :         h2 = f2.out.file.handle;
      79             : 
      80           2 :         torture_comment(tctx, "Checking data integrity over %d ops\n",
      81             :                         torture_numops);
      82             : 
      83          44 :         for (i = 0; i < torture_numops; i++) {
      84          20 :                 struct smb2_write w = {0};
      85          20 :                 struct smb2_read r = {0};
      86          20 :                 size_t buf_size = ((unsigned int)random()%(sizeof(buf)-1))+ 1;
      87             : 
      88          20 :                 if (i % 10 == 0) {
      89           2 :                         if (torture_setting_bool(tctx, "progress", true)) {
      90           0 :                                 torture_comment(tctx, "%d\r", i); fflush(stdout);
      91             :                         }
      92             :                 }
      93             : 
      94          20 :                 generate_random_buffer(buf, buf_size);
      95             : 
      96          20 :                 w.in.file.handle = h1;
      97          20 :                 w.in.offset = 0;
      98          20 :                 w.in.data.data = buf;
      99          20 :                 w.in.data.length = buf_size;
     100             : 
     101          20 :                 status = smb2_write(t1, &w);
     102          20 :                 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          20 :                 r.in.file.handle = h2;
     113          20 :                 r.in.offset = 0;
     114          20 :                 r.in.length = buf_size;
     115          20 :                 status = smb2_read(t2, tctx, &r);
     116          20 :                 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          20 :                 torture_assert_mem_equal_goto(tctx, r.out.data.data, buf,
     127             :                         buf_size, correct, done, "read/write compare failed\n");
     128             :         }
     129             : 
     130           2 :         status = smb2_util_close(t2, h2);
     131           2 :         torture_assert_ntstatus_ok_goto(tctx, status, correct, done,
     132             :                 talloc_asprintf(tctx, "close failed (%s)", nt_errstr(status)));
     133           2 :         ZERO_STRUCT(h2);
     134             : 
     135           2 :         status = smb2_util_close(t1, h1);
     136           2 :         torture_assert_ntstatus_ok_goto(tctx, status, correct, done,
     137             :                 talloc_asprintf(tctx, "close failed (%s)", nt_errstr(status)));
     138           2 :         ZERO_STRUCT(h1);
     139             : 
     140           2 : done:
     141           2 :         if (!smb2_util_handle_empty(h2)) {
     142           0 :                 smb2_util_close(t2, h2);
     143             :         }
     144           2 :         if (!smb2_util_handle_empty(h1)) {
     145           0 :                 smb2_util_close(t1, h1);
     146             :         }
     147             : 
     148           2 :         status = smb2_util_unlink(t1, lockfname);
     149           2 :         if (!NT_STATUS_IS_OK(status)) {
     150           0 :                 torture_comment(tctx, "unlink failed (%s)", nt_errstr(status));
     151             :         }
     152             : 
     153           2 :         return correct;
     154             : }
     155             : 
     156             : 
     157           1 : static bool run_smb2_wrap_readwritetest(struct torture_context *tctx,
     158             :                                         struct smb2_tree *tree1,
     159             :                                         struct smb2_tree *tree2)
     160             : {
     161           1 :         return run_smb2_readwritetest(tctx, tree1, tree1);
     162             : }
     163             : 
     164           1 : static bool test_rw_invalid(struct torture_context *torture, struct smb2_tree *tree)
     165             : {
     166           1 :         bool ret = true;
     167             :         NTSTATUS status;
     168             :         struct smb2_handle h;
     169             :         uint8_t buf[64*1024];
     170             :         struct smb2_read rd;
     171           1 :         struct smb2_write w = {0};
     172             :         union smb_setfileinfo sfinfo;
     173           1 :         TALLOC_CTX *tmp_ctx = talloc_new(tree);
     174             : 
     175           1 :         ZERO_STRUCT(buf);
     176             : 
     177           1 :         smb2_util_unlink(tree, FNAME);
     178             : 
     179           1 :         status = torture_smb2_testfile(tree, FNAME, &h);
     180           1 :         CHECK_STATUS(status, NT_STATUS_OK);
     181             : 
     182             :         /* set delete-on-close */
     183           1 :         ZERO_STRUCT(sfinfo);
     184           1 :         sfinfo.generic.level = RAW_SFILEINFO_DISPOSITION_INFORMATION;
     185           1 :         sfinfo.disposition_info.in.delete_on_close = 1;
     186           1 :         sfinfo.generic.in.file.handle = h;
     187           1 :         status = smb2_setinfo_file(tree, &sfinfo);
     188           1 :         CHECK_STATUS(status, NT_STATUS_OK);
     189             : 
     190           1 :         status = smb2_util_write(tree, h, buf, 0, ARRAY_SIZE(buf));
     191           1 :         CHECK_STATUS(status, NT_STATUS_OK);
     192             : 
     193           1 :         ZERO_STRUCT(rd);
     194           1 :         rd.in.file.handle = h;
     195           1 :         rd.in.length = 10;
     196           1 :         rd.in.offset = 0;
     197           1 :         rd.in.min_count = 1;
     198             : 
     199           1 :         status = smb2_read(tree, tmp_ctx, &rd);
     200           1 :         CHECK_STATUS(status, NT_STATUS_OK);
     201           1 :         CHECK_VALUE(rd.out.data.length, 10);
     202             : 
     203           1 :         rd.in.min_count = 0;
     204           1 :         rd.in.length = 10;
     205           1 :         rd.in.offset = sizeof(buf);
     206           1 :         status = smb2_read(tree, tmp_ctx, &rd);
     207           1 :         CHECK_STATUS(status, NT_STATUS_END_OF_FILE);
     208             : 
     209           1 :         rd.in.min_count = 0;
     210           1 :         rd.in.length = 0;
     211           1 :         rd.in.offset = sizeof(buf);
     212           1 :         status = smb2_read(tree, tmp_ctx, &rd);
     213           1 :         CHECK_STATUS(status, NT_STATUS_OK);
     214           1 :         CHECK_VALUE(rd.out.data.length, 0);
     215             : 
     216           1 :         rd.in.min_count = 0;
     217           1 :         rd.in.length = 1;
     218           1 :         rd.in.offset = INT64_MAX - 1;
     219           1 :         status = smb2_read(tree, tmp_ctx, &rd);
     220           1 :         CHECK_STATUS(status, NT_STATUS_END_OF_FILE);
     221             : 
     222           1 :         rd.in.min_count = 0;
     223           1 :         rd.in.length = 0;
     224           1 :         rd.in.offset = INT64_MAX;
     225           1 :         status = smb2_read(tree, tmp_ctx, &rd);
     226           1 :         CHECK_STATUS(status, NT_STATUS_OK);
     227           1 :         CHECK_VALUE(rd.out.data.length, 0);
     228             : 
     229           1 :         rd.in.min_count = 0;
     230           1 :         rd.in.length = 1;
     231           1 :         rd.in.offset = INT64_MAX;
     232           1 :         status = smb2_read(tree, tmp_ctx, &rd);
     233           1 :         CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
     234             : 
     235           1 :         rd.in.min_count = 0;
     236           1 :         rd.in.length = 0;
     237           1 :         rd.in.offset = (uint64_t)INT64_MAX + 1;
     238           1 :         status = smb2_read(tree, tmp_ctx, &rd);
     239           1 :         CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
     240             : 
     241           1 :         rd.in.min_count = 0;
     242           1 :         rd.in.length = 0;
     243           1 :         rd.in.offset = (uint64_t)INT64_MIN;
     244           1 :         status = smb2_read(tree, tmp_ctx, &rd);
     245           1 :         CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
     246             : 
     247           1 :         rd.in.min_count = 0;
     248           1 :         rd.in.length = 0;
     249           1 :         rd.in.offset = (uint64_t)(int64_t)-1;
     250           1 :         status = smb2_read(tree, tmp_ctx, &rd);
     251           1 :         CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
     252             : 
     253           1 :         rd.in.min_count = 0;
     254           1 :         rd.in.length = 0;
     255           1 :         rd.in.offset = (uint64_t)(int64_t)-2;
     256           1 :         status = smb2_read(tree, tmp_ctx, &rd);
     257           1 :         CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
     258             : 
     259           1 :         rd.in.min_count = 0;
     260           1 :         rd.in.length = 0;
     261           1 :         rd.in.offset = (uint64_t)(int64_t)-3;
     262           1 :         status = smb2_read(tree, tmp_ctx, &rd);
     263           1 :         CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
     264             : 
     265           1 :         w.in.file.handle = h;
     266           1 :         w.in.offset = (int64_t)-1;
     267           1 :         w.in.data.data = buf;
     268           1 :         w.in.data.length = ARRAY_SIZE(buf);
     269             : 
     270           1 :         status = smb2_write(tree, &w);
     271           1 :         CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
     272             : 
     273           0 :         w.in.file.handle = h;
     274           0 :         w.in.offset = (int64_t)-2;
     275           0 :         w.in.data.data = buf;
     276           0 :         w.in.data.length = ARRAY_SIZE(buf);
     277             : 
     278           0 :         status = smb2_write(tree, &w);
     279           0 :         CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
     280             : 
     281           0 :         w.in.file.handle = h;
     282           0 :         w.in.offset = INT64_MIN;
     283           0 :         w.in.data.data = buf;
     284           0 :         w.in.data.length = 1;
     285             : 
     286           0 :         status = smb2_write(tree, &w);
     287           0 :         CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
     288             : 
     289           0 :         w.in.file.handle = h;
     290           0 :         w.in.offset = INT64_MIN;
     291           0 :         w.in.data.data = buf;
     292           0 :         w.in.data.length = 0;
     293           0 :         status = smb2_write(tree, &w);
     294           0 :         CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
     295             : 
     296           0 :         w.in.file.handle = h;
     297           0 :         w.in.offset = INT64_MAX;
     298           0 :         w.in.data.data = buf;
     299           0 :         w.in.data.length = 0;
     300           0 :         status = smb2_write(tree, &w);
     301           0 :         CHECK_STATUS(status, NT_STATUS_OK);
     302           0 :         CHECK_VALUE(w.out.nwritten, 0);
     303             : 
     304           0 :         w.in.file.handle = h;
     305           0 :         w.in.offset = INT64_MAX;
     306           0 :         w.in.data.data = buf;
     307           0 :         w.in.data.length = 1;
     308           0 :         status = smb2_write(tree, &w);
     309           0 :         CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
     310             : 
     311           0 :         w.in.file.handle = h;
     312           0 :         w.in.offset = (uint64_t)INT64_MAX + 1;
     313           0 :         w.in.data.data = buf;
     314           0 :         w.in.data.length = 0;
     315           0 :         status = smb2_write(tree, &w);
     316           0 :         CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
     317             : 
     318           0 :         w.in.file.handle = h;
     319           0 :         w.in.offset = 0xfffffff0000; /* MAXFILESIZE */
     320           0 :         w.in.data.data = buf;
     321           0 :         w.in.data.length = 1;
     322           0 :         status = smb2_write(tree, &w);
     323           0 :         CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
     324             : 
     325           0 :         w.in.file.handle = h;
     326           0 :         w.in.offset = 0xfffffff0000 - 1; /* MAXFILESIZE - 1 */
     327           0 :         w.in.data.data = buf;
     328           0 :         w.in.data.length = 1;
     329           0 :         status = smb2_write(tree, &w);
     330           0 :         if (TARGET_IS_SAMBA3(torture) || TARGET_IS_SAMBA4(torture)) {
     331           0 :                 CHECK_STATUS(status, NT_STATUS_OK);
     332           0 :                 CHECK_VALUE(w.out.nwritten, 1);
     333             :         } else {
     334           0 :                 CHECK_STATUS(status, NT_STATUS_DISK_FULL);
     335             :         }
     336             : 
     337           0 :         w.in.file.handle = h;
     338           0 :         w.in.offset = 0xfffffff0000; /* MAXFILESIZE */
     339           0 :         w.in.data.data = buf;
     340           0 :         w.in.data.length = 0;
     341           0 :         status = smb2_write(tree, &w);
     342           0 :         CHECK_STATUS(status, NT_STATUS_OK);
     343           0 :         CHECK_VALUE(w.out.nwritten, 0);
     344             : 
     345           1 : done:
     346           1 :         talloc_free(tmp_ctx);
     347           1 :         return ret;
     348             : }
     349             : 
     350         964 : struct torture_suite *torture_smb2_readwrite_init(TALLOC_CTX *ctx)
     351             : {
     352         964 :         struct torture_suite *suite = torture_suite_create(ctx, "rw");
     353             : 
     354         964 :         torture_suite_add_2smb2_test(suite, "rw1", run_smb2_readwritetest);
     355         964 :         torture_suite_add_2smb2_test(suite, "rw2", run_smb2_wrap_readwritetest);
     356         964 :         torture_suite_add_1smb2_test(suite, "invalid", test_rw_invalid);
     357             : 
     358         964 :         suite->description = talloc_strdup(suite, "SMB2 Samba4 Read/Write");
     359             : 
     360         964 :         return suite;
     361             : }

Generated by: LCOV version 1.13