Skip to content

Commit

Permalink
syncookies: check decoded options against sysctl settings
Browse files Browse the repository at this point in the history
Discard the ACK if we find options that do not match current sysctl
settings.

Previously it was possible to create a connection with sack, wscale,
etc. enabled even if the feature was disabled via sysctl.

Also remove an unneeded call to tcp_sack_reset() in
cookie_check_timestamp: Both call sites (cookie_v4_check,
cookie_v6_check) zero "struct tcp_options_received", hand it to
tcp_parse_options() (which does not change tcp_opt->num_sacks/dsack)
and then call cookie_check_timestamp().

Even if num_sacks/dsacks were changed, the structure is allocated on
the stack and after cookie_check_timestamp returns only a few selected
members are copied to the inet_request_sock.

Signed-off-by: Florian Westphal <fw@strlen.de>
Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
Florian Westphal authored and David S. Miller committed Jun 16, 2010
1 parent 317fe0e commit 8c76368
Show file tree
Hide file tree
Showing 3 changed files with 22 additions and 9 deletions.
2 changes: 1 addition & 1 deletion include/net/tcp.h
Original file line number Diff line number Diff line change
Expand Up @@ -464,7 +464,7 @@ extern __u32 cookie_v4_init_sequence(struct sock *sk, struct sk_buff *skb,
__u16 *mss);

extern __u32 cookie_init_timestamp(struct request_sock *req);
extern void cookie_check_timestamp(struct tcp_options_received *tcp_opt);
extern bool cookie_check_timestamp(struct tcp_options_received *tcp_opt);

/* From net/ipv6/syncookies.c */
extern struct sock *cookie_v6_check(struct sock *sk, struct sk_buff *skb);
Expand Down
25 changes: 19 additions & 6 deletions net/ipv4/syncookies.c
Original file line number Diff line number Diff line change
Expand Up @@ -230,23 +230,36 @@ static inline struct sock *get_cookie_sock(struct sock *sk, struct sk_buff *skb,
* The lowest 4 bits are for snd_wscale
* The next 4 lsb are for rcv_wscale
* The next lsb is for sack_ok
*
* return false if we decode an option that should not be.
*/
void cookie_check_timestamp(struct tcp_options_received *tcp_opt)
bool cookie_check_timestamp(struct tcp_options_received *tcp_opt)
{
/* echoed timestamp, 9 lowest bits contain options */
u32 options = tcp_opt->rcv_tsecr & TSMASK;

if (!tcp_opt->saw_tstamp) {
tcp_clear_options(tcp_opt);
return true;
}

if (!sysctl_tcp_timestamps)
return false;

tcp_opt->snd_wscale = options & 0xf;
options >>= 4;
tcp_opt->rcv_wscale = options & 0xf;

tcp_opt->sack_ok = (options >> 4) & 0x1;

if (tcp_opt->sack_ok)
tcp_sack_reset(tcp_opt);
if (tcp_opt->sack_ok && !sysctl_tcp_sack)
return false;

if (tcp_opt->snd_wscale || tcp_opt->rcv_wscale)
if (tcp_opt->snd_wscale || tcp_opt->rcv_wscale) {
tcp_opt->wscale_ok = 1;
return sysctl_tcp_window_scaling != 0;
}
return true;
}
EXPORT_SYMBOL(cookie_check_timestamp);

Expand Down Expand Up @@ -281,8 +294,8 @@ struct sock *cookie_v4_check(struct sock *sk, struct sk_buff *skb,
memset(&tcp_opt, 0, sizeof(tcp_opt));
tcp_parse_options(skb, &tcp_opt, &hash_location, 0);

if (tcp_opt.saw_tstamp)
cookie_check_timestamp(&tcp_opt);
if (!cookie_check_timestamp(&tcp_opt))
goto out;

ret = NULL;
req = inet_reqsk_alloc(&tcp_request_sock_ops); /* for safety */
Expand Down
4 changes: 2 additions & 2 deletions net/ipv6/syncookies.c
Original file line number Diff line number Diff line change
Expand Up @@ -180,8 +180,8 @@ struct sock *cookie_v6_check(struct sock *sk, struct sk_buff *skb)
memset(&tcp_opt, 0, sizeof(tcp_opt));
tcp_parse_options(skb, &tcp_opt, &hash_location, 0);

if (tcp_opt.saw_tstamp)
cookie_check_timestamp(&tcp_opt);
if (!cookie_check_timestamp(&tcp_opt))
goto out;

ret = NULL;
req = inet6_reqsk_alloc(&tcp6_request_sock_ops);
Expand Down

0 comments on commit 8c76368

Please sign in to comment.