summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGordon Ross <gwr@nexenta.com>2018-09-22 16:23:42 -0400
committerGordon Ross <gwr@nexenta.com>2019-05-22 22:59:03 -0400
commit8f70e16bf3f533fa0e164d0da06d00cffc63b9bb (patch)
tree55f0a8934cf74ab386f95d5089b90cd1bc7c5ee2
parentb210fede5519ffcaa92e5409d891c77b945d73bb (diff)
downloadillumos-joyent-8f70e16bf3f533fa0e164d0da06d00cffc63b9bb.tar.gz
10977 Windows 10 SMB client exhausts smbauth sockets
Reviewed by: Matt Barden <matt.barden@nexenta.com> Reviewed by: Yuri Pankov <yuri.pankov@nexenta.com> Approved by: Dan McDonald <danmcd@joyent.com>
-rw-r--r--usr/src/lib/libfakekernel/Makefile.com1
-rw-r--r--usr/src/lib/libfakekernel/common/callout.c96
-rw-r--r--usr/src/lib/libfakekernel/common/mapfile-vers2
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_authenticate.c19
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_session.c8
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_user.c89
-rw-r--r--usr/src/uts/common/smbsrv/smb_kproto.h2
-rw-r--r--usr/src/uts/common/smbsrv/smb_ktypes.h1
8 files changed, 212 insertions, 6 deletions
diff --git a/usr/src/lib/libfakekernel/Makefile.com b/usr/src/lib/libfakekernel/Makefile.com
index f9135717e6..95d690f117 100644
--- a/usr/src/lib/libfakekernel/Makefile.com
+++ b/usr/src/lib/libfakekernel/Makefile.com
@@ -18,6 +18,7 @@ LIBRARY = libfakekernel.a
VERS = .1
COBJS = \
+ callout.o \
clock.o \
cond.o \
copy.o \
diff --git a/usr/src/lib/libfakekernel/common/callout.c b/usr/src/lib/libfakekernel/common/callout.c
new file mode 100644
index 0000000000..24bb41cdff
--- /dev/null
+++ b/usr/src/lib/libfakekernel/common/callout.c
@@ -0,0 +1,96 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright 2018 Nexenta Systems, Inc. All rights reserved.
+ */
+
+/*
+ * Implement timeout(9f), untimeout(9f) on top of
+ * libc timer_create, timer_settime, etc.
+ */
+
+#include <sys/types.h>
+#include <sys/systm.h>
+#include <time.h>
+
+typedef void (*sigev_notify_func_t)(union sigval);
+
+/*
+ * We never actually reference anything in this array, using it
+ * just as a collection of addresses mapped from/to int values.
+ * It would be fine to take addresses even beyond the end, but
+ * to avoid confusion it's sized larger than _TIMER_MAX (32).
+ */
+static char timeout_base[100];
+
+timeout_id_t
+timeout(void (*func)(void *), void *arg, clock_t delta)
+{
+ struct sigevent sev;
+ struct itimerspec its;
+ timer_t tid;
+ int err;
+
+ if (delta <= 0)
+ return (NULL);
+
+ bzero(&sev, sizeof (sev));
+ sev.sigev_notify = SIGEV_THREAD;
+ sev.sigev_value.sival_ptr = arg;
+ sev.sigev_notify_function = (sigev_notify_func_t)func;
+ err = timer_create(CLOCK_REALTIME, &sev, &tid);
+ if (err != 0)
+ return (NULL);
+
+ bzero(&its, sizeof (its));
+ TICK_TO_TIMESTRUC(delta, &its.it_value);
+ err = timer_settime(tid, 0, &its, NULL);
+ if (err != 0) {
+ (void) timer_delete(tid);
+ return (NULL);
+ }
+
+ /* Convert return to a (sort of) pointer */
+ return (timeout_base + tid);
+}
+
+clock_t
+untimeout(timeout_id_t id_arg)
+{
+ struct itimerspec its;
+ char *id_cp = id_arg;
+ clock_t delta;
+ timer_t tid;
+ int rc;
+
+ if (id_arg == NULL)
+ return (-1);
+
+ /* Convert id_arg back to small integer. */
+ tid = (int)(id_cp - timeout_base);
+
+ bzero(&its, sizeof (its));
+ rc = timer_settime(tid, 0, &its, &its);
+ if (rc != 0) {
+ delta = 0;
+ } else {
+ delta = TIMESTRUC_TO_TICK(&its.it_value);
+ if (delta < 0)
+ delta = 0;
+ }
+
+ rc = timer_delete(tid);
+ if (rc != 0)
+ delta = -1;
+
+ return (delta);
+}
diff --git a/usr/src/lib/libfakekernel/common/mapfile-vers b/usr/src/lib/libfakekernel/common/mapfile-vers
index 2a307c7a88..de6ab07345 100644
--- a/usr/src/lib/libfakekernel/common/mapfile-vers
+++ b/usr/src/lib/libfakekernel/common/mapfile-vers
@@ -228,9 +228,11 @@ SYMBOL_VERSION SUNWprivate_1.1 {
tsd_destroy;
tick_per_msec;
+ timeout;
tsignal;
uiomove;
uioskip;
+ untimeout;
usec_per_tick;
vcmn_err;
vmem_qcache_reap;
diff --git a/usr/src/uts/common/fs/smbsrv/smb_authenticate.c b/usr/src/uts/common/fs/smbsrv/smb_authenticate.c
index 2fec5c061c..29fcf0d26b 100644
--- a/usr/src/uts/common/fs/smbsrv/smb_authenticate.c
+++ b/usr/src/uts/common/fs/smbsrv/smb_authenticate.c
@@ -20,7 +20,7 @@
*/
/*
* Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright 2015 Nexenta Systems, Inc. All rights reserved.
+ * Copyright 2018 Nexenta Systems, Inc. All rights reserved.
*/
/*
@@ -650,6 +650,11 @@ struct timeval smb_auth_recv_tmo = { 45, 0 };
*/
struct timeval smb_auth_send_tmo = { 15, 0 };
+/*
+ * Maximum time a user object may stay in state LOGGING_ON
+ */
+int smb_auth_total_tmo = 45; /* seconds */
+
static uint32_t
smb_authsock_open(smb_request_t *sr)
{
@@ -684,17 +689,22 @@ smb_authsock_open(smb_request_t *sr)
* This (new) user object now gets an authsocket.
* Note: u_authsock cleanup in smb_user_logoff.
* After we've set u_authsock, smb_threshold_exit
- * is done in smb_authsock_close().
+ * is done in smb_authsock_close(). If we somehow
+ * already have an authsock, close the new one and
+ * error out.
*/
mutex_enter(&user->u_mutex);
if (user->u_authsock != NULL) {
mutex_exit(&user->u_mutex);
- (void) ksocket_close(so, CRED());
- smb_threshold_exit(&sv->sv_ssetup_ct);
+ smb_authsock_close(user, so);
status = NT_STATUS_INTERNAL_ERROR;
goto errout;
}
user->u_authsock = so;
+ if (smb_auth_total_tmo != 0) {
+ user->u_auth_tmo = timeout(smb_user_auth_tmo, user,
+ SEC_TO_TICK(smb_auth_total_tmo));
+ }
mutex_exit(&user->u_mutex);
/*
@@ -801,6 +811,7 @@ void
smb_authsock_close(smb_user_t *user, ksocket_t so)
{
+ (void) ksocket_shutdown(so, SHUT_RDWR, CRED());
(void) ksocket_close(so, CRED());
smb_threshold_exit(&user->u_server->sv_ssetup_ct);
}
diff --git a/usr/src/uts/common/fs/smbsrv/smb_session.c b/usr/src/uts/common/fs/smbsrv/smb_session.c
index 4882c48e1d..0a67bf0dd6 100644
--- a/usr/src/uts/common/fs/smbsrv/smb_session.c
+++ b/usr/src/uts/common/fs/smbsrv/smb_session.c
@@ -20,7 +20,7 @@
*/
/*
* Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright 2016 Nexenta Systems, Inc. All rights reserved.
+ * Copyright 2018 Nexenta Systems, Inc. All rights reserved.
*/
#include <sys/atomic.h>
@@ -1413,6 +1413,12 @@ smb_request_free(smb_request_t *sr)
if (sr->uid_user != NULL)
smb_user_release(sr->uid_user);
+ /*
+ * The above may have left work on the delete queues
+ */
+ smb_llist_flush(&sr->session->s_tree_list);
+ smb_llist_flush(&sr->session->s_user_list);
+
smb_slist_remove(&sr->session->s_req_list, sr);
sr->session = NULL;
diff --git a/usr/src/uts/common/fs/smbsrv/smb_user.c b/usr/src/uts/common/fs/smbsrv/smb_user.c
index 0e5f56f187..046fa00b4d 100644
--- a/usr/src/uts/common/fs/smbsrv/smb_user.c
+++ b/usr/src/uts/common/fs/smbsrv/smb_user.c
@@ -20,7 +20,7 @@
*/
/*
* Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright 2014 Nexenta Systems, Inc. All rights reserved.
+ * Copyright 2018 Nexenta Systems, Inc. All rights reserved.
* Copyright (c) 2016 by Delphix. All rights reserved.
*/
@@ -210,6 +210,7 @@
static int smb_user_enum_private(smb_user_t *, smb_svcenum_t *);
static void smb_user_auth_logoff(smb_user_t *);
+static void smb_user_logoff_tq(void *);
/*
@@ -267,6 +268,7 @@ smb_user_logon(
uint32_t audit_sid)
{
ksocket_t authsock = NULL;
+ timeout_id_t tmo = NULL;
ASSERT(user->u_magic == SMB_USER_MAGIC);
ASSERT(cr);
@@ -287,6 +289,8 @@ smb_user_logon(
authsock = user->u_authsock;
ASSERT(authsock != NULL);
user->u_authsock = NULL;
+ tmo = user->u_auth_tmo;
+ user->u_auth_tmo = NULL;
user->u_state = SMB_USER_STATE_LOGGED_ON;
user->u_flags = flags;
@@ -300,6 +304,10 @@ smb_user_logon(
mutex_exit(&user->u_mutex);
+ /* Timeout callback takes u_mutex. See untimeout(9f) */
+ if (tmo != NULL)
+ (void) untimeout(tmo);
+
/* This close can block, so not under the mutex. */
smb_authsock_close(user, authsock);
@@ -317,6 +325,7 @@ smb_user_logoff(
smb_user_t *user)
{
ksocket_t authsock = NULL;
+ timeout_id_t tmo = NULL;
ASSERT(user->u_magic == SMB_USER_MAGIC);
@@ -326,6 +335,8 @@ smb_user_logoff(
case SMB_USER_STATE_LOGGING_ON:
authsock = user->u_authsock;
user->u_authsock = NULL;
+ tmo = user->u_auth_tmo;
+ user->u_auth_tmo = NULL;
user->u_state = SMB_USER_STATE_LOGGED_OFF;
smb_server_dec_users(user->u_server);
break;
@@ -354,6 +365,10 @@ smb_user_logoff(
}
mutex_exit(&user->u_mutex);
+ /* Timeout callback takes u_mutex. See untimeout(9f) */
+ if (tmo != NULL)
+ (void) untimeout(tmo);
+
/* This close can block, so not under the mutex. */
if (authsock != NULL) {
smb_authsock_close(user, authsock);
@@ -429,6 +444,77 @@ smb_user_release(
}
/*
+ * Timeout handler for user logons that stay too long in
+ * state SMB_USER_STATE_LOGGING_ON. This is setup by a
+ * timeout call in smb_authsock_open, and called in a
+ * callout thread, so schedule a taskq job to do the
+ * real work of logging off this user.
+ */
+void
+smb_user_auth_tmo(void *arg)
+{
+ smb_user_t *user = arg;
+ smb_request_t *sr;
+
+ SMB_USER_VALID(user);
+
+ /*
+ * If we can't allocate a request, it means the
+ * session is being torn down, so nothing to do.
+ */
+ sr = smb_request_alloc(user->u_session, 0);
+ if (sr == NULL)
+ return;
+
+ /*
+ * Check user state, and take a hold if it's
+ * still logging on. If not, we're done.
+ */
+ mutex_enter(&user->u_mutex);
+ if (user->u_state != SMB_USER_STATE_LOGGING_ON) {
+ mutex_exit(&user->u_mutex);
+ smb_request_free(sr);
+ return;
+ }
+ /* smb_user_hold_internal */
+ user->u_refcnt++;
+ mutex_exit(&user->u_mutex);
+
+ /*
+ * The user hold is given to the SR, and released in
+ * smb_user_logoff_tq / smb_request_free
+ */
+ sr->uid_user = user;
+ sr->user_cr = user->u_cred;
+ sr->sr_state = SMB_REQ_STATE_SUBMITTED;
+
+ (void) taskq_dispatch(
+ user->u_server->sv_worker_pool,
+ smb_user_logoff_tq, sr, TQ_SLEEP);
+}
+
+/*
+ * Helper for smb_user_auth_tmo()
+ */
+static void
+smb_user_logoff_tq(void *arg)
+{
+ smb_request_t *sr = arg;
+
+ SMB_REQ_VALID(sr);
+
+ mutex_enter(&sr->sr_mutex);
+ sr->sr_worker = curthread;
+ sr->sr_state = SMB_REQ_STATE_ACTIVE;
+ mutex_exit(&sr->sr_mutex);
+
+ smb_user_logoff(sr->uid_user);
+
+ sr->sr_state = SMB_REQ_STATE_COMPLETED;
+ smb_request_free(sr);
+}
+
+/*
* Determine whether or not the user is an administrator.
* Members of the administrators group have administrative rights.
*/
@@ -550,6 +636,7 @@ smb_user_delete(void *arg)
ASSERT(user->u_refcnt == 0);
ASSERT(user->u_state == SMB_USER_STATE_LOGGED_OFF);
ASSERT(user->u_authsock == NULL);
+ ASSERT(user->u_auth_tmo == NULL);
session = user->u_session;
smb_llist_enter(&session->s_user_list, RW_WRITER);
diff --git a/usr/src/uts/common/smbsrv/smb_kproto.h b/usr/src/uts/common/smbsrv/smb_kproto.h
index dae67ccc1a..6ce11b4621 100644
--- a/usr/src/uts/common/smbsrv/smb_kproto.h
+++ b/usr/src/uts/common/smbsrv/smb_kproto.h
@@ -736,6 +736,8 @@ int smb_user_logon(smb_user_t *, cred_t *,
char *, char *, uint32_t, uint32_t, uint32_t);
void smb_user_logoff(smb_user_t *);
void smb_user_delete(void *);
+void smb_user_auth_tmo(void *);
+
boolean_t smb_user_is_admin(smb_user_t *);
boolean_t smb_user_namecmp(smb_user_t *, const char *);
int smb_user_enum(smb_user_t *, smb_svcenum_t *);
diff --git a/usr/src/uts/common/smbsrv/smb_ktypes.h b/usr/src/uts/common/smbsrv/smb_ktypes.h
index 448c760f4d..bacfbe56ac 100644
--- a/usr/src/uts/common/smbsrv/smb_ktypes.h
+++ b/usr/src/uts/common/smbsrv/smb_ktypes.h
@@ -958,6 +958,7 @@ typedef struct smb_user {
struct smb_server *u_server;
smb_session_t *u_session;
ksocket_t u_authsock;
+ timeout_id_t u_auth_tmo;
uint16_t u_name_len;
char *u_name;
uint16_t u_domain_len;