Coverage Report

Created: 2025-07-23 07:04

/src/samba/source3/smbd/smb2_ioctl_smbtorture.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
   Unix SMB/CIFS implementation.
3
   Core SMB2 server
4
5
   Copyright (C) Stefan Metzmacher 2009
6
   Copyright (C) Jeremy Allison 2021
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
22
#include "includes.h"
23
#include "smbd/smbd.h"
24
#include "smbd/globals.h"
25
#include "../libcli/smb/smb_common.h"
26
#include "../lib/util/tevent_ntstatus.h"
27
#include "include/ntioctl.h"
28
#include "smb2_ioctl_private.h"
29
#include "librpc/gen_ndr/ioctl.h"
30
31
#undef DBGC_CLASS
32
#define DBGC_CLASS DBGC_SMB2
33
34
struct async_sleep_state {
35
  struct smbd_server_connection *sconn;
36
  files_struct *fsp;
37
};
38
39
static void smbd_fsctl_torture_async_sleep_done(struct tevent_req *subreq);
40
41
static struct tevent_req *smbd_fsctl_torture_async_sleep_send(
42
        TALLOC_CTX *mem_ctx,
43
        struct tevent_context *ev,
44
        files_struct *fsp,
45
        uint8_t msecs)
46
0
{
47
0
  struct async_sleep_state *state = NULL;
48
0
  struct tevent_req *subreq = NULL;
49
0
  bool ok;
50
51
0
  subreq = tevent_req_create(mem_ctx,
52
0
        &state,
53
0
        struct async_sleep_state);
54
0
  if (!subreq) {
55
0
    return NULL;
56
0
  }
57
58
  /*
59
   * Store the conn separately, as the test is to
60
   * see if fsp is still a valid pointer, so we can't
61
   * do anything other than test it for entry in the
62
   * open files on this server connection.
63
   */
64
0
  state->sconn = fsp->conn->sconn;
65
0
  state->fsp = fsp;
66
67
  /*
68
   * Just wait for the specified number of micro seconds,
69
   * to allow the client time to close fsp.
70
   */
71
0
  ok = tevent_req_set_endtime(subreq,
72
0
            ev,
73
0
            timeval_current_ofs(0, msecs));
74
0
  if (!ok) {
75
0
    tevent_req_nterror(subreq, NT_STATUS_NO_MEMORY);
76
0
    return tevent_req_post(subreq, ev);
77
0
  }
78
79
0
  return subreq;
80
0
}
81
82
static files_struct *find_my_fsp(struct files_struct *fsp,
83
         void *private_data)
84
0
{
85
0
  struct files_struct *myfsp = (struct files_struct *)private_data;
86
87
0
  if (fsp == myfsp) {
88
0
    return myfsp;
89
0
  }
90
0
  return NULL;
91
0
}
92
93
static bool smbd_fsctl_torture_async_sleep_recv(struct tevent_req *subreq)
94
0
{
95
0
  tevent_req_received(subreq);
96
0
  return true;
97
0
}
98
99
static void smbd_fsctl_torture_async_sleep_done(struct tevent_req *subreq)
100
0
{
101
0
  struct files_struct *found_fsp;
102
0
  struct tevent_req *req = tevent_req_callback_data(
103
0
          subreq,
104
0
          struct tevent_req);
105
0
  struct async_sleep_state *state = tevent_req_data(
106
0
          subreq,
107
0
          struct async_sleep_state);
108
109
  /* Does state->fsp still exist on state->sconn ? */
110
0
  found_fsp = files_forall(state->sconn,
111
0
         find_my_fsp,
112
0
         state->fsp);
113
114
0
  smbd_fsctl_torture_async_sleep_recv(subreq);
115
0
  TALLOC_FREE(subreq);
116
117
0
  if (found_fsp == NULL) {
118
    /*
119
     * We didn't find it - return an error to the
120
     * smb2 ioctl request. Use NT_STATUS_FILE_CLOSED so
121
     * the client can tell the difference between
122
     * a bad fsp handle and
123
     *
124
     * BUG: https://bugzilla.samba.org/show_bug.cgi?id=14769
125
     *
126
     * This request should block file closure until it
127
     * has completed.
128
     */
129
0
    tevent_req_nterror(req, NT_STATUS_FILE_CLOSED);
130
0
    return;
131
0
  }
132
0
  tevent_req_done(req);
133
0
}
134
135
struct tevent_req *smb2_ioctl_smbtorture(uint32_t ctl_code,
136
           struct tevent_context *ev,
137
           struct tevent_req *req,
138
           struct smbd_smb2_ioctl_state *state)
