LCOV - code coverage report
Current view: top level - source4/torture/smb2 - read_write.c (source / functions) Hit Total Coverage
Test: coverage report for master 6248eab5 Lines: 208 223 93.3 %
Date: 2021-08-25 13:27:56 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          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         220 :         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           9 : done:
     346           5 :         talloc_free(tmp_ctx);
     347           5 :         return ret;
     348             : }
     349             : 
     350        2353 : struct torture_suite *torture_smb2_readwrite_init(TALLOC_CTX *ctx)
     351             : {
     352        2353 :         struct torture_suite *suite = torture_suite_create(ctx, "rw");
     353             : 
     354        2353 :         torture_suite_add_2smb2_test(suite, "rw1", run_smb2_readwritetest);
     355        2353 :         torture_suite_add_2smb2_test(suite, "rw2", run_smb2_wrap_readwritetest);
     356        2353 :         torture_suite_add_1smb2_test(suite, "invalid", test_rw_invalid);
     357             : 
     358        2353 :         suite->description = talloc_strdup(suite, "SMB2 Samba4 Read/Write");
     359             : 
     360        2353 :         return suite;
     361             : }

Generated by: LCOV version 1.13