From patchwork Wed Feb 17 13:22:02 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Huw Davies X-Patchwork-Id: 584133 X-Patchwork-Delegate: davem@davemloft.net Return-Path: X-Original-To: patchwork-incoming@ozlabs.org Delivered-To: patchwork-incoming@ozlabs.org Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 69ADE140273 for ; Thu, 18 Feb 2016 00:22:36 +1100 (AEDT) Authentication-Results: ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=codeweavers.com header.i=@codeweavers.com header.b=DTXauZcr; dkim-atps=neutral Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1161712AbcBQNWc (ORCPT ); Wed, 17 Feb 2016 08:22:32 -0500 Received: from mail.codeweavers.com ([216.251.189.131]:37723 "EHLO mail.codeweavers.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1161700AbcBQNW0 (ORCPT ); Wed, 17 Feb 2016 08:22:26 -0500 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=codeweavers.com; s=6377696661; h=Message-Id:Date:Subject:Cc:To:From; bh=vK5e5LcmjBgklEg8vYnk63zFXNFKC+PYQfpdYFzMXDY=; b=DTXauZcrWCAurlrBsSYG9CzKPjP+bpTR8UKXCYujrPKT8ATBSCnULfCOtNNCqiwJ/nYybPFlZaKSMfV0h2/gHhK+puK7rl+zzss+V5hfa9fbjWavZGAjVtt2r+R8mCSAS3sZu9DIfOJlotz/31O8di77nkC0rEcCMI6HXcpBAuc=; Received: from merlot.physics.ox.ac.uk ([163.1.241.98]) by mail.codeweavers.com with esmtpsa (TLS1.0:RSA_AES_256_CBC_SHA1:256) (Exim 4.80) (envelope-from ) id 1aW23k-0008Nj-4g; Wed, 17 Feb 2016 07:22:25 -0600 Received: from daviesh by merlot.physics.ox.ac.uk with local (Exim 4.71) (envelope-from ) id 1aW23Z-0002ks-0Y; Wed, 17 Feb 2016 13:22:13 +0000 From: Huw Davies To: netdev@vger.kernel.org, linux-security-module@vger.kernel.org, selinux@tycho.nsa.gov Cc: Paul Moore Subject: [RFC PATCH v3 12/19] ipv6: Allow request socks to contain IPv6 options. Date: Wed, 17 Feb 2016 13:22:02 +0000 Message-Id: <1455715329-9601-13-git-send-email-huw@codeweavers.com> X-Mailer: git-send-email 2.7.0 X-Spam-Score: -2.9 Sender: netdev-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org If set, these will take precedence over the parent's options during both sending and child creation. If they're not set, the parent's options (if any) will be used. This is to allow the security_inet_conn_request() hook to modify the IPv6 options in just the same way that it already may do for IPv4. Signed-off-by: Huw Davies --- include/net/inet_sock.h | 7 ++++++- net/dccp/ipv6.c | 12 +++++++++--- net/ipv4/tcp_input.c | 3 +++ net/ipv6/tcp_ipv6.c | 12 +++++++++--- 4 files changed, 27 insertions(+), 7 deletions(-) diff --git a/include/net/inet_sock.h b/include/net/inet_sock.h index 012b1f9..236a810 100644 --- a/include/net/inet_sock.h +++ b/include/net/inet_sock.h @@ -97,7 +97,12 @@ struct inet_request_sock { u32 ir_mark; union { struct ip_options_rcu *opt; - struct sk_buff *pktopts; +#if IS_ENABLED(CONFIG_IPV6) + struct { + struct ipv6_txoptions *ipv6_opt; + struct sk_buff *pktopts; + }; +#endif }; }; diff --git a/net/dccp/ipv6.c b/net/dccp/ipv6.c index 9c6d050..8bb1c3a 100644 --- a/net/dccp/ipv6.c +++ b/net/dccp/ipv6.c @@ -216,14 +216,17 @@ static int dccp_v6_send_response(const struct sock *sk, struct request_sock *req skb = dccp_make_response(sk, dst, req); if (skb != NULL) { struct dccp_hdr *dh = dccp_hdr(skb); + struct ipv6_txoptions *opt; dh->dccph_checksum = dccp_v6_csum_finish(skb, &ireq->ir_v6_loc_addr, &ireq->ir_v6_rmt_addr); fl6.daddr = ireq->ir_v6_rmt_addr; rcu_read_lock(); - err = ip6_xmit(sk, skb, &fl6, rcu_dereference(np->opt), - np->tclass); + opt = ireq->ipv6_opt; + if (!opt) + opt = rcu_dereference(np->opt); + err = ip6_xmit(sk, skb, &fl6, opt, np->tclass); rcu_read_unlock(); err = net_xmit_eval(err); } @@ -236,6 +239,7 @@ done: static void dccp_v6_reqsk_destructor(struct request_sock *req) { dccp_feat_list_purge(&dccp_rsk(req)->dreq_featneg); + kfree(inet_rsk(req)->ipv6_opt); kfree_skb(inet_rsk(req)->pktopts); } @@ -494,7 +498,9 @@ static struct sock *dccp_v6_request_recv_sock(const struct sock *sk, * Yes, keeping reference count would be much more clever, but we make * one more one thing there: reattach optmem to newsk. */ - opt = rcu_dereference(np->opt); + opt = ireq->ipv6_opt; + if (!opt) + opt = rcu_dereference(np->opt); if (opt) { opt = ipv6_dup_options(newsk, opt); RCU_INIT_POINTER(newnp->opt, opt); diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index 1c2a734..f8baa08 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -6095,6 +6095,9 @@ struct request_sock *inet_reqsk_alloc(const struct request_sock_ops *ops, kmemcheck_annotate_bitfield(ireq, flags); ireq->opt = NULL; +#if IS_ENABLED(CONFIG_IPV6) + ireq->pktopts = NULL; +#endif atomic64_set(&ireq->ir_cookie, 0); ireq->ireq_state = TCP_NEW_SYN_RECV; write_pnet(&ireq->ireq_net, sock_net(sk_listener)); diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index 1a5a70f..6b05a43 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c @@ -443,6 +443,7 @@ static int tcp_v6_send_synack(const struct sock *sk, struct dst_entry *dst, { struct inet_request_sock *ireq = inet_rsk(req); struct ipv6_pinfo *np = inet6_sk(sk); + struct ipv6_txoptions *opt; struct flowi6 *fl6 = &fl->u.ip6; struct sk_buff *skb; int err = -ENOMEM; @@ -463,8 +464,10 @@ static int tcp_v6_send_synack(const struct sock *sk, struct dst_entry *dst, fl6->flowlabel = ip6_flowlabel(ipv6_hdr(ireq->pktopts)); rcu_read_lock(); - err = ip6_xmit(sk, skb, fl6, rcu_dereference(np->opt), - np->tclass); + opt = ireq->ipv6_opt; + if (!opt) + opt = rcu_dereference(np->opt); + err = ip6_xmit(sk, skb, fl6, opt, np->tclass); rcu_read_unlock(); err = net_xmit_eval(err); } @@ -476,6 +479,7 @@ done: static void tcp_v6_reqsk_destructor(struct request_sock *req) { + kfree(inet_rsk(req)->ipv6_opt); kfree_skb(inet_rsk(req)->pktopts); } @@ -1103,7 +1107,9 @@ static struct sock *tcp_v6_syn_recv_sock(const struct sock *sk, struct sk_buff * but we make one more one thing there: reattach optmem to newsk. */ - opt = rcu_dereference(np->opt); + opt = ireq->ipv6_opt; + if (!opt) + opt = rcu_dereference(np->opt); if (opt) { opt = ipv6_dup_options(newsk, opt); RCU_INIT_POINTER(newnp->opt, opt);