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

Generated by: LCOV version 1.14