Print this page
14619 Race between udp_activate() and conn_get_socket_info()

*** 19,29 **** * CDDL HEADER END */ /* * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved. * Copyright 2019 OmniOS Community Edition (OmniOSce) Association. ! * Copyright 2020 Joyent, Inc. */ /* * IP PACKET CLASSIFIER * --- 19,29 ---- * CDDL HEADER END */ /* * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved. * Copyright 2019 OmniOS Community Edition (OmniOSce) Association. ! * Copyright 2022 Joyent, Inc. */ /* * IP PACKET CLASSIFIER *
*** 2730,2739 **** --- 2730,2741 ---- 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 * access the stream associated with the connection. * The callers of this function have a reference on connp itself
*** 2748,2762 **** /* * 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. */ ! if (connp->conn_upper_handle != NULL) { ! vn = (*connp->conn_upcalls->su_get_vnode) ! (connp->conn_upper_handle); } else if (!IPCL_IS_NONSTR(connp) && connp->conn_rq != NULL) { vn = STREAM(connp->conn_rq)->sd_pvnode; if (vn != NULL) VN_HOLD(vn); flags |= MIB2_SOCKINFO_STREAM; --- 2750,2774 ---- /* * 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. */ ! 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) VN_HOLD(vn); flags |= MIB2_SOCKINFO_STREAM;