139
0
{
140
0
  NTSTATUS status;
141
0
  bool ok;
142
143
0
  ok = lp_parm_bool(-1, "smbd", "FSCTL_SMBTORTURE", false);
144
0
  if (!ok) {
145
0
    goto not_supported;
146
0
  }
147
148
0
  switch (ctl_code) {
149
0
  case FSCTL_SMBTORTURE_FORCE_UNACKED_TIMEOUT:
150
0
    if (state->in_input.length != 0) {
151
0
      tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
152
0
      return tevent_req_post(req, ev);
153
0
    }
154
155
0
    state->smb2req->xconn->ack.force_unacked_timeout = true;
156
0
    tevent_req_done(req);
157
0
    return tevent_req_post(req, ev);
158
159
0
  case FSCTL_SMBTORTURE_IOCTL_RESPONSE_BODY_PADDING8:
160
0
    if (state->in_input.length != 0) {
161
0
      tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
162
0
      return tevent_req_post(req, ev);
163
0
    }
164
165
0
    if (state->in_max_output > 0) {
166
0
      uint32_t size = state->in_max_output;
167
168
0
      state->out_output = data_blob_talloc(state, NULL, size);
169
0
      if (tevent_req_nomem(state->out_output.data, req)) {
170
0
        return tevent_req_post(req, ev);
171
0
      }
172
0
      memset(state->out_output.data, 8, size);
173
0
    }
174
175
0
    state->body_padding = 8;
176
0
    tevent_req_done(req);
177
0
    return tevent_req_post(req, ev);
178
179
0
  case FSCTL_SMBTORTURE_GLOBAL_READ_RESPONSE_BODY_PADDING8:
180
0
    if (state->in_input.length != 0) {
181
0
      tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
182
0
      return tevent_req_post(req, ev);
183
0
    }
184
185
0
    state->smb2req->xconn->smb2.smbtorture.read_body_padding = 8;
186
0
    tevent_req_done(req);
187
0
    return tevent_req_post(req, ev);
188
189
0
  case FSCTL_SMBTORTURE_FSP_ASYNC_SLEEP: {
190
0
    struct tevent_req *subreq = NULL;
191
192
    /* Data is 1 byte of CVAL stored seconds to delay for. */
193
0
    if (state->in_input.length != 1) {
194
0
      tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
195
0
      return tevent_req_post(req, ev);
196
0
    }
197
0
    if (state->fsp == NULL) {
198
0
      tevent_req_nterror(req, NT_STATUS_INVALID_HANDLE);
199
0
      return tevent_req_post(req, ev);
200
0
    }
201
202
0
    subreq = smbd_fsctl_torture_async_sleep_send(
203
0
            req,
204
0
            ev,
205
0
            state->fsp,
206
0
            CVAL(state->in_input.data,0));
207
0
    if (subreq == NULL) {
208
0
      tevent_req_nterror(req, NT_STATUS_NO_MEMORY);
209
0
      return tevent_req_post(req, ev);
210
0
    }
211
0
    tevent_req_set_callback(subreq,
212
0
          smbd_fsctl_torture_async_sleep_done,
213
0
          req);
214
0
    return req;
215
0
        }
216
217
0
  default:
218
0
    goto not_supported;
219
0
  }
220
221
0
not_supported:
222
0
  if (IS_IPC(state->smbreq->conn)) {
223
0
    status = NT_STATUS_FS_DRIVER_REQUIRED;
224
0
  } else {
225
0
    status = NT_STATUS_INVALID_DEVICE_REQUEST;
226
0
  }
227
228
0
  tevent_req_nterror(req, status);
229
0
  return tevent_req_post(req, ev);
230
0
}