Line data Source code
1 : /*
2 : * Unix SMB/CIFS implementation.
3 : * Samba VFS module for delay injection in VFS calls
4 : * Copyright (C) Ralph Boehme 2018
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 "locking/share_mode_lock.h"
22 : #include "smbd/smbd.h"
23 : #include "lib/util/tevent_unix.h"
24 : #include "lib/global_contexts.h"
25 :
26 : #undef DBGC_CLASS
27 : #define DBGC_CLASS DBGC_VFS
28 :
29 12 : static void inject_delay(const char *vfs_func, vfs_handle_struct *handle)
30 : {
31 : int delay;
32 :
33 12 : delay = lp_parm_int(SNUM(handle->conn), "delay_inject", vfs_func, 0);
34 12 : if (delay == 0) {
35 10 : return;
36 : }
37 :
38 2 : DBG_DEBUG("Injected delay for [%s] of [%d] ms\n", vfs_func, delay);
39 :
40 2 : smb_msleep(delay);
41 : }
42 :
43 12 : static int vfs_delay_inject_fntimes(vfs_handle_struct *handle,
44 : files_struct *fsp,
45 : struct smb_file_time *ft)
46 : {
47 12 : inject_delay("fntimes", handle);
48 :
49 12 : return SMB_VFS_NEXT_FNTIMES(handle, fsp, ft);
50 : }
51 :
52 : struct vfs_delay_inject_pread_state {
53 : struct tevent_context *ev;
54 : struct vfs_handle_struct *handle;
55 : struct files_struct *fsp;
56 : void *data;
57 : size_t n;
58 : off_t offset;
59 : ssize_t ret;
60 : struct vfs_aio_state vfs_aio_state;
61 : };
62 :
63 : static void vfs_delay_inject_pread_wait_done(struct tevent_req *subreq);
64 : static void vfs_delay_inject_pread_done(struct tevent_req *subreq);
65 :
66 4 : static struct tevent_req *vfs_delay_inject_pread_send(
67 : struct vfs_handle_struct *handle,
68 : TALLOC_CTX *mem_ctx,
69 : struct tevent_context *ev,
70 : struct files_struct *fsp,
71 : void *data,
72 : size_t n,
73 : off_t offset)
74 : {
75 4 : struct tevent_req *req = NULL, *subreq = NULL;
76 4 : struct vfs_delay_inject_pread_state *state = NULL;
77 : int delay;
78 : struct timeval delay_tv;
79 :
80 4 : delay = lp_parm_int(
81 4 : SNUM(handle->conn), "delay_inject", "pread_send", 0);
82 4 : delay_tv = tevent_timeval_current_ofs(delay / 1000,
83 4 : (delay * 1000) % 1000000);
84 :
85 4 : req = tevent_req_create(mem_ctx, &state,
86 : struct vfs_delay_inject_pread_state);
87 4 : if (req == NULL) {
88 0 : return NULL;
89 : }
90 4 : *state = (struct vfs_delay_inject_pread_state) {
91 : .ev = ev,
92 : .handle = handle,
93 : .fsp = fsp,
94 : .data = data,
95 : .n = n,
96 : .offset = offset,
97 : };
98 :
99 4 : if (delay == 0) {
100 0 : subreq = SMB_VFS_NEXT_PREAD_SEND(state,
101 : state->ev,
102 : state->handle,
103 : state->fsp,
104 : state->data,
105 : state->n,
106 : state->offset);
107 0 : if (tevent_req_nomem(subreq, req)) {
108 0 : return tevent_req_post(req, ev);
109 : }
110 0 : tevent_req_set_callback(subreq,
111 : vfs_delay_inject_pread_done,
112 : req);
113 0 : return req;
114 : }
115 :
116 4 : subreq = tevent_wakeup_send(state, ev, delay_tv);
117 4 : if (tevent_req_nomem(subreq, req)) {
118 0 : return tevent_req_post(req, ev);
119 : }
120 4 : tevent_req_set_callback(subreq, vfs_delay_inject_pread_wait_done, req);
121 4 : return req;
122 : }
123 :
124 :
125 4 : static void vfs_delay_inject_pread_wait_done(struct tevent_req *subreq)
126 : {
127 4 : struct tevent_req *req = tevent_req_callback_data(
128 : subreq, struct tevent_req);
129 4 : struct vfs_delay_inject_pread_state *state = tevent_req_data(
130 : req, struct vfs_delay_inject_pread_state);
131 : bool ok;
132 :
133 4 : ok = tevent_wakeup_recv(subreq);
134 4 : TALLOC_FREE(subreq);
135 4 : if (!ok) {
136 0 : tevent_req_error(req, EIO);
137 0 : return;
138 : }
139 :
140 4 : subreq = SMB_VFS_NEXT_PREAD_SEND(state,
141 : state->ev,
142 : state->handle,
143 : state->fsp,
144 : state->data,
145 : state->n,
146 : state->offset);
147 4 : if (tevent_req_nomem(subreq, req)) {
148 0 : return;
149 : }
150 4 : tevent_req_set_callback(subreq, vfs_delay_inject_pread_done, req);
151 : }
152 :
153 4 : static void vfs_delay_inject_pread_done(struct tevent_req *subreq)
154 : {
155 4 : struct tevent_req *req = tevent_req_callback_data(
156 : subreq, struct tevent_req);
157 4 : struct vfs_delay_inject_pread_state *state = tevent_req_data(
158 : req, struct vfs_delay_inject_pread_state);
159 :
160 4 : state->ret = SMB_VFS_PREAD_RECV(subreq, &state->vfs_aio_state);
161 4 : TALLOC_FREE(subreq);
162 :
163 4 : tevent_req_done(req);
164 4 : }
165 :
166 4 : static ssize_t vfs_delay_inject_pread_recv(struct tevent_req *req,
167 : struct vfs_aio_state *vfs_aio_state)
168 : {
169 4 : struct vfs_delay_inject_pread_state *state = tevent_req_data(
170 : req, struct vfs_delay_inject_pread_state);
171 :
172 4 : if (tevent_req_is_unix_error(req, &vfs_aio_state->error)) {
173 0 : return -1;
174 : }
175 :
176 4 : *vfs_aio_state = state->vfs_aio_state;
177 4 : return state->ret;
178 : }
179 :
180 : struct vfs_delay_inject_pwrite_state {
181 : struct tevent_context *ev;
182 : struct vfs_handle_struct *handle;
183 : struct files_struct *fsp;
184 : const void *data;
185 : size_t n;
186 : off_t offset;
187 : ssize_t ret;
188 : struct vfs_aio_state vfs_aio_state;
189 : };
190 :
191 : static void vfs_delay_inject_pwrite_wait_done(struct tevent_req *subreq);
192 : static void vfs_delay_inject_pwrite_done(struct tevent_req *subreq);
193 :
194 16 : static struct tevent_req *vfs_delay_inject_pwrite_send(
195 : struct vfs_handle_struct *handle,
196 : TALLOC_CTX *mem_ctx,
197 : struct tevent_context *ev,
198 : struct files_struct *fsp,
199 : const void *data,
200 : size_t n,
201 : off_t offset)
202 : {
203 16 : struct tevent_req *req = NULL, *subreq = NULL;
204 16 : struct vfs_delay_inject_pwrite_state *state = NULL;
205 : int delay;
206 : struct timeval delay_tv;
207 :
208 16 : delay = lp_parm_int(
209 16 : SNUM(handle->conn), "delay_inject", "pwrite_send", 0);
210 16 : delay_tv = tevent_timeval_current_ofs(delay / 1000,
211 16 : (delay * 1000) % 1000000);
212 :
213 16 : req = tevent_req_create(mem_ctx, &state,
214 : struct vfs_delay_inject_pwrite_state);
215 16 : if (req == NULL) {
216 0 : return NULL;
217 : }
218 16 : *state = (struct vfs_delay_inject_pwrite_state) {
219 : .ev = ev,
220 : .handle = handle,
221 : .fsp = fsp,
222 : .data = data,
223 : .n = n,
224 : .offset = offset,
225 : };
226 :
227 16 : if (delay == 0) {
228 2 : subreq = SMB_VFS_NEXT_PWRITE_SEND(state,
229 : state->ev,
230 : state->handle,
231 : state->fsp,
232 : state->data,
233 : state->n,
234 : state->offset);
235 2 : if (tevent_req_nomem(subreq, req)) {
236 0 : return tevent_req_post(req, ev);
237 : }
238 2 : tevent_req_set_callback(subreq,
239 : vfs_delay_inject_pwrite_done,
240 : req);
241 2 : return req;
242 : }
243 :
244 14 : subreq = tevent_wakeup_send(state, ev, delay_tv);
245 14 : if (tevent_req_nomem(subreq, req)) {
246 0 : return tevent_req_post(req, ev);
247 : }
248 14 : tevent_req_set_callback(
249 : subreq, vfs_delay_inject_pwrite_wait_done, req);
250 14 : return req;
251 : }
252 :
253 :
254 10 : static void vfs_delay_inject_pwrite_wait_done(struct tevent_req *subreq)
255 : {
256 10 : struct tevent_req *req = tevent_req_callback_data(
257 : subreq, struct tevent_req);
258 10 : struct vfs_delay_inject_pwrite_state *state = tevent_req_data(
259 : req, struct vfs_delay_inject_pwrite_state);
260 : bool ok;
261 :
262 10 : ok = tevent_wakeup_recv(subreq);
263 10 : TALLOC_FREE(subreq);
264 10 : if (!ok) {
265 0 : tevent_req_error(req, EIO);
266 0 : return;
267 : }
268 :
269 10 : subreq = SMB_VFS_NEXT_PWRITE_SEND(state,
270 : state->ev,
271 : state->handle,
272 : state->fsp,
273 : state->data,
274 : state->n,
275 : state->offset);
276 10 : if (tevent_req_nomem(subreq, req)) {
277 0 : return;
278 : }
279 10 : tevent_req_set_callback(subreq, vfs_delay_inject_pwrite_done, req);
280 : }
281 :
282 12 : static void vfs_delay_inject_pwrite_done(struct tevent_req *subreq)
283 : {
284 12 : struct tevent_req *req = tevent_req_callback_data(
285 : subreq, struct tevent_req);
286 12 : struct vfs_delay_inject_pwrite_state *state = tevent_req_data(
287 : req, struct vfs_delay_inject_pwrite_state);
288 :
289 12 : state->ret = SMB_VFS_PWRITE_RECV(subreq, &state->vfs_aio_state);
290 12 : TALLOC_FREE(subreq);
291 :
292 12 : tevent_req_done(req);
293 12 : }
294 :
295 12 : static ssize_t vfs_delay_inject_pwrite_recv(struct tevent_req *req,
296 : struct vfs_aio_state *vfs_aio_state)
297 : {
298 12 : struct vfs_delay_inject_pwrite_state *state = tevent_req_data(
299 : req, struct vfs_delay_inject_pwrite_state);
300 :
301 12 : if (tevent_req_is_unix_error(req, &vfs_aio_state->error)) {
302 0 : return -1;
303 : }
304 :
305 12 : *vfs_aio_state = state->vfs_aio_state;
306 12 : return state->ret;
307 : }
308 :
309 : struct vfs_delay_inject_brl_lock_state {
310 : struct vfs_delay_inject_brl_lock_state *prev, *next;
311 : struct files_struct *fsp;
312 : struct GUID req_guid;
313 : struct timeval delay_tv;
314 : struct tevent_timer *delay_te;
315 : };
316 :
317 : static struct vfs_delay_inject_brl_lock_state *brl_lock_states;
318 :
319 30 : static int vfs_delay_inject_brl_lock_state_destructor(struct vfs_delay_inject_brl_lock_state *state)
320 : {
321 30 : DLIST_REMOVE(brl_lock_states, state);
322 30 : return 0;
323 : }
324 :
325 16 : static void vfs_delay_inject_brl_lock_timer(struct tevent_context *ev,
326 : struct tevent_timer *te,
327 : struct timeval current_time,
328 : void *private_data)
329 : {
330 : struct vfs_delay_inject_brl_lock_state *state =
331 16 : talloc_get_type_abort(private_data,
332 : struct vfs_delay_inject_brl_lock_state);
333 : NTSTATUS status;
334 :
335 16 : TALLOC_FREE(state->delay_te);
336 :
337 16 : status = share_mode_wakeup_waiters(state->fsp->file_id);
338 16 : if (!NT_STATUS_IS_OK(status)) {
339 : struct file_id_buf idbuf;
340 0 : DBG_ERR("share_mode_wakeup_waiters(%s) %s\n",
341 : file_id_str_buf(state->fsp->file_id, &idbuf),
342 : nt_errstr(status));
343 : }
344 16 : }
345 :
346 60 : static NTSTATUS vfs_delay_inject_brl_lock_windows(struct vfs_handle_struct *handle,
347 : struct byte_range_lock *br_lck,
348 : struct lock_struct *plock)
349 : {
350 60 : struct files_struct *fsp = brl_fsp(br_lck);
351 60 : TALLOC_CTX *req_mem_ctx = brl_req_mem_ctx(br_lck);
352 60 : const struct GUID *req_guid = brl_req_guid(br_lck);
353 60 : struct vfs_delay_inject_brl_lock_state *state = NULL;
354 : bool expired;
355 :
356 60 : for (state = brl_lock_states; state != NULL; state = state->next) {
357 : bool match;
358 :
359 30 : match = GUID_equal(&state->req_guid, req_guid);
360 30 : if (match) {
361 30 : break;
362 : }
363 : }
364 :
365 60 : if (state == NULL) {
366 : int delay;
367 : bool use_timer;
368 :
369 30 : state = talloc_zero(req_mem_ctx,
370 : struct vfs_delay_inject_brl_lock_state);
371 30 : if (state == NULL) {
372 0 : return NT_STATUS_NO_MEMORY;
373 : }
374 30 : state->fsp = fsp;
375 30 : state->req_guid = *req_guid;
376 :
377 30 : delay = lp_parm_int(SNUM(handle->conn),
378 : "delay_inject", "brl_lock_windows", 0);
379 30 : state->delay_tv = timeval_current_ofs_msec(delay);
380 :
381 30 : use_timer = lp_parm_bool(SNUM(handle->conn),
382 : "delay_inject", "brl_lock_windows_use_timer", true);
383 :
384 30 : if (use_timer) {
385 16 : state->delay_te = tevent_add_timer(
386 : global_event_context(),
387 : state,
388 : state->delay_tv,
389 : vfs_delay_inject_brl_lock_timer,
390 : state);
391 16 : if (state->delay_te == NULL) {
392 0 : return NT_STATUS_NO_MEMORY;
393 : }
394 : }
395 :
396 30 : talloc_set_destructor(state,
397 : vfs_delay_inject_brl_lock_state_destructor);
398 30 : DLIST_ADD_END(brl_lock_states, state);
399 : }
400 :
401 60 : if (state->delay_te != NULL) {
402 16 : plock->context.smblctx = 0;
403 16 : return NT_STATUS_RETRY;
404 : }
405 :
406 44 : expired = timeval_expired(&state->delay_tv);
407 44 : if (!expired) {
408 14 : plock->context.smblctx = UINT64_MAX;
409 14 : return NT_STATUS_RETRY;
410 : }
411 :
412 30 : TALLOC_FREE(state);
413 :
414 30 : return SMB_VFS_NEXT_BRL_LOCK_WINDOWS(handle, br_lck, plock);
415 : }
416 :
417 8 : static bool vfs_delay_inject_brl_unlock_windows(struct vfs_handle_struct *handle,
418 : struct byte_range_lock *br_lck,
419 : const struct lock_struct *plock)
420 : {
421 8 : return SMB_VFS_NEXT_BRL_UNLOCK_WINDOWS(handle, br_lck, plock);
422 : }
423 :
424 : static struct vfs_fn_pointers vfs_delay_inject_fns = {
425 : .fntimes_fn = vfs_delay_inject_fntimes,
426 : .pread_send_fn = vfs_delay_inject_pread_send,
427 : .pread_recv_fn = vfs_delay_inject_pread_recv,
428 : .pwrite_send_fn = vfs_delay_inject_pwrite_send,
429 : .pwrite_recv_fn = vfs_delay_inject_pwrite_recv,
430 :
431 : .brl_lock_windows_fn = vfs_delay_inject_brl_lock_windows,
432 : .brl_unlock_windows_fn = vfs_delay_inject_brl_unlock_windows,
433 : };
434 :
435 : static_decl_vfs;
436 65 : NTSTATUS vfs_delay_inject_init(TALLOC_CTX *ctx)
437 : {
438 65 : return smb_register_vfs(SMB_VFS_INTERFACE_VERSION, "delay_inject",
439 : &vfs_delay_inject_fns);
440 : }
|