Skip to content

Commit

Permalink
net: synack packets can be attached to request sockets
Browse files Browse the repository at this point in the history
selinux needs few changes to accommodate fact that SYNACK messages
can be attached to a request socket, lacking sk_security pointer

(Only syncookies are still attached to a TCP_LISTEN socket)

Adds a new sk_listener() helper, and use it in selinux and sch_fq

Fixes: ca6fb06 ("tcp: attach SYNACK messages to request sockets instead of listener")
Signed-off-by: Eric Dumazet <edumazet@google.com>
Reported by: kernel test robot <ying.huang@linux.intel.com>
Cc: Paul Moore <paul@paul-moore.com>
Cc: Stephen Smalley <sds@tycho.nsa.gov>
Cc: Eric Paris <eparis@parisplace.org>
Acked-by: Paul Moore <paul@paul-moore.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
Eric Dumazet authored and David S. Miller committed Oct 11, 2015
1 parent 21d11bd commit e446f9d
Show file tree
Hide file tree
Showing 3 changed files with 18 additions and 5 deletions.
8 changes: 8 additions & 0 deletions include/net/sock.h
Original file line number Diff line number Diff line change
Expand Up @@ -2201,6 +2201,14 @@ static inline bool sk_fullsock(const struct sock *sk)
return (1 << sk->sk_state) & ~(TCPF_TIME_WAIT | TCPF_NEW_SYN_RECV);
}

/* This helper checks if a socket is a LISTEN or NEW_SYN_RECV
* SYNACK messages can be attached to either ones (depending on SYNCOOKIE)
*/
static inline bool sk_listener(const struct sock *sk)
{
return (1 << sk->sk_state) & (TCPF_LISTEN | TCPF_NEW_SYN_RECV);
}

void sock_enable_timestamp(struct sock *sk, int flag);
int sock_get_timestamp(struct sock *, struct timeval __user *);
int sock_get_timestampns(struct sock *, struct timespec __user *);
Expand Down
3 changes: 2 additions & 1 deletion net/sched/sch_fq.c
Original file line number Diff line number Diff line change
Expand Up @@ -225,14 +225,15 @@ static struct fq_flow *fq_classify(struct sk_buff *skb, struct fq_sched_data *q)
return &q->internal;

/* SYNACK messages are attached to a TCP_NEW_SYN_RECV request socket
* or a listener (SYNCOOKIE mode)
* 1) request sockets are not full blown,
* they do not contain sk_pacing_rate
* 2) They are not part of a 'flow' yet
* 3) We do not want to rate limit them (eg SYNFLOOD attack),
* especially if the listener set SO_MAX_PACING_RATE
* 4) We pretend they are orphaned
*/
if (!sk || sk->sk_state == TCP_NEW_SYN_RECV) {
if (!sk || sk_listener(sk)) {
unsigned long hash = skb_get_hash(skb) & q->orphan_mask;

/* By forcing low order bit to 1, we make sure to not
Expand Down
12 changes: 8 additions & 4 deletions security/selinux/hooks.c
Original file line number Diff line number Diff line change
Expand Up @@ -4898,7 +4898,7 @@ static unsigned int selinux_ip_output(struct sk_buff *skb,
if (sk) {
struct sk_security_struct *sksec;

if (sk->sk_state == TCP_LISTEN)
if (sk_listener(sk))
/* if the socket is the listening state then this
* packet is a SYN-ACK packet which means it needs to
* be labeled based on the connection/request_sock and
Expand Down Expand Up @@ -5005,7 +5005,7 @@ static unsigned int selinux_ip_postroute(struct sk_buff *skb,
* unfortunately, this means more work, but it is only once per
* connection. */
if (skb_dst(skb) != NULL && skb_dst(skb)->xfrm != NULL &&
!(sk != NULL && sk->sk_state == TCP_LISTEN))
!(sk && sk_listener(sk)))
return NF_ACCEPT;
#endif

Expand All @@ -5022,7 +5022,7 @@ static unsigned int selinux_ip_postroute(struct sk_buff *skb,
secmark_perm = PACKET__SEND;
peer_sid = SECINITSID_KERNEL;
}
} else if (sk->sk_state == TCP_LISTEN) {
} else if (sk_listener(sk)) {
/* Locally generated packet but the associated socket is in the
* listening state which means this is a SYN-ACK packet. In
* this particular case the correct security label is assigned
Expand All @@ -5033,7 +5033,11 @@ static unsigned int selinux_ip_postroute(struct sk_buff *skb,
* selinux_inet_conn_request(). See also selinux_ip_output()
* for similar problems. */
u32 skb_sid;
struct sk_security_struct *sksec = sk->sk_security;
struct sk_security_struct *sksec;

if (sk->sk_state == TCP_NEW_SYN_RECV)
sk = inet_reqsk(sk)->rsk_listener;
sksec = sk->sk_security;
if (selinux_skb_peerlbl_sid(skb, family, &skb_sid))
return NF_DROP;
/* At this point, if the returned skb peerlbl is SECSID_NULL
Expand Down

0 comments on commit e446f9d

Please sign in to comment.