LCOV - code coverage report
Current view: top level - source3/modules - vfs_delay_inject.c (source / functions) Hit Total Coverage
Test: coverage report for master 2f515e9b Lines: 129 150 86.0 %
Date: 2024-04-21 15:09:00 Functions: 16 16 100.0 %

          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             : }

Generated by: LCOV version 1.14