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


   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  * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
  23  * Copyright 2019 OmniOS Community Edition (OmniOSce) Association.
  24  * Copyright 2020 Joyent, Inc.
  25  */
  26 
  27 /*
  28  * IP PACKET CLASSIFIER
  29  *
  30  * The IP packet classifier provides mapping between IP packets and persistent
  31  * connection state for connection-oriented protocols. It also provides
  32  * interface for managing connection states.
  33  *
  34  * The connection state is kept in conn_t data structure and contains, among
  35  * other things:
  36  *
  37  *      o local/remote address and ports
  38  *      o Transport protocol
  39  *      o squeue for the connection (for TCP only)
  40  *      o reference counter
  41  *      o Connection state
  42  *      o hash table linkage
  43  *      o interface/ire information
  44  *      o credentials


2715 
2716         ASSERT(MUTEX_HELD(&connp->conn_lock));
2717         last = connp->conn_trace_last;
2718         last++;
2719         if (last == CONN_TRACE_MAX)
2720                 last = 0;
2721 
2722         ctb = &connp->conn_trace_buf[last];
2723         ctb->ctb_depth = getpcstack(ctb->ctb_stack, CONN_STACK_DEPTH);
2724         connp->conn_trace_last = last;
2725         return (1);
2726 }
2727 #endif
2728 
2729 mib2_socketInfoEntry_t *
2730 conn_get_socket_info(conn_t *connp, mib2_socketInfoEntry_t *sie)
2731 {
2732         vnode_t *vn = NULL;
2733         vattr_t attr;
2734         uint64_t flags = 0;


2735 
2736         /*
2737          * If the connection is closing, it is not safe to make an upcall or
2738          * access the stream associated with the connection.
2739          * The callers of this function have a reference on connp itself
2740          * so, as long as it is not closing, it's safe to continue.
2741          */
2742         mutex_enter(&connp->conn_lock);
2743 
2744         if ((connp->conn_state_flags & CONN_CLOSING)) {
2745                 mutex_exit(&connp->conn_lock);
2746                 return (NULL);
2747         }
2748 
2749         /*
2750          * Continue to hold conn_lock because we don't want to race with an
2751          * in-progress close, which will have set-to-NULL (and destroyed
2752          * upper_handle, aka sonode (and vnode)) BEFORE setting CONN_CLOSING.







2753          */
2754 
2755         if (connp->conn_upper_handle != NULL) {
2756                 vn = (*connp->conn_upcalls->su_get_vnode)
2757                     (connp->conn_upper_handle);



2758         } else if (!IPCL_IS_NONSTR(connp) && connp->conn_rq != NULL) {
2759                 vn = STREAM(connp->conn_rq)->sd_pvnode;
2760                 if (vn != NULL)
2761                         VN_HOLD(vn);
2762                 flags |= MIB2_SOCKINFO_STREAM;
2763         }
2764 
2765         mutex_exit(&connp->conn_lock);
2766 
2767         if (vn == NULL || VOP_GETATTR(vn, &attr, 0, CRED(), NULL) != 0) {
2768                 if (vn != NULL)
2769                         VN_RELE(vn);
2770                 return (NULL);
2771         }
2772 
2773         VN_RELE(vn);
2774 
2775         bzero(sie, sizeof (*sie));
2776 
2777         sie->sie_flags = flags;


   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  * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
  23  * Copyright 2019 OmniOS Community Edition (OmniOSce) Association.
  24  * Copyright 2022 Joyent, Inc.
  25  */
  26 
  27 /*
  28  * IP PACKET CLASSIFIER
  29  *
  30  * The IP packet classifier provides mapping between IP packets and persistent
  31  * connection state for connection-oriented protocols. It also provides
  32  * interface for managing connection states.
  33  *
  34  * The connection state is kept in conn_t data structure and contains, among
  35  * other things:
  36  *
  37  *      o local/remote address and ports
  38  *      o Transport protocol
  39  *      o squeue for the connection (for TCP only)
  40  *      o reference counter
  41  *      o Connection state
  42  *      o hash table linkage
  43  *      o interface/ire information
  44  *      o credentials


2715 
2716         ASSERT(MUTEX_HELD(&connp->conn_lock));
2717         last = connp->conn_trace_last;
2718         last++;
2719         if (last == CONN_TRACE_MAX)
2720                 last = 0;
2721 
2722         ctb = &connp->conn_trace_buf[last];
2723         ctb->ctb_depth = getpcstack(ctb->ctb_stack, CONN_STACK_DEPTH);
2724         connp->conn_trace_last = last;
2725         return (1);
2726 }
2727 #endif
2728 
2729 mib2_socketInfoEntry_t *
2730 conn_get_socket_info(conn_t *connp, mib2_socketInfoEntry_t *sie)
2731 {
2732         vnode_t *vn = NULL;
2733         vattr_t attr;
2734         uint64_t flags = 0;
2735         sock_upcalls_t *upcalls;
2736         sock_upper_handle_t upper_handle;
2737 
2738         /*
2739          * If the connection is closing, it is not safe to make an upcall or
2740          * access the stream associated with the connection.
2741          * The callers of this function have a reference on connp itself
2742          * so, as long as it is not closing, it's safe to continue.
2743          */
2744         mutex_enter(&connp->conn_lock);
2745 
2746         if ((connp->conn_state_flags & CONN_CLOSING)) {
2747                 mutex_exit(&connp->conn_lock);
2748                 return (NULL);
2749         }
2750 
2751         /*
2752          * Continue to hold conn_lock because we don't want to race with an
2753          * in-progress close, which will have set-to-NULL (and destroyed
2754          * upper_handle, aka sonode (and vnode)) BEFORE setting CONN_CLOSING.
2755          *
2756          * There is still a race with an in-progress OPEN, however, where
2757          * conn_upper_handle and conn_upcalls are being assigned (in multiple
2758          * codepaths) WITHOUT conn_lock being held.  We address that race
2759          * HERE, however, given that both are going from NULL to non-NULL,
2760          * if we lose the race, we don't get any data for the in-progress-OPEN
2761          * socket.
2762          */
2763 
2764         upcalls = connp->conn_upcalls;
2765         upper_handle = connp->conn_upper_handle;
2766         /* Check BOTH for non-NULL before attempting an upcall. */
2767         if (upper_handle != NULL && upcalls != NULL) {
2768                 /* su_get_vnode() returns one with VN_HOLD() already done. */
2769                 vn = upcalls->su_get_vnode(upper_handle);
2770         } else if (!IPCL_IS_NONSTR(connp) && connp->conn_rq != NULL) {
2771                 vn = STREAM(connp->conn_rq)->sd_pvnode;
2772                 if (vn != NULL)
2773                         VN_HOLD(vn);
2774                 flags |= MIB2_SOCKINFO_STREAM;
2775         }
2776 
2777         mutex_exit(&connp->conn_lock);
2778 
2779         if (vn == NULL || VOP_GETATTR(vn, &attr, 0, CRED(), NULL) != 0) {
2780                 if (vn != NULL)
2781                         VN_RELE(vn);
2782                 return (NULL);
2783         }
2784 
2785         VN_RELE(vn);
2786 
2787         bzero(sie, sizeof (*sie));
2788 
2789         sie->sie_flags = flags;