LCOV - code coverage report
Current view: top level - source4/torture/vfs - streams_xattr.c (source / functions) Hit Total Coverage
Test: coverage report for v4-17-lts cc996e7c Lines: 5 87 5.7 %
Date: 2025-10-17 03:45:34 Functions: 1 4 25.0 %

          Line data    Source code
       1             : /*
       2             :    Unix SMB/CIFS implementation.
       3             : 
       4             :    Copyright (C) Andrew Walker (2025)
       5             : 
       6             :    This program is free software; you can redistribute it and/or modify
       7             :    it under the terms of the GNU General Public License as published by
       8             :    the Free Software Foundation; either version 3 of the License, or
       9             :    (at your option) any later version.
      10             : 
      11             :    This program is distributed in the hope that it will be useful,
      12             :    but WITHOUT ANY WARRANTY; without even the implied warranty of
      13             :    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      14             :    GNU General Public License for more details.
      15             : 
      16             :    You should have received a copy of the GNU General Public License
      17             :    along with this program.  If not, see <http://www.gnu.org/licenses/>.
      18             : */
      19             : 
      20             : #include "includes.h"
      21             : #include "lib/cmdline/cmdline.h"
      22             : #include "libcli/smb2/smb2.h"
      23             : #include "libcli/smb2/smb2_calls.h"
      24             : #include "libcli/smb/smbXcli_base.h"
      25             : #include "torture/torture.h"
      26             : #include "torture/vfs/proto.h"
      27             : #include "libcli/resolve/resolve.h"
      28             : #include "torture/util.h"
      29             : #include "torture/smb2/proto.h"
      30             : #include "lib/param/param.h"
      31             : 
      32             : #define BASEDIR "smb2-testads"
      33             : 
      34             : 
      35           0 : static bool get_stream_handle(struct torture_context *tctx,
      36             :                               struct smb2_tree *tree,
      37             :                               const char *dname,
      38             :                               const char *fname,
      39             :                               const char *sname,
      40             :                               struct smb2_handle *hdl_in)
      41             : {
      42           0 :         bool ret = true;
      43             :         NTSTATUS status;
      44           0 :         struct smb2_handle fhandle = {{0}};
      45           0 :         struct smb2_handle dhandle = {{0}};
      46             : 
      47           0 :         torture_comment(tctx, "Create dir\n");
      48             : 
      49           0 :         status = torture_smb2_testdir(tree, dname, &dhandle);
      50           0 :         torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "torture_smb2_testdir\n");
      51             : 
      52           0 :         torture_comment(tctx, "Create file\n");
      53             : 
      54           0 :         status = torture_smb2_testfile(tree, fname, &fhandle);
      55           0 :         torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "torture_smb2_testfile\n");
      56             : 
      57           0 :         status = torture_smb2_testfile(tree, sname, hdl_in);
      58           0 :         torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "torture_smb2_testfile\n");
      59             : 
      60           0 : done:
      61           0 :         if (!smb2_util_handle_empty(fhandle)) {
      62           0 :                 smb2_util_close(tree, fhandle);
      63             :         }
      64           0 :         if (!smb2_util_handle_empty(dhandle)) {
      65           0 :                 smb2_util_close(tree, dhandle);
      66             :         }
      67           0 :         return ret;
      68             : }
      69             : 
      70           0 : static bool read_stream(struct torture_context *tctx,
      71             :                         TALLOC_CTX *mem_ctx,
      72             :                         struct smb2_tree *tree,
      73             :                         struct smb2_handle *stream_hdl,
      74             :                         off_t read_offset,
      75             :                         size_t read_count,
      76             :                         char **data_out,
      77             :                         size_t *data_out_sz)
      78             : {
      79             :         NTSTATUS status;
      80             :         struct smb2_read r;
      81           0 :         bool ret = true;
      82             : 
      83           0 :         ZERO_STRUCT(r);
      84           0 :         r.in.file.handle = *stream_hdl;
      85           0 :         r.in.length = read_count;
      86           0 :         r.in.offset = read_offset;
      87             : 
      88           0 :         status = smb2_read(tree, mem_ctx, &r);
      89           0 :         torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "stream read\n");
      90             : 
      91           0 :         *data_out = (char *)r.out.data.data;
      92           0 :         *data_out_sz = r.out.data.length;
      93             : 
      94           0 : done:
      95           0 :         return ret;
      96             : }
      97             : 
      98             : 
      99             : #define WRITE_PAYLOAD "canary"
     100             : #define ADS_LEN 1024
     101             : #define ADS_OFF_TAIL ADS_LEN - sizeof(WRITE_PAYLOAD)
     102             : 
     103           0 : static bool test_streams_pwrite_hole(struct torture_context *tctx,
     104             :                                      struct smb2_tree *tree)
     105             : {
     106             :         NTSTATUS status;
     107             :         bool ok;
     108           0 :         bool ret = true;
     109           0 :         const char *dname = BASEDIR "\\testdir";
     110           0 :         const char *fname = BASEDIR "\\testdir\\testfile";
     111           0 :         const char *sname = BASEDIR "\\testdir\\testfile:test_stream";
     112           0 :         const char *canary = "canary";
     113           0 :         struct smb2_handle shandle = {{0}};
     114           0 :         TALLOC_CTX *tmp_ctx = NULL;
     115           0 :         char *data = NULL;
     116             :         size_t data_sz, i;
     117             : 
     118           0 :         ok = smb2_util_setup_dir(tctx, tree, BASEDIR);
     119           0 :         torture_assert_goto(tctx, ok == true, ret, done, "Unable to setup testdir\n");
     120             : 
     121           0 :         tmp_ctx = talloc_new(tree);
     122           0 :         torture_assert_goto(tctx, tmp_ctx != NULL, ret, done, "Memory failure\n");
     123             : 
     124           0 :         ok = get_stream_handle(tctx, tree, dname, fname, sname, &shandle);
     125           0 :         if (!ok) {
     126             :                 // torture assert already set
     127           0 :                 goto done;
     128             :         }
     129             : 
     130             :         /*
     131             :          * We're going to write a string at the beginning at the ADS, then write the same
     132             :          * string at a later offset, introducing a hole in the file
     133             :          */
     134           0 :         torture_comment(tctx, "writing at varying offsets to create hole\n");
     135           0 :         status = smb2_util_write(tree, shandle, WRITE_PAYLOAD, 0, sizeof(WRITE_PAYLOAD));
     136           0 :         if (!NT_STATUS_IS_OK(status)) {
     137           0 :                 torture_comment(tctx, "Failed to write %zu bytes to "
     138             :                     "stream at offset 0\n", sizeof(canary));
     139           0 :                 return false;
     140             :         }
     141             : 
     142           0 :         status = smb2_util_write(tree, shandle, WRITE_PAYLOAD, ADS_OFF_TAIL, sizeof(WRITE_PAYLOAD));
     143           0 :         if (!NT_STATUS_IS_OK(status)) {
     144           0 :                 torture_comment(tctx, "Failed to write %zu bytes to "
     145             :                     "stream at offset 1018\n", sizeof(canary));
     146           0 :                 return false;
     147             :         }
     148             : 
     149             :         /* Now we'll read the stream contents */
     150           0 :         torture_comment(tctx, "Read stream data\n");
     151           0 :         ok = read_stream(tctx, tmp_ctx, tree, &shandle, 0, ADS_LEN, &data, &data_sz);
     152           0 :         if (!ok) {
     153             :                 // torture assert already set
     154           0 :                 goto done;
     155             :         }
     156             : 
     157           0 :         torture_assert_goto(tctx, data_sz == ADS_LEN, ret, done, "Short read on ADS\n");
     158             : 
     159             :         /* Make sure our strings actually got written */
     160           0 :         if (strncmp(data, WRITE_PAYLOAD, sizeof(WRITE_PAYLOAD)) != 0) {
     161           0 :                 torture_result(tctx, TORTURE_FAIL,
     162             :                                "Payload write at beginning of file failed");
     163           0 :                 ret = false;
     164           0 :                 goto done;
     165             :         }
     166             : 
     167           0 :         if (strncmp(data + ADS_OFF_TAIL, WRITE_PAYLOAD, sizeof(WRITE_PAYLOAD)) != 0) {
     168           0 :                 torture_result(tctx, TORTURE_FAIL,
     169             :                                "Payload write at end of file failed");
     170           0 :                 ret = false;
     171           0 :                 goto done;
     172             :         }
     173             : 
     174             :         /* Now we'll check that the hole is full of null bytes */
     175           0 :         for (i = sizeof(WRITE_PAYLOAD); i < ADS_OFF_TAIL; i++) {
     176           0 :                 if (data[i] != '\0') {
     177           0 :                         torture_comment(tctx, "idx: %zu, got 0x%02x when expected 0x00\n",
     178           0 :                                         i, (uint8_t)data[i]);
     179           0 :                         torture_result(tctx, TORTURE_FAIL,
     180             :                                        "0x%08x: unexpected non-null byte in ADS read\n",
     181           0 :                                        data[i]);
     182           0 :                         ret = false;
     183           0 :                         goto done;
     184             :                 }
     185             :         }
     186             : 
     187           0 : done:
     188           0 :         talloc_free(tmp_ctx);
     189             : 
     190           0 :         if (!smb2_util_handle_empty(shandle)) {
     191           0 :                 smb2_util_close(tree, shandle);
     192             :         }
     193             : 
     194           0 :         smb2_deltree(tree, BASEDIR);
     195             : 
     196           0 :         return ret;
     197             : }
     198             : 
     199             : /*
     200             :    basic testing of vfs_streams_xattr
     201             : */
     202         964 : struct torture_suite *torture_vfs_streams_xattr(TALLOC_CTX *ctx)
     203             : {
     204         964 :         struct torture_suite *suite = torture_suite_create(ctx, "streams_xattr");
     205             : 
     206         964 :         torture_suite_add_1smb2_test(suite, "streams-pwrite-hole", test_streams_pwrite_hole);
     207             : 
     208         964 :         suite->description = talloc_strdup(suite, "vfs_streams_xattr tests");
     209             : 
     210         964 :         return suite;
     211             : }

Generated by: LCOV version 1.13