mirror of
https://github.com/torvalds/linux.git
synced 2026-11-06 21:58:01 +01:00
tcp: use the echoed source route in cookie_v4_check()
When the ACK carries a source route option, cookie_v4_check() routes
the new socket to opt->faddr, where opt points to the options of the
received packet.
ip_options_compile() only fills faddr for options given by
setsockopt() (when called without an skb), so on receive faddr is 0
and the lookup is done for daddr 0, which gives a local route.
Use the options echoed by tcp_v4_save_options() instead, as
inet_csk_route_req() and inet_csk_route_child_sock() do with
ireq->ireq_opt. Read them after security_inet_conn_request(),
since CIPSO can replace ireq->ireq_opt there.
The route now goes to the first hop of the source route, so also
refuse a strict source route through a gateway, as
inet_csk_route_req() does.
Found by sashiko while reviewing the sk_mc_loop() fix.
Fixes: 1da177e4c3 ("Linux-2.6.12-rc2")
Signed-off-by: Eric Dumazet <edumazet@kernel.org>
Reviewed-by: Kuniyuki Iwashima <kuniyu@google.com>
Link: https://patch.msgid.link/20261012101029.927296-3-edumazet@kernel.org
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
parent
31b564f70d
commit
54d574d4af
|
|
@ -404,12 +404,12 @@ static struct request_sock *cookie_tcp_check(struct net *net, struct sock *sk,
|
|||
*/
|
||||
struct sock *cookie_v4_check(struct sock *sk, struct sk_buff *skb)
|
||||
{
|
||||
struct ip_options *opt = &TCP_SKB_CB(skb)->header.h4.opt;
|
||||
const struct tcphdr *th = tcp_hdr(skb);
|
||||
struct tcp_sock *tp = tcp_sk(sk);
|
||||
struct inet_request_sock *ireq;
|
||||
struct net *net = sock_net(sk);
|
||||
struct tcp_request_sock *treq;
|
||||
struct ip_options_rcu *opt;
|
||||
struct request_sock *req;
|
||||
struct sock *ret = sk;
|
||||
struct flowi4 fl4;
|
||||
|
|
@ -449,6 +449,8 @@ struct sock *cookie_v4_check(struct sock *sk, struct sk_buff *skb)
|
|||
SKB_DR_SET(reason, SECURITY_HOOK);
|
||||
goto out_free;
|
||||
}
|
||||
/* Load ireq->ireq_opt after the LSM hook, which can replace it. */
|
||||
opt = rcu_dereference_protected(ireq->ireq_opt, true);
|
||||
|
||||
tcp_ao_syncookie(sk, skb, req, AF_INET);
|
||||
|
||||
|
|
@ -461,7 +463,7 @@ struct sock *cookie_v4_check(struct sock *sk, struct sk_buff *skb)
|
|||
flowi4_init_output(&fl4, ireq->ir_iif, ireq->ir_mark,
|
||||
ip_sock_rt_tos(sk), ip_sock_rt_scope(sk),
|
||||
IPPROTO_TCP, inet_sk_flowi_flags(sk),
|
||||
opt->srr ? opt->faddr : ireq->ir_rmt_addr,
|
||||
(opt && opt->opt.srr) ? opt->opt.faddr : ireq->ir_rmt_addr,
|
||||
ireq->ir_loc_addr, th->source, th->dest,
|
||||
sk_uid(sk));
|
||||
security_req_classify_flow(req, flowi4_to_flowi_common(&fl4));
|
||||
|
|
@ -470,6 +472,12 @@ struct sock *cookie_v4_check(struct sock *sk, struct sk_buff *skb)
|
|||
SKB_DR_SET(reason, IP_OUTNOROUTES);
|
||||
goto out_free;
|
||||
}
|
||||
/* Same check as in inet_csk_route_req(). */
|
||||
if (opt && opt->opt.is_strictroute && rt->rt_uses_gateway) {
|
||||
ip_rt_put(rt);
|
||||
SKB_DR_SET(reason, IP_OUTNOROUTES);
|
||||
goto out_free;
|
||||
}
|
||||
|
||||
/* Try to redo what tcp_v4_send_synack did. */
|
||||
req->rsk_window_clamp = READ_ONCE(tp->window_clamp) ? :
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user