diff options
Diffstat (limited to 'usr/src/cmd')
| -rw-r--r-- | usr/src/cmd/devfsadm/Makefile.com | 3 | ||||
| -rw-r--r-- | usr/src/cmd/devfsadm/vscan_link.c | 58 | ||||
| -rw-r--r-- | usr/src/cmd/vscan/vscand/vs_door.c | 24 | ||||
| -rw-r--r-- | usr/src/cmd/vscan/vscand/vs_eng.c | 585 | ||||
| -rw-r--r-- | usr/src/cmd/vscan/vscand/vs_icap.c | 34 | ||||
| -rw-r--r-- | usr/src/cmd/vscan/vscand/vs_incl.h | 44 | ||||
| -rw-r--r-- | usr/src/cmd/vscan/vscand/vs_main.c | 270 | ||||
| -rw-r--r-- | usr/src/cmd/vscan/vscand/vs_stats.c | 59 | ||||
| -rw-r--r-- | usr/src/cmd/vscan/vscand/vs_svc.c | 288 | ||||
| -rwxr-xr-x | usr/src/cmd/vscan/vscand/vscan.d | 318 |
10 files changed, 1252 insertions, 431 deletions
diff --git a/usr/src/cmd/devfsadm/Makefile.com b/usr/src/cmd/devfsadm/Makefile.com index 01ee1836e3..ebafe17839 100644 --- a/usr/src/cmd/devfsadm/Makefile.com +++ b/usr/src/cmd/devfsadm/Makefile.com @@ -18,7 +18,7 @@ # # CDDL HEADER END # -# Copyright 2007 Sun Microsystems, Inc. All rights reserved. +# Copyright 2008 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # # ident "%Z%%M% %I% %E% SMI" @@ -65,6 +65,7 @@ LINK_OBJS_CMN = \ smp_link.o \ md_link.o \ dtrace_link.o \ + vscan_link.o \ zfs_link.o LINK_OBJS = $(LINK_OBJS_CMN) \ diff --git a/usr/src/cmd/devfsadm/vscan_link.c b/usr/src/cmd/devfsadm/vscan_link.c new file mode 100644 index 0000000000..c84ea231f0 --- /dev/null +++ b/usr/src/cmd/devfsadm/vscan_link.c @@ -0,0 +1,58 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <devfsadm.h> +#include <strings.h> +#include <stdio.h> +#include <sys/vscan.h> + +static int vscan(di_minor_t minor, di_node_t node); + +static devfsadm_create_t vscan_create_cbt[] = { + { "pseudo", "ddi_pseudo", "vscan", + TYPE_EXACT | DRV_EXACT, ILEVEL_0, vscan }, +}; +DEVFSADM_CREATE_INIT_V0(vscan_create_cbt); + +static devfsadm_remove_t vscan_remove_cbt[] = { + { "vscan", "^vscan/vscan[0-9]+$", RM_HOT | RM_POST, + ILEVEL_0, devfsadm_rm_all + } +}; +DEVFSADM_REMOVE_INIT_V0(vscan_remove_cbt); + +static int +vscan(di_minor_t minor, di_node_t node) +{ + char *mname = di_minor_name(minor); + char path[MAXPATHLEN]; + + (void) snprintf(path, sizeof (path), "vscan/%s", mname); + (void) devfsadm_mklink(path, node, minor, 0); + + return (DEVFSADM_CONTINUE); +} diff --git a/usr/src/cmd/vscan/vscand/vs_door.c b/usr/src/cmd/vscan/vscand/vs_door.c index 1d2bbd522d..8061318d56 100644 --- a/usr/src/cmd/vscan/vscand/vs_door.c +++ b/usr/src/cmd/vscan/vscand/vs_door.c @@ -111,30 +111,14 @@ static void vs_door_scan_req(void *cookie, char *ptr, size_t size, door_desc_t *dp, uint_t n_desc) { - int flags = 0; - vs_scan_req_t scan_rsp; vs_scan_req_t *scan_req; - char devname[MAXPATHLEN]; - vs_attr_t fattr; + uint32_t result = VS_STATUS_ERROR; - if (ptr == NULL) { - scan_rsp.vsr_result = VS_STATUS_ERROR; - scan_rsp.vsr_scanstamp[0] = '\0'; - } else { + if (ptr != NULL) { /* LINTED E_BAD_PTR_CAST_ALIGN - to be fixed with encoding */ scan_req = (vs_scan_req_t *)ptr; - (void) snprintf(devname, MAXPATHLEN, "%s%d", - VS_DRV_PATH, scan_req->vsr_id); - - fattr.vsa_size = scan_req->vsr_size; - fattr.vsa_modified = scan_req->vsr_modified; - fattr.vsa_quarantined = scan_req->vsr_quarantined; - (void) strlcpy(fattr.vsa_scanstamp, scan_req->vsr_scanstamp, - sizeof (vs_scanstamp_t)); - - scan_rsp.vsr_result = vs_svc_scan_file(devname, - scan_req->vsr_path, &fattr, flags, &scan_rsp.vsr_scanstamp); + result = vs_svc_queue_scan_req(scan_req); } - (void) door_return((char *)&scan_rsp, sizeof (vs_scan_req_t), NULL, 0); + (void) door_return((char *)&result, sizeof (uint32_t), NULL, 0); } diff --git a/usr/src/cmd/vscan/vscand/vs_eng.c b/usr/src/cmd/vscan/vscand/vs_eng.c index 24ededc6af..0bdcb3b7bb 100644 --- a/usr/src/cmd/vscan/vscand/vs_eng.c +++ b/usr/src/cmd/vscan/vscand/vs_eng.c @@ -38,6 +38,7 @@ #include <sys/filio.h> #include <sys/ioctl.h> #include <sys/debug.h> +#include <sys/time.h> #include <netinet/in.h> #include <netinet/tcp.h> #include <arpa/inet.h> @@ -50,14 +51,76 @@ #include <pthread.h> #include <time.h> +#include <signal.h> +#include <thread.h> + #include "vs_incl.h" +/* max connections per scan engine */ +#define VS_CXN_MAX VS_VAL_SE_MAXCONN_MAX + +/* + * vs_eng_state_t - connection state + * + * Each configured scan engine supports up to vse_cfg.vep_maxconn + * connections. These connections are represented by a vs_connection_t + * which defines the connection state, associated socket descriptor + * and how long the connection has been available. A connection + * that has been available but unused for vs_inactivity_timeout + * seconds will be closed by the housekeeper thread. + * + * When a scan engine is reconfigured to have less connections + * (or is disabled) any of he superflous connections which are in + * AVAILABLE state are closed (DISCONNECTED). Others are set to + * CLOSE_PENDING to be closed (DISCONNECTED) when the engine is + * released (when the current request completes). + * + * +---------------------+ + * |---------->| VS_ENG_DISCONNECTED |<-----------------| + * | +---------------------+ | + * | | | + * | | eng_get | + * | v | release/ + * | shutdown +---------------------+ reconfig | shutdown + * |<----------| VS_ENG_RESERVED | -----------| | + * | +---------------------+ | | + * | | v | + * | | +----------------------+ + * | | connect | VS_ENG_CLOSE_PENDING | + * | | +----------------------+ + * | v ^ + * | shutdown +---------------------+ | + * |<----------| VS_ENG_INUSE |------------| + * | +---------------------+ reconfig/error + * | | ^ + * | | release | eng_get + * | reconfig/ | | + * | timeout/ v | + * | shutdown +---------------------+ + * |<----------| VS_ENG_AVAILABLE | + * +---------------------+ + * + */ + +typedef enum { + VS_ENG_DISCONNECTED = 0, + VS_ENG_RESERVED, + VS_ENG_INUSE, + VS_ENG_AVAILABLE, + VS_ENG_CLOSE_PENDING +} vs_eng_state_t; + +typedef struct vs_connection { + vs_eng_state_t vsc_state; + int vsc_sockfd; + struct timeval vsc_avail_time; +} vs_connection_t; typedef struct vs_engine { - vs_props_se_t vse_cfg; /* host, port, maxcon */ - int vse_in_use; /* # connections in use */ - int vse_error; - vs_eng_conn_t vse_conn_root; + vs_props_se_t vse_cfg; /* host, port, maxconn */ + int vse_inuse; /* # connections in use */ + boolean_t vse_error; + vs_connection_t vse_cxns[VS_CXN_MAX]; } vs_engine_t; static vs_engine_t vs_engines[VS_SE_MAX]; @@ -70,22 +133,24 @@ static int vs_eng_wait_count; /* # threads waiting for connection */ static pthread_mutex_t vs_eng_mutex = PTHREAD_MUTEX_INITIALIZER; static pthread_cond_t vs_eng_cv; -static pthread_cond_t vs_eng_shutdown_cv; +int vs_inactivity_timeout = 60; /* seconds */ +int vs_reuse_connection = 1; -static time_t vs_eng_wait = VS_ENG_WAIT_DFLT; +time_t vs_eng_wait = VS_ENG_WAIT_DFLT; /* local functions */ -static int vs_eng_check_errors(void); -static int vs_eng_find_next(int); -static void vs_eng_add_connection(vs_eng_conn_t *); -static void vs_eng_remove_connection(vs_eng_conn_t *); -static void vs_eng_close_connections(void); +static int vs_eng_connect(char *, int); +static boolean_t vs_eng_check_errors(void); +static int vs_eng_find_connection(int *, int *, boolean_t); +static int vs_eng_find_next(boolean_t); static int vs_eng_compare(int, char *, int); +static void vs_eng_config_close(vs_engine_t *, int); +static void *vs_eng_housekeeper(void *); #ifdef FIONBIO /* non-blocking connect */ -static int nbio_connect(vs_eng_conn_t *, const struct sockaddr *, int); +static int nbio_connect(int, const struct sockaddr *, int); int vs_connect_timeout = 5000; /* milliseconds */ #endif /* FIONBIO */ @@ -96,18 +161,21 @@ int vs_connect_timeout = 5000; /* milliseconds */ void vs_eng_init() { + pthread_t tid; + (void) pthread_cond_init(&vs_eng_cv, NULL); - (void) pthread_cond_init(&vs_eng_shutdown_cv, NULL); (void) pthread_mutex_lock(&vs_eng_mutex); - (void) memset(vs_engines, 0, - sizeof (vs_engine_t) * VS_SE_MAX); + (void) memset(vs_engines, 0, sizeof (vs_engine_t) * VS_SE_MAX); + vs_eng_total_maxcon = 0; vs_eng_total_inuse = 0; vs_eng_count = 0; vs_eng_next = 0; (void) pthread_mutex_unlock(&vs_eng_mutex); + + (void) pthread_create(&tid, NULL, vs_eng_housekeeper, NULL); } @@ -119,6 +187,10 @@ vs_eng_init() * If a scan engine has been reconfigured (different host or port) * the scan engine's error count is reset. * + * If the host/port has changed, the engine has been disabled + * or less connections are configured now, connections need + * to be closed or placed in CLOSE_PENDING state (vs_eng_config_close) + * * vs_icap_config is invoked to reset engine-specific data stored * in vs_icap. * @@ -139,14 +211,20 @@ vs_eng_config(vs_props_all_t *config) cfg = &config->va_se[i]; eng = &vs_engines[i]; - if (vs_eng_compare(i, cfg->vep_host, cfg->vep_port) != 0) - eng->vse_error = 0; + if (vs_eng_compare(i, cfg->vep_host, cfg->vep_port) != 0) { + vs_eng_config_close(eng, 0); + eng->vse_error = B_FALSE; + } if (cfg->vep_enable) { + if (cfg->vep_maxconn < eng->vse_cfg.vep_maxconn) + vs_eng_config_close(eng, cfg->vep_maxconn); + eng->vse_cfg = *cfg; vs_eng_total_maxcon += cfg->vep_maxconn; vs_eng_count++; } else { + vs_eng_config_close(eng, 0); (void) memset(&eng->vse_cfg, 0, sizeof (vs_props_se_t)); } @@ -161,29 +239,93 @@ vs_eng_config(vs_props_all_t *config) /* - * vs_eng_fini + * vs_eng_config_close * - * Close all scan engine connections to abort in-progress scans, - * and wait until all to sessions are complete, and there are no - * waiting threads. - * Set vs_eng_total_maxcon to 0 to ensure no new engine sessions - * can be initiated while we're waiting. + * If the host/port has changed, the engine has been disabled + * or less connections are configured now, connections need + * to be closed or placed in CLOSE_PENDING state + */ +static void +vs_eng_config_close(vs_engine_t *eng, int start_idx) +{ + int i; + vs_connection_t *cxn; + + for (i = start_idx; i < eng->vse_cfg.vep_maxconn; i++) { + cxn = &(eng->vse_cxns[i]); + + switch (cxn->vsc_state) { + case VS_ENG_RESERVED: + case VS_ENG_INUSE: + cxn->vsc_state = VS_ENG_CLOSE_PENDING; + break; + case VS_ENG_AVAILABLE: + (void) close(cxn->vsc_sockfd); + cxn->vsc_sockfd = -1; + cxn->vsc_state = VS_ENG_DISCONNECTED; + break; + case VS_ENG_CLOSE_PENDING: + case VS_ENG_DISCONNECTED: + break; + } + } +} + + +/* + * vs_eng_fini */ void vs_eng_fini() { - (void) pthread_mutex_lock(&vs_eng_mutex); + (void) pthread_cond_destroy(&vs_eng_cv); +} - vs_eng_total_maxcon = 0; - vs_eng_close_connections(); +/* + * vs_eng_housekeeper + * + * Wakeup every (vs_inactivity_timeout / 2) seconds and close + * any connections that are in AVAILABLE state but have not + * been used for vs_inactivity_timeout seconds. + */ +/* ARGSUSED */ +static void * +vs_eng_housekeeper(void *arg) +{ + struct timeval now; + long expire; + int i, j; + vs_engine_t *eng; + vs_connection_t *cxn; - while (vs_eng_total_inuse > 0 || vs_eng_wait_count > 0) - (void) pthread_cond_wait(&vs_eng_shutdown_cv, &vs_eng_mutex); + for (;;) { + (void) sleep(vs_inactivity_timeout / 2); - (void) pthread_mutex_unlock(&vs_eng_mutex); - (void) pthread_cond_destroy(&vs_eng_cv); - (void) pthread_cond_destroy(&vs_eng_shutdown_cv); + if (vscand_get_state() == VS_STATE_SHUTDOWN) + break; + + (void) gettimeofday(&now, NULL); + expire = now.tv_sec - vs_inactivity_timeout; + + (void) pthread_mutex_lock(&vs_eng_mutex); + for (i = 0; i < VS_SE_MAX; i++) { + eng = &(vs_engines[i]); + for (j = 0; j < eng->vse_cfg.vep_maxconn; j++) { + cxn = &(eng->vse_cxns[j]); + + if ((cxn->vsc_state == VS_ENG_AVAILABLE) && + (cxn->vsc_avail_time.tv_sec < expire)) { + (void) close(cxn->vsc_sockfd); + cxn->vsc_sockfd = -1; + cxn->vsc_state = VS_ENG_DISCONNECTED; + } + } + } + (void) pthread_mutex_unlock(&vs_eng_mutex); + } + + return (NULL); } @@ -194,45 +336,56 @@ vs_eng_fini() * engine in vs_engines set or clear the error state of the * engine and update the error statistics. * - * If error == 0, clear the error state(0), else set the error - * state (1) + * If error == 0, clear the error state(B_FALSE), else set + * the error state (B_TRUE) and increment engine error stats */ void -vs_eng_set_error(vs_eng_conn_t *conn, int error) +vs_eng_set_error(vs_eng_ctx_t *eng_ctx, int error) { - int idx = conn->vsc_idx; + int eidx = eng_ctx->vse_eidx; + int cidx = eng_ctx->vse_cidx; + vs_engine_t *eng; (void) pthread_mutex_lock(&vs_eng_mutex); - if (vs_eng_compare(idx, conn->vsc_host, conn->vsc_port) == 0) - vs_engines[idx].vse_error = error ? 1 : 0; + eng = &(vs_engines[eidx]); + + if (vs_eng_compare(eidx, eng_ctx->vse_host, eng_ctx->vse_port) == 0) + eng->vse_error = (error == 0) ? B_FALSE : B_TRUE; + + if (error != 0) { + eng->vse_cxns[cidx].vsc_state = VS_ENG_CLOSE_PENDING; + vs_stats_eng_err(eng_ctx->vse_engid); + } (void) pthread_mutex_unlock(&vs_eng_mutex); } - /* * vs_eng_get * Get next available scan engine connection. - * If retry != 0 look for a scan engine with no errors. + * If retry == B_TRUE look for a scan engine with no errors. * * Returns: 0 - success * -1 - error */ int -vs_eng_get(vs_eng_conn_t *conn, int retry) +vs_eng_get(vs_eng_ctx_t *eng_ctx, boolean_t retry) { struct timespec tswait; - int idx; + int eidx, cidx, sockfd; + vs_engine_t *eng; + vs_connection_t *cxn; (void) pthread_mutex_lock(&vs_eng_mutex); /* - * If no engines connections configured or + * If no engines connections configured OR * retry and only one engine configured, give up */ - if ((vs_eng_total_maxcon <= 0) || (retry && (vs_eng_count <= 1))) { + if ((vs_eng_total_maxcon <= 0) || + ((retry == B_TRUE) && (vs_eng_count <= 1))) { (void) pthread_mutex_unlock(&vs_eng_mutex); return (-1); } @@ -241,9 +394,9 @@ vs_eng_get(vs_eng_conn_t *conn, int retry) tswait.tv_nsec = 0; while ((vscand_get_state() != VS_STATE_SHUTDOWN) && - ((idx = vs_eng_find_next(retry)) == -1)) { + (vs_eng_find_connection(&eidx, &cidx, retry) == -1)) { /* If retry and all configured engines have errors, give up */ - if (retry && vs_eng_check_errors()) { + if (retry && vs_eng_check_errors() == B_TRUE) { (void) pthread_mutex_unlock(&vs_eng_mutex); return (-1); } @@ -255,8 +408,6 @@ vs_eng_get(vs_eng_conn_t *conn, int retry) syslog(LOG_WARNING, "Scan Engine " "- timeout waiting for available engine"); vs_eng_wait_count--; - if (vscand_get_state() == VS_STATE_SHUTDOWN) - (void) pthread_cond_signal(&vs_eng_shutdown_cv); (void) pthread_mutex_unlock(&vs_eng_mutex); return (-1); } @@ -264,31 +415,81 @@ vs_eng_get(vs_eng_conn_t *conn, int retry) } if (vscand_get_state() == VS_STATE_SHUTDOWN) { - (void) pthread_cond_signal(&vs_eng_shutdown_cv); (void) pthread_mutex_unlock(&vs_eng_mutex); return (-1); } - conn->vsc_idx = idx; - (void) strlcpy(conn->vsc_engid, vs_engines[idx].vse_cfg.vep_engid, - sizeof (conn->vsc_engid)); - (void) strlcpy(conn->vsc_host, vs_engines[idx].vse_cfg.vep_host, - sizeof (conn->vsc_host)); - conn->vsc_port = vs_engines[idx].vse_cfg.vep_port; + eng = &(vs_engines[eidx]); + cxn = &(eng->vse_cxns[cidx]); /* update in use counts */ - vs_engines[idx].vse_in_use++; + eng->vse_inuse++; vs_eng_total_inuse++; - /* add to connections list for engine */ - vs_eng_add_connection(conn); - /* update round-robin index */ if (!retry) - vs_eng_next = (idx == VS_SE_MAX) ? 0 : idx + 1; + vs_eng_next = (eidx == VS_SE_MAX) ? 0 : eidx + 1; + + /* populate vs_eng_ctx_t */ + eng_ctx->vse_eidx = eidx; + eng_ctx->vse_cidx = cidx; + (void) strlcpy(eng_ctx->vse_engid, eng->vse_cfg.vep_engid, + sizeof (eng_ctx->vse_engid)); + (void) strlcpy(eng_ctx->vse_host, eng->vse_cfg.vep_host, + sizeof (eng_ctx->vse_host)); + eng_ctx->vse_port = eng->vse_cfg.vep_port; + eng_ctx->vse_sockfd = cxn->vsc_sockfd; + + if (cxn->vsc_state == VS_ENG_INUSE) { + (void) pthread_mutex_unlock(&vs_eng_mutex); + return (0); + } + + /* state == VS_ENG_RESERVED, need to connect */ (void) pthread_mutex_unlock(&vs_eng_mutex); + sockfd = vs_eng_connect(eng_ctx->vse_host, eng_ctx->vse_port); + + /* retry a failed connection once */ + if (sockfd == -1) { + (void) sleep(1); + sockfd = vs_eng_connect(eng_ctx->vse_host, eng_ctx->vse_port); + } + + if (sockfd == -1) { + syslog(LOG_WARNING, "Scan Engine - connection error (%s:%d) %s", + eng_ctx->vse_host, eng_ctx->vse_port, + errno ? strerror(errno) : ""); + vs_eng_set_error(eng_ctx, 1); + vs_eng_release(eng_ctx); + return (-1); + } + + (void) pthread_mutex_lock(&vs_eng_mutex); + switch (cxn->vsc_state) { + case VS_ENG_DISCONNECTED: + /* SHUTDOWN occured */ + (void) pthread_mutex_unlock(&vs_eng_mutex); + vs_eng_release(eng_ctx); + return (-1); + case VS_ENG_RESERVED: + cxn->vsc_state = VS_ENG_INUSE; + break; + case VS_ENG_CLOSE_PENDING: + /* reconfigure occured. Connection will be closed after use */ + break; + case VS_ENG_INUSE: + case VS_ENG_AVAILABLE: + default: + ASSERT(0); + break; + } + + cxn->vsc_sockfd = sockfd; + eng_ctx->vse_sockfd = sockfd; + + (void) pthread_mutex_unlock(&vs_eng_mutex); return (0); } @@ -296,24 +497,73 @@ vs_eng_get(vs_eng_conn_t *conn, int retry) /* * vs_eng_check_errors * - * Check if there are any engines, with maxcon > 0, - * which are not in error state + * Check if all engines with maxconn > 0 are in error state * - * Returns: 1 - all (valid) engines are in error state - * 0 - otherwise + * Returns: B_TRUE - all (valid) engines are in error state + * B_FALSE - otherwise */ -static int +static boolean_t vs_eng_check_errors() { int i; for (i = 0; i < VS_SE_MAX; i++) { if (vs_engines[i].vse_cfg.vep_maxconn > 0 && - (vs_engines[i].vse_error == 0)) + (vs_engines[i].vse_error == B_FALSE)) + return (B_FALSE); + } + + return (B_TRUE); +} + + +/* + * vs_eng_find_connection + * + * Identify the next engine to be used (vs_eng_find_next()). + * Select the engine's first connection in AVAILABLE state. + * If no connection is in AVAILABLE state, select the first + * that is in DISCONNECTED state. + * + * Returns: 0 success + * -1 no engine connections available (eng_idx & cxn_idx undefined) + */ +static int +vs_eng_find_connection(int *eng_idx, int *cxn_idx, boolean_t retry) +{ + int i, idx; + vs_engine_t *eng; + vs_connection_t *cxn; + + /* identify engine */ + if ((idx = vs_eng_find_next(retry)) == -1) + return (-1); + + eng = &(vs_engines[idx]); + *eng_idx = idx; + + /* identify connection */ + idx = -1; + for (i = 0; i < eng->vse_cfg.vep_maxconn; i++) { + cxn = &(eng->vse_cxns[i]); + if (cxn->vsc_state == VS_ENG_AVAILABLE) { + *cxn_idx = i; + cxn->vsc_state = VS_ENG_INUSE; return (0); + } + + if ((idx == -1) && + (cxn->vsc_state == VS_ENG_DISCONNECTED)) { + idx = i; + } } - return (1); + if (idx == -1) + return (-1); + + eng->vse_cxns[idx].vsc_state = VS_ENG_RESERVED; + *cxn_idx = idx; + return (0); } @@ -321,25 +571,25 @@ vs_eng_check_errors() * vs_eng_find_next * * Returns: -1 no engine connections available - * idx of engine to use + * idx of engine to use */ static int -vs_eng_find_next(int retry) +vs_eng_find_next(boolean_t retry) { int i; for (i = vs_eng_next; i < VS_SE_MAX; i++) { - if (vs_engines[i].vse_in_use < + if (vs_engines[i].vse_inuse < vs_engines[i].vse_cfg.vep_maxconn) { - if (!retry || (vs_engines[i].vse_error == 0)) + if (!retry || (vs_engines[i].vse_error == B_FALSE)) return (i); } } for (i = 0; i < vs_eng_next; i++) { - if (vs_engines[i].vse_in_use < + if (vs_engines[i].vse_inuse < vs_engines[i].vse_cfg.vep_maxconn) { - if (!retry || (vs_engines[i].vse_error == 0)) + if (!retry || (vs_engines[i].vse_error == B_FALSE)) return (i); } } @@ -352,135 +602,144 @@ vs_eng_find_next(int retry) * vs_eng_release */ void -vs_eng_release(vs_eng_conn_t *conn) +vs_eng_release(const vs_eng_ctx_t *eng_ctx) { - int idx = conn->vsc_idx; - - /* disconnect */ - if (conn->vsc_sockfd != -1) { - (void) close(conn->vsc_sockfd); - conn->vsc_sockfd = -1; - } + int eidx = eng_ctx->vse_eidx; + int cidx = eng_ctx->vse_cidx; + vs_connection_t *cxn; (void) pthread_mutex_lock(&vs_eng_mutex); + cxn = &(vs_engines[eidx].vse_cxns[cidx]); + + switch (cxn->vsc_state) { + case VS_ENG_DISCONNECTED: + break; + case VS_ENG_RESERVED: + cxn->vsc_state = VS_ENG_DISCONNECTED; + break; + case VS_ENG_INUSE: + if (vs_reuse_connection) { + cxn->vsc_state = VS_ENG_AVAILABLE; + (void) gettimeofday(&cxn->vsc_avail_time, NULL); + break; + } + /* LINTED E_CASE_FALL_THROUGH - close connection */ + case VS_ENG_CLOSE_PENDING: + (void) close(cxn->vsc_sockfd); + cxn->vsc_sockfd = -1; + cxn->vsc_state = VS_ENG_DISCONNECTED; + break; + case VS_ENG_AVAILABLE: + default: + ASSERT(0); + break; + } /* decrement in use counts */ - vs_engines[idx].vse_in_use--; + vs_engines[eidx].vse_inuse--; vs_eng_total_inuse--; - /* remove from connections list for engine */ - vs_eng_remove_connection(conn); - /* wake up next thread waiting for a connection */ (void) pthread_cond_signal(&vs_eng_cv); - /* if shutdown, send shutdown signal */ - if (vscand_get_state() == VS_STATE_SHUTDOWN) - (void) pthread_cond_signal(&vs_eng_shutdown_cv); - (void) pthread_mutex_unlock(&vs_eng_mutex); } /* - * vs_eng_add_connection - * Add a connection into appropriate engine's connections list - */ -static void -vs_eng_add_connection(vs_eng_conn_t *conn) -{ - vs_eng_conn_t *conn_root; - - conn_root = &(vs_engines[conn->vsc_idx].vse_conn_root); - conn->vsc_prev = conn_root; - conn->vsc_next = conn_root->vsc_next; - if (conn->vsc_next) - (conn->vsc_next)->vsc_prev = conn; - conn_root->vsc_next = conn; -} - - -/* - * vs_eng_remove_connection - * Remove a connection from appropriate engine's connections list - */ -static void -vs_eng_remove_connection(vs_eng_conn_t *conn) -{ - (conn->vsc_prev)->vsc_next = conn->vsc_next; - if (conn->vsc_next) - (conn->vsc_next)->vsc_prev = conn->vsc_prev; -} - - -/* * vs_eng_close_connections + * + * Set vs_eng_total_maxcon to 0 to ensure no new engine sessions + * can be initiated. * Close all open connections to abort in-progress scans. + * Set connection state to DISCONNECTED. */ -static void +void vs_eng_close_connections(void) { - int i; - vs_eng_conn_t *conn; + int i, j; + vs_connection_t *cxn; + + (void) pthread_mutex_lock(&vs_eng_mutex); + vs_eng_total_maxcon = 0; for (i = 0; i < VS_SE_MAX; i++) { - conn = vs_engines[i].vse_conn_root.vsc_next; - while (conn) { - (void) close(conn->vsc_sockfd); - conn->vsc_sockfd = -1; - conn = conn->vsc_next; + for (j = 0; j < VS_CXN_MAX; j++) { + cxn = &(vs_engines[i].vse_cxns[j]); + + switch (cxn->vsc_state) { + case VS_ENG_INUSE: + case VS_ENG_AVAILABLE: + case VS_ENG_CLOSE_PENDING: + (void) close(cxn->vsc_sockfd); + cxn->vsc_sockfd = -1; + break; + case VS_ENG_DISCONNECTED: + case VS_ENG_RESERVED: + default: + break; + + } + + cxn->vsc_state = VS_ENG_DISCONNECTED; } } + (void) pthread_mutex_unlock(&vs_eng_mutex); } /* * vs_eng_connect * open socket connection to remote scan engine + * + * Returns: sockfd or -1 (error) */ -int -vs_eng_connect(vs_eng_conn_t *conn) +static int +vs_eng_connect(char *host, int port) { - int rc, sock_opt, err_num; + int rc, sockfd, opt_nodelay, opt_keepalive, opt_reuseaddr, err_num; struct sockaddr_in addr; struct hostent *hp; - if ((conn->vsc_sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) + if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) return (-1); - hp = getipnodebyname(conn->vsc_host, AF_INET, 0, &err_num); - if (hp == NULL) + hp = getipnodebyname(host, AF_INET, 0, &err_num); + if (hp == NULL) { + (void) close(sockfd); return (-1); + } (void) memset(&addr, 0, sizeof (addr)); (void) memcpy(&addr.sin_addr, hp->h_addr, hp->h_length); - addr.sin_port = htons(conn->vsc_port); + addr.sin_port = htons(port); addr.sin_family = hp->h_addrtype; freehostent(hp); #ifdef FIONBIO /* Use non-blocking mode for connect. */ - rc = nbio_connect(conn, (struct sockaddr *)&addr, + rc = nbio_connect(sockfd, (struct sockaddr *)&addr, sizeof (struct sockaddr)); #else - rc = connect(conn->vsc_sockfd, (struct sockaddr *)&addr, + rc = connect(sockfd, (struct sockaddr *)&addr, sizeof (struct sockaddr)); #endif - sock_opt = 1; - - if ((rc < 0) || (vscand_get_state() == VS_STATE_SHUTDOWN) || - (setsockopt(conn->vsc_sockfd, IPPROTO_TCP, TCP_NODELAY, - &sock_opt, sizeof (sock_opt)) < 0) || - (setsockopt(conn->vsc_sockfd, SOL_SOCKET, SO_KEEPALIVE, - &sock_opt, sizeof (sock_opt)) < 0)) { - syslog(LOG_WARNING, "Scan Engine - connection error (%s:%d) %s", - conn->vsc_host, conn->vsc_port, strerror(errno)); - (void) close(conn->vsc_sockfd); - conn->vsc_sockfd = -1; + opt_nodelay = 1; + opt_keepalive = 1; + opt_reuseaddr = 1; + + if ((rc < 0) || + (setsockopt(sockfd, IPPROTO_TCP, TCP_NODELAY, + &opt_nodelay, sizeof (opt_nodelay)) < 0) || + (setsockopt(sockfd, SOL_SOCKET, SO_KEEPALIVE, + &opt_keepalive, sizeof (opt_keepalive)) < 0) || + (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, + &opt_reuseaddr, sizeof (opt_reuseaddr)) < 0)) { + (void) close(sockfd); return (-1); } - return (0); + return (sockfd); } @@ -493,20 +752,20 @@ vs_eng_connect(vs_eng_conn_t *conn) */ #ifdef FIONBIO static int -nbio_connect(vs_eng_conn_t *conn, const struct sockaddr *sa, int sa_len) +nbio_connect(int sockfd, const struct sockaddr *sa, int sa_len) { struct pollfd pfd; int nbio, rc; - int soc = conn->vsc_sockfd; int error, len = sizeof (error); nbio = 1; - if ((ioctl(soc, FIONBIO, &nbio)) < 0) - return (connect(soc, sa, sa_len)); + if ((ioctl(sockfd, FIONBIO, &nbio)) < 0) + return (connect(sockfd, sa, sa_len)); - if ((rc = connect(soc, sa, sa_len)) != 0) { + if ((rc = connect(sockfd, sa, sa_len)) != 0) { if (errno == EINPROGRESS || errno == EINTR) { - pfd.fd = soc; + errno = 0; + pfd.fd = sockfd; pfd.events = POLLOUT; pfd.revents = 0; @@ -515,16 +774,24 @@ nbio_connect(vs_eng_conn_t *conn, const struct sockaddr *sa, int sa_len) errno = ETIMEDOUT; rc = -1; } else { - rc = getsockopt(soc, SOL_SOCKET, SO_ERROR, - &error, &len); - if (rc != 0 || error != 0) + if ((pfd.revents & + (POLLHUP | POLLERR | POLLNVAL)) || + (!(pfd.revents & POLLOUT))) { rc = -1; + } else { + rc = getsockopt(sockfd, SOL_SOCKET, + SO_ERROR, &error, &len); + if (rc != 0 || error != 0) + rc = -1; + if (error != 0) + errno = error; + } } } } nbio = 0; - (void) ioctl(soc, FIONBIO, &nbio); + (void) ioctl(sockfd, FIONBIO, &nbio); return (rc); } @@ -555,7 +822,7 @@ vs_eng_scanstamp_current(vs_scanstamp_t scanstamp) (void) pthread_mutex_lock(&vs_eng_mutex); for (i = 0; i < VS_SE_MAX; i++) { if ((vs_engines[i].vse_cfg.vep_enable) && - (vs_engines[i].vse_error == 0) && + (vs_engines[i].vse_error == B_FALSE) && (vs_icap_compare_scanstamp(i, scanstamp) == 0)) break; } diff --git a/usr/src/cmd/vscan/vscand/vs_icap.c b/usr/src/cmd/vscan/vscand/vs_icap.c index cb970ffe32..ec9634841a 100644 --- a/usr/src/cmd/vscan/vscand/vs_icap.c +++ b/usr/src/cmd/vscan/vscand/vs_icap.c @@ -235,24 +235,33 @@ vs_icap_config(int idx, char *host, int port) * Returns: result->vsr_rc */ int -vs_icap_scan_file(vs_eng_conn_t *conn, char *devname, char *fname, +vs_icap_scan_file(vs_eng_ctx_t *eng, char *devname, char *fname, uint64_t fsize, int flags, vs_result_t *result) { vs_scan_ctx_t ctx; int fd; - if ((fd = open(devname, O_RDONLY)) == -1) { - syslog(LOG_ERR, "Failed to open device %s", devname); + fd = open(devname, O_RDONLY); + + /* retry once on ENOENT as /dev link may not be created yet */ + if ((fd == -1) && (errno == ENOENT)) { + (void) sleep(1); + fd = open(devname, O_RDONLY); + } + + if (fd == -1) { + syslog(LOG_ERR, "Failed to open device %s - %s", + devname, strerror(errno)); result->vsr_rc = VS_RESULT_ERROR; return (result->vsr_rc); } /* initialize context */ (void) memset(&ctx, 0, sizeof (vs_scan_ctx_t)); - ctx.vsc_idx = conn->vsc_idx; - (void) strlcpy(ctx.vsc_host, conn->vsc_host, sizeof (ctx.vsc_host)); - ctx.vsc_port = conn->vsc_port; - ctx.vsc_sockfd = conn->vsc_sockfd; + ctx.vsc_idx = eng->vse_eidx; + (void) strlcpy(ctx.vsc_host, eng->vse_host, sizeof (ctx.vsc_host)); + ctx.vsc_port = eng->vse_port; + ctx.vsc_sockfd = eng->vse_sockfd; ctx.vsc_fd = fd; ctx.vsc_fname = fname; ctx.vsc_fsize = fsize; @@ -1141,7 +1150,7 @@ vs_icap_write(int fd, char *buf, int buflen) while (resid > 0) { errno = 0; - bytes_sent = write(fd, buf, resid); + bytes_sent = write(fd, ptr, resid); if (bytes_sent < 0) { if (errno == EINTR) continue; @@ -1171,7 +1180,7 @@ vs_icap_read(int fd, char *buf, int len) while (resid > 0) { errno = 0; - bytes_read = read(fd, buf, resid); + bytes_read = read(fd, ptr, resid); if (bytes_read < 0) { if (errno == EINTR) continue; @@ -1275,9 +1284,10 @@ vs_icap_readline(vs_scan_ctx_t *ctx, char *buf, int buflen) continue; if (retval <= 0) { - syslog(LOG_ERR, "Error receiving data from Scan Engine:" - " %s", retval == 0 ? "Scan Engine disconnected" - : strerror(errno)); + if (vscand_get_state() != VS_STATE_SHUTDOWN) { + syslog(LOG_ERR, "Error receiving data from " + "Scan Engine: %s", strerror(errno)); + } return (-1); } diff --git a/usr/src/cmd/vscan/vscand/vs_incl.h b/usr/src/cmd/vscan/vscand/vs_incl.h index 9977f2a1c2..488ef4243b 100644 --- a/usr/src/cmd/vscan/vscand/vs_incl.h +++ b/usr/src/cmd/vscan/vscand/vs_incl.h @@ -90,51 +90,43 @@ typedef struct vs_result { } vs_result_t; -/* scan engine connection */ -typedef struct vs_eng_conn { - int vsc_idx; - char vsc_engid[VS_SE_NAME_LEN]; - char vsc_host[MAXHOSTNAMELEN]; - int vsc_port; - int vsc_sockfd; - struct vs_eng_conn *vsc_next; - struct vs_eng_conn *vsc_prev; -} vs_eng_conn_t; - - -/* file attributes used by virus scanning */ -typedef struct vs_attr { - int vsa_modified; - int vsa_quarantined; - uint64_t vsa_size; - vs_scanstamp_t vsa_scanstamp; -}vs_attr_t; +/* scan engine connection context */ +typedef struct vs_eng_ctx { + int vse_eidx; /* engine index */ + int vse_cidx; /* connection index */ + char vse_engid[VS_SE_NAME_LEN]; + char vse_host[MAXHOSTNAMELEN]; + int vse_port; + int vse_sockfd; +} vs_eng_ctx_t; /* Function Prototypes */ vs_daemon_state_t vscand_get_state(void); char *vscand_viruslog(void); +int vscand_kernel_result(vs_scan_rsp_t *); int vs_door_init(void); void vs_door_fini(void); -void vs_svc_init(void); +int vs_svc_init(uint32_t); void vs_svc_fini(void); -int vs_svc_scan_file(char *, char *, vs_attr_t *, int, vs_scanstamp_t *); +int vs_svc_queue_scan_req(vs_scan_req_t *); +void vs_svc_terminate(void); void vs_eng_init(void); void vs_eng_fini(void); void vs_eng_config(vs_props_all_t *); -void vs_eng_set_error(vs_eng_conn_t *, int); -int vs_eng_get(vs_eng_conn_t *, int); -int vs_eng_connect(vs_eng_conn_t *); -void vs_eng_release(vs_eng_conn_t *); +void vs_eng_set_error(vs_eng_ctx_t *, int); +int vs_eng_get(vs_eng_ctx_t *, boolean_t); +void vs_eng_release(const vs_eng_ctx_t *); +void vs_eng_close_connections(void); int vs_eng_scanstamp_current(vs_scanstamp_t); void vs_icap_init(void); void vs_icap_fini(void); void vs_icap_config(int, char *, int); -int vs_icap_scan_file(vs_eng_conn_t *, char *, char *, uint64_t, +int vs_icap_scan_file(vs_eng_ctx_t *, char *, char *, uint64_t, int, vs_result_t *); void vs_icap_print_options(int); int vs_icap_compare_scanstamp(int, vs_scanstamp_t); diff --git a/usr/src/cmd/vscan/vscand/vs_main.c b/usr/src/cmd/vscan/vscand/vs_main.c index dd138557cc..b66d762a91 100644 --- a/usr/src/cmd/vscan/vscand/vs_main.c +++ b/usr/src/cmd/vscan/vscand/vs_main.c @@ -19,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -57,13 +57,18 @@ #include <pwd.h> #include <grp.h> #include <priv_utils.h> +#include <rctl.h> #include "vs_incl.h" +#define VS_FILE_DESCRIPTORS 512 + static int vscand_fg = 0; /* daemon by default */ static vs_daemon_state_t vscand_state = VS_STATE_INIT; static int vscand_sigval = 0; static int vscand_kdrv_fd = -1; static pthread_mutex_t vscand_cfg_mutex = PTHREAD_MUTEX_INITIALIZER; +static pthread_cond_t vscand_cfg_cv; +static pthread_t vscand_cfg_tid = 0; /* virus log path */ static char vscand_vlog[MAXPATHLEN]; @@ -83,14 +88,20 @@ static int vscand_daemonize_init(void); static void vscand_daemonize_fini(int, int); static int vscand_init(void); static void vscand_fini(void); +static int vscand_cfg_init(void); +static void vscand_cfg_fini(void); +static void *vscand_cfg_handler(void *); static int vscand_configure(void); +static void vscand_dtrace_cfg(vs_props_all_t *); static int vscand_kernel_bind(void); static void vscand_kernel_unbind(void); static int vscand_kernel_enable(int); static void vscand_kernel_disable(void); static int vscand_kernel_config(vs_config_t *); +static int vscand_kernel_max_req(uint32_t *); static void vscand_error(const char *); static int vscand_get_viruslog(void); +static int vscand_set_resource_limits(void); /* @@ -137,6 +148,8 @@ main(int argc, char **argv) int err_stat = 0, pfd = -1; sigset_t set; struct sigaction act; + int sigval; + mode_t log_mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP; mode_t door_mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH; @@ -172,14 +185,12 @@ main(int argc, char **argv) *vscand_vlog = 0; } - (void) unlink(VS_STATS_DOOR_NAME); (void) vscand_init_file(VS_STATS_DOOR_NAME, daemon_uid, sys_gid, door_mode); /* * Once we're done setting our global state up, set up signal handlers - * for ensuring orderly termination on SIGTERM. If we are starting in - * the foreground, we also use the same handler for SIGINT and SIGHUP. + * for ensuring orderly termination on SIGTERM. */ (void) sigfillset(&set); (void) sigdelset(&set, SIGABRT); /* always unblocked for ASSERT() */ @@ -191,11 +202,11 @@ main(int argc, char **argv) (void) sigaction(SIGTERM, &act, NULL); (void) sigaction(SIGHUP, &act, NULL); /* Refresh config */ (void) sigaction(SIGINT, &act, NULL); - (void) sigaction(SIGUSR1, &act, NULL); + (void) sigaction(SIGPIPE, &act, NULL); (void) sigdelset(&set, SIGTERM); (void) sigdelset(&set, SIGHUP); (void) sigdelset(&set, SIGINT); - (void) sigdelset(&set, SIGUSR1); + (void) sigdelset(&set, SIGPIPE); if (vscand_fg) { (void) sigdelset(&set, SIGTSTP); @@ -227,23 +238,23 @@ main(int argc, char **argv) /* Wait here until shutdown */ while (vscand_state == VS_STATE_RUNNING) { + if (vscand_sigval == 0) + (void) sigsuspend(&set); - (void) sigsuspend(&set); + sigval = vscand_sigval; + vscand_sigval = 0; - switch (vscand_sigval) { + switch (sigval) { case 0: - case SIGUSR1: + case SIGPIPE: break; case SIGHUP: - if (vscand_configure() != 0) - vscand_state = VS_STATE_SHUTDOWN; + (void) pthread_cond_signal(&vscand_cfg_cv); break; default: vscand_state = VS_STATE_SHUTDOWN; break; } - - vscand_sigval = 0; } vscand_fini(); @@ -252,7 +263,7 @@ main(int argc, char **argv) /* - * vscand_parse_args - + * vscand_parse_args * Routine to parse the arguments to the daemon program * 'f' argument runs process in the foreground instead of as a daemon */ @@ -424,20 +435,20 @@ vscand_daemonize_fini(int fd, int err_status) * create specified file and set its uid, gid and mode */ static int -vscand_init_file(char *filepath, uid_t uid, gid_t gid, mode_t mode) +vscand_init_file(char *filepath, uid_t uid, gid_t gid, mode_t access_mode) { int fd, rc = 0; struct stat stat_buf; char buf[MAXPATHLEN]; - if ((fd = open(filepath, O_RDONLY | O_CREAT, mode)) == -1) + if ((fd = open(filepath, O_RDONLY | O_CREAT, access_mode)) == -1) { rc = -1; - else { - if (fstat(fd, &stat_buf) != 0) + } else { + if (fstat(fd, &stat_buf) != 0) { rc = -1; - else { - if (stat_buf.st_mode != mode) { - if (fchmod(fd, mode) != 0) + } else { + if ((stat_buf.st_mode & S_IAMB) != access_mode) { + if (fchmod(fd, access_mode) != 0) rc = -1; } @@ -478,23 +489,33 @@ static int vscand_init(void) { int door_fd = -1; + uint32_t max_req; if (vscand_kernel_bind() < 0) return (-1); + if (vscand_kernel_max_req(&max_req) == -1) + return (-1); + + if (vs_svc_init(max_req) != 0) + return (-1); + if (vs_stats_init() != 0) vscand_error( gettext("failed to initialize statistics interface")); - vs_svc_init(); vs_icap_init(); vs_eng_init(); - if (vscand_configure() != 0) { + /* initialize configuration and handler thread */ + if (vscand_cfg_init() != 0) { vscand_error(gettext("failed to initialize configuration")); + vscand_fini(); return (-1); } + (void) vscand_set_resource_limits(); + if (((door_fd = vs_door_init()) < 0) || (vscand_kernel_enable(door_fd) < 0)) { vscand_fini(); @@ -510,8 +531,8 @@ vscand_init(void) * * vscand_kernel_disable - should be called first to ensure that no * more scan requests are initiated from the kernel module - * vs_door_fini - shouldn't be called until after the in-progress - * scans complete (vs_eng_fini waits for in progress scans) + * vs_svc_terminate - terminate requests and wait for thread completion + * vs_xxx_fini - module cleanup routines * vscand_kernel_unbind - should be called last to tell the kernel module * that vscand is shutdown. */ @@ -520,10 +541,16 @@ vscand_fini(void) { vscand_kernel_disable(); + /* terminate reconfiguration handler thread */ + vscand_cfg_fini(); + + /* terminate requests and wait for completion */ + vs_svc_terminate(); + + /* clean up */ vs_svc_fini(); vs_eng_fini(); vs_icap_fini(); - vs_door_fini(); vs_stats_fini(); @@ -532,6 +559,75 @@ vscand_fini(void) /* + * vscand_cfg_init + * + * initialize configuration and reconfiguration handler thread + */ +static int +vscand_cfg_init(void) +{ + int rc; + + (void) pthread_cond_init(&vscand_cfg_cv, NULL); + + (void) pthread_mutex_lock(&vscand_cfg_mutex); + rc = vscand_configure(); + (void) pthread_mutex_unlock(&vscand_cfg_mutex); + + if (rc != 0) + return (-1); + + if (pthread_create(&vscand_cfg_tid, NULL, vscand_cfg_handler, 0) != 0) { + vscand_cfg_tid = 0; + return (-1); + } + + return (0); +} + + +/* + * vscand_cfg_fini + * + * terminate reconfiguration handler thread + */ +static void +vscand_cfg_fini() +{ + if (vscand_cfg_tid != 0) { + (void) pthread_cond_signal(&vscand_cfg_cv); + (void) pthread_join(vscand_cfg_tid, NULL); + vscand_cfg_tid = 0; + } + (void) pthread_cond_destroy(&vscand_cfg_cv); +} + + +/* + * vscand_cfg_handler + * wait for reconfiguration event and reload configuration + * exit on VS_STATE_SHUTDOWN + */ +/*ARGSUSED*/ +static void * +vscand_cfg_handler(void *arg) +{ + (void) pthread_mutex_lock(&vscand_cfg_mutex); + + while (pthread_cond_wait(&vscand_cfg_cv, &vscand_cfg_mutex) == 0) { + if (vscand_state == VS_STATE_SHUTDOWN) + break; + + (void) vscand_configure(); + } + + (void) pthread_mutex_unlock(&vscand_cfg_mutex); + + return (NULL); +} + + +/* * vscand_configure */ static int @@ -541,12 +637,9 @@ vscand_configure(void) vs_config_t kconfig; vs_props_all_t config; - (void) pthread_mutex_lock(&vscand_cfg_mutex); - (void) memset(&config, 0, sizeof (vs_props_all_t)); if (vs_props_get_all(&config) != VS_ERR_NONE) { vscand_error(gettext("configuration data error")); - (void) pthread_mutex_unlock(&vscand_cfg_mutex); return (-1); } @@ -555,7 +648,6 @@ vscand_configure(void) if (vs_parse_types(config.va_props.vp_types, kconfig.vsc_types, &len) != 0) { vscand_error(gettext("configuration data error - types")); - (void) pthread_mutex_unlock(&vscand_cfg_mutex); return (-1); } kconfig.vsc_types_len = len; @@ -564,24 +656,22 @@ vscand_configure(void) if (vs_strtonum(config.va_props.vp_maxsize, &kconfig.vsc_max_size) != 0) { vscand_error(gettext("configuration data error - max-size")); - (void) pthread_mutex_unlock(&vscand_cfg_mutex); return (-1); } kconfig.vsc_allow = config.va_props.vp_maxsize_action ? 1LL : 0LL; /* Send configuration update to kernel */ if (vscand_kernel_config(&kconfig) != 0) { - (void) pthread_mutex_unlock(&vscand_cfg_mutex); return (-1); } - /* Tell vs_eng things have changed. */ - vs_eng_config(&config); + /* dtrace the configuration data */ + vscand_dtrace_cfg(&config); - /* Tell vs_stats things have changed */ + /* propagate configuration changes */ + vs_eng_config(&config); vs_stats_config(&config); - (void) pthread_mutex_unlock(&vscand_cfg_mutex); return (0); } @@ -667,7 +757,7 @@ vscand_kernel_unbind(void) static int vscand_kernel_enable(int door_fd) { - if (ioctl(vscand_kdrv_fd, VS_DRV_IOCTL_ENABLE, door_fd) < 0) { + if (ioctl(vscand_kdrv_fd, VS_IOCTL_ENABLE, door_fd) < 0) { vscand_error(gettext("failed to bind to kernel")); (void) close(vscand_kdrv_fd); vscand_kdrv_fd = -1; @@ -684,7 +774,7 @@ static void vscand_kernel_disable() { if (vscand_kdrv_fd >= 0) - (void) ioctl(vscand_kdrv_fd, VS_DRV_IOCTL_DISABLE); + (void) ioctl(vscand_kdrv_fd, VS_IOCTL_DISABLE); } @@ -694,11 +784,41 @@ vscand_kernel_disable() int vscand_kernel_config(vs_config_t *conf) { - if (vscand_kdrv_fd < 0) + if ((vscand_kdrv_fd < 0) || + (ioctl(vscand_kdrv_fd, VS_IOCTL_CONFIG, conf) < 0)) { + vscand_error(gettext("failed to send config to kernel")); return (-1); + } - if (ioctl(vscand_kdrv_fd, VS_DRV_IOCTL_CONFIG, conf) < 0) { - vscand_error(gettext("failed to send config to kernel")); + return (0); +} + + +/* + * vscand_kernel_result + */ +int +vscand_kernel_result(vs_scan_rsp_t *scan_rsp) +{ + if ((vscand_kdrv_fd < 0) || + (ioctl(vscand_kdrv_fd, VS_IOCTL_RESULT, scan_rsp) < 0)) { + vscand_error(gettext("failed to send result to kernel")); + return (-1); + } + + return (0); +} + + +/* + * vscand_kernel_max_req + */ +int +vscand_kernel_max_req(uint32_t *max_req) +{ + if ((vscand_kdrv_fd < 0) || + (ioctl(vscand_kdrv_fd, VS_IOCTL_MAX_REQ, max_req) < 0)) { + vscand_error(gettext("failed to get config data from kernel")); return (-1); } @@ -707,6 +827,35 @@ vscand_kernel_config(vs_config_t *conf) /* + * vscand_set_resource_limits + * + * If the process's max file descriptor limit is less than + * VS_FILE_DESCRIPTORS, increae it to VS_FILE_DESCRIPTORS. + */ +static int +vscand_set_resource_limits(void) +{ + int rc = -1; + rctlblk_t *rblk; + char *limit = "process.max-file-descriptor"; + + rblk = (rctlblk_t *)malloc(rctlblk_size()); + + if (rblk != NULL) { + rc = getrctl(limit, NULL, rblk, 0); + if ((rc == 0) && + (rctlblk_get_value(rblk) < VS_FILE_DESCRIPTORS)) { + rctlblk_set_value(rblk, VS_FILE_DESCRIPTORS); + rc = setrctl(limit, NULL, rblk, 0); + } + (void) free(rblk); + } + + return (rc); +} + + +/* * vscand_error */ static void @@ -715,3 +864,42 @@ vscand_error(const char *errmsg) (void) fprintf(stderr, "vscand: %s", errmsg); syslog(LOG_ERR, "%s\n", errmsg); } + + +/* + * vscand_dtrace_cfg + * vscand_dtrace_gen + * vscand_dtrace_eng + * + * Support for dtracing vscand configuration when processing + * a reconfiguration event (SIGHUP) + */ +/*ARGSUSED*/ +static void +vscand_dtrace_eng(char *id, boolean_t enable, char *host, int port, int conn) +{ +} +/*ARGSUSED*/ +static void +vscand_dtrace_gen(char *size, boolean_t action, char *types, char *log) +{ +} +static void +vscand_dtrace_cfg(vs_props_all_t *config) +{ + int i; + + vscand_dtrace_gen(config->va_props.vp_maxsize, + config->va_props.vp_maxsize_action, + config->va_props.vp_types, + config->va_props.vp_vlog); + + for (i = 0; i < VS_SE_MAX; i++) { + if (config->va_se[i].vep_engid[0] != 0) + vscand_dtrace_eng(config->va_se[i].vep_engid, + config->va_se[i].vep_enable, + config->va_se[i].vep_host, + config->va_se[i].vep_port, + config->va_se[i].vep_maxconn); + } +} diff --git a/usr/src/cmd/vscan/vscand/vs_stats.c b/usr/src/cmd/vscan/vscand/vs_stats.c index 0d30c40d32..c053169727 100644 --- a/usr/src/cmd/vscan/vscand/vs_stats.c +++ b/usr/src/cmd/vscan/vscand/vs_stats.c @@ -19,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -53,6 +53,7 @@ static pthread_mutex_t vs_stats_mutex = PTHREAD_MUTEX_INITIALIZER; /* function prototype */ static int vs_stats_check_auth(void); +static void vs_stats_reset(void); static void vs_stats_door_call(void *, char *, size_t, door_desc_t *, uint_t); @@ -144,35 +145,67 @@ static void vs_stats_door_call(void *cookie, char *ptr, size_t size, door_desc_t *dp, uint_t n_desc) { - /* LINTED E_BAD_PTR_CAST_ALIGN - to be fixed with encoding */ + /* LINTED E_BAD_PTR_CAST_ALIGN */ vs_stats_req_t *req = (vs_stats_req_t *)ptr; - vs_stats_t rsp; + vs_stats_rsp_t rsp; - switch (*req) { + if ((cookie != &vs_stats_door_cookie) || + (ptr == NULL) || + (size != sizeof (vs_stats_req_t)) || + (req->vsr_magic != VS_STATS_DOOR_MAGIC)) { + return; + } + + rsp.vsr_magic = VS_STATS_DOOR_MAGIC; + + switch (req->vsr_id) { case VS_STATS_GET: (void) pthread_mutex_lock(&vs_stats_mutex); - (void) memcpy(&rsp, &vscan_stats, sizeof (vs_stats_t)); + rsp.vsr_stats = vscan_stats; (void) pthread_mutex_unlock(&vs_stats_mutex); - (void) door_return((char *)&rsp, sizeof (vs_stats_t), NULL, 0); + (void) door_return((char *)&rsp, sizeof (vs_stats_rsp_t), + NULL, 0); break; case VS_STATS_RESET: - if (vs_stats_check_auth() == 0) { - (void) pthread_mutex_lock(&vs_stats_mutex); - (void) memset(&vscan_stats, 0, sizeof (vs_stats_t)); - (void) pthread_mutex_unlock(&vs_stats_mutex); - } + vs_stats_reset(); (void) door_return(NULL, 0, NULL, 0); break; default: - (void) door_return(NULL, 0, NULL, 0); - break; + return; } } /* + * vs_stats_reset + * + * Reset totals and per-engine statistics to 0 + */ +static void +vs_stats_reset() +{ + int i; + + if (vs_stats_check_auth() != 0) + return; + + (void) pthread_mutex_lock(&vs_stats_mutex); + + vscan_stats.vss_scanned = 0; + vscan_stats.vss_infected = 0; + vscan_stats.vss_cleaned = 0; + vscan_stats.vss_failed = 0; + + for (i = 0; i < VS_SE_MAX; i++) + vscan_stats.vss_eng[i].vss_errors = 0; + + (void) pthread_mutex_unlock(&vs_stats_mutex); +} + + +/* * vs_stats_set * * Update scan request stats diff --git a/usr/src/cmd/vscan/vscand/vs_svc.c b/usr/src/cmd/vscan/vscand/vs_svc.c index d0fee6db30..80029fec08 100644 --- a/usr/src/cmd/vscan/vscand/vs_svc.c +++ b/usr/src/cmd/vscan/vscand/vs_svc.c @@ -39,26 +39,183 @@ #include <fcntl.h> #include <bsm/adt.h> #include <bsm/adt_event.h> +#include <pthread.h> #include "vs_incl.h" +/* + * vs_svc_nodes - table of scan requests and their thread id and + * scan engine context. + * The table is sized by the value passed to vs_svc_init. This + * value is obtained from the kernel and represents the maximum + * request idx that the kernel will request vscand to process. + * The table is indexed by the vsr_idx value passed in + * the scan request - always non-zero. This value is also the index + * into the kernel scan request table and identifies the instance of + * the driver being used to access file data for the scan. Although + * this is of no consequence here, it is useful information for debug. + * + * When a scan request is received a response is sent indicating + * one of the following: + * VS_STATUS_ERROR - an error occurred + * VS_STATUS_NO_SCAN - no scan is required + * VS_STATUS_SCANNING - request has been queued for async processing + * + * If the scan is required (VS_STATUS_SCANNING) a thread is created + * to perform the scan. It's tid is saved in vs_svc_nodes. + * + * In the case of SHUTDOWN, vs_terminate requests that all scan + * engine connections be closed, thus termintaing any in-progress + * scans, then awaits completion of all scanning threads as identified + * in vs_svc_nodes. + */ + +typedef struct vs_svc_node { + pthread_t vsn_tid; + vs_scan_req_t vsn_req; + vs_eng_ctx_t vsn_eng; +} vs_svc_node_t; + +static vs_svc_node_t *vs_svc_nodes; +static uint32_t vs_svc_max_node; /* max idx into vs_svc_nodes */ +static pthread_mutex_t vs_svc_mutex = PTHREAD_MUTEX_INITIALIZER; + + /* local functions */ +static void *vs_svc_async_scan(void *); +static int vs_svc_scan_file(vs_svc_node_t *, vs_scanstamp_t *); static void vs_svc_vlog(char *, vs_result_t *); static void vs_svc_audit(char *, vs_result_t *); + /* * vs_svc_init, vs_svc_fini * * Invoked on daemon load and unload */ -void -vs_svc_init() +int +vs_svc_init(uint32_t max_req) { + vs_svc_max_node = max_req; + vs_svc_nodes = (vs_svc_node_t *) + calloc(max_req + 1, sizeof (vs_svc_node_t)); + + return (vs_svc_nodes == NULL ? -1 : 0); } void vs_svc_fini() { + if (vs_svc_nodes) + free(vs_svc_nodes); +} + + +/* + * vs_svc_terminate + * + * Close all scan engine connections to terminate in-progress scan + * requests, and wait for all threads in vs_svc_nodes to complete + */ +void +vs_svc_terminate() +{ + int i; + pthread_t tid; + + /* close connections to abort requests */ + vs_eng_close_connections(); + + /* wait for threads */ + for (i = 1; i <= vs_svc_max_node; i++) { + + (void) pthread_mutex_lock(&vs_svc_mutex); + tid = vs_svc_nodes[i].vsn_tid; + (void) pthread_mutex_unlock(&vs_svc_mutex); + + if (tid != 0) + (void) pthread_join(tid, NULL); + } +} + + +/* + * vs_svc_queue_scan_req + * + * Determine if the file needs to be scanned - either it has + * been modified or its scanstamp is not current. + * Initiate a thread to process the request, saving the tid + * in vs_svc_nodes[idx].vsn_tid, where idx is the vsr_idx passed in + * the scan request. + * + * Returns: VS_STATUS_ERROR - error + * VS_STATUS_NO_SCAN - no scan required + * VS_STATUS_SCANNING - async scan initiated + */ +int +vs_svc_queue_scan_req(vs_scan_req_t *req) +{ + pthread_t tid; + vs_svc_node_t *node; + + /* No scan if file quarantined */ + if (req->vsr_quarantined) + return (VS_STATUS_NO_SCAN); + + /* No scan if file not modified AND scanstamp is current */ + if ((req->vsr_modified == 0) && + vs_eng_scanstamp_current(req->vsr_scanstamp)) { + return (VS_STATUS_NO_SCAN); + } + + /* scan required */ + node = &(vs_svc_nodes[req->vsr_idx]); + + (void) pthread_mutex_lock(&vs_svc_mutex); + if ((node->vsn_tid != 0) || (req->vsr_idx > vs_svc_max_node)) { + (void) pthread_mutex_unlock(&vs_svc_mutex); + return (VS_STATUS_ERROR); + } + + node->vsn_req = *req; + + if (pthread_create(&tid, NULL, vs_svc_async_scan, (void *)node) != 0) { + (void) pthread_mutex_unlock(&vs_svc_mutex); + return (VS_STATUS_ERROR); + } + + node->vsn_tid = tid; + (void) pthread_mutex_unlock(&vs_svc_mutex); + + return (VS_STATUS_SCANNING); +} + + +/* + * vs_svc_async_scan + * + * Initialize response structure, invoke vs_svc_scan_file to + * perform the scan, then send the result to the kernel. + */ +static void * +vs_svc_async_scan(void *arg) +{ + vs_svc_node_t *node = (vs_svc_node_t *)arg; + vs_scan_req_t *scan_req = &(node->vsn_req); + vs_scan_rsp_t scan_rsp; + + scan_rsp.vsr_idx = scan_req->vsr_idx; + scan_rsp.vsr_seqnum = scan_req->vsr_seqnum; + scan_rsp.vsr_result = vs_svc_scan_file(node, &scan_rsp.vsr_scanstamp); + + /* clear node and send async response to kernel */ + (void) pthread_mutex_lock(&vs_svc_mutex); + (void) memset(node, 0, sizeof (vs_svc_node_t)); + (void) pthread_mutex_unlock(&vs_svc_mutex); + + (void) vscand_kernel_result(&scan_rsp); + + return (NULL); } @@ -66,7 +223,6 @@ vs_svc_fini() * vs_svc_scan_file * * vs_svc_scan_file is responsible for: - * - determining if a scan is required * - obtaining & releasing a scan engine connection * - invoking the scan engine interface code to do the scan * - retrying a failed scan (up to VS_MAX_RETRY times) @@ -75,78 +231,66 @@ vs_svc_fini() * * * Returns: - * VS_STATUS_NO_SCAN - scan not reqd, or daemon shutting down + * VS_STATUS_NO_SCAN - scan not reqd; daemon shutting down * VS_STATUS_CLEAN - scan success. File clean. * new scanstamp returned in scanstamp param. * VS_STATUS_INFECTED - scan success. File infected. * VS_STATUS_ERROR - scan failure either in vscand or scan engine. */ -int -vs_svc_scan_file(char *devname, char *fname, vs_attr_t *fattr, int flags, - vs_scanstamp_t *scanstamp) +static int +vs_svc_scan_file(vs_svc_node_t *node, vs_scanstamp_t *scanstamp) { - vs_eng_conn_t conn; + char devname[MAXPATHLEN]; + int flags = 0; int retries; vs_result_t result; + vs_scan_req_t *req = &(node->vsn_req); + vs_eng_ctx_t *eng = &(node->vsn_eng); - /* initialize response scanstamp to current scanstamp value */ - (void) strlcpy(*scanstamp, fattr->vsa_scanstamp, - sizeof (vs_scanstamp_t)); - - - /* No scan if file quarantined */ - if (fattr->vsa_quarantined) - return (VS_STATUS_NO_SCAN); + (void) snprintf(devname, MAXPATHLEN, "%s%d", VS_DRV_PATH, req->vsr_idx); - /* No scan if file not modified AND scanstamp is current */ - if ((fattr->vsa_modified == 0) && - vs_eng_scanstamp_current(fattr->vsa_scanstamp)) { - return (VS_STATUS_NO_SCAN); - } + /* initialize response scanstamp to current scanstamp value */ + (void) strlcpy(*scanstamp, req->vsr_scanstamp, sizeof (vs_scanstamp_t)); (void) memset(&result, 0, sizeof (vs_result_t)); result.vsr_rc = VS_RESULT_UNDEFINED; for (retries = 0; retries <= VS_MAX_RETRY; retries++) { - /* identify available engine connection */ - if (vs_eng_get(&conn, retries) != 0) { + /* get engine connection */ + if (vs_eng_get(eng, (retries != 0)) != 0) { result.vsr_rc = VS_RESULT_ERROR; continue; } - /* connect to engine and scan file */ - if (vs_eng_connect(&conn) != 0) { - result.vsr_rc = VS_RESULT_SE_ERROR; - } else { - if (vscand_get_state() == VS_STATE_SHUTDOWN) { - vs_eng_release(&conn); - return (VS_STATUS_NO_SCAN); - } - - (void) vs_icap_scan_file(&conn, devname, fname, - fattr->vsa_size, flags, &result); + /* shutdown could occur while waiting for engine connection */ + if (vscand_get_state() == VS_STATE_SHUTDOWN) { + vs_eng_release(eng); + return (VS_STATUS_NO_SCAN); } + /* scan file */ + (void) vs_icap_scan_file(eng, devname, req->vsr_path, + req->vsr_size, flags, &result); + /* if no error, clear error state on engine and break */ if ((result.vsr_rc != VS_RESULT_SE_ERROR) && (result.vsr_rc != VS_RESULT_ERROR)) { - vs_eng_set_error(&conn, 0); - vs_eng_release(&conn); + vs_eng_set_error(eng, 0); + vs_eng_release(eng); break; } /* treat error on shutdown as scan not required */ if (vscand_get_state() == VS_STATE_SHUTDOWN) { - vs_eng_release(&conn); + vs_eng_release(eng); return (VS_STATUS_NO_SCAN); } /* set engine's error state and update engine stats */ - if (result.vsr_rc == VS_RESULT_SE_ERROR) { - vs_eng_set_error(&conn, 1); - vs_stats_eng_err(conn.vsc_engid); - } - vs_eng_release(&conn); + if (result.vsr_rc == VS_RESULT_SE_ERROR) + vs_eng_set_error(eng, 1); + + vs_eng_release(eng); } vs_stats_set(result.vsr_rc); @@ -158,8 +302,8 @@ vs_svc_scan_file(char *devname, char *fname, vs_attr_t *fattr, int flags, */ if (result.vsr_rc == VS_RESULT_CLEANED || result.vsr_rc == VS_RESULT_FORBIDDEN) { - vs_svc_vlog(fname, &result); - vs_svc_audit(fname, &result); + vs_svc_vlog(req->vsr_path, &result); + vs_svc_audit(req->vsr_path, &result); return (VS_STATUS_INFECTED); } @@ -177,8 +321,8 @@ vs_svc_scan_file(char *devname, char *fname, vs_attr_t *fattr, int flags, /* * vs_svc_vlog * - * log details of infections detected in file - * If virus log is not configured or cannot be opened, use syslog. + * log details of infections detected in syslig + * If virus log is configured log details there too */ static void vs_svc_vlog(char *filepath, vs_result_t *result) @@ -190,40 +334,42 @@ vs_svc_vlog(char *filepath, vs_result_t *result) int i; char *log; - if ((log = vscand_viruslog()) != NULL) - fp = fopen(log, "a"); + /* syslog */ + if (result->vsr_nviolations == 0) { + syslog(LOG_WARNING, "quarantine %s\n", filepath); + } else { + for (i = 0; i < result->vsr_nviolations; i++) { + syslog(LOG_WARNING, "quarantine %s %d - %s\n", + filepath, + result->vsr_vrec[i].vr_id, + result->vsr_vrec[i].vr_desc); + } + } - if (fp) { - (void) time(&sec); - timestamp = localtime(&sec); - (void) strftime(timebuf, sizeof (timebuf), "%D %T", timestamp); + /* log file */ + if (((log = vscand_viruslog()) == NULL) || + ((fp = fopen(log, "a")) == NULL)) { + return; } + (void) time(&sec); + timestamp = localtime(&sec); + (void) strftime(timebuf, sizeof (timebuf), "%D %T", timestamp); + if (result->vsr_nviolations == 0) { - if (fp) { - (void) fprintf(fp, "%s quarantine %s", - timebuf, filepath); - } else { - syslog(LOG_WARNING, "quarantine %s\n", filepath); - } + (void) fprintf(fp, "%s quarantine %d[%s]\n", + timebuf, strlen(filepath), filepath); } else { for (i = 0; i < result->vsr_nviolations; i++) { - if (fp) { - (void) fprintf(fp, "%s quarantine %s %d - %s\n", - timebuf, filepath, - result->vsr_vrec[i].vr_id, - result->vsr_vrec[i].vr_desc); - } else { - syslog(LOG_WARNING, "quarantine %s %d - %s\n", - filepath, - result->vsr_vrec[i].vr_id, - result->vsr_vrec[i].vr_desc); - } + (void) fprintf(fp, "%s quarantine %d[%s] %d - %d[%s]\n", + timebuf, strlen(filepath), filepath, + result->vsr_vrec[i].vr_id, + strlen(result->vsr_vrec[i].vr_desc), + result->vsr_vrec[i].vr_desc); } } - if (fp) - (void) fclose(fp); + (void) fclose(fp); } diff --git a/usr/src/cmd/vscan/vscand/vscan.d b/usr/src/cmd/vscan/vscand/vscan.d index f7a16172d6..62a88f23a8 100755 --- a/usr/src/cmd/vscan/vscand/vscan.d +++ b/usr/src/cmd/vscan/vscand/vscan.d @@ -26,155 +26,251 @@ #pragma ident "%Z%%M% %I% %E% SMI" +/* #pragma D option flowindent +*/ /* *** vscan kernel pseudo driver *** */ -/* vscan_svc.c */ -sdt:vscan::vscan-scan-file +/* + * vscan_svc.c + */ +sdt:vscan::vscan-req-counts { - printf("%s (%s)", stringof(arg0), arg1 ? "async" : "sync"); + printf("%s reql: %d, node: %d, taskq: %d", + stringof(arg0), + ((vscan_svc_counts_t *)arg1)->vsc_reql, + ((vscan_svc_counts_t *)arg1)->vsc_node, + ((vscan_svc_counts_t *)arg1)->vsc_tq); } -sdt:vscan::vscan-exempt-filesize +sdt:vscan::vscan-svc-state-violation { - printf("%s EXEMPT (%s)", stringof(arg0), arg1 ? "DENY" : "ALLOW"); + printf("%d %s", arg0, + arg0 == 0 ? "UNCONFIG" : + arg0 == 1 ? "IDLE" : + arg0 == 2 ? "ENABLED" : + arg0 == 3 ? "DISABLED" : "UNKNOWN"); } -sdt:vscan::vscan-type-match +sdt:vscan::vscan-scan-timeout { - printf("ext: %s matched: %s", stringof(arg0), stringof(arg1)); + printf("idx: %d, seqnum: %d - %s", + ((vscan_req_t *)arg0)->vsr_idx, + ((vscan_req_t *)arg0)->vsr_seqnum, + stringof(((vscan_req_t *)arg0)->vsr_vp->v_path)); } -sdt:vscan::vscan-exempt-filetype -{ - printf("%s EXEMPT", stringof(arg0)); -} - -sdt:vscan::vscan-wait-scan +sdt:vscan::vscan-scan-file { - printf("%s (%d) waiters: %d", - stringof(((vscan_file_t *)arg0)->vsf_req.vsr_vp->v_path), - arg1, ((vscan_file_t *)arg0)->vsf_wait_count); + printf("%s (%s)", stringof(arg0), arg1 ? "async" : "sync"); } -sdt:vscan::vscan-wait-slot +sdt:vscan::vscan-exempt-filesize { - printf("%s", stringof(arg0)); + printf("%s EXEMPT (%s)", stringof(arg0), arg1 ? "DENY" : "ALLOW"); } -sdt:vscan::vscan-insert +sdt:vscan::vscan-type-match { - printf("idx: %d - %s", arg1, stringof(arg0)); + printf("ext: %s matched: %s", stringof(arg0), stringof(arg1)); } -sdt:vscan::vscan-release +sdt:vscan::vscan-exempt-filetype { - printf("idx: %d - %s", arg1, stringof(arg0)); + printf("%s EXEMPT", stringof(arg0)); } sdt:vscan::vscan-getattr { printf("%s, m: %d, q: %d, scanstamp: %s", - stringof(((vscan_file_t *)arg0)->vsf_req.vsr_vp->v_path), - ((vscan_file_t *)arg0)->vsf_modified, - ((vscan_file_t *)arg0)->vsf_quarantined, - stringof(((vscan_file_t *)arg0)->vsf_scanstamp)); + stringof(((vscan_svc_node_t *)arg0)->vsn_req->vsr_vp->v_path), + ((vscan_svc_node_t *)arg0)->vsn_modified, + ((vscan_svc_node_t *)arg0)->vsn_quarantined, + stringof(((vscan_svc_node_t *)arg0)->vsn_scanstamp)); } sdt:vscan::vscan-setattr { /* XAT_AV_QUARANTINED */ printf("%s", (arg1 & 0x400) == 0 ? "" : - ((vscan_file_t *)arg0)->vsf_quarantined ? "q: 1, " : "q: 0, "); + ((vscan_svc_node_t *)arg0)->vsn_quarantined ? "q: 1, " : "q: 0, "); /* XAT_AV_MODIFIED */ printf("%s", (arg1 & 0x800) == 0 ? "" : - ((vscan_file_t *)arg0)->vsf_modified ? "m: 1, " : "m: 0, "); + ((vscan_svc_node_t *)arg0)->vsn_modified ? "m: 1, " : "m: 0, "); /* XAT_AV_SCANSTAMP */ printf("%s", (arg1 & 0x1000) == 0 ? "" : "scanstamp: "); printf("%s", (arg1 & 0x1000) == 0 ? "" : - stringof(((vscan_file_t *)arg0)->vsf_scanstamp)); + stringof(((vscan_svc_node_t *)arg0)->vsn_scanstamp)); } sdt:vscan::vscan-mtime-changed { printf("%s", - stringof(((vscan_file_t *)arg0)->vsf_req.vsr_vp->v_path)); + stringof(((vscan_svc_node_t *)arg0)->vsn_req->vsr_vp->v_path)); } sdt:vscan::vscan-result { - printf("VS_STATUS_%s - VS_ACCESS_%s", - arg0 == 0 ? "UNDEFINED" : - arg0 == 1 ? "NO_SCAN" : - arg0 == 2 ? "ERROR" : - arg0 == 3 ? "CLEAN" : - arg0 == 4 ? "INFECTED" : "XXX unknown", - arg1 == 0 ? "UNDEFINED" : - arg1 == 1 ? "ALLOW" : "DENY"); + printf("idx: %d, seqnum: %d, VS_STATUS_%s - VS_ACCESS_%s", + arg0, arg1, + arg2 == 0 ? "UNDEFINED" : + arg2 == 1 ? "NO_SCAN" : + arg2 == 2 ? "ERROR" : + arg2 == 3 ? "CLEAN" : + arg2 == 4 ? "INFECTED" : + arg2 == 5 ? "SCANNING" : "XXX unknown", + arg3 == 0 ? "UNDEFINED" : + arg3 == 1 ? "ALLOW" : "DENY"); +} + +/* insert request into request list */ +fbt:vscan:vscan_svc_reql_insert:entry +{ + printf("%s", stringof(args[0]->v_path)); +} +fbt:vscan:vscan_svc_reql_insert:return +/args[1] != 0/ +{ + printf("seqnum %d %s", args[1]->vsr_seqnum, + stringof(args[1]->vsr_vp->v_path)); +} +fbt:vscan:vscan_svc_reql_insert:return +/args[1] == 0/ +{ + printf("request list full"); +} +/* insert request into scan table */ +fbt:vscan:vscan_svc_insert_req:entry +{ + printf("seqnum: %d - %s", + args[0]->vsr_seqnum, stringof(args[0]->vsr_vp->v_path)); +} +fbt:vscan:vscan_svc_insert_req:return +{ + printf("idx: %d", args[1]); +} +/* remove request from request list and scan table and delete it*/ +fbt:vscan:vscan_svc_delete_req:entry +{ + printf("idx: %d, seqnum: %d - %s", + args[0]->vsr_idx, args[0]->vsr_seqnum, + stringof(args[0]->vsr_vp->v_path)); } +fbt:vscan:vscan_svc_delete_req:return, +fbt:vscan:vscan_svc_reql_handler:entry, +fbt:vscan:vscan_svc_reql_handler:return +{ +} + +fbt:vscan:vscan_svc_taskq_callback:entry, +fbt:vscan:vscan_svc_do_scan:entry +{ + printf("idx: %d, seqnum: %d - %s", + ((vscan_req_t *)(args[0]))->vsr_idx, + ((vscan_req_t *)(args[0]))->vsr_seqnum, + stringof(((vscan_req_t *)(args[0]))->vsr_vp->v_path)); +} +fbt:vscan:vscan_svc_scan_complete:entry +{ + printf("idx: %d, seqnum: %d, state: %s - %s", + args[0]->vsr_idx, args[0]->vsr_seqnum, + args[0]->vsr_state == 0 ? "INIT" : + args[0]->vsr_state == 1 ? "QUEUED" : + args[0]->vsr_state == 2 ? "IN_PROGRESS" : + args[0]->vsr_state == 3 ? "SCANNING" : + args[0]->vsr_state == 4 ? "ASYNC_COMPLETE" : + args[0]->vsr_state == 5 ? "COMPLETE" : "UNKNOWN", + stringof(args[0]->vsr_vp->v_path)); +} + +fbt:vscan:vscan_svc_taskq_callback:return, +fbt:vscan:vscan_svc_do_scan:return, +fbt:vscan:vscan_svc_scan_complete:return +{ +} + +sdt:vscan::vscan-abort +{ + printf("idx: %d, seqnum: %d - %s", + ((vscan_req_t *)(arg0))->vsr_idx, + ((vscan_req_t *)(arg0))->vsr_seqnum, + stringof(((vscan_req_t *)(arg0))->vsr_vp->v_path)); +} fbt:vscan:vscan_svc_enable:entry, fbt:vscan:vscan_svc_enable:return, fbt:vscan:vscan_svc_disable:entry, fbt:vscan:vscan_svc_disable:return, fbt:vscan:vscan_svc_configure:entry, -fbt:vscan:vscan_svc_configure:return, -fbt:vscan:vscan_svc_exempt_filetype:entry, -fbt:vscan:vscan_svc_scan_file:return, -fbt:vscan:vscan_svc_taskq_callback:entry, -fbt:vscan:vscan_svc_taskq_callback:return, -fbt:vscan:vscan_svc_do_scan:return +fbt:vscan:vscan_svc_configure:return { } /* -fbt:vscan:vscan_svc_match_ext:entry + * vscan_door.c + */ +fbt:vscan:vscan_door_open:entry, +fbt:vscan:vscan_door_open:return, +fbt:vscan:vscan_door_close:entry, +fbt:vscan:vscan_door_close:return { - printf("ext: %s, check: %s", stringof(args[1]), stringof(args[0])); } -fbt:vscan:vscan_svc_match_ext:return -{ -} -*/ - -/* vscan_door.c */ fbt:vscan:vscan_door_scan_file:entry { - printf("%s (%d)", args[0]->vsr_path, args[0]->vsr_id); + printf("idx: %d, seqnum: %d - %s", + args[0]->vsr_idx, args[0]->vsr_seqnum, args[0]->vsr_path); } fbt:vscan:vscan_door_scan_file:return { - printf("%s", args[1] == 0 ? "success" : "error"); + printf("VS_STATUS_%s", + args[1] == 0 ? "UNDEFINED" : + args[1] == 1 ? "NO_SCAN" : + args[1] == 2 ? "ERROR" : + args[1] == 3 ? "CLEAN" : + args[1] == 4 ? "INFECTED" : + args[1] == 5 ? "SCANNING" : "XXX unknown"); } -/* vscan_drv.c */ + +/* + * vscan_drv.c + */ +sdt:vscan::vscan-drv-state-violation +{ + printf("%d %s", arg0, + arg0 == 0 ? "UNCONFIG" : + arg0 == 1 ? "IDLE" : + arg0 == 2 ? "CONNECTED" : + arg0 == 3 ? "ENABLED" : + arg0 == 4 ? "DELAYED_DISABLE" : "UNKNOWN"); +} sdt:vscan::vscan-minor-node { printf("vscan%d %s", arg0, arg1 != 0 ? "created" : "error"); } -/* - * unprivileged vscan driver access attempt - */ +/* unprivileged vscan driver access attempt */ sdt:vscan::vscan-priv /arg0 != 0/ { printf("vscan driver access attempt by unprivileged process"); } -/* - * daemon-driver synchronization - */ +/* daemon-driver synchronization */ +sdt:vscan::vscan-reconnect +{ +} + fbt:vscan:vscan_drv_open:entry / *(int *)args[0] == 0/ { @@ -193,37 +289,31 @@ fbt:vscan:vscan_drv_ioctl:entry printf("vscan daemon ioctl %d %s", args[1], args[1] == 1 ? "ENABLE" : args[1] == 2 ? "DISABLE" : - args[1] == 4 ? "CONFIG" : "unknown"); + args[1] == 3 ? "CONFIG" : + args[1] == 4 ? "RESULT" : + args[1] == 5 ? "MAX FILES" : "unknown"); } fbt:vscan:vscan_drv_delayed_disable:entry, -fbt:vscan:vscan_drv_delayed_disable:return -{ -} - -sdt:vscan::vscan-reconnect +fbt:vscan:vscan_drv_delayed_disable:return, +fbt:vscan:vscan_drv_attach:entry, +fbt:vscan:vscan_drv_detach:entry { } -/* -fbt:vscan:vscan_drv_attach:entry, fbt:vscan:vscan_drv_attach:return, -fbt:vscan:vscan_drv_detach:entry, fbt:vscan:vscan_drv_detach:return { + printf("%s", args[1] ? "DDI_FAILURE" : "DDI_SUCCESS"); } -fbt:vscan:vscan_drv_in_use:return, -fbt:vscan:vscan_svc_in_use:return +fbt:vscan:vscan_drv_in_use:return { - printf("%s", args[1] ? "in use" : "not in use"); + printf("%s", args[1] ? "TRUE" : "FALSE"); } -*/ -/* - * file access - */ +/* file access */ /* fbt:vscan:vscan_drv_open:entry @@ -245,13 +335,30 @@ fbt:vscan:vscan_drv_read:entry *** vscan daemon - vscand *** */ +pid$target::vs_svc_init:entry +{ + printf("Max concurrent scan requests from kernel: %d", arg1); +} + +pid$target::vs_svc_init:return +{ +} + + pid$target::vs_door_scan_req:entry, pid$target::vs_svc_scan_file:entry, +pid$target::vs_svc_queue_scan_req:entry, +pid$target::vs_svc_async_scan:entry, pid$target::vs_eng_scanstamp_current:entry, pid$target::vs_icap_scan_file:entry { } +pid$target::vs_svc_queue_scan_req:return, +pid$target::vs_svc_async_scan:return +{ +} + pid$target::vs_svc_scan_file:return { printf("VS_STATUS_%s", @@ -259,7 +366,8 @@ pid$target::vs_svc_scan_file:return arg1 == 1 ? "NO_SCAN" : arg1 == 2 ? "ERROR" : arg1 == 3 ? "CLEAN" : - arg1 == 4 ? "INFECTED" : "XXX unknown"); + arg1 == 4 ? "INFECTED" : + arg1 == 5 ? "SCANNING" : "XXX unknown"); } pid$target::vs_eng_scanstamp_current:return @@ -269,11 +377,11 @@ pid$target::vs_eng_scanstamp_current:return pid$target::vs_icap_scan_file:return { - printf("%ld VS_RESULT_%s", arg1, - arg1 == 0 ? "UNDEFINED" : - arg1 == 1 ? "CLEAN" : - arg1 == 2 ? "CLEANED" : - arg1 == 3 ? "FORBIDDEN" : "(SE)_ERROR"); + printf("%d VS_RESULT_%s", (int)arg1, + (int)arg1 == 0 ? "UNDEFINED" : + (int)arg1 == 1 ? "CLEAN" : + (int)arg1 == 2 ? "CLEANED" : + (int)arg1 == 3 ? "FORBIDDEN" : "(SE)_ERROR"); } pid$target::vs_stats_set:entry @@ -289,7 +397,9 @@ pid$target::vs_stats_set:return /* get engine connection */ pid$target::vs_eng_get:entry, -pid$target::vs_eng_connect:entry +pid$target::vs_eng_connect:entry, +pid$target::vs_eng_release:entry, +pid$target::vs_eng_release:return { } pid$target::vs_eng_get:return, @@ -302,9 +412,35 @@ pid$target::vs_eng_connect:return pid$target::vs_eng_set_error:entry / arg1 == 1 / { - printf("scan engine %d error", arg0 + 1); + printf("scan engine error"); } +/* configuration */ +pid$target::vscand_cfg_init:entry, +pid$target::vscand_cfg_fini:entry, +pid$target::vscand_cfg_init:return, +pid$target::vscand_cfg_fini:return, +pid$target::vscand_cfg_handler:entry, +pid$target::vscand_cfg_handler:return +{ +} + +pid$target::vscand_dtrace_gen:entry +{ + printf("maxsize: %s action: %s\n", + copyinstr(arg0), (arg1 == 1) ? "allow" : "deny"); + printf("types: %s\n", copyinstr(arg2)); + printf("log: %s\n", copyinstr(arg3)); +} +pid$target::vscand_dtrace_eng:entry +{ + printf("\n%s %s \nhost: %s \nport: %d \nmax connections: %d\n", + copyinstr(arg0), (arg1 == 1) ? "enabled" : "disabled", + copyinstr(arg2), arg3, arg4); +} + + + /* shutdown */ pid$target::vscand_sig_handler:entry { @@ -317,6 +453,10 @@ pid$target::vscand_kernel_disable:entry, pid$target::vscand_kernel_disable:return, pid$target::vscand_kernel_unbind:entry, pid$target::vscand_kernel_unbind:return, +pid$target::vscand_kernel_result:entry, +pid$target::vscand_kernel_result:return, +pid$target::vs_svc_terminate:entry, +pid$target::vs_svc_terminate:return, pid$target::vs_eng_fini:entry, pid$target::vs_eng_fini:return, pid$target::vs_eng_close_connections:entry, @@ -346,7 +486,7 @@ pid$target::vs_icap_send_preview:return, pid$target::vs_icap_send_respmod_hdr:return, pid$target::vs_icap_read_respmod_resp:return { - printf("%s", arg1 < 0 ? "error" : "success"); + printf("%s", (int)arg1 < 0 ? "error" : "success"); } pid$target::vs_icap_may_preview:return @@ -368,7 +508,7 @@ pid$target::vs_icap_read:return, pid$target::vs_icap_readline:return, pid$target::vs_icap_send_chunk:return, pid$target::gethostname:return -/arg1 < 0/ +/(int)arg1 == -1/ { printf("error"); } @@ -389,10 +529,12 @@ pid$target::vs_icap_resp_encap:return pid$target::write:return, pid$target::read:return, -pid$target::recv:return, pid$target::open:return, pid$target::calloc:return /arg1 <= 0/ { printf("error"); } +/* +pid$target::recv:return, +*/ |
