summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDan McDonald <danmcd@joyent.com>2022-04-05 11:07:47 -0400
committerDan McDonald <danmcd@joyent.com>2022-04-06 17:07:03 -0400
commit041297c2d66302c15134da1d1bdd91cf787a945a (patch)
treed1288b22a0aed9b9595a3492ce1cb727cd364ba8
parent7271f09891bb39b64f2a58632c92c1456ed9cf31 (diff)
downloadillumos-joyent-041297c2d66302c15134da1d1bdd91cf787a945a.tar.gz
14619 Race between udp_activate() and conn_get_socket_info()
Reviewed by: Andy Fiddaman <andy@omnios.org> Reviewed by: Marco van Wieringen <marco.van.wieringen@planets.elm.net> Approved by: Hans Rosenfeld <rosenfeld@grumpf.hope-2000.org> Approved by: Robert Mustacchi <rm@fingolfin.org>
-rw-r--r--usr/src/uts/common/inet/ip/ipclassifier.c20
1 files changed, 16 insertions, 4 deletions
diff --git a/usr/src/uts/common/inet/ip/ipclassifier.c b/usr/src/uts/common/inet/ip/ipclassifier.c
index 26cc629cca..34832d56e5 100644
--- a/usr/src/uts/common/inet/ip/ipclassifier.c
+++ b/usr/src/uts/common/inet/ip/ipclassifier.c
@@ -21,7 +21,7 @@
/*
* Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright 2019 OmniOS Community Edition (OmniOSce) Association.
- * Copyright 2020 Joyent, Inc.
+ * Copyright 2022 Joyent, Inc.
*/
/*
@@ -2732,6 +2732,8 @@ conn_get_socket_info(conn_t *connp, mib2_socketInfoEntry_t *sie)
vnode_t *vn = NULL;
vattr_t attr;
uint64_t flags = 0;
+ sock_upcalls_t *upcalls;
+ sock_upper_handle_t upper_handle;
/*
* If the connection is closing, it is not safe to make an upcall or
@@ -2750,11 +2752,21 @@ conn_get_socket_info(conn_t *connp, mib2_socketInfoEntry_t *sie)
* Continue to hold conn_lock because we don't want to race with an
* in-progress close, which will have set-to-NULL (and destroyed
* upper_handle, aka sonode (and vnode)) BEFORE setting CONN_CLOSING.
+ *
+ * There is still a race with an in-progress OPEN, however, where
+ * conn_upper_handle and conn_upcalls are being assigned (in multiple
+ * codepaths) WITHOUT conn_lock being held. We address that race
+ * HERE, however, given that both are going from NULL to non-NULL,
+ * if we lose the race, we don't get any data for the in-progress-OPEN
+ * socket.
*/
- if (connp->conn_upper_handle != NULL) {
- vn = (*connp->conn_upcalls->su_get_vnode)
- (connp->conn_upper_handle);
+ upcalls = connp->conn_upcalls;
+ upper_handle = connp->conn_upper_handle;
+ /* Check BOTH for non-NULL before attempting an upcall. */
+ if (upper_handle != NULL && upcalls != NULL) {
+ /* su_get_vnode() returns one with VN_HOLD() already done. */
+ vn = upcalls->su_get_vnode(upper_handle);
} else if (!IPCL_IS_NONSTR(connp) && connp->conn_rq != NULL) {
vn = STREAM(connp->conn_rq)->sd_pvnode;
if (vn != NULL)