netwerk/sctp/src/netinet/sctp_peeloff.c

Tue, 06 Jan 2015 21:39:09 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Tue, 06 Jan 2015 21:39:09 +0100
branch
TOR_BUG_9701
changeset 8
97036ab72558
permissions
-rwxr-xr-x

Conditionally force memory storage according to privacy.thirdparty.isolate;
This solves Tor bug #9701, complying with disk avoidance documented in
https://www.torproject.org/projects/torbrowser/design/#disk-avoidance.

     1 /*-
     2  * Copyright (c) 2001-2007, by Cisco Systems, Inc. All rights reserved.
     3  * Copyright (c) 2008-2012, by Randall Stewart. All rights reserved.
     4  * Copyright (c) 2008-2012, by Michael Tuexen. All rights reserved.
     5  *
     6  * Redistribution and use in source and binary forms, with or without
     7  * modification, are permitted provided that the following conditions are met:
     8  *
     9  * a) Redistributions of source code must retain the above copyright notice,
    10  *    this list of conditions and the following disclaimer.
    11  *
    12  * b) Redistributions in binary form must reproduce the above copyright
    13  *    notice, this list of conditions and the following disclaimer in
    14  *    the documentation and/or other materials provided with the distribution.
    15  *
    16  * c) Neither the name of Cisco Systems, Inc. nor the names of its
    17  *    contributors may be used to endorse or promote products derived
    18  *    from this software without specific prior written permission.
    19  *
    20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
    21  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
    22  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
    23  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
    24  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
    25  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
    26  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
    27  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
    28  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
    29  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
    30  * THE POSSIBILITY OF SUCH DAMAGE.
    31  */
    33 #ifdef __FreeBSD__
    34 #include <sys/cdefs.h>
    35 __FBSDID("$FreeBSD: head/sys/netinet/sctp_peeloff.c 243565 2012-11-26 16:44:03Z tuexen $");
    36 #endif
    38 #include <netinet/sctp_os.h>
    39 #include <netinet/sctp_pcb.h>
    40 #include <netinet/sctputil.h>
    41 #include <netinet/sctp_var.h>
    42 #include <netinet/sctp_var.h>
    43 #include <netinet/sctp_sysctl.h>
    44 #include <netinet/sctp.h>
    45 #include <netinet/sctp_uio.h>
    46 #include <netinet/sctp_peeloff.h>
    47 #include <netinet/sctputil.h>
    48 #include <netinet/sctp_auth.h>
    50 #if defined(__APPLE__)
    51 #define APPLE_FILE_NO 5
    52 #endif
    54 int
    55 sctp_can_peel_off(struct socket *head, sctp_assoc_t assoc_id)
    56 {
    57 	struct sctp_inpcb *inp;
    58 	struct sctp_tcb *stcb;
    59 	uint32_t state;
    61 	if (head == NULL) {
    62 		SCTP_LTRACE_ERR_RET(NULL, NULL, NULL, SCTP_FROM_SCTP_PEELOFF, EBADF);
    63 		return (EBADF);
    64 	}
    65 	inp = (struct sctp_inpcb *)head->so_pcb;
    66 	if (inp == NULL) {
    67 		SCTP_LTRACE_ERR_RET(NULL, NULL, NULL, SCTP_FROM_SCTP_PEELOFF, EFAULT);
    68 		return (EFAULT);
    69 	}
    70 	if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
    71 	    (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL)) {
    72 		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_PEELOFF, EOPNOTSUPP);
    73 		return (EOPNOTSUPP);
    74 	}
    75 	stcb = sctp_findassociation_ep_asocid(inp, assoc_id, 1);
    76 	if (stcb == NULL) {
    77 		SCTP_LTRACE_ERR_RET(inp, stcb, NULL, SCTP_FROM_SCTP_PEELOFF, ENOENT);
    78 		return (ENOENT);
    79 	}
    80 	state = SCTP_GET_STATE((&stcb->asoc));
    81 	if ((state == SCTP_STATE_EMPTY) ||
    82 	    (state == SCTP_STATE_INUSE)) {
    83 		SCTP_TCB_UNLOCK(stcb);
    84 		SCTP_LTRACE_ERR_RET(inp, stcb, NULL, SCTP_FROM_SCTP_PEELOFF, ENOTCONN);
    85 		return (ENOTCONN);
    86 	}
    87 	SCTP_TCB_UNLOCK(stcb);
    88 	/* We are clear to peel this one off */
    89 	return (0);
    90 }
    92 int
    93 sctp_do_peeloff(struct socket *head, struct socket *so, sctp_assoc_t assoc_id)
    94 {
    95 	struct sctp_inpcb *inp, *n_inp;
    96 	struct sctp_tcb *stcb;
    97 	uint32_t state;
    99 	inp = (struct sctp_inpcb *)head->so_pcb;
   100 	if (inp == NULL) {
   101 		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_PEELOFF, EFAULT);
   102 		return (EFAULT);
   103 	}
   104 	stcb = sctp_findassociation_ep_asocid(inp, assoc_id, 1);
   105 	if (stcb == NULL) {
   106 		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_PEELOFF, ENOTCONN);
   107 		return (ENOTCONN);
   108 	}
   110 	state = SCTP_GET_STATE((&stcb->asoc));
   111 	if ((state == SCTP_STATE_EMPTY) ||
   112 	    (state == SCTP_STATE_INUSE)) {
   113 		SCTP_TCB_UNLOCK(stcb);
   114 		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_PEELOFF, ENOTCONN);
   115 		return (ENOTCONN);
   116 	}
   118 	n_inp = (struct sctp_inpcb *)so->so_pcb;
   119 	n_inp->sctp_flags = (SCTP_PCB_FLAGS_UDPTYPE |
   120 	    SCTP_PCB_FLAGS_CONNECTED |
   121 	    SCTP_PCB_FLAGS_IN_TCPPOOL |	/* Turn on Blocking IO */
   122 	    (SCTP_PCB_COPY_FLAGS & inp->sctp_flags));
   123 	n_inp->sctp_socket = so;
   124 	n_inp->sctp_features = inp->sctp_features;
   125 	n_inp->sctp_mobility_features = inp->sctp_mobility_features;
   126 	n_inp->sctp_frag_point = inp->sctp_frag_point;
   127 	n_inp->sctp_cmt_on_off = inp->sctp_cmt_on_off;
   128 	n_inp->sctp_ecn_enable = inp->sctp_ecn_enable;
   129 	n_inp->partial_delivery_point = inp->partial_delivery_point;
   130 	n_inp->sctp_context = inp->sctp_context;
   131 	n_inp->local_strreset_support = inp->local_strreset_support;
   132 	n_inp->inp_starting_point_for_iterator = NULL;
   133 	/* copy in the authentication parameters from the original endpoint */
   134 	if (n_inp->sctp_ep.local_hmacs)
   135 		sctp_free_hmaclist(n_inp->sctp_ep.local_hmacs);
   136 	n_inp->sctp_ep.local_hmacs =
   137 	    sctp_copy_hmaclist(inp->sctp_ep.local_hmacs);
   138 	if (n_inp->sctp_ep.local_auth_chunks)
   139 		sctp_free_chunklist(n_inp->sctp_ep.local_auth_chunks);
   140 	n_inp->sctp_ep.local_auth_chunks =
   141 	    sctp_copy_chunklist(inp->sctp_ep.local_auth_chunks);
   142 	(void)sctp_copy_skeylist(&inp->sctp_ep.shared_keys,
   143 	    &n_inp->sctp_ep.shared_keys);
   144 #if defined(__Userspace__)
   145 	n_inp->ulp_info = inp->ulp_info;
   146 	n_inp->recv_callback = inp->recv_callback;
   147 	n_inp->send_callback = inp->send_callback;
   148 	n_inp->send_sb_threshold = inp->send_sb_threshold;
   149 #endif
   150 	/*
   151 	 * Now we must move it from one hash table to another and get the
   152 	 * stcb in the right place.
   153 	 */
   154 	sctp_move_pcb_and_assoc(inp, n_inp, stcb);
   155 	atomic_add_int(&stcb->asoc.refcnt, 1);
   156 	SCTP_TCB_UNLOCK(stcb);
   158 #if defined(__FreeBSD__)
   159 	sctp_pull_off_control_to_new_inp(inp, n_inp, stcb, SBL_WAIT);
   160 #else
   161 	sctp_pull_off_control_to_new_inp(inp, n_inp, stcb, M_WAITOK);
   162 #endif
   163 	atomic_subtract_int(&stcb->asoc.refcnt, 1);
   165 	return (0);
   166 }
   168 #if defined(HAVE_SCTP_PEELOFF_SOCKOPT)
   169 struct socket *
   170 sctp_get_peeloff(struct socket *head, sctp_assoc_t assoc_id, int *error)
   171 {
   172 #if defined(__Userspace__)
   173     /* if __Userspace__ chooses to originally not support peeloff, put it here... */
   174 #endif
   175 #if defined(__Panda__)
   176 	SCTP_LTRACE_ERR_RET(NULL, NULL, NULL, SCTP_FROM_SCTP_PEELOFF, EINVAL);
   177 	*error = EINVAL;
   178 	return (NULL);
   179 #else
   180 	struct socket *newso;
   181 	struct sctp_inpcb *inp, *n_inp;
   182 	struct sctp_tcb *stcb;
   184 	SCTPDBG(SCTP_DEBUG_PEEL1, "SCTP peel-off called\n");
   185 	inp = (struct sctp_inpcb *)head->so_pcb;
   186 	if (inp == NULL) {
   187 		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_PEELOFF, EFAULT);
   188 		*error = EFAULT;
   189 		return (NULL);
   190 	}
   191 	stcb = sctp_findassociation_ep_asocid(inp, assoc_id, 1);
   192 	if (stcb == NULL) {
   193 		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_PEELOFF, ENOTCONN);
   194 		*error = ENOTCONN;
   195 		return (NULL);
   196 	}
   197 	atomic_add_int(&stcb->asoc.refcnt, 1);
   198 	SCTP_TCB_UNLOCK(stcb);
   199 #if defined(__FreeBSD__) && __FreeBSD_version >= 801000
   200 	CURVNET_SET(head->so_vnet);
   201 #endif
   202 	newso = sonewconn(head, SS_ISCONNECTED
   203 #if defined(__APPLE__)
   204 	    , NULL
   205 #elif defined(__Panda__)
   206 	    /* place this socket in the assoc's vrf id */
   207 	    , NULL, stcb->asoc.vrf_id
   208 #endif
   209 		);
   210 #if defined(__FreeBSD__) && __FreeBSD_version >= 801000
   211 	CURVNET_RESTORE();
   212 #endif
   213 	if (newso == NULL) {
   214 		SCTPDBG(SCTP_DEBUG_PEEL1, "sctp_peeloff:sonewconn failed\n");
   215 		SCTP_LTRACE_ERR_RET(NULL, stcb, NULL, SCTP_FROM_SCTP_PEELOFF, ENOMEM);
   216 		*error = ENOMEM;
   217 		atomic_subtract_int(&stcb->asoc.refcnt, 1);
   218 		return (NULL);
   220 	}
   221 #if defined(__APPLE__)
   222 	  else {
   223 		SCTP_SOCKET_LOCK(newso, 1);
   224 	}
   225 #endif
   226 	SCTP_TCB_LOCK(stcb);
   227 	atomic_subtract_int(&stcb->asoc.refcnt, 1);
   228 	n_inp = (struct sctp_inpcb *)newso->so_pcb;
   229 	SOCK_LOCK(head);
   230 	n_inp->sctp_flags = (SCTP_PCB_FLAGS_UDPTYPE |
   231 	    SCTP_PCB_FLAGS_CONNECTED |
   232 	    SCTP_PCB_FLAGS_IN_TCPPOOL |	/* Turn on Blocking IO */
   233 	    (SCTP_PCB_COPY_FLAGS & inp->sctp_flags));
   234 	n_inp->sctp_features = inp->sctp_features;
   235 	n_inp->sctp_frag_point = inp->sctp_frag_point;
   236 	n_inp->sctp_cmt_on_off = inp->sctp_cmt_on_off;
   237 	n_inp->sctp_ecn_enable = inp->sctp_ecn_enable;
   238 	n_inp->partial_delivery_point = inp->partial_delivery_point;
   239 	n_inp->sctp_context = inp->sctp_context;
   240 	n_inp->local_strreset_support = inp->local_strreset_support;
   241 	n_inp->inp_starting_point_for_iterator = NULL;
   242 #if defined(__Userspace__)
   243 	n_inp->ulp_info = inp->ulp_info;
   244 	n_inp->recv_callback = inp->recv_callback;
   245 	n_inp->send_callback = inp->send_callback;
   246 	n_inp->send_sb_threshold = inp->send_sb_threshold;
   247 #endif
   249 	/* copy in the authentication parameters from the original endpoint */
   250 	if (n_inp->sctp_ep.local_hmacs)
   251 		sctp_free_hmaclist(n_inp->sctp_ep.local_hmacs);
   252 	n_inp->sctp_ep.local_hmacs =
   253 	    sctp_copy_hmaclist(inp->sctp_ep.local_hmacs);
   254 	if (n_inp->sctp_ep.local_auth_chunks)
   255 		sctp_free_chunklist(n_inp->sctp_ep.local_auth_chunks);
   256 	n_inp->sctp_ep.local_auth_chunks =
   257 	    sctp_copy_chunklist(inp->sctp_ep.local_auth_chunks);
   258 	(void)sctp_copy_skeylist(&inp->sctp_ep.shared_keys,
   259 	    &n_inp->sctp_ep.shared_keys);
   261 	n_inp->sctp_socket = newso;
   262 	if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_AUTOCLOSE)) {
   263 		sctp_feature_off(n_inp, SCTP_PCB_FLAGS_AUTOCLOSE);
   264 		n_inp->sctp_ep.auto_close_time = 0;
   265 		sctp_timer_stop(SCTP_TIMER_TYPE_AUTOCLOSE, n_inp, stcb, NULL,
   266 				SCTP_FROM_SCTP_PEELOFF+SCTP_LOC_1);
   267 	}
   268 	/* Turn off any non-blocking semantic. */
   269 	SCTP_CLEAR_SO_NBIO(newso);
   270         newso->so_state |= SS_ISCONNECTED;
   271 	/* We remove it right away */
   273 #if defined(__FreeBSD__) || defined(__APPLE__) || defined(__Windows__) || defined(__Userspace__)
   274 #ifdef SCTP_LOCK_LOGGING
   275 	if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_LOCK_LOGGING_ENABLE) {
   276 		sctp_log_lock(inp, (struct sctp_tcb *)NULL, SCTP_LOG_LOCK_SOCK);
   277 	}
   278 #endif
   279 	TAILQ_REMOVE(&head->so_comp, newso, so_list);
   280 	head->so_qlen--;
   281 	SOCK_UNLOCK(head);
   282 #else
   283         newso = TAILQ_FIRST(&head->so_q);
   284 	if (soqremque(newso, 1) == 0) {
   285 		SCTP_PRINTF("soremque failed, peeloff-fails (invarients would panic)\n");
   286 		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_PEELOFF, ENOTCONN);
   287 		*error = ENOTCONN;
   288 		return (NULL);
   290 	}
   291 #endif
   292 	/*
   293 	 * Now we must move it from one hash table to another and get the
   294 	 * stcb in the right place.
   295 	 */
   296         sctp_move_pcb_and_assoc(inp, n_inp, stcb);
   297 	atomic_add_int(&stcb->asoc.refcnt, 1);
   298 	SCTP_TCB_UNLOCK(stcb);
   299 	/*
   300 	 * And now the final hack. We move data in the pending side i.e.
   301 	 * head to the new socket buffer. Let the GRUBBING begin :-0
   302 	 */
   303 #if defined(__FreeBSD__)
   304 	sctp_pull_off_control_to_new_inp(inp, n_inp, stcb, SBL_WAIT);
   305 #else
   306 	sctp_pull_off_control_to_new_inp(inp, n_inp, stcb, M_WAITOK);
   307 #endif
   308 	atomic_subtract_int(&stcb->asoc.refcnt, 1);
   309 	return (newso);
   310 #endif
   311 }
   312 #endif

mercurial