aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorHuw Davies <huw@codeweavers.com>2016-06-27 15:05:28 -0400
committerPaul Moore <paul@paul-moore.com>2016-06-27 15:05:28 -0400
commit56ac42bc94b18d45b6c484edeac33be86bfb3efa (patch)
treed14e433bcc0b3fef9349a86cbb6d8d87dedfb232 /net
parent1f440c99d3207d684a3ac48d6e528af548b5c915 (diff)
ipv6: Allow request socks to contain IPv6 options.
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 <huw@codeweavers.com> Signed-off-by: Paul Moore <paul@paul-moore.com>
Diffstat (limited to 'net')
-rw-r--r--net/dccp/ipv6.c12
-rw-r--r--net/ipv4/tcp_input.c3
-rw-r--r--net/ipv6/tcp_ipv6.c12
3 files changed, 21 insertions, 6 deletions
diff --git a/net/dccp/ipv6.c b/net/dccp/ipv6.c
index 4663a01d5039..3381748bd0f3 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
216 skb = dccp_make_response(sk, dst, req); 216 skb = dccp_make_response(sk, dst, req);
217 if (skb != NULL) { 217 if (skb != NULL) {
218 struct dccp_hdr *dh = dccp_hdr(skb); 218 struct dccp_hdr *dh = dccp_hdr(skb);
219 struct ipv6_txoptions *opt;
219 220
220 dh->dccph_checksum = dccp_v6_csum_finish(skb, 221 dh->dccph_checksum = dccp_v6_csum_finish(skb,
221 &ireq->ir_v6_loc_addr, 222 &ireq->ir_v6_loc_addr,
222 &ireq->ir_v6_rmt_addr); 223 &ireq->ir_v6_rmt_addr);
223 fl6.daddr = ireq->ir_v6_rmt_addr; 224 fl6.daddr = ireq->ir_v6_rmt_addr;
224 rcu_read_lock(); 225 rcu_read_lock();
225 err = ip6_xmit(sk, skb, &fl6, rcu_dereference(np->opt), 226 opt = ireq->ipv6_opt;
226 np->tclass); 227 if (!opt)
228 opt = rcu_dereference(np->opt);
229 err = ip6_xmit(sk, skb, &fl6, opt, np->tclass);
227 rcu_read_unlock(); 230 rcu_read_unlock();
228 err = net_xmit_eval(err); 231 err = net_xmit_eval(err);
229 } 232 }
@@ -236,6 +239,7 @@ done:
236static void dccp_v6_reqsk_destructor(struct request_sock *req) 239static void dccp_v6_reqsk_destructor(struct request_sock *req)
237{ 240{
238 dccp_feat_list_purge(&dccp_rsk(req)->dreq_featneg); 241 dccp_feat_list_purge(&dccp_rsk(req)->dreq_featneg);
242 kfree(inet_rsk(req)->ipv6_opt);
239 kfree_skb(inet_rsk(req)->pktopts); 243 kfree_skb(inet_rsk(req)->pktopts);
240} 244}
241 245
@@ -494,7 +498,9 @@ static struct sock *dccp_v6_request_recv_sock(const struct sock *sk,
494 * Yes, keeping reference count would be much more clever, but we make 498 * Yes, keeping reference count would be much more clever, but we make
495 * one more one thing there: reattach optmem to newsk. 499 * one more one thing there: reattach optmem to newsk.
496 */ 500 */
497 opt = rcu_dereference(np->opt); 501 opt = ireq->ipv6_opt;
502 if (!opt)
503 opt = rcu_dereference(np->opt);
498 if (opt) { 504 if (opt) {
499 opt = ipv6_dup_options(newsk, opt); 505 opt = ipv6_dup_options(newsk, opt);
500 RCU_INIT_POINTER(newnp->opt, opt); 506 RCU_INIT_POINTER(newnp->opt, opt);
diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c
index e6e65f79ade8..071174c13bf9 100644
--- a/net/ipv4/tcp_input.c
+++ b/net/ipv4/tcp_input.c
@@ -6146,6 +6146,9 @@ struct request_sock *inet_reqsk_alloc(const struct request_sock_ops *ops,
6146 6146
6147 kmemcheck_annotate_bitfield(ireq, flags); 6147 kmemcheck_annotate_bitfield(ireq, flags);
6148 ireq->opt = NULL; 6148 ireq->opt = NULL;
6149#if IS_ENABLED(CONFIG_IPV6)
6150 ireq->pktopts = NULL;
6151#endif
6149 atomic64_set(&ireq->ir_cookie, 0); 6152 atomic64_set(&ireq->ir_cookie, 0);
6150 ireq->ireq_state = TCP_NEW_SYN_RECV; 6153 ireq->ireq_state = TCP_NEW_SYN_RECV;
6151 write_pnet(&ireq->ireq_net, sock_net(sk_listener)); 6154 write_pnet(&ireq->ireq_net, sock_net(sk_listener));
diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c
index 711d209f9124..18daddc6001c 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,
443{ 443{
444 struct inet_request_sock *ireq = inet_rsk(req); 444 struct inet_request_sock *ireq = inet_rsk(req);
445 struct ipv6_pinfo *np = inet6_sk(sk); 445 struct ipv6_pinfo *np = inet6_sk(sk);
446 struct ipv6_txoptions *opt;
446 struct flowi6 *fl6 = &fl->u.ip6; 447 struct flowi6 *fl6 = &fl->u.ip6;
447 struct sk_buff *skb; 448 struct sk_buff *skb;
448 int err = -ENOMEM; 449 int err = -ENOMEM;
@@ -463,8 +464,10 @@ static int tcp_v6_send_synack(const struct sock *sk, struct dst_entry *dst,
463 fl6->flowlabel = ip6_flowlabel(ipv6_hdr(ireq->pktopts)); 464 fl6->flowlabel = ip6_flowlabel(ipv6_hdr(ireq->pktopts));
464 465
465 rcu_read_lock(); 466 rcu_read_lock();
466 err = ip6_xmit(sk, skb, fl6, rcu_dereference(np->opt), 467 opt = ireq->ipv6_opt;
467 np->tclass); 468 if (!opt)
469 opt = rcu_dereference(np->opt);
470 err = ip6_xmit(sk, skb, fl6, opt, np->tclass);
468 rcu_read_unlock(); 471 rcu_read_unlock();
469 err = net_xmit_eval(err); 472 err = net_xmit_eval(err);
470 } 473 }
@@ -476,6 +479,7 @@ done:
476 479
477static void tcp_v6_reqsk_destructor(struct request_sock *req) 480static void tcp_v6_reqsk_destructor(struct request_sock *req)
478{ 481{
482 kfree(inet_rsk(req)->ipv6_opt);
479 kfree_skb(inet_rsk(req)->pktopts); 483 kfree_skb(inet_rsk(req)->pktopts);
480} 484}
481 485
@@ -1107,7 +1111,9 @@ static struct sock *tcp_v6_syn_recv_sock(const struct sock *sk, struct sk_buff *
1107 but we make one more one thing there: reattach optmem 1111 but we make one more one thing there: reattach optmem
1108 to newsk. 1112 to newsk.
1109 */ 1113 */
1110 opt = rcu_dereference(np->opt); 1114 opt = ireq->ipv6_opt;
1115 if (!opt)
1116 opt = rcu_dereference(np->opt);
1111 if (opt) { 1117 if (opt) {
1112 opt = ipv6_dup_options(newsk, opt); 1118 opt = ipv6_dup_options(newsk, opt);
1113 RCU_INIT_POINTER(newnp->opt, opt); 1119 RCU_INIT_POINTER(newnp->opt, opt);