jm199354 | 911106d | 2007-11-08 16:09:20 -0800 | [diff] [blame] | 1 | /* |
| 2 | * CDDL HEADER START |
| 3 | * |
| 4 | * The contents of this file are subject to the terms of the |
| 5 | * Common Development and Distribution License (the "License"). |
| 6 | * You may not use this file except in compliance with the License. |
| 7 | * |
| 8 | * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE |
| 9 | * or http://www.opensolaris.org/os/licensing. |
| 10 | * See the License for the specific language governing permissions |
| 11 | * and limitations under the License. |
| 12 | * |
| 13 | * When distributing Covered Code, include this CDDL HEADER in each |
| 14 | * file and include the License file at usr/src/OPENSOLARIS.LICENSE. |
| 15 | * If applicable, add the following below this CDDL HEADER, with the |
| 16 | * fields enclosed by brackets "[]" replaced with your own identifying |
| 17 | * information: Portions Copyright [yyyy] [name of copyright owner] |
| 18 | * |
| 19 | * CDDL HEADER END |
| 20 | */ |
| 21 | |
| 22 | /* |
Rafael Vanoni | d3d5073 | 2009-11-13 01:32:32 -0800 | [diff] [blame] | 23 | * Copyright 2009 Sun Microsystems, Inc. All rights reserved. |
jm199354 | 911106d | 2007-11-08 16:09:20 -0800 | [diff] [blame] | 24 | * Use is subject to license terms. |
Patrick Mooney | e2fc340 | 2017-06-08 21:57:45 +0000 | [diff] [blame] | 25 | * Copyright (c) 2015, Joyent, Inc. |
jm199354 | 911106d | 2007-11-08 16:09:20 -0800 | [diff] [blame] | 26 | */ |
| 27 | |
jm199354 | 911106d | 2007-11-08 16:09:20 -0800 | [diff] [blame] | 28 | #include <sys/stat.h> |
| 29 | #include <sys/ddi.h> |
| 30 | #include <sys/sunddi.h> |
| 31 | #include <sys/time.h> |
| 32 | #include <sys/varargs.h> |
| 33 | #include <sys/conf.h> |
| 34 | #include <sys/modctl.h> |
| 35 | #include <sys/cmn_err.h> |
| 36 | #include <sys/vnode.h> |
| 37 | #include <fs/fs_subr.h> |
| 38 | #include <sys/types.h> |
| 39 | #include <sys/file.h> |
| 40 | #include <sys/disp.h> |
| 41 | #include <sys/sdt.h> |
| 42 | #include <sys/cred.h> |
jm199354 | bfc848c | 2008-04-10 17:45:54 -0700 | [diff] [blame] | 43 | #include <sys/list.h> |
jm199354 | 911106d | 2007-11-08 16:09:20 -0800 | [diff] [blame] | 44 | #include <sys/vscan.h> |
Richard Lowe | 5c5f137 | 2012-07-08 19:01:30 +0100 | [diff] [blame] | 45 | #include <sys/sysmacros.h> |
jm199354 | 911106d | 2007-11-08 16:09:20 -0800 | [diff] [blame] | 46 | |
jm199354 | bfc848c | 2008-04-10 17:45:54 -0700 | [diff] [blame] | 47 | #define VS_REQ_MAGIC 0x52515354 /* 'RQST' */ |
jm199354 | 911106d | 2007-11-08 16:09:20 -0800 | [diff] [blame] | 48 | |
jm199354 | bfc848c | 2008-04-10 17:45:54 -0700 | [diff] [blame] | 49 | #define VS_REQS_DEFAULT 20000 /* pending scan requests - reql */ |
| 50 | #define VS_NODES_DEFAULT 128 /* concurrent file scans */ |
| 51 | #define VS_WORKERS_DEFAULT 32 /* worker threads */ |
| 52 | #define VS_SCANWAIT_DEFAULT 15*60 /* seconds to wait for scan result */ |
| 53 | #define VS_REQL_HANDLER_TIMEOUT 30 |
| 54 | #define VS_EXT_RECURSE_DEPTH 8 |
| 55 | |
| 56 | /* access derived from scan result (VS_STATUS_XXX) and file attributes */ |
| 57 | #define VS_ACCESS_UNDEFINED 0 |
| 58 | #define VS_ACCESS_ALLOW 1 /* return 0 */ |
| 59 | #define VS_ACCESS_DENY 2 /* return EACCES */ |
| 60 | |
| 61 | #define tolower(C) (((C) >= 'A' && (C) <= 'Z') ? (C) - 'A' + 'a' : (C)) |
jm199354 | bfc848c | 2008-04-10 17:45:54 -0700 | [diff] [blame] | 62 | |
| 63 | /* global variables - tunable via /etc/system */ |
| 64 | uint32_t vs_reqs_max = VS_REQS_DEFAULT; /* max scan requests */ |
| 65 | uint32_t vs_nodes_max = VS_NODES_DEFAULT; /* max in-progress scan requests */ |
| 66 | uint32_t vs_workers = VS_WORKERS_DEFAULT; /* max workers send reqs to vscand */ |
| 67 | uint32_t vs_scan_wait = VS_SCANWAIT_DEFAULT; /* secs to wait for scan result */ |
| 68 | |
jm199354 | 911106d | 2007-11-08 16:09:20 -0800 | [diff] [blame] | 69 | |
| 70 | /* |
jm199354 | bfc848c | 2008-04-10 17:45:54 -0700 | [diff] [blame] | 71 | * vscan_svc_state |
| 72 | * |
| 73 | * +-----------------+ |
| 74 | * | VS_SVC_UNCONFIG | |
| 75 | * +-----------------+ |
| 76 | * | ^ |
| 77 | * | svc_init | svc_fini |
| 78 | * v | |
| 79 | * +-----------------+ |
| 80 | * | VS_SVC_IDLE |<----| |
| 81 | * +-----------------+ | |
| 82 | * | | |
| 83 | * | svc_enable | |
| 84 | * |<----------------| | |
| 85 | * v | | |
| 86 | * +-----------------+ | | |
| 87 | * | VS_SVC_ENABLED |--| | |
| 88 | * +-----------------+ | |
| 89 | * | | |
| 90 | * | svc_disable | handler thread exit, |
| 91 | * v | all requests complete |
| 92 | * +-----------------+ | |
| 93 | * | VS_SVC_DISABLED |-----| |
| 94 | * +-----------------+ |
| 95 | * |
| 96 | * svc_enable may occur when we are already in the ENABLED |
| 97 | * state if vscand has exited without clean shutdown and |
| 98 | * then reconnected within the delayed disable time period |
| 99 | * (vs_reconnect_timeout) - see vscan_drv |
| 100 | */ |
| 101 | |
| 102 | typedef enum { |
| 103 | VS_SVC_UNCONFIG, |
| 104 | VS_SVC_IDLE, |
| 105 | VS_SVC_ENABLED, /* service enabled and registered */ |
| 106 | VS_SVC_DISABLED /* service disabled and nunregistered */ |
| 107 | } vscan_svc_state_t; |
| 108 | static vscan_svc_state_t vscan_svc_state = VS_SVC_UNCONFIG; |
| 109 | |
| 110 | |
| 111 | /* |
| 112 | * vscan_svc_req_state |
| 113 | * |
| 114 | * When a scan request is received from the file system it is |
| 115 | * identified in or inserted into the vscan_svc_reql (INIT). |
| 116 | * If the request is asynchronous 0 is then returned to the caller. |
| 117 | * If the request is synchronous the req's refcnt is incremented |
| 118 | * and the caller waits for the request to complete. |
| 119 | * The refcnt is also incremented when the request is inserted |
| 120 | * in vscan_svc_nodes, and decremented on scan_complete. |
| 121 | * |
| 122 | * vscan_svc_handler processes requests from the request list, |
| 123 | * inserting them into vscan_svc_nodes and the task queue (QUEUED). |
| 124 | * When the task queue call back (vscan_svc_do_scan) is invoked |
| 125 | * the request transitions to IN_PROGRESS state. If the request |
| 126 | * is sucessfully sent to vscand (door_call) and the door response |
| 127 | * is SCANNING then the scan result will be received asynchronously. |
| 128 | * Although unusual, it is possible that the async response is |
| 129 | * received before the door call returns (hence the ASYNC_COMPLETE |
| 130 | * state). |
| 131 | * When the result has been determined / received, |
| 132 | * vscan_svc_scan_complete is invoked to transition the request to |
| 133 | * COMPLETE state, decrement refcnt and signal all waiting callers. |
| 134 | * When the last waiting caller has processed the result (refcnt == 0) |
| 135 | * the request is removed from vscan_svc_reql and vscan_svc_nodes |
| 136 | * and deleted. |
| 137 | * |
| 138 | * | ^ |
| 139 | * | reql_insert | refcnt == 0 |
| 140 | * v | (delete) |
| 141 | * +------------------------+ +---------------------+ |
| 142 | * | VS_SVC_REQ_INIT | -----DISABLE----> | VS_SVC_REQ_COMPLETE | |
| 143 | * +------------------------+ +---------------------+ |
| 144 | * | ^ |
| 145 | * | insert_req, tq_dispatch | |
| 146 | * v | |
| 147 | * +------------------------+ | |
| 148 | * | VS_SVC_REQ_QUEUED | scan_complete |
| 149 | * +------------------------+ | |
| 150 | * | | |
| 151 | * | tq_callback (do_scan) | |
| 152 | * | | |
| 153 | * v scan not req'd, error, | |
| 154 | * +------------------------+ or door_result != SCANNING | |
| 155 | * | VS_SVC_REQ_IN_PROGRESS |----------------->-------------| |
| 156 | * +------------------------+ | |
| 157 | * | | | |
| 158 | * | | door_result == SCANNING | |
| 159 | * | v | |
| 160 | * | +---------------------------+ async result | |
| 161 | * | | VS_SVC_REQ_SCANNING |-------->---------| |
| 162 | * | +---------------------------+ | |
| 163 | * | | |
| 164 | * | async result | |
| 165 | * v | |
| 166 | * +---------------------------+ door_result = SCANNING | |
| 167 | * | VS_SVC_REQ_ASYNC_COMPLETE |-------->------------------| |
| 168 | * +---------------------------+ |
| 169 | */ |
| 170 | typedef enum { |
| 171 | VS_SVC_REQ_INIT, |
| 172 | VS_SVC_REQ_QUEUED, |
| 173 | VS_SVC_REQ_IN_PROGRESS, |
| 174 | VS_SVC_REQ_SCANNING, |
| 175 | VS_SVC_REQ_ASYNC_COMPLETE, |
| 176 | VS_SVC_REQ_COMPLETE |
| 177 | } vscan_svc_req_state_t; |
| 178 | |
| 179 | |
| 180 | /* |
| 181 | * vscan_svc_reql - the list of pending and in-progress scan requests |
| 182 | */ |
| 183 | typedef struct vscan_req { |
| 184 | uint32_t vsr_magic; /* VS_REQ_MAGIC */ |
| 185 | list_node_t vsr_lnode; |
| 186 | vnode_t *vsr_vp; |
| 187 | uint32_t vsr_idx; /* vscan_svc_nodes index */ |
| 188 | uint32_t vsr_seqnum; /* unigue request id */ |
| 189 | uint32_t vsr_refcnt; |
| 190 | kcondvar_t vsr_cv; |
| 191 | vscan_svc_req_state_t vsr_state; |
| 192 | } vscan_req_t; |
| 193 | |
| 194 | static list_t vscan_svc_reql; |
| 195 | |
| 196 | |
| 197 | /* |
| 198 | * vscan_svc_nodes - table of files being scanned |
jm199354 | 911106d | 2007-11-08 16:09:20 -0800 | [diff] [blame] | 199 | * |
| 200 | * The index into this table is passed in the door call to |
| 201 | * vscand. vscand uses the idx to determine which minor node |
| 202 | * to open to read the file data. Within the kernel driver |
| 203 | * the minor device number can thus be used to identify the |
| 204 | * table index to get the appropriate vnode. |
| 205 | * |
| 206 | * Instance 0 is reserved for the daemon/driver control |
| 207 | * interface: enable/configure/disable |
| 208 | */ |
jm199354 | bfc848c | 2008-04-10 17:45:54 -0700 | [diff] [blame] | 209 | typedef struct vscan_svc_node { |
| 210 | vscan_req_t *vsn_req; |
| 211 | uint8_t vsn_quarantined; |
| 212 | uint8_t vsn_modified; |
| 213 | uint64_t vsn_size; |
| 214 | timestruc_t vsn_mtime; |
| 215 | vs_scanstamp_t vsn_scanstamp; |
| 216 | uint32_t vsn_result; |
| 217 | uint32_t vsn_access; |
| 218 | } vscan_svc_node_t; |
jm199354 | 911106d | 2007-11-08 16:09:20 -0800 | [diff] [blame] | 219 | |
jm199354 | bfc848c | 2008-04-10 17:45:54 -0700 | [diff] [blame] | 220 | static vscan_svc_node_t *vscan_svc_nodes; |
| 221 | static int vscan_svc_nodes_sz; |
jm199354 | 911106d | 2007-11-08 16:09:20 -0800 | [diff] [blame] | 222 | |
jm199354 | bfc848c | 2008-04-10 17:45:54 -0700 | [diff] [blame] | 223 | |
| 224 | /* vscan_svc_taskq - queue of requests waiting to be sent to vscand */ |
jm199354 | 911106d | 2007-11-08 16:09:20 -0800 | [diff] [blame] | 225 | static taskq_t *vscan_svc_taskq = NULL; |
jm199354 | bfc848c | 2008-04-10 17:45:54 -0700 | [diff] [blame] | 226 | |
| 227 | /* counts of entries in vscan_svc_reql, vscan_svc_nodes & vscan_svc_taskq */ |
| 228 | typedef struct { |
| 229 | uint32_t vsc_reql; |
| 230 | uint32_t vsc_node; |
| 231 | uint32_t vsc_tq; |
| 232 | } vscan_svc_counts_t; |
| 233 | static vscan_svc_counts_t vscan_svc_counts; |
jm199354 | 911106d | 2007-11-08 16:09:20 -0800 | [diff] [blame] | 234 | |
| 235 | /* |
| 236 | * vscan_svc_mutex protects the data pertaining to scan requests: |
jm199354 | bfc848c | 2008-04-10 17:45:54 -0700 | [diff] [blame] | 237 | * request list - vscan_svc_reql |
| 238 | * node table - vscan_svc_nodes |
jm199354 | 911106d | 2007-11-08 16:09:20 -0800 | [diff] [blame] | 239 | */ |
| 240 | static kmutex_t vscan_svc_mutex; |
| 241 | |
jm199354 | bfc848c | 2008-04-10 17:45:54 -0700 | [diff] [blame] | 242 | /* unique request id for vscand request/response correlation */ |
| 243 | static uint32_t vscan_svc_seqnum = 0; |
| 244 | |
jm199354 | 911106d | 2007-11-08 16:09:20 -0800 | [diff] [blame] | 245 | /* |
| 246 | * vscan_svc_cfg_mutex protects the configuration data: |
| 247 | * vscan_svc_config, vscan_svc_types |
| 248 | */ |
| 249 | static kmutex_t vscan_svc_cfg_mutex; |
| 250 | |
| 251 | /* configuration data - for virus scan exemption */ |
| 252 | static vs_config_t vscan_svc_config; |
| 253 | static char *vscan_svc_types[VS_TYPES_MAX]; |
| 254 | |
jm199354 | bfc848c | 2008-04-10 17:45:54 -0700 | [diff] [blame] | 255 | /* thread to insert reql entries into vscan_svc_nodes & vscan_svc_taskq */ |
| 256 | static kthread_t *vscan_svc_reql_thread; |
| 257 | static kcondvar_t vscan_svc_reql_cv; |
| 258 | static vscan_req_t *vscan_svc_reql_next; /* next pending scan request */ |
| 259 | |
jm199354 | 911106d | 2007-11-08 16:09:20 -0800 | [diff] [blame] | 260 | /* local functions */ |
| 261 | int vscan_svc_scan_file(vnode_t *, cred_t *, int); |
jm199354 | bfc848c | 2008-04-10 17:45:54 -0700 | [diff] [blame] | 262 | static void vscan_svc_taskq_callback(void *); |
jm199354 | 911106d | 2007-11-08 16:09:20 -0800 | [diff] [blame] | 263 | static int vscan_svc_exempt_file(vnode_t *, boolean_t *); |
| 264 | static int vscan_svc_exempt_filetype(char *); |
| 265 | static int vscan_svc_match_ext(char *, char *, int); |
jm199354 | bfc848c | 2008-04-10 17:45:54 -0700 | [diff] [blame] | 266 | static void vscan_svc_do_scan(vscan_req_t *); |
| 267 | static vs_scan_req_t *vscan_svc_populate_req(int); |
jm199354 | 53c1102 | 2008-01-29 13:27:28 -0800 | [diff] [blame] | 268 | static void vscan_svc_process_scan_result(int); |
jm199354 | bfc848c | 2008-04-10 17:45:54 -0700 | [diff] [blame] | 269 | static void vscan_svc_scan_complete(vscan_req_t *); |
| 270 | static void vscan_svc_delete_req(vscan_req_t *); |
| 271 | static int vscan_svc_insert_req(vscan_req_t *); |
| 272 | static void vscan_svc_remove_req(int); |
| 273 | static vscan_req_t *vscan_svc_reql_find(vnode_t *); |
| 274 | static vscan_req_t *vscan_svc_reql_insert(vnode_t *); |
| 275 | static void vscan_svc_reql_remove(vscan_req_t *); |
| 276 | |
jm199354 | 911106d | 2007-11-08 16:09:20 -0800 | [diff] [blame] | 277 | static int vscan_svc_getattr(int); |
jm199354 | 53c1102 | 2008-01-29 13:27:28 -0800 | [diff] [blame] | 278 | static int vscan_svc_setattr(int, int); |
jm199354 | 911106d | 2007-11-08 16:09:20 -0800 | [diff] [blame] | 279 | |
jm199354 | bfc848c | 2008-04-10 17:45:54 -0700 | [diff] [blame] | 280 | /* thread to insert reql entries into vscan_svc_nodes & vscan_svc_taskq */ |
| 281 | static void vscan_svc_reql_handler(void); |
jm199354 | 911106d | 2007-11-08 16:09:20 -0800 | [diff] [blame] | 282 | |
| 283 | |
| 284 | /* |
| 285 | * vscan_svc_init |
| 286 | */ |
| 287 | int |
| 288 | vscan_svc_init() |
| 289 | { |
jm199354 | bfc848c | 2008-04-10 17:45:54 -0700 | [diff] [blame] | 290 | if (vscan_svc_state != VS_SVC_UNCONFIG) { |
| 291 | DTRACE_PROBE1(vscan__svc__state__violation, |
| 292 | int, vscan_svc_state); |
| 293 | return (-1); |
| 294 | } |
| 295 | |
| 296 | mutex_init(&vscan_svc_mutex, NULL, MUTEX_DEFAULT, NULL); |
| 297 | mutex_init(&vscan_svc_cfg_mutex, NULL, MUTEX_DEFAULT, NULL); |
| 298 | cv_init(&vscan_svc_reql_cv, NULL, CV_DEFAULT, NULL); |
| 299 | |
| 300 | vscan_svc_nodes_sz = sizeof (vscan_svc_node_t) * (vs_nodes_max + 1); |
| 301 | vscan_svc_nodes = kmem_zalloc(vscan_svc_nodes_sz, KM_SLEEP); |
| 302 | |
| 303 | vscan_svc_counts.vsc_reql = 0; |
| 304 | vscan_svc_counts.vsc_node = 0; |
| 305 | vscan_svc_counts.vsc_tq = 0; |
| 306 | |
| 307 | vscan_svc_state = VS_SVC_IDLE; |
jm199354 | 911106d | 2007-11-08 16:09:20 -0800 | [diff] [blame] | 308 | |
jm199354 | 911106d | 2007-11-08 16:09:20 -0800 | [diff] [blame] | 309 | return (0); |
| 310 | } |
| 311 | |
jm199354 | bfc848c | 2008-04-10 17:45:54 -0700 | [diff] [blame] | 312 | |
jm199354 | 911106d | 2007-11-08 16:09:20 -0800 | [diff] [blame] | 313 | /* |
| 314 | * vscan_svc_fini |
| 315 | */ |
| 316 | void |
| 317 | vscan_svc_fini() |
| 318 | { |
jm199354 | bfc848c | 2008-04-10 17:45:54 -0700 | [diff] [blame] | 319 | if (vscan_svc_state != VS_SVC_IDLE) { |
| 320 | DTRACE_PROBE1(vscan__svc__state__violation, |
| 321 | int, vscan_svc_state); |
| 322 | return; |
| 323 | } |
jm199354 | 911106d | 2007-11-08 16:09:20 -0800 | [diff] [blame] | 324 | |
jm199354 | bfc848c | 2008-04-10 17:45:54 -0700 | [diff] [blame] | 325 | kmem_free(vscan_svc_nodes, vscan_svc_nodes_sz); |
| 326 | |
| 327 | cv_destroy(&vscan_svc_reql_cv); |
jm199354 | 911106d | 2007-11-08 16:09:20 -0800 | [diff] [blame] | 328 | mutex_destroy(&vscan_svc_mutex); |
| 329 | mutex_destroy(&vscan_svc_cfg_mutex); |
jm199354 | bfc848c | 2008-04-10 17:45:54 -0700 | [diff] [blame] | 330 | vscan_svc_state = VS_SVC_UNCONFIG; |
jm199354 | 911106d | 2007-11-08 16:09:20 -0800 | [diff] [blame] | 331 | } |
| 332 | |
jm199354 | bfc848c | 2008-04-10 17:45:54 -0700 | [diff] [blame] | 333 | |
jm199354 | 911106d | 2007-11-08 16:09:20 -0800 | [diff] [blame] | 334 | /* |
| 335 | * vscan_svc_enable |
| 336 | */ |
jm199354 | bfc848c | 2008-04-10 17:45:54 -0700 | [diff] [blame] | 337 | int |
jm199354 | 53c1102 | 2008-01-29 13:27:28 -0800 | [diff] [blame] | 338 | vscan_svc_enable(void) |
jm199354 | 911106d | 2007-11-08 16:09:20 -0800 | [diff] [blame] | 339 | { |
jm199354 | 53c1102 | 2008-01-29 13:27:28 -0800 | [diff] [blame] | 340 | mutex_enter(&vscan_svc_mutex); |
jm199354 | 911106d | 2007-11-08 16:09:20 -0800 | [diff] [blame] | 341 | |
jm199354 | bfc848c | 2008-04-10 17:45:54 -0700 | [diff] [blame] | 342 | switch (vscan_svc_state) { |
| 343 | case VS_SVC_ENABLED: |
| 344 | /* |
| 345 | * it's possible (and okay) for vscan_svc_enable to be |
| 346 | * called when already enabled if vscand reconnects |
| 347 | * during a delayed disable |
| 348 | */ |
| 349 | break; |
| 350 | case VS_SVC_IDLE: |
| 351 | list_create(&vscan_svc_reql, sizeof (vscan_req_t), |
| 352 | offsetof(vscan_req_t, vsr_lnode)); |
| 353 | vscan_svc_reql_next = list_head(&vscan_svc_reql); |
| 354 | |
| 355 | vscan_svc_taskq = taskq_create("vscan_taskq", vs_workers, |
| 356 | MINCLSYSPRI, 1, INT_MAX, TASKQ_DYNAMIC); |
| 357 | ASSERT(vscan_svc_taskq != NULL); |
| 358 | |
| 359 | vscan_svc_reql_thread = thread_create(NULL, 0, |
| 360 | vscan_svc_reql_handler, 0, 0, &p0, TS_RUN, MINCLSYSPRI); |
| 361 | ASSERT(vscan_svc_reql_thread != NULL); |
| 362 | |
| 363 | /* ready to start processing requests */ |
| 364 | vscan_svc_state = VS_SVC_ENABLED; |
| 365 | fs_vscan_register(vscan_svc_scan_file); |
| 366 | break; |
| 367 | default: |
| 368 | DTRACE_PROBE1(vscan__svc__state__violation, |
| 369 | int, vscan_svc_state); |
| 370 | return (-1); |
jm199354 | 53c1102 | 2008-01-29 13:27:28 -0800 | [diff] [blame] | 371 | } |
| 372 | |
jm199354 | 53c1102 | 2008-01-29 13:27:28 -0800 | [diff] [blame] | 373 | mutex_exit(&vscan_svc_mutex); |
jm199354 | bfc848c | 2008-04-10 17:45:54 -0700 | [diff] [blame] | 374 | return (0); |
jm199354 | 911106d | 2007-11-08 16:09:20 -0800 | [diff] [blame] | 375 | } |
| 376 | |
jm199354 | 53c1102 | 2008-01-29 13:27:28 -0800 | [diff] [blame] | 377 | |
| 378 | /* |
| 379 | * vscan_svc_disable |
jm199354 | bfc848c | 2008-04-10 17:45:54 -0700 | [diff] [blame] | 380 | * |
| 381 | * Resources allocated during vscan_svc_enable are free'd by |
| 382 | * the handler thread immediately prior to exiting |
jm199354 | 53c1102 | 2008-01-29 13:27:28 -0800 | [diff] [blame] | 383 | */ |
| 384 | void |
| 385 | vscan_svc_disable(void) |
| 386 | { |
| 387 | mutex_enter(&vscan_svc_mutex); |
jm199354 | 53c1102 | 2008-01-29 13:27:28 -0800 | [diff] [blame] | 388 | |
jm199354 | bfc848c | 2008-04-10 17:45:54 -0700 | [diff] [blame] | 389 | switch (vscan_svc_state) { |
| 390 | case VS_SVC_ENABLED: |
| 391 | fs_vscan_register(NULL); |
| 392 | vscan_svc_state = VS_SVC_DISABLED; |
| 393 | cv_signal(&vscan_svc_reql_cv); /* wake handler thread */ |
| 394 | break; |
| 395 | default: |
| 396 | DTRACE_PROBE1(vscan__svc__state__violation, int, |
| 397 | vscan_svc_state); |
jm199354 | 53c1102 | 2008-01-29 13:27:28 -0800 | [diff] [blame] | 398 | } |
jm199354 | bfc848c | 2008-04-10 17:45:54 -0700 | [diff] [blame] | 399 | |
jm199354 | 53c1102 | 2008-01-29 13:27:28 -0800 | [diff] [blame] | 400 | mutex_exit(&vscan_svc_mutex); |
| 401 | } |
| 402 | |
| 403 | |
jm199354 | 911106d | 2007-11-08 16:09:20 -0800 | [diff] [blame] | 404 | /* |
| 405 | * vscan_svc_in_use |
| 406 | */ |
| 407 | boolean_t |
| 408 | vscan_svc_in_use() |
| 409 | { |
jm199354 | bfc848c | 2008-04-10 17:45:54 -0700 | [diff] [blame] | 410 | boolean_t in_use; |
jm199354 | 911106d | 2007-11-08 16:09:20 -0800 | [diff] [blame] | 411 | |
| 412 | mutex_enter(&vscan_svc_mutex); |
jm199354 | 911106d | 2007-11-08 16:09:20 -0800 | [diff] [blame] | 413 | |
jm199354 | bfc848c | 2008-04-10 17:45:54 -0700 | [diff] [blame] | 414 | switch (vscan_svc_state) { |
| 415 | case VS_SVC_IDLE: |
| 416 | case VS_SVC_UNCONFIG: |
| 417 | in_use = B_FALSE; |
| 418 | break; |
| 419 | default: |
| 420 | in_use = B_TRUE; |
| 421 | break; |
| 422 | } |
| 423 | |
| 424 | mutex_exit(&vscan_svc_mutex); |
| 425 | return (in_use); |
jm199354 | 911106d | 2007-11-08 16:09:20 -0800 | [diff] [blame] | 426 | } |
| 427 | |
jm199354 | bfc848c | 2008-04-10 17:45:54 -0700 | [diff] [blame] | 428 | |
jm199354 | 911106d | 2007-11-08 16:09:20 -0800 | [diff] [blame] | 429 | /* |
| 430 | * vscan_svc_get_vnode |
| 431 | * |
| 432 | * Get the file vnode indexed by idx. |
jm199354 | 911106d | 2007-11-08 16:09:20 -0800 | [diff] [blame] | 433 | */ |
| 434 | vnode_t * |
| 435 | vscan_svc_get_vnode(int idx) |
| 436 | { |
jm199354 | bfc848c | 2008-04-10 17:45:54 -0700 | [diff] [blame] | 437 | vnode_t *vp = NULL; |
jm199354 | 911106d | 2007-11-08 16:09:20 -0800 | [diff] [blame] | 438 | |
jm199354 | bfc848c | 2008-04-10 17:45:54 -0700 | [diff] [blame] | 439 | ASSERT(idx > 0); |
| 440 | ASSERT(idx <= vs_nodes_max); |
| 441 | |
| 442 | mutex_enter(&vscan_svc_mutex); |
| 443 | if (vscan_svc_nodes[idx].vsn_req) |
| 444 | vp = vscan_svc_nodes[idx].vsn_req->vsr_vp; |
| 445 | mutex_exit(&vscan_svc_mutex); |
| 446 | |
| 447 | return (vp); |
jm199354 | 911106d | 2007-11-08 16:09:20 -0800 | [diff] [blame] | 448 | } |
| 449 | |
| 450 | |
| 451 | /* |
| 452 | * vscan_svc_scan_file |
| 453 | * |
| 454 | * This function is the entry point for the file system to |
| 455 | * request that a file be virus scanned. |
jm199354 | 911106d | 2007-11-08 16:09:20 -0800 | [diff] [blame] | 456 | */ |
| 457 | int |
| 458 | vscan_svc_scan_file(vnode_t *vp, cred_t *cr, int async) |
| 459 | { |
jm199354 | bfc848c | 2008-04-10 17:45:54 -0700 | [diff] [blame] | 460 | int access; |
| 461 | vscan_req_t *req; |
jm199354 | 911106d | 2007-11-08 16:09:20 -0800 | [diff] [blame] | 462 | boolean_t allow; |
jm199354 | bfc848c | 2008-04-10 17:45:54 -0700 | [diff] [blame] | 463 | clock_t timeout, time_left; |
jm199354 | 911106d | 2007-11-08 16:09:20 -0800 | [diff] [blame] | 464 | |
Patrick Mooney | e2fc340 | 2017-06-08 21:57:45 +0000 | [diff] [blame] | 465 | if ((vp == NULL) || (vp->v_path == vn_vpath_empty) || cr == NULL) |
jm199354 | 911106d | 2007-11-08 16:09:20 -0800 | [diff] [blame] | 466 | return (0); |
jm199354 | 911106d | 2007-11-08 16:09:20 -0800 | [diff] [blame] | 467 | |
| 468 | DTRACE_PROBE2(vscan__scan__file, char *, vp->v_path, int, async); |
| 469 | |
| 470 | /* check if size or type exempts file from scanning */ |
| 471 | if (vscan_svc_exempt_file(vp, &allow)) { |
jm199354 | 911106d | 2007-11-08 16:09:20 -0800 | [diff] [blame] | 472 | if ((allow == B_TRUE) || (async != 0)) |
| 473 | return (0); |
| 474 | |
| 475 | return (EACCES); |
| 476 | } |
| 477 | |
jm199354 | bfc848c | 2008-04-10 17:45:54 -0700 | [diff] [blame] | 478 | mutex_enter(&vscan_svc_mutex); |
jm199354 | 911106d | 2007-11-08 16:09:20 -0800 | [diff] [blame] | 479 | |
jm199354 | bfc848c | 2008-04-10 17:45:54 -0700 | [diff] [blame] | 480 | if (vscan_svc_state != VS_SVC_ENABLED) { |
| 481 | DTRACE_PROBE1(vscan__svc__state__violation, |
| 482 | int, vscan_svc_state); |
| 483 | mutex_exit(&vscan_svc_mutex); |
| 484 | return (0); |
jm199354 | 911106d | 2007-11-08 16:09:20 -0800 | [diff] [blame] | 485 | } |
| 486 | |
jm199354 | bfc848c | 2008-04-10 17:45:54 -0700 | [diff] [blame] | 487 | /* insert (or find) request in list */ |
| 488 | if ((req = vscan_svc_reql_insert(vp)) == NULL) { |
| 489 | mutex_exit(&vscan_svc_mutex); |
| 490 | cmn_err(CE_WARN, "Virus scan request list full"); |
| 491 | return ((async != 0) ? 0 : EACCES); |
| 492 | } |
jm199354 | 911106d | 2007-11-08 16:09:20 -0800 | [diff] [blame] | 493 | |
jm199354 | bfc848c | 2008-04-10 17:45:54 -0700 | [diff] [blame] | 494 | /* asynchronous request: return 0 */ |
| 495 | if (async) { |
| 496 | mutex_exit(&vscan_svc_mutex); |
| 497 | return (0); |
| 498 | } |
| 499 | |
| 500 | /* synchronous scan request: wait for result */ |
| 501 | ++(req->vsr_refcnt); |
| 502 | time_left = SEC_TO_TICK(vs_scan_wait); |
| 503 | while ((time_left > 0) && (req->vsr_state != VS_SVC_REQ_COMPLETE)) { |
Rafael Vanoni | d3d5073 | 2009-11-13 01:32:32 -0800 | [diff] [blame] | 504 | timeout = time_left; |
| 505 | time_left = cv_reltimedwait_sig(&(req->vsr_cv), |
| 506 | &vscan_svc_mutex, timeout, TR_CLOCK_TICK); |
jm199354 | bfc848c | 2008-04-10 17:45:54 -0700 | [diff] [blame] | 507 | } |
| 508 | |
| 509 | if (time_left == -1) { |
| 510 | cmn_err(CE_WARN, "Virus scan request timeout %s (%d) \n", |
| 511 | vp->v_path, req->vsr_seqnum); |
| 512 | DTRACE_PROBE1(vscan__scan__timeout, vscan_req_t *, req); |
| 513 | } |
| 514 | |
| 515 | ASSERT(req->vsr_magic == VS_REQ_MAGIC); |
| 516 | if (vscan_svc_state == VS_SVC_DISABLED) |
| 517 | access = VS_ACCESS_ALLOW; |
| 518 | else if (req->vsr_idx == 0) |
| 519 | access = VS_ACCESS_DENY; |
| 520 | else |
| 521 | access = vscan_svc_nodes[req->vsr_idx].vsn_access; |
| 522 | |
| 523 | if ((--req->vsr_refcnt) == 0) |
| 524 | vscan_svc_delete_req(req); |
| 525 | |
| 526 | mutex_exit(&vscan_svc_mutex); |
| 527 | return ((access == VS_ACCESS_ALLOW) ? 0 : EACCES); |
jm199354 | 911106d | 2007-11-08 16:09:20 -0800 | [diff] [blame] | 528 | } |
| 529 | |
| 530 | |
| 531 | /* |
jm199354 | bfc848c | 2008-04-10 17:45:54 -0700 | [diff] [blame] | 532 | * vscan_svc_reql_handler |
jm199354 | 911106d | 2007-11-08 16:09:20 -0800 | [diff] [blame] | 533 | * |
jm199354 | bfc848c | 2008-04-10 17:45:54 -0700 | [diff] [blame] | 534 | * inserts scan requests (from vscan_svc_reql) into |
| 535 | * vscan_svc_nodes and vscan_svc_taskq |
jm199354 | 911106d | 2007-11-08 16:09:20 -0800 | [diff] [blame] | 536 | */ |
jm199354 | bfc848c | 2008-04-10 17:45:54 -0700 | [diff] [blame] | 537 | static void |
| 538 | vscan_svc_reql_handler(void) |
| 539 | { |
| 540 | vscan_req_t *req, *next; |
| 541 | |
| 542 | for (;;) { |
| 543 | mutex_enter(&vscan_svc_mutex); |
| 544 | |
| 545 | if ((vscan_svc_state == VS_SVC_DISABLED) && |
| 546 | (vscan_svc_counts.vsc_reql == 0)) { |
| 547 | /* free resources allocated durining enable */ |
| 548 | taskq_destroy(vscan_svc_taskq); |
| 549 | vscan_svc_taskq = NULL; |
| 550 | list_destroy(&vscan_svc_reql); |
| 551 | vscan_svc_state = VS_SVC_IDLE; |
| 552 | mutex_exit(&vscan_svc_mutex); |
| 553 | return; |
| 554 | } |
| 555 | |
| 556 | /* |
| 557 | * If disabled, scan_complete any pending requests. |
| 558 | * Otherwise insert pending requests into vscan_svc_nodes |
| 559 | * and vscan_svc_taskq. If no slots are available in |
| 560 | * vscan_svc_nodes break loop and wait for one |
| 561 | */ |
| 562 | req = vscan_svc_reql_next; |
| 563 | |
| 564 | while (req != NULL) { |
| 565 | ASSERT(req->vsr_magic == VS_REQ_MAGIC); |
| 566 | next = list_next(&vscan_svc_reql, req); |
| 567 | |
| 568 | if (vscan_svc_state == VS_SVC_DISABLED) { |
| 569 | vscan_svc_scan_complete(req); |
| 570 | } else { |
| 571 | /* insert request into vscan_svc_nodes */ |
| 572 | if (vscan_svc_insert_req(req) == -1) |
| 573 | break; |
| 574 | |
| 575 | /* add the scan request into the taskq */ |
| 576 | (void) taskq_dispatch(vscan_svc_taskq, |
| 577 | vscan_svc_taskq_callback, |
| 578 | (void *)req, TQ_SLEEP); |
| 579 | ++(vscan_svc_counts.vsc_tq); |
| 580 | |
| 581 | req->vsr_state = VS_SVC_REQ_QUEUED; |
| 582 | } |
| 583 | req = next; |
| 584 | } |
| 585 | |
| 586 | vscan_svc_reql_next = req; |
| 587 | |
| 588 | DTRACE_PROBE2(vscan__req__counts, char *, "handler wait", |
| 589 | vscan_svc_counts_t *, &vscan_svc_counts); |
| 590 | |
Rafael Vanoni | d3d5073 | 2009-11-13 01:32:32 -0800 | [diff] [blame] | 591 | (void) cv_reltimedwait(&vscan_svc_reql_cv, &vscan_svc_mutex, |
| 592 | SEC_TO_TICK(VS_REQL_HANDLER_TIMEOUT), TR_CLOCK_TICK); |
jm199354 | bfc848c | 2008-04-10 17:45:54 -0700 | [diff] [blame] | 593 | |
| 594 | DTRACE_PROBE2(vscan__req__counts, char *, "handler wake", |
| 595 | vscan_svc_counts_t *, &vscan_svc_counts); |
| 596 | |
| 597 | mutex_exit(&vscan_svc_mutex); |
| 598 | } |
| 599 | } |
| 600 | |
| 601 | |
| 602 | static void |
jm199354 | 911106d | 2007-11-08 16:09:20 -0800 | [diff] [blame] | 603 | vscan_svc_taskq_callback(void *data) |
| 604 | { |
jm199354 | bfc848c | 2008-04-10 17:45:54 -0700 | [diff] [blame] | 605 | vscan_req_t *req; |
jm199354 | 911106d | 2007-11-08 16:09:20 -0800 | [diff] [blame] | 606 | |
| 607 | mutex_enter(&vscan_svc_mutex); |
jm199354 | bfc848c | 2008-04-10 17:45:54 -0700 | [diff] [blame] | 608 | |
| 609 | req = (vscan_req_t *)data; |
| 610 | ASSERT(req->vsr_magic == VS_REQ_MAGIC); |
| 611 | vscan_svc_do_scan(req); |
| 612 | if (req->vsr_state != VS_SVC_REQ_SCANNING) |
| 613 | vscan_svc_scan_complete(req); |
| 614 | |
| 615 | --(vscan_svc_counts.vsc_tq); |
jm199354 | 911106d | 2007-11-08 16:09:20 -0800 | [diff] [blame] | 616 | mutex_exit(&vscan_svc_mutex); |
| 617 | } |
| 618 | |
| 619 | |
| 620 | /* |
| 621 | * vscan_svc_do_scan |
| 622 | * |
jm199354 | bfc848c | 2008-04-10 17:45:54 -0700 | [diff] [blame] | 623 | * Note: To avoid potential deadlock it is important that |
| 624 | * vscan_svc_mutex is not held during the call to |
| 625 | * vscan_drv_create_note. vscan_drv_create_note enters |
| 626 | * the vscan_drv_mutex and it is possible that a thread |
| 627 | * holding that mutex could be waiting for vscan_svc_mutex. |
jm199354 | 911106d | 2007-11-08 16:09:20 -0800 | [diff] [blame] | 628 | */ |
jm199354 | bfc848c | 2008-04-10 17:45:54 -0700 | [diff] [blame] | 629 | static void |
| 630 | vscan_svc_do_scan(vscan_req_t *req) |
jm199354 | 911106d | 2007-11-08 16:09:20 -0800 | [diff] [blame] | 631 | { |
jm199354 | bfc848c | 2008-04-10 17:45:54 -0700 | [diff] [blame] | 632 | int idx, result; |
| 633 | vscan_svc_node_t *node; |
| 634 | vs_scan_req_t *door_req; |
| 635 | |
| 636 | ASSERT(MUTEX_HELD(&vscan_svc_mutex)); |
| 637 | |
| 638 | idx = req->vsr_idx; |
| 639 | node = &vscan_svc_nodes[idx]; |
| 640 | |
| 641 | req->vsr_state = VS_SVC_REQ_IN_PROGRESS; |
| 642 | |
| 643 | /* if vscan not enabled (shutting down), allow ACCESS */ |
| 644 | if (vscan_svc_state != VS_SVC_ENABLED) { |
| 645 | node->vsn_access = VS_ACCESS_ALLOW; |
| 646 | return; |
| 647 | } |
| 648 | |
| 649 | if (vscan_svc_getattr(idx) != 0) { |
| 650 | cmn_err(CE_WARN, "Can't access xattr for %s\n", |
| 651 | req->vsr_vp->v_path); |
| 652 | node->vsn_access = VS_ACCESS_DENY; |
| 653 | return; |
| 654 | } |
| 655 | |
| 656 | /* valid scan_req ptr guaranteed */ |
| 657 | door_req = vscan_svc_populate_req(idx); |
| 658 | |
| 659 | /* free up mutex around create node and door call */ |
| 660 | mutex_exit(&vscan_svc_mutex); |
| 661 | if (vscan_drv_create_node(idx) != B_TRUE) |
| 662 | result = VS_STATUS_ERROR; |
| 663 | else |
| 664 | result = vscan_door_scan_file(door_req); |
| 665 | kmem_free(door_req, sizeof (vs_scan_req_t)); |
| 666 | mutex_enter(&vscan_svc_mutex); |
| 667 | |
| 668 | if (result != VS_STATUS_SCANNING) { |
| 669 | vscan_svc_nodes[idx].vsn_result = result; |
| 670 | vscan_svc_process_scan_result(idx); |
| 671 | } else { /* async response */ |
| 672 | if (req->vsr_state == VS_SVC_REQ_IN_PROGRESS) |
| 673 | req->vsr_state = VS_SVC_REQ_SCANNING; |
| 674 | } |
| 675 | } |
| 676 | |
| 677 | |
| 678 | /* |
| 679 | * vscan_svc_populate_req |
| 680 | * |
| 681 | * Allocate a scan request to be sent to vscand, populating it |
| 682 | * from the data in vscan_svc_nodes[idx]. |
| 683 | * |
| 684 | * Returns: scan request object |
| 685 | */ |
| 686 | static vs_scan_req_t * |
| 687 | vscan_svc_populate_req(int idx) |
| 688 | { |
jm199354 | 911106d | 2007-11-08 16:09:20 -0800 | [diff] [blame] | 689 | vs_scan_req_t *scan_req; |
jm199354 | bfc848c | 2008-04-10 17:45:54 -0700 | [diff] [blame] | 690 | vscan_req_t *req; |
| 691 | vscan_svc_node_t *node; |
| 692 | |
| 693 | ASSERT(MUTEX_HELD(&vscan_svc_mutex)); |
| 694 | |
| 695 | node = &vscan_svc_nodes[idx]; |
| 696 | req = node->vsn_req; |
| 697 | scan_req = kmem_zalloc(sizeof (vs_scan_req_t), KM_SLEEP); |
| 698 | |
| 699 | scan_req->vsr_idx = idx; |
| 700 | scan_req->vsr_seqnum = req->vsr_seqnum; |
| 701 | (void) strncpy(scan_req->vsr_path, req->vsr_vp->v_path, MAXPATHLEN); |
| 702 | scan_req->vsr_size = node->vsn_size; |
| 703 | scan_req->vsr_modified = node->vsn_modified; |
| 704 | scan_req->vsr_quarantined = node->vsn_quarantined; |
| 705 | scan_req->vsr_flags = 0; |
| 706 | (void) strncpy(scan_req->vsr_scanstamp, |
| 707 | node->vsn_scanstamp, sizeof (vs_scanstamp_t)); |
| 708 | |
| 709 | return (scan_req); |
| 710 | } |
| 711 | |
| 712 | |
| 713 | /* |
| 714 | * vscan_svc_scan_complete |
| 715 | */ |
| 716 | static void |
| 717 | vscan_svc_scan_complete(vscan_req_t *req) |
| 718 | { |
| 719 | ASSERT(MUTEX_HELD(&vscan_svc_mutex)); |
| 720 | ASSERT(req != NULL); |
| 721 | |
| 722 | req->vsr_state = VS_SVC_REQ_COMPLETE; |
| 723 | |
| 724 | if ((--req->vsr_refcnt) == 0) |
| 725 | vscan_svc_delete_req(req); |
| 726 | else |
| 727 | cv_broadcast(&(req->vsr_cv)); |
| 728 | } |
| 729 | |
| 730 | |
| 731 | /* |
| 732 | * vscan_svc_delete_req |
| 733 | */ |
| 734 | static void |
| 735 | vscan_svc_delete_req(vscan_req_t *req) |
| 736 | { |
| 737 | int idx; |
| 738 | |
| 739 | ASSERT(MUTEX_HELD(&vscan_svc_mutex)); |
| 740 | ASSERT(req != NULL); |
| 741 | ASSERT(req->vsr_refcnt == 0); |
| 742 | ASSERT(req->vsr_state == VS_SVC_REQ_COMPLETE); |
| 743 | |
| 744 | if ((idx = req->vsr_idx) != 0) |
| 745 | vscan_svc_remove_req(idx); |
| 746 | |
| 747 | vscan_svc_reql_remove(req); |
| 748 | |
| 749 | cv_signal(&vscan_svc_reql_cv); |
| 750 | } |
| 751 | |
| 752 | |
| 753 | /* |
| 754 | * vscan_svc_scan_result |
| 755 | * |
| 756 | * Invoked from vscan_drv.c on receipt of an ioctl containing |
| 757 | * an async scan result (VS_DRV_IOCTL_RESULT) |
| 758 | * If the vsr_seqnum in the response does not match that in the |
| 759 | * vscan_svc_nodes entry the result is discarded. |
| 760 | */ |
| 761 | void |
| 762 | vscan_svc_scan_result(vs_scan_rsp_t *scan_rsp) |
| 763 | { |
| 764 | vscan_req_t *req; |
| 765 | vscan_svc_node_t *node; |
jm199354 | 911106d | 2007-11-08 16:09:20 -0800 | [diff] [blame] | 766 | |
| 767 | mutex_enter(&vscan_svc_mutex); |
| 768 | |
jm199354 | bfc848c | 2008-04-10 17:45:54 -0700 | [diff] [blame] | 769 | node = &vscan_svc_nodes[scan_rsp->vsr_idx]; |
jm199354 | 911106d | 2007-11-08 16:09:20 -0800 | [diff] [blame] | 770 | |
jm199354 | bfc848c | 2008-04-10 17:45:54 -0700 | [diff] [blame] | 771 | if ((req = node->vsn_req) == NULL) { |
| 772 | mutex_exit(&vscan_svc_mutex); |
| 773 | return; |
| 774 | } |
jm199354 | 53c1102 | 2008-01-29 13:27:28 -0800 | [diff] [blame] | 775 | |
jm199354 | bfc848c | 2008-04-10 17:45:54 -0700 | [diff] [blame] | 776 | ASSERT(req->vsr_magic == VS_REQ_MAGIC); |
| 777 | |
| 778 | if (scan_rsp->vsr_seqnum != req->vsr_seqnum) { |
| 779 | mutex_exit(&vscan_svc_mutex); |
| 780 | return; |
| 781 | } |
| 782 | |
| 783 | node->vsn_result = scan_rsp->vsr_result; |
| 784 | (void) strncpy(node->vsn_scanstamp, |
| 785 | scan_rsp->vsr_scanstamp, sizeof (vs_scanstamp_t)); |
| 786 | |
| 787 | vscan_svc_process_scan_result(scan_rsp->vsr_idx); |
| 788 | |
| 789 | if (node->vsn_req->vsr_state == VS_SVC_REQ_SCANNING) |
| 790 | vscan_svc_scan_complete(node->vsn_req); |
| 791 | else |
| 792 | node->vsn_req->vsr_state = VS_SVC_REQ_ASYNC_COMPLETE; |
| 793 | |
| 794 | mutex_exit(&vscan_svc_mutex); |
| 795 | } |
| 796 | |
| 797 | |
| 798 | /* |
| 799 | * vscan_svc_scan_abort |
| 800 | * |
| 801 | * Abort in-progress scan requests. |
| 802 | */ |
| 803 | void |
| 804 | vscan_svc_scan_abort() |
| 805 | { |
| 806 | int idx; |
| 807 | vscan_req_t *req; |
| 808 | |
| 809 | mutex_enter(&vscan_svc_mutex); |
| 810 | |
| 811 | for (idx = 1; idx <= vs_nodes_max; idx++) { |
| 812 | if ((req = vscan_svc_nodes[idx].vsn_req) == NULL) |
| 813 | continue; |
| 814 | |
| 815 | ASSERT(req->vsr_magic == VS_REQ_MAGIC); |
| 816 | |
| 817 | if (req->vsr_state == VS_SVC_REQ_SCANNING) { |
| 818 | DTRACE_PROBE1(vscan__abort, vscan_req_t *, req); |
| 819 | vscan_svc_process_scan_result(idx); |
| 820 | vscan_svc_scan_complete(req); |
jm199354 | 911106d | 2007-11-08 16:09:20 -0800 | [diff] [blame] | 821 | } |
| 822 | } |
| 823 | |
jm199354 | 911106d | 2007-11-08 16:09:20 -0800 | [diff] [blame] | 824 | mutex_exit(&vscan_svc_mutex); |
jm199354 | 911106d | 2007-11-08 16:09:20 -0800 | [diff] [blame] | 825 | } |
| 826 | |
jm199354 | 53c1102 | 2008-01-29 13:27:28 -0800 | [diff] [blame] | 827 | |
| 828 | /* |
| 829 | * vscan_svc_process_scan_result |
| 830 | * |
jm199354 | bfc848c | 2008-04-10 17:45:54 -0700 | [diff] [blame] | 831 | * Sets vsn_access and updates file attributes based on vsn_result, |
jm199354 | 53c1102 | 2008-01-29 13:27:28 -0800 | [diff] [blame] | 832 | * as follows: |
| 833 | * |
| 834 | * VS_STATUS_INFECTED |
| 835 | * deny access, set quarantine attribute, clear scanstamp |
| 836 | * VS_STATUS_CLEAN |
| 837 | * allow access, set scanstamp, |
| 838 | * if file not modified since scan initiated, clear modified attribute |
| 839 | * VS_STATUS_NO_SCAN |
| 840 | * deny access if file quarantined, otherwise allow access |
| 841 | * VS_STATUS_UNDEFINED, VS_STATUS_ERROR |
| 842 | * deny access if file quarantined, modified or no scanstamp |
| 843 | * otherwise, allow access |
| 844 | */ |
| 845 | static void |
| 846 | vscan_svc_process_scan_result(int idx) |
| 847 | { |
| 848 | struct vattr attr; |
| 849 | vnode_t *vp; |
| 850 | timestruc_t *mtime; |
jm199354 | bfc848c | 2008-04-10 17:45:54 -0700 | [diff] [blame] | 851 | vscan_svc_node_t *node; |
jm199354 | 53c1102 | 2008-01-29 13:27:28 -0800 | [diff] [blame] | 852 | |
| 853 | ASSERT(MUTEX_HELD(&vscan_svc_mutex)); |
| 854 | |
jm199354 | bfc848c | 2008-04-10 17:45:54 -0700 | [diff] [blame] | 855 | node = &vscan_svc_nodes[idx]; |
jm199354 | 53c1102 | 2008-01-29 13:27:28 -0800 | [diff] [blame] | 856 | |
jm199354 | bfc848c | 2008-04-10 17:45:54 -0700 | [diff] [blame] | 857 | switch (node->vsn_result) { |
jm199354 | 53c1102 | 2008-01-29 13:27:28 -0800 | [diff] [blame] | 858 | case VS_STATUS_INFECTED: |
jm199354 | bfc848c | 2008-04-10 17:45:54 -0700 | [diff] [blame] | 859 | node->vsn_access = VS_ACCESS_DENY; |
| 860 | node->vsn_quarantined = 1; |
| 861 | node->vsn_scanstamp[0] = '\0'; |
jm199354 | 53c1102 | 2008-01-29 13:27:28 -0800 | [diff] [blame] | 862 | (void) vscan_svc_setattr(idx, |
| 863 | XAT_AV_QUARANTINED | XAT_AV_SCANSTAMP); |
jm199354 | bfc848c | 2008-04-10 17:45:54 -0700 | [diff] [blame] | 864 | break; |
jm199354 | 53c1102 | 2008-01-29 13:27:28 -0800 | [diff] [blame] | 865 | |
| 866 | case VS_STATUS_CLEAN: |
jm199354 | bfc848c | 2008-04-10 17:45:54 -0700 | [diff] [blame] | 867 | node->vsn_access = VS_ACCESS_ALLOW; |
jm199354 | 53c1102 | 2008-01-29 13:27:28 -0800 | [diff] [blame] | 868 | |
| 869 | /* if mtime has changed, don't clear the modified attribute */ |
jm199354 | bfc848c | 2008-04-10 17:45:54 -0700 | [diff] [blame] | 870 | vp = node->vsn_req->vsr_vp; |
| 871 | mtime = &(node->vsn_mtime); |
jm199354 | 53c1102 | 2008-01-29 13:27:28 -0800 | [diff] [blame] | 872 | attr.va_mask = AT_MTIME; |
| 873 | if ((VOP_GETATTR(vp, &attr, 0, kcred, NULL) != 0) || |
| 874 | (mtime->tv_sec != attr.va_mtime.tv_sec) || |
| 875 | (mtime->tv_nsec != attr.va_mtime.tv_nsec)) { |
jm199354 | bfc848c | 2008-04-10 17:45:54 -0700 | [diff] [blame] | 876 | DTRACE_PROBE1(vscan__mtime__changed, vscan_svc_node_t *, |
| 877 | node); |
jm199354 | 53c1102 | 2008-01-29 13:27:28 -0800 | [diff] [blame] | 878 | (void) vscan_svc_setattr(idx, XAT_AV_SCANSTAMP); |
jm199354 | bfc848c | 2008-04-10 17:45:54 -0700 | [diff] [blame] | 879 | break; |
jm199354 | 53c1102 | 2008-01-29 13:27:28 -0800 | [diff] [blame] | 880 | } |
| 881 | |
jm199354 | bfc848c | 2008-04-10 17:45:54 -0700 | [diff] [blame] | 882 | node->vsn_modified = 0; |
jm199354 | 53c1102 | 2008-01-29 13:27:28 -0800 | [diff] [blame] | 883 | (void) vscan_svc_setattr(idx, |
| 884 | XAT_AV_SCANSTAMP | XAT_AV_MODIFIED); |
jm199354 | bfc848c | 2008-04-10 17:45:54 -0700 | [diff] [blame] | 885 | break; |
jm199354 | 53c1102 | 2008-01-29 13:27:28 -0800 | [diff] [blame] | 886 | |
| 887 | case VS_STATUS_NO_SCAN: |
jm199354 | bfc848c | 2008-04-10 17:45:54 -0700 | [diff] [blame] | 888 | if (node->vsn_quarantined) |
| 889 | node->vsn_access = VS_ACCESS_DENY; |
jm199354 | 53c1102 | 2008-01-29 13:27:28 -0800 | [diff] [blame] | 890 | else |
jm199354 | bfc848c | 2008-04-10 17:45:54 -0700 | [diff] [blame] | 891 | node->vsn_access = VS_ACCESS_ALLOW; |
| 892 | break; |
jm199354 | 53c1102 | 2008-01-29 13:27:28 -0800 | [diff] [blame] | 893 | |
| 894 | case VS_STATUS_ERROR: |
| 895 | case VS_STATUS_UNDEFINED: |
| 896 | default: |
jm199354 | bfc848c | 2008-04-10 17:45:54 -0700 | [diff] [blame] | 897 | if ((node->vsn_quarantined) || |
| 898 | (node->vsn_modified) || |
| 899 | (node->vsn_scanstamp[0] == '\0')) |
| 900 | node->vsn_access = VS_ACCESS_DENY; |
jm199354 | 53c1102 | 2008-01-29 13:27:28 -0800 | [diff] [blame] | 901 | else |
jm199354 | bfc848c | 2008-04-10 17:45:54 -0700 | [diff] [blame] | 902 | node->vsn_access = VS_ACCESS_ALLOW; |
| 903 | break; |
jm199354 | 911106d | 2007-11-08 16:09:20 -0800 | [diff] [blame] | 904 | } |
| 905 | |
jm199354 | bfc848c | 2008-04-10 17:45:54 -0700 | [diff] [blame] | 906 | DTRACE_PROBE4(vscan__result, |
| 907 | int, idx, int, node->vsn_req->vsr_seqnum, |
| 908 | int, node->vsn_result, int, node->vsn_access); |
jm199354 | 911106d | 2007-11-08 16:09:20 -0800 | [diff] [blame] | 909 | } |
| 910 | |
| 911 | |
| 912 | /* |
| 913 | * vscan_svc_getattr |
| 914 | * |
jm199354 | 53c1102 | 2008-01-29 13:27:28 -0800 | [diff] [blame] | 915 | * Get the vscan related system attributes, AT_SIZE & AT_MTIME. |
jm199354 | 911106d | 2007-11-08 16:09:20 -0800 | [diff] [blame] | 916 | */ |
| 917 | static int |
| 918 | vscan_svc_getattr(int idx) |
| 919 | { |
| 920 | xvattr_t xvattr; |
| 921 | xoptattr_t *xoap = NULL; |
| 922 | vnode_t *vp; |
jm199354 | bfc848c | 2008-04-10 17:45:54 -0700 | [diff] [blame] | 923 | vscan_svc_node_t *node; |
jm199354 | 911106d | 2007-11-08 16:09:20 -0800 | [diff] [blame] | 924 | |
| 925 | ASSERT(MUTEX_HELD(&vscan_svc_mutex)); |
| 926 | |
jm199354 | bfc848c | 2008-04-10 17:45:54 -0700 | [diff] [blame] | 927 | node = &vscan_svc_nodes[idx]; |
| 928 | if ((vp = node->vsn_req->vsr_vp) == NULL) |
jm199354 | 911106d | 2007-11-08 16:09:20 -0800 | [diff] [blame] | 929 | return (-1); |
| 930 | |
| 931 | /* get the attributes */ |
| 932 | xva_init(&xvattr); /* sets AT_XVATTR */ |
| 933 | |
| 934 | xvattr.xva_vattr.va_mask |= AT_SIZE; |
jm199354 | 53c1102 | 2008-01-29 13:27:28 -0800 | [diff] [blame] | 935 | xvattr.xva_vattr.va_mask |= AT_MTIME; |
jm199354 | 911106d | 2007-11-08 16:09:20 -0800 | [diff] [blame] | 936 | XVA_SET_REQ(&xvattr, XAT_AV_MODIFIED); |
| 937 | XVA_SET_REQ(&xvattr, XAT_AV_QUARANTINED); |
| 938 | XVA_SET_REQ(&xvattr, XAT_AV_SCANSTAMP); |
| 939 | |
| 940 | if (VOP_GETATTR(vp, (vattr_t *)&xvattr, 0, kcred, NULL) != 0) |
| 941 | return (-1); |
| 942 | |
| 943 | if ((xoap = xva_getxoptattr(&xvattr)) == NULL) { |
| 944 | cmn_err(CE_NOTE, "Virus scan request failed; " |
| 945 | "file system does not support virus scanning"); |
| 946 | return (-1); |
| 947 | } |
| 948 | |
jm199354 | bfc848c | 2008-04-10 17:45:54 -0700 | [diff] [blame] | 949 | node->vsn_size = xvattr.xva_vattr.va_size; |
| 950 | node->vsn_mtime.tv_sec = xvattr.xva_vattr.va_mtime.tv_sec; |
| 951 | node->vsn_mtime.tv_nsec = xvattr.xva_vattr.va_mtime.tv_nsec; |
jm199354 | 911106d | 2007-11-08 16:09:20 -0800 | [diff] [blame] | 952 | |
| 953 | if (XVA_ISSET_RTN(&xvattr, XAT_AV_MODIFIED) == 0) |
| 954 | return (-1); |
jm199354 | bfc848c | 2008-04-10 17:45:54 -0700 | [diff] [blame] | 955 | node->vsn_modified = xoap->xoa_av_modified; |
jm199354 | 911106d | 2007-11-08 16:09:20 -0800 | [diff] [blame] | 956 | |
| 957 | if (XVA_ISSET_RTN(&xvattr, XAT_AV_QUARANTINED) == 0) |
| 958 | return (-1); |
jm199354 | bfc848c | 2008-04-10 17:45:54 -0700 | [diff] [blame] | 959 | node->vsn_quarantined = xoap->xoa_av_quarantined; |
jm199354 | 911106d | 2007-11-08 16:09:20 -0800 | [diff] [blame] | 960 | |
| 961 | if (XVA_ISSET_RTN(&xvattr, XAT_AV_SCANSTAMP) != 0) { |
jm199354 | bfc848c | 2008-04-10 17:45:54 -0700 | [diff] [blame] | 962 | (void) memcpy(node->vsn_scanstamp, |
jm199354 | 911106d | 2007-11-08 16:09:20 -0800 | [diff] [blame] | 963 | xoap->xoa_av_scanstamp, AV_SCANSTAMP_SZ); |
| 964 | } |
| 965 | |
jm199354 | bfc848c | 2008-04-10 17:45:54 -0700 | [diff] [blame] | 966 | DTRACE_PROBE1(vscan__getattr, vscan_svc_node_t *, node); |
jm199354 | 911106d | 2007-11-08 16:09:20 -0800 | [diff] [blame] | 967 | return (0); |
| 968 | } |
| 969 | |
| 970 | |
| 971 | /* |
| 972 | * vscan_svc_setattr |
| 973 | * |
| 974 | * Set the vscan related system attributes. |
jm199354 | 911106d | 2007-11-08 16:09:20 -0800 | [diff] [blame] | 975 | */ |
| 976 | static int |
jm199354 | 53c1102 | 2008-01-29 13:27:28 -0800 | [diff] [blame] | 977 | vscan_svc_setattr(int idx, int which) |
jm199354 | 911106d | 2007-11-08 16:09:20 -0800 | [diff] [blame] | 978 | { |
| 979 | xvattr_t xvattr; |
| 980 | xoptattr_t *xoap = NULL; |
| 981 | vnode_t *vp; |
| 982 | int len; |
jm199354 | bfc848c | 2008-04-10 17:45:54 -0700 | [diff] [blame] | 983 | vscan_svc_node_t *node; |
jm199354 | 911106d | 2007-11-08 16:09:20 -0800 | [diff] [blame] | 984 | |
| 985 | ASSERT(MUTEX_HELD(&vscan_svc_mutex)); |
| 986 | |
jm199354 | bfc848c | 2008-04-10 17:45:54 -0700 | [diff] [blame] | 987 | node = &vscan_svc_nodes[idx]; |
| 988 | if ((vp = node->vsn_req->vsr_vp) == NULL) |
jm199354 | 911106d | 2007-11-08 16:09:20 -0800 | [diff] [blame] | 989 | return (-1); |
| 990 | |
| 991 | /* update the attributes */ |
| 992 | xva_init(&xvattr); /* sets AT_XVATTR */ |
| 993 | if ((xoap = xva_getxoptattr(&xvattr)) == NULL) |
| 994 | return (-1); |
| 995 | |
jm199354 | 53c1102 | 2008-01-29 13:27:28 -0800 | [diff] [blame] | 996 | if (which & XAT_AV_MODIFIED) { |
| 997 | XVA_SET_REQ(&xvattr, XAT_AV_MODIFIED); |
jm199354 | bfc848c | 2008-04-10 17:45:54 -0700 | [diff] [blame] | 998 | xoap->xoa_av_modified = node->vsn_modified; |
jm199354 | 53c1102 | 2008-01-29 13:27:28 -0800 | [diff] [blame] | 999 | } |
jm199354 | 911106d | 2007-11-08 16:09:20 -0800 | [diff] [blame] | 1000 | |
jm199354 | 53c1102 | 2008-01-29 13:27:28 -0800 | [diff] [blame] | 1001 | if (which & XAT_AV_QUARANTINED) { |
| 1002 | XVA_SET_REQ(&xvattr, XAT_AV_QUARANTINED); |
jm199354 | bfc848c | 2008-04-10 17:45:54 -0700 | [diff] [blame] | 1003 | xoap->xoa_av_quarantined = node->vsn_quarantined; |
jm199354 | 53c1102 | 2008-01-29 13:27:28 -0800 | [diff] [blame] | 1004 | } |
jm199354 | 911106d | 2007-11-08 16:09:20 -0800 | [diff] [blame] | 1005 | |
jm199354 | 53c1102 | 2008-01-29 13:27:28 -0800 | [diff] [blame] | 1006 | if (which & XAT_AV_SCANSTAMP) { |
| 1007 | XVA_SET_REQ(&xvattr, XAT_AV_SCANSTAMP); |
jm199354 | bfc848c | 2008-04-10 17:45:54 -0700 | [diff] [blame] | 1008 | len = strlen(node->vsn_scanstamp); |
jm199354 | 53c1102 | 2008-01-29 13:27:28 -0800 | [diff] [blame] | 1009 | (void) memcpy(xoap->xoa_av_scanstamp, |
jm199354 | bfc848c | 2008-04-10 17:45:54 -0700 | [diff] [blame] | 1010 | node->vsn_scanstamp, len); |
jm199354 | 53c1102 | 2008-01-29 13:27:28 -0800 | [diff] [blame] | 1011 | } |
jm199354 | 911106d | 2007-11-08 16:09:20 -0800 | [diff] [blame] | 1012 | |
| 1013 | /* if access is denied, set mtime to invalidate client cache */ |
jm199354 | bfc848c | 2008-04-10 17:45:54 -0700 | [diff] [blame] | 1014 | if (node->vsn_access != VS_ACCESS_ALLOW) { |
jm199354 | 911106d | 2007-11-08 16:09:20 -0800 | [diff] [blame] | 1015 | xvattr.xva_vattr.va_mask |= AT_MTIME; |
| 1016 | gethrestime(&xvattr.xva_vattr.va_mtime); |
| 1017 | } |
| 1018 | |
| 1019 | if (VOP_SETATTR(vp, (vattr_t *)&xvattr, 0, kcred, NULL) != 0) |
| 1020 | return (-1); |
| 1021 | |
jm199354 | 53c1102 | 2008-01-29 13:27:28 -0800 | [diff] [blame] | 1022 | DTRACE_PROBE2(vscan__setattr, |
jm199354 | bfc848c | 2008-04-10 17:45:54 -0700 | [diff] [blame] | 1023 | vscan_svc_node_t *, node, int, which); |
jm199354 | 53c1102 | 2008-01-29 13:27:28 -0800 | [diff] [blame] | 1024 | |
jm199354 | 911106d | 2007-11-08 16:09:20 -0800 | [diff] [blame] | 1025 | return (0); |
| 1026 | } |
| 1027 | |
| 1028 | |
| 1029 | /* |
| 1030 | * vscan_svc_configure |
| 1031 | * |
| 1032 | * store configuration in vscan_svc_config |
| 1033 | * set up vscan_svc_types array of pointers into |
| 1034 | * vscan_svc_config.vsc_types for efficient searching |
| 1035 | */ |
| 1036 | int |
| 1037 | vscan_svc_configure(vs_config_t *conf) |
| 1038 | { |
| 1039 | int count = 0; |
| 1040 | char *p, *beg, *end; |
| 1041 | |
| 1042 | mutex_enter(&vscan_svc_cfg_mutex); |
| 1043 | |
| 1044 | vscan_svc_config = *conf; |
| 1045 | |
| 1046 | (void) memset(vscan_svc_types, 0, sizeof (vscan_svc_types)); |
| 1047 | |
| 1048 | beg = vscan_svc_config.vsc_types; |
| 1049 | end = beg + vscan_svc_config.vsc_types_len; |
| 1050 | |
| 1051 | for (p = beg; p < end; p += strlen(p) + 1) { |
| 1052 | if (count >= VS_TYPES_MAX) { |
| 1053 | mutex_exit(&vscan_svc_mutex); |
| 1054 | return (-1); |
| 1055 | } |
| 1056 | |
| 1057 | vscan_svc_types[count] = p; |
| 1058 | ++count; |
| 1059 | } |
| 1060 | |
| 1061 | mutex_exit(&vscan_svc_cfg_mutex); |
| 1062 | return (0); |
| 1063 | } |
| 1064 | |
| 1065 | |
| 1066 | /* |
| 1067 | * vscan_svc_exempt_file |
| 1068 | * |
| 1069 | * check if a file's size or type exempts it from virus scanning |
| 1070 | * |
| 1071 | * If the file is exempt from virus scanning, allow will be set |
| 1072 | * to define whether files access should be allowed (B_TRUE) or |
| 1073 | * denied (B_FALSE) |
| 1074 | * |
| 1075 | * Returns: 1 exempt |
| 1076 | * 0 scan required |
| 1077 | */ |
| 1078 | static int |
| 1079 | vscan_svc_exempt_file(vnode_t *vp, boolean_t *allow) |
| 1080 | { |
| 1081 | struct vattr attr; |
| 1082 | |
| 1083 | ASSERT(vp != NULL); |
jm199354 | 911106d | 2007-11-08 16:09:20 -0800 | [diff] [blame] | 1084 | |
| 1085 | attr.va_mask = AT_SIZE; |
| 1086 | |
| 1087 | if (VOP_GETATTR(vp, &attr, 0, kcred, NULL) != 0) { |
| 1088 | *allow = B_FALSE; |
| 1089 | return (0); |
| 1090 | } |
| 1091 | |
| 1092 | mutex_enter(&vscan_svc_cfg_mutex); |
| 1093 | |
| 1094 | if (attr.va_size > vscan_svc_config.vsc_max_size) { |
| 1095 | DTRACE_PROBE2(vscan__exempt__filesize, char *, |
| 1096 | vp->v_path, int, *allow); |
| 1097 | |
| 1098 | *allow = (vscan_svc_config.vsc_allow) ? B_TRUE : B_FALSE; |
| 1099 | mutex_exit(&vscan_svc_cfg_mutex); |
| 1100 | return (1); |
| 1101 | } |
| 1102 | |
| 1103 | if (vscan_svc_exempt_filetype(vp->v_path)) { |
| 1104 | DTRACE_PROBE1(vscan__exempt__filetype, char *, vp->v_path); |
| 1105 | *allow = B_TRUE; |
| 1106 | mutex_exit(&vscan_svc_cfg_mutex); |
| 1107 | return (1); |
| 1108 | } |
| 1109 | |
| 1110 | mutex_exit(&vscan_svc_cfg_mutex); |
| 1111 | return (0); |
| 1112 | } |
| 1113 | |
| 1114 | |
| 1115 | /* |
| 1116 | * vscan_svc_exempt_filetype |
| 1117 | * |
| 1118 | * Each entry in vscan_svc_types includes a rule indicator (+,-) |
| 1119 | * followed by the match string for file types to which the rule |
| 1120 | * applies. Look for first match of file type in vscan_svc_types |
| 1121 | * and return 1 (exempt) if the indicator is '-', and 0 (not exempt) |
| 1122 | * if the indicator is '+'. |
| 1123 | * If vscan_svc_match_ext fails, or no match is found, return 0 |
| 1124 | * (not exempt) |
| 1125 | * |
| 1126 | * Returns 1: exempt, 0: not exempt |
| 1127 | */ |
| 1128 | static int |
| 1129 | vscan_svc_exempt_filetype(char *filepath) |
| 1130 | { |
| 1131 | int i, rc, exempt = 0; |
| 1132 | char *filename, *ext; |
| 1133 | |
| 1134 | ASSERT(MUTEX_HELD(&vscan_svc_cfg_mutex)); |
| 1135 | |
| 1136 | if ((filename = strrchr(filepath, '/')) == 0) |
| 1137 | filename = filepath; |
| 1138 | else |
| 1139 | filename++; |
| 1140 | |
| 1141 | if ((ext = strrchr(filename, '.')) == NULL) |
| 1142 | ext = ""; |
| 1143 | else |
| 1144 | ext++; |
| 1145 | |
jm199354 | 911106d | 2007-11-08 16:09:20 -0800 | [diff] [blame] | 1146 | for (i = 0; i < VS_TYPES_MAX; i ++) { |
| 1147 | if (vscan_svc_types[i] == 0) |
| 1148 | break; |
| 1149 | |
| 1150 | rc = vscan_svc_match_ext(vscan_svc_types[i] + 1, ext, 1); |
| 1151 | if (rc == -1) |
| 1152 | break; |
| 1153 | if (rc > 0) { |
| 1154 | DTRACE_PROBE2(vscan__type__match, char *, ext, |
| 1155 | char *, vscan_svc_types[i]); |
| 1156 | exempt = (vscan_svc_types[i][0] == '-'); |
| 1157 | break; |
| 1158 | } |
| 1159 | } |
| 1160 | |
| 1161 | return (exempt); |
| 1162 | } |
| 1163 | |
| 1164 | |
| 1165 | /* |
| 1166 | * vscan_svc_match_ext |
| 1167 | * |
| 1168 | * Performs a case-insensitive match for two strings. The first string |
| 1169 | * argument can contain the wildcard characters '?' and '*' |
| 1170 | * |
| 1171 | * Returns: 0 no match |
| 1172 | * 1 match |
| 1173 | * -1 recursion error |
| 1174 | */ |
| 1175 | static int |
| 1176 | vscan_svc_match_ext(char *patn, char *str, int depth) |
| 1177 | { |
| 1178 | int c1, c2; |
| 1179 | if (depth > VS_EXT_RECURSE_DEPTH) |
| 1180 | return (-1); |
| 1181 | |
| 1182 | for (;;) { |
| 1183 | switch (*patn) { |
| 1184 | case 0: |
| 1185 | return (*str == 0); |
| 1186 | |
| 1187 | case '?': |
| 1188 | if (*str != 0) { |
| 1189 | str++; |
| 1190 | patn++; |
| 1191 | continue; |
| 1192 | } |
| 1193 | return (0); |
| 1194 | |
| 1195 | case '*': |
| 1196 | patn++; |
| 1197 | if (*patn == 0) |
| 1198 | return (1); |
| 1199 | |
| 1200 | while (*str) { |
| 1201 | if (vscan_svc_match_ext(patn, str, depth + 1)) |
| 1202 | return (1); |
| 1203 | str++; |
| 1204 | } |
| 1205 | return (0); |
| 1206 | |
| 1207 | default: |
| 1208 | if (*str != *patn) { |
| 1209 | c1 = *str; |
| 1210 | c2 = *patn; |
| 1211 | |
| 1212 | c1 = tolower(c1); |
| 1213 | c2 = tolower(c2); |
| 1214 | if (c1 != c2) |
| 1215 | return (0); |
| 1216 | } |
| 1217 | str++; |
| 1218 | patn++; |
| 1219 | continue; |
| 1220 | } |
| 1221 | } |
| 1222 | /* NOT REACHED */ |
| 1223 | } |
jm199354 | bfc848c | 2008-04-10 17:45:54 -0700 | [diff] [blame] | 1224 | |
| 1225 | |
| 1226 | /* |
| 1227 | * vscan_svc_insert_req |
| 1228 | * |
| 1229 | * Insert request in next available available slot in vscan_svc_nodes |
| 1230 | * |
| 1231 | * Returns: idx of slot, or -1 if no slot available |
| 1232 | */ |
| 1233 | static int |
| 1234 | vscan_svc_insert_req(vscan_req_t *req) |
| 1235 | { |
| 1236 | int idx; |
| 1237 | vscan_svc_node_t *node; |
| 1238 | |
| 1239 | ASSERT(MUTEX_HELD(&vscan_svc_mutex)); |
| 1240 | |
| 1241 | if (vscan_svc_counts.vsc_node == vs_nodes_max) |
| 1242 | return (-1); |
| 1243 | |
| 1244 | for (idx = 1; idx <= vs_nodes_max; idx++) { |
| 1245 | if (vscan_svc_nodes[idx].vsn_req == NULL) { |
| 1246 | req->vsr_idx = idx; |
| 1247 | |
| 1248 | node = &vscan_svc_nodes[idx]; |
| 1249 | (void) memset(node, 0, sizeof (vscan_svc_node_t)); |
| 1250 | node->vsn_req = req; |
| 1251 | node->vsn_modified = 1; |
| 1252 | node->vsn_result = VS_STATUS_UNDEFINED; |
| 1253 | node->vsn_access = VS_ACCESS_UNDEFINED; |
| 1254 | |
| 1255 | ++(vscan_svc_counts.vsc_node); |
| 1256 | return (idx); |
| 1257 | } |
| 1258 | } |
| 1259 | |
| 1260 | return (-1); |
| 1261 | } |
| 1262 | |
| 1263 | |
| 1264 | /* |
| 1265 | * vscan_svc_remove_req |
| 1266 | */ |
| 1267 | static void |
| 1268 | vscan_svc_remove_req(int idx) |
| 1269 | { |
| 1270 | ASSERT(MUTEX_HELD(&vscan_svc_mutex)); |
| 1271 | |
| 1272 | if (idx != 0) { |
| 1273 | (void) memset(&vscan_svc_nodes[idx], 0, |
| 1274 | sizeof (vscan_svc_node_t)); |
| 1275 | --(vscan_svc_counts.vsc_node); |
| 1276 | } |
| 1277 | } |
| 1278 | |
| 1279 | |
| 1280 | /* |
| 1281 | * vscan_svc_reql_find |
| 1282 | */ |
| 1283 | static vscan_req_t * |
| 1284 | vscan_svc_reql_find(vnode_t *vp) |
| 1285 | { |
| 1286 | vscan_req_t *req; |
| 1287 | ASSERT(MUTEX_HELD(&vscan_svc_mutex)); |
| 1288 | |
| 1289 | req = list_head(&vscan_svc_reql); |
| 1290 | |
| 1291 | while (req != NULL) { |
| 1292 | ASSERT(req->vsr_magic == VS_REQ_MAGIC); |
| 1293 | if ((req->vsr_vp == vp) && |
| 1294 | (req->vsr_state != VS_SVC_REQ_COMPLETE)) |
| 1295 | break; |
| 1296 | |
| 1297 | req = list_next(&vscan_svc_reql, req); |
| 1298 | } |
| 1299 | |
| 1300 | return (req); |
| 1301 | } |
| 1302 | |
| 1303 | |
| 1304 | /* |
| 1305 | * vscan_svc_reql_insert |
| 1306 | */ |
| 1307 | static vscan_req_t * |
| 1308 | vscan_svc_reql_insert(vnode_t *vp) |
| 1309 | { |
| 1310 | vscan_req_t *req; |
| 1311 | |
| 1312 | ASSERT(MUTEX_HELD(&vscan_svc_mutex)); |
| 1313 | |
| 1314 | /* if request already in list then return it */ |
| 1315 | if ((req = vscan_svc_reql_find(vp)) != NULL) |
| 1316 | return (req); |
| 1317 | |
| 1318 | /* if list is full return NULL */ |
| 1319 | if (vscan_svc_counts.vsc_reql == vs_reqs_max) |
| 1320 | return (NULL); |
| 1321 | |
| 1322 | /* create a new request and insert into list */ |
| 1323 | VN_HOLD(vp); |
| 1324 | |
| 1325 | req = kmem_zalloc(sizeof (vscan_req_t), KM_SLEEP); |
| 1326 | |
| 1327 | req->vsr_magic = VS_REQ_MAGIC; |
| 1328 | if (vscan_svc_seqnum == UINT32_MAX) |
| 1329 | vscan_svc_seqnum = 0; |
| 1330 | req->vsr_seqnum = ++vscan_svc_seqnum; |
| 1331 | req->vsr_vp = vp; |
| 1332 | req->vsr_refcnt = 1; /* decremented in vscan_svc_scan_complete */ |
| 1333 | req->vsr_state = VS_SVC_REQ_INIT; |
| 1334 | cv_init(&(req->vsr_cv), NULL, CV_DEFAULT, NULL); |
| 1335 | |
| 1336 | list_insert_tail(&vscan_svc_reql, req); |
| 1337 | if (vscan_svc_reql_next == NULL) |
| 1338 | vscan_svc_reql_next = req; |
| 1339 | |
| 1340 | ++(vscan_svc_counts.vsc_reql); |
| 1341 | |
| 1342 | /* wake reql handler thread */ |
| 1343 | cv_signal(&vscan_svc_reql_cv); |
| 1344 | |
| 1345 | return (req); |
| 1346 | } |
| 1347 | |
| 1348 | |
| 1349 | /* |
| 1350 | * vscan_svc_reql_remove |
| 1351 | */ |
| 1352 | static void |
| 1353 | vscan_svc_reql_remove(vscan_req_t *req) |
| 1354 | { |
| 1355 | ASSERT(MUTEX_HELD(&vscan_svc_mutex)); |
| 1356 | ASSERT(req->vsr_magic == VS_REQ_MAGIC); |
| 1357 | |
| 1358 | if (vscan_svc_reql_next == req) |
| 1359 | vscan_svc_reql_next = list_next(&vscan_svc_reql, req); |
| 1360 | |
| 1361 | list_remove(&vscan_svc_reql, req); |
| 1362 | cv_destroy(&(req->vsr_cv)); |
| 1363 | VN_RELE(req->vsr_vp); |
| 1364 | |
| 1365 | kmem_free(req, sizeof (vscan_req_t)); |
| 1366 | --(vscan_svc_counts.vsc_reql); |
| 1367 | } |