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.

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

mercurial