Netdev List
 help / color / mirror / Atom feed
* [PATCH net-next] ip6_tunnel: Allow rcv/xmit even if remote address is a local address
From: Shmulik Ladkani @ 2017-10-20 21:25 UTC (permalink / raw)
  To: David S . Miller, netdev; +Cc: Shmulik Ladkani

From: Shmulik Ladkani <shmulik.ladkani@gmail.com>

Currently, ip6_tnl_xmit_ctl drops tunneled packets if the remote
address (outer v6 destination) is one of host's locally configured
addresses.
Same applies to ip6_tnl_rcv_ctl: it drops packets if the remote address
(outer v6 source) is a local address.

This prevents using ipxip6 (and ip6_gre) tunnels whose local/remote
endpoints are on same host; OTOH v4 tunnels (ipip or gre) allow such
configurations.

An example where this proves useful is a system where entities are
identified by their unique v6 addresses, and use tunnels to encapsulate
traffic between them. The limitation prevents placing several entities
on same host.

Introduce IP6_TNL_F_ALLOW_LOCAL_REMOTE which allows to bypass this
restriction.

Signed-off-by: Shmulik Ladkani <shmulik.ladkani@gmail.com>
---
The restriction's history is pre-git era.

The warning in ip6_tnl_xmit_ctl states "Routing loop! Remote address
found on this node" - but having the outer v6 destination being a host
address does not necessarily mean the packets will go into a routing
loop: it depends on ip6_tunnel setup and routing setup for the packets
ingressing from the peer ip6_tunnel device.

Also, the same "routing loop" argument could have been applied to ipip
v4 tunnels, but these completely lack this validation.

Decided it is best for the admin to specify whether the restriction is
needed per tunnel. An alternative is to remove the restriction
completely.
---
 include/uapi/linux/ip6_tunnel.h | 2 ++
 net/ipv6/ip6_tunnel.c           | 6 ++++--
 2 files changed, 6 insertions(+), 2 deletions(-)

diff --git a/include/uapi/linux/ip6_tunnel.h b/include/uapi/linux/ip6_tunnel.h
index 425926c467d7..ffebbe365478 100644
--- a/include/uapi/linux/ip6_tunnel.h
+++ b/include/uapi/linux/ip6_tunnel.h
@@ -20,6 +20,8 @@
 #define IP6_TNL_F_RCV_DSCP_COPY 0x10
 /* copy fwmark from inner packet */
 #define IP6_TNL_F_USE_ORIG_FWMARK 0x20
+/* allow remote endpoint on the local node */
+#define IP6_TNL_F_ALLOW_LOCAL_REMOTE 0x40
 
 struct ip6_tnl_parm {
 	char name[IFNAMSIZ];	/* name of tunnel device */
diff --git a/net/ipv6/ip6_tunnel.c b/net/ipv6/ip6_tunnel.c
index 4212879ff35e..439d65f7e094 100644
--- a/net/ipv6/ip6_tunnel.c
+++ b/net/ipv6/ip6_tunnel.c
@@ -770,7 +770,8 @@ int ip6_tnl_rcv_ctl(struct ip6_tnl *t,
 
 		if ((ipv6_addr_is_multicast(laddr) ||
 		     likely(ipv6_chk_addr(net, laddr, ldev, 0))) &&
-		    likely(!ipv6_chk_addr(net, raddr, NULL, 0)))
+		    ((p->flags & IP6_TNL_F_ALLOW_LOCAL_REMOTE) ||
+		     likely(!ipv6_chk_addr(net, raddr, NULL, 0))))
 			ret = 1;
 	}
 	return ret;
@@ -1000,7 +1001,8 @@ int ip6_tnl_xmit_ctl(struct ip6_tnl *t,
 		if (unlikely(!ipv6_chk_addr(net, laddr, ldev, 0)))
 			pr_warn("%s xmit: Local address not yet configured!\n",
 				p->name);
-		else if (!ipv6_addr_is_multicast(raddr) &&
+		else if (!(p->flags & IP6_TNL_F_ALLOW_LOCAL_REMOTE) &&
+			 !ipv6_addr_is_multicast(raddr) &&
 			 unlikely(ipv6_chk_addr(net, raddr, NULL, 0)))
 			pr_warn("%s xmit: Routing loop! Remote address found on this node!\n",
 				p->name);
-- 
2.14.2

^ permalink raw reply related

* [PATCH net-next 4/6] tcp: add tracepoint trace_tcp_receive_reset
From: Song Liu @ 2017-10-20 21:20 UTC (permalink / raw)
  To: netdev, davem; +Cc: alexei.starovoitov, liu.song.a23, Song Liu
In-Reply-To: <20171020212046.577888-1-songliubraving@fb.com>

New tracepoint trace_tcp_receive_reset is added and called from
tcp_reset(). This tracepoint is define with a new class tcp_event_sk.

Signed-off-by: Song Liu <songliubraving@fb.com>
---
 include/trace/events/tcp.h | 66 ++++++++++++++++++++++++++++++++++++++++++++++
 net/ipv4/tcp_input.c       |  3 +++
 2 files changed, 69 insertions(+)

diff --git a/include/trace/events/tcp.h b/include/trace/events/tcp.h
index 3e57e1a..c83c711 100644
--- a/include/trace/events/tcp.h
+++ b/include/trace/events/tcp.h
@@ -88,6 +88,72 @@ DEFINE_EVENT(tcp_event_sk_skb, tcp_send_reset,
 	TP_ARGS(sk, skb)
 );
 
+/*
+ * tcp event with arguments sk
+ *
+ * Note: this class requires a valid sk pointer.
+ */
+DECLARE_EVENT_CLASS(tcp_event_sk,
+
+	TP_PROTO(const struct sock *sk),
+
+	TP_ARGS(sk),
+
+	TP_STRUCT__entry(
+		__field(const void *, skaddr)
+		__field(__u16, sport)
+		__field(__u16, dport)
+		__array(__u8, saddr, 4)
+		__array(__u8, daddr, 4)
+		__array(__u8, saddr_v6, 16)
+		__array(__u8, daddr_v6, 16)
+	),
+
+	TP_fast_assign(
+		struct inet_sock *inet = inet_sk(sk);
+		struct in6_addr *pin6;
+		__be32 *p32;
+
+		__entry->skaddr = sk;
+
+		__entry->sport = ntohs(inet->inet_sport);
+		__entry->dport = ntohs(inet->inet_dport);
+
+		p32 = (__be32 *) __entry->saddr;
+		*p32 = inet->inet_saddr;
+
+		p32 = (__be32 *) __entry->daddr;
+		*p32 =  inet->inet_daddr;
+
+#if IS_ENABLED(CONFIG_IPV6)
+		if (sk->sk_family == AF_INET6) {
+			pin6 = (struct in6_addr *)__entry->saddr_v6;
+			*pin6 = sk->sk_v6_rcv_saddr;
+			pin6 = (struct in6_addr *)__entry->daddr_v6;
+			*pin6 = sk->sk_v6_daddr;
+		} else
+#endif
+		{
+			pin6 = (struct in6_addr *)__entry->saddr_v6;
+			ipv6_addr_set_v4mapped(inet->inet_saddr, pin6);
+			pin6 = (struct in6_addr *)__entry->daddr_v6;
+			ipv6_addr_set_v4mapped(inet->inet_daddr, pin6);
+		}
+	),
+
+	TP_printk("sport=%hu dport=%hu saddr=%pI4 daddr=%pI4 saddrv6=%pI6c daddrv6=%pI6c",
+		  __entry->sport, __entry->dport,
+		  __entry->saddr, __entry->daddr,
+		  __entry->saddr_v6, __entry->daddr_v6)
+);
+
+DEFINE_EVENT(tcp_event_sk, tcp_receive_reset,
+
+	TP_PROTO(const struct sock *sk),
+
+	TP_ARGS(sk)
+);
+
 #endif /* _TRACE_TCP_H */
 
 /* This part must be outside protection */
diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c
index b2390bf..f041f38 100644
--- a/net/ipv4/tcp_input.c
+++ b/net/ipv4/tcp_input.c
@@ -75,6 +75,7 @@
 #include <linux/ipsec.h>
 #include <asm/unaligned.h>
 #include <linux/errqueue.h>
+#include <trace/events/tcp.h>
 
 int sysctl_tcp_fack __read_mostly;
 int sysctl_tcp_max_reordering __read_mostly = 300;
@@ -4010,6 +4011,8 @@ static inline bool tcp_sequence(const struct tcp_sock *tp, u32 seq, u32 end_seq)
 /* When we get a reset we do this. */
 void tcp_reset(struct sock *sk)
 {
+	trace_tcp_receive_reset(sk);
+
 	/* We want the right error as BSD sees it (and indeed as we do). */
 	switch (sk->sk_state) {
 	case TCP_SYN_SENT:
-- 
2.9.5

^ permalink raw reply related

* [PATCH net-next 3/6] tcp: add tracepoint trace_tcp_send_reset
From: Song Liu @ 2017-10-20 21:20 UTC (permalink / raw)
  To: netdev, davem; +Cc: alexei.starovoitov, liu.song.a23, Song Liu
In-Reply-To: <20171020212046.577888-1-songliubraving@fb.com>

New tracepoint trace_tcp_send_reset is added and called from
tcp_v4_send_reset(), tcp_v6_send_reset() and tcp_send_active_reset().

Signed-off-by: Song Liu <songliubraving@fb.com>
---
 include/trace/events/tcp.h | 11 +++++++++++
 net/ipv4/tcp_ipv4.c        |  6 +++++-
 net/ipv4/tcp_output.c      |  5 +++++
 net/ipv6/tcp_ipv6.c        | 10 ++++++++--
 4 files changed, 29 insertions(+), 3 deletions(-)

diff --git a/include/trace/events/tcp.h b/include/trace/events/tcp.h
index 2b6fe72..3e57e1a 100644
--- a/include/trace/events/tcp.h
+++ b/include/trace/events/tcp.h
@@ -77,6 +77,17 @@ DEFINE_EVENT(tcp_event_sk_skb, tcp_retransmit_skb,
 	TP_ARGS(sk, skb)
 );
 
+/*
+ * skb of trace_tcp_send_reset is the skb that caused RST. In case of
+ * active reset, skb should be NULL
+ */
+DEFINE_EVENT(tcp_event_sk_skb, tcp_send_reset,
+
+	TP_PROTO(const struct sock *sk, const struct sk_buff *skb),
+
+	TP_ARGS(sk, skb)
+);
+
 #endif /* _TRACE_TCP_H */
 
 /* This part must be outside protection */
diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c
index 28ca4e1..aa99d9d 100644
--- a/net/ipv4/tcp_ipv4.c
+++ b/net/ipv4/tcp_ipv4.c
@@ -85,6 +85,8 @@
 #include <crypto/hash.h>
 #include <linux/scatterlist.h>
 
+#include <trace/events/tcp.h>
+
 #ifdef CONFIG_TCP_MD5SIG
 static int tcp_v4_md5_hash_hdr(char *md5_hash, const struct tcp_md5sig_key *key,
 			       __be32 daddr, __be32 saddr, const struct tcphdr *th);
@@ -701,8 +703,10 @@ static void tcp_v4_send_reset(const struct sock *sk, struct sk_buff *skb)
 	 * routing might fail in this case. No choice here, if we choose to force
 	 * input interface, we will misroute in case of asymmetric route.
 	 */
-	if (sk)
+	if (sk) {
 		arg.bound_dev_if = sk->sk_bound_dev_if;
+		trace_tcp_send_reset(sk, skb);
+	}
 
 	BUILD_BUG_ON(offsetof(struct sock, sk_bound_dev_if) !=
 		     offsetof(struct inet_timewait_sock, tw_bound_dev_if));
diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c
index 53dc126..04ae660 100644
--- a/net/ipv4/tcp_output.c
+++ b/net/ipv4/tcp_output.c
@@ -3084,6 +3084,11 @@ void tcp_send_active_reset(struct sock *sk, gfp_t priority)
 	/* Send it off. */
 	if (tcp_transmit_skb(sk, skb, 0, priority))
 		NET_INC_STATS(sock_net(sk), LINUX_MIB_TCPABORTFAILED);
+
+	/* skb of trace_tcp_send_reset() keeps the skb that caused RST,
+	 * skb here is different to the troublesome skb, so use NULL
+	 */
+	trace_tcp_send_reset(sk, NULL);
 }
 
 /* Send a crossed SYN-ACK during socket establishment.
diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c
index ae83615..0e25299 100644
--- a/net/ipv6/tcp_ipv6.c
+++ b/net/ipv6/tcp_ipv6.c
@@ -69,6 +69,8 @@
 #include <crypto/hash.h>
 #include <linux/scatterlist.h>
 
+#include <trace/events/tcp.h>
+
 static void	tcp_v6_send_reset(const struct sock *sk, struct sk_buff *skb);
 static void	tcp_v6_reqsk_send_ack(const struct sock *sk, struct sk_buff *skb,
 				      struct request_sock *req);
@@ -890,7 +892,7 @@ static void tcp_v6_send_reset(const struct sock *sk, struct sk_buff *skb)
 	int genhash;
 	struct sock *sk1 = NULL;
 #endif
-	int oif;
+	int oif = 0;
 
 	if (th->rst)
 		return;
@@ -939,7 +941,11 @@ static void tcp_v6_send_reset(const struct sock *sk, struct sk_buff *skb)
 		ack_seq = ntohl(th->seq) + th->syn + th->fin + skb->len -
 			  (th->doff << 2);
 
-	oif = sk ? sk->sk_bound_dev_if : 0;
+	if (sk) {
+		oif = sk->sk_bound_dev_if;
+		trace_tcp_send_reset(sk, skb);
+	}
+
 	tcp_v6_send_response(sk, skb, seq, ack_seq, 0, 0, 0, oif, key, 1, 0, 0);
 
 #ifdef CONFIG_TCP_MD5SIG
-- 
2.9.5

^ permalink raw reply related

* [PATCH net-next 2/6] tcp: mark trace event arguments sk and skb as const
From: Song Liu @ 2017-10-20 21:20 UTC (permalink / raw)
  To: netdev, davem; +Cc: alexei.starovoitov, liu.song.a23, Song Liu
In-Reply-To: <20171020212046.577888-1-songliubraving@fb.com>

Some functions that we plan to add trace points require const sk
and/or skb. So we mark these fields as const in the tracepoint.

Signed-off-by: Song Liu <songliubraving@fb.com>
---
 include/trace/events/tcp.h | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/include/trace/events/tcp.h b/include/trace/events/tcp.h
index 14b0a708..2b6fe72 100644
--- a/include/trace/events/tcp.h
+++ b/include/trace/events/tcp.h
@@ -17,13 +17,13 @@
  */
 DECLARE_EVENT_CLASS(tcp_event_sk_skb,
 
-	TP_PROTO(struct sock *sk, struct sk_buff *skb),
+	TP_PROTO(const struct sock *sk, const struct sk_buff *skb),
 
 	TP_ARGS(sk, skb),
 
 	TP_STRUCT__entry(
-		__field(void *, skbaddr)
-		__field(void *, skaddr)
+		__field(const void *, skbaddr)
+		__field(const void *, skaddr)
 		__field(__u16, sport)
 		__field(__u16, dport)
 		__array(__u8, saddr, 4)
@@ -72,7 +72,7 @@ DECLARE_EVENT_CLASS(tcp_event_sk_skb,
 
 DEFINE_EVENT(tcp_event_sk_skb, tcp_retransmit_skb,
 
-	TP_PROTO(struct sock *sk, struct sk_buff *skb),
+	TP_PROTO(const struct sock *sk, const struct sk_buff *skb),
 
 	TP_ARGS(sk, skb)
 );
-- 
2.9.5

^ permalink raw reply related

* [PATCH net-next 1/6] tcp: add trace event class tcp_event_sk_skb
From: Song Liu @ 2017-10-20 21:20 UTC (permalink / raw)
  To: netdev, davem; +Cc: alexei.starovoitov, liu.song.a23, Song Liu
In-Reply-To: <20171020212046.577888-1-songliubraving@fb.com>

Introduce event class tcp_event_sk_skb for tcp tracepoints that
have arguments sk and skb.

Existing tracepoint trace_tcp_retransmit_skb() falls into this class.
This patch rewrites the definition of trace_tcp_retransmit_skb() with
tcp_event_sk_skb.

Signed-off-by: Song Liu <songliubraving@fb.com>
---
 include/trace/events/tcp.h | 15 ++++++++++++++-
 1 file changed, 14 insertions(+), 1 deletion(-)

diff --git a/include/trace/events/tcp.h b/include/trace/events/tcp.h
index c3220d9..14b0a708 100644
--- a/include/trace/events/tcp.h
+++ b/include/trace/events/tcp.h
@@ -9,7 +9,13 @@
 #include <linux/tracepoint.h>
 #include <net/ipv6.h>
 
-TRACE_EVENT(tcp_retransmit_skb,
+/*
+ * tcp event with arguments sk and skb
+ *
+ * Note: this class requires a valid sk pointer; while skb pointer could
+ *       be NULL.
+ */
+DECLARE_EVENT_CLASS(tcp_event_sk_skb,
 
 	TP_PROTO(struct sock *sk, struct sk_buff *skb),
 
@@ -64,6 +70,13 @@ TRACE_EVENT(tcp_retransmit_skb,
 		  __entry->saddr_v6, __entry->daddr_v6)
 );
 
+DEFINE_EVENT(tcp_event_sk_skb, tcp_retransmit_skb,
+
+	TP_PROTO(struct sock *sk, struct sk_buff *skb),
+
+	TP_ARGS(sk, skb)
+);
+
 #endif /* _TRACE_TCP_H */
 
 /* This part must be outside protection */
-- 
2.9.5

^ permalink raw reply related

* [PATCH net-next 6/6] tcp: add tracepoint trace_tcp_set_state()
From: Song Liu @ 2017-10-20 21:20 UTC (permalink / raw)
  To: netdev, davem; +Cc: alexei.starovoitov, liu.song.a23, Song Liu
In-Reply-To: <20171020212046.577888-1-songliubraving@fb.com>

This patch adds tracepoint trace_tcp_set_state. Besides usual fields
(s/d ports, IP addresses), old and new state of the socket is also
printed with TP_printk, with __print_symbolic().

Signed-off-by: Song Liu <songliubraving@fb.com>
---
 include/trace/events/tcp.h | 76 ++++++++++++++++++++++++++++++++++++++++++++++
 net/ipv4/tcp.c             |  4 +++
 2 files changed, 80 insertions(+)

diff --git a/include/trace/events/tcp.h b/include/trace/events/tcp.h
index 1724c12..03699ba 100644
--- a/include/trace/events/tcp.h
+++ b/include/trace/events/tcp.h
@@ -9,6 +9,22 @@
 #include <linux/tracepoint.h>
 #include <net/ipv6.h>
 
+#define tcp_state_name(state)	{ state, #state }
+#define show_tcp_state_name(val)			\
+	__print_symbolic(val,				\
+		tcp_state_name(TCP_ESTABLISHED),	\
+		tcp_state_name(TCP_SYN_SENT),		\
+		tcp_state_name(TCP_SYN_RECV),		\
+		tcp_state_name(TCP_FIN_WAIT1),		\
+		tcp_state_name(TCP_FIN_WAIT2),		\
+		tcp_state_name(TCP_TIME_WAIT),		\
+		tcp_state_name(TCP_CLOSE),		\
+		tcp_state_name(TCP_CLOSE_WAIT),		\
+		tcp_state_name(TCP_LAST_ACK),		\
+		tcp_state_name(TCP_LISTEN),		\
+		tcp_state_name(TCP_CLOSING),		\
+		tcp_state_name(TCP_NEW_SYN_RECV))
+
 /*
  * tcp event with arguments sk and skb
  *
@@ -161,6 +177,66 @@ DEFINE_EVENT(tcp_event_sk, tcp_destroy_sock,
 	TP_ARGS(sk)
 );
 
+TRACE_EVENT(tcp_set_state,
+
+	TP_PROTO(const struct sock *sk, const int oldstate, const int newstate),
+
+	TP_ARGS(sk, oldstate, newstate),
+
+	TP_STRUCT__entry(
+		__field(const void *, skaddr)
+		__field(int, oldstate)
+		__field(int, newstate)
+		__field(__u16, sport)
+		__field(__u16, dport)
+		__array(__u8, saddr, 4)
+		__array(__u8, daddr, 4)
+		__array(__u8, saddr_v6, 16)
+		__array(__u8, daddr_v6, 16)
+	),
+
+	TP_fast_assign(
+		struct inet_sock *inet = inet_sk(sk);
+		struct in6_addr *pin6;
+		__be32 *p32;
+
+		__entry->skaddr = sk;
+		__entry->oldstate = oldstate;
+		__entry->newstate = newstate;
+
+		__entry->sport = ntohs(inet->inet_sport);
+		__entry->dport = ntohs(inet->inet_dport);
+
+		p32 = (__be32 *) __entry->saddr;
+		*p32 = inet->inet_saddr;
+
+		p32 = (__be32 *) __entry->daddr;
+		*p32 =  inet->inet_daddr;
+
+#if IS_ENABLED(CONFIG_IPV6)
+		if (sk->sk_family == AF_INET6) {
+			pin6 = (struct in6_addr *)__entry->saddr_v6;
+			*pin6 = sk->sk_v6_rcv_saddr;
+			pin6 = (struct in6_addr *)__entry->daddr_v6;
+			*pin6 = sk->sk_v6_daddr;
+		} else
+#endif
+		{
+			pin6 = (struct in6_addr *)__entry->saddr_v6;
+			ipv6_addr_set_v4mapped(inet->inet_saddr, pin6);
+			pin6 = (struct in6_addr *)__entry->daddr_v6;
+			ipv6_addr_set_v4mapped(inet->inet_daddr, pin6);
+		}
+	),
+
+	TP_printk("sport=%hu dport=%hu saddr=%pI4 daddr=%pI4 saddrv6=%pI6c daddrv6=%pI6c oldstate=%s newstate=%s",
+		  __entry->sport, __entry->dport,
+		  __entry->saddr, __entry->daddr,
+		  __entry->saddr_v6, __entry->daddr_v6,
+		  show_tcp_state_name(__entry->oldstate),
+		  show_tcp_state_name(__entry->newstate))
+);
+
 #endif /* _TRACE_TCP_H */
 
 /* This part must be outside protection */
diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c
index 8b1fa4d..be07e9b 100644
--- a/net/ipv4/tcp.c
+++ b/net/ipv4/tcp.c
@@ -282,6 +282,8 @@
 #include <asm/ioctls.h>
 #include <net/busy_poll.h>
 
+#include <trace/events/tcp.h>
+
 int sysctl_tcp_min_tso_segs __read_mostly = 2;
 
 int sysctl_tcp_autocorking __read_mostly = 1;
@@ -2040,6 +2042,8 @@ void tcp_set_state(struct sock *sk, int state)
 {
 	int oldstate = sk->sk_state;
 
+	trace_tcp_set_state(sk, oldstate, state);
+
 	switch (state) {
 	case TCP_ESTABLISHED:
 		if (oldstate != TCP_ESTABLISHED)
-- 
2.9.5

^ permalink raw reply related

* [PATCH net-next 0/6] add a set of tracepoints to tcp stack
From: Song Liu @ 2017-10-20 21:20 UTC (permalink / raw)
  To: netdev, davem; +Cc: alexei.starovoitov, liu.song.a23, Song Liu

Resending the patch set as there were something wrong with my email
server.

These patches add the following tracepoints to tcp stack.

tcp_send_reset
tcp_receive_reset
tcp_destroy_sock
tcp_set_state

These tracepoints can be used to track TCP state changes. Such state
changes include but are not limited to: connection establish,
connection termination, tx and rx of RST, various retransmits.

Currently, we use the following kprobes to trace these events:

int kprobe__tcp_validate_incoming
int kprobe__tcp_send_active_reset
int kprobe__tcp_v4_send_reset
int kprobe__tcp_v6_send_reset
int kprobe__tcp_v4_destroy_sock
int kprobe__tcp_set_state
int kprobe__tcp_retransmit_skb

These tracepoints will help us simplify this work.

Thanks,
Song

Song Liu (6):
  tcp: add trace event class tcp_event_sk_skb
  tcp: mark trace event arguments sk and skb as const
  tcp: add tracepoint trace_tcp_send_reset
  tcp: add tracepoint trace_tcp_receive_reset
  tcp: add tracepoint trace_tcp_destroy_sock
  tcp: add tracepoint trace_tcp_set_state()

 include/trace/events/tcp.h | 181 ++++++++++++++++++++++++++++++++++++++++++++-
 net/ipv4/tcp.c             |   4 +
 net/ipv4/tcp_input.c       |   3 +
 net/ipv4/tcp_ipv4.c        |   8 +-
 net/ipv4/tcp_output.c      |   5 ++
 net/ipv6/tcp_ipv6.c        |  10 ++-
 6 files changed, 204 insertions(+), 7 deletions(-)

^ permalink raw reply

* [PATCH net-next 5/6] tcp: add tracepoint trace_tcp_destroy_sock
From: Song Liu @ 2017-10-20 21:20 UTC (permalink / raw)
  To: netdev, davem; +Cc: alexei.starovoitov, liu.song.a23, Song Liu
In-Reply-To: <20171020212046.577888-1-songliubraving@fb.com>

This patch adds trace event trace_tcp_destroy_sock.

Signed-off-by: Song Liu <songliubraving@fb.com>
---
 include/trace/events/tcp.h | 7 +++++++
 net/ipv4/tcp_ipv4.c        | 2 ++
 2 files changed, 9 insertions(+)

diff --git a/include/trace/events/tcp.h b/include/trace/events/tcp.h
index c83c711..1724c12 100644
--- a/include/trace/events/tcp.h
+++ b/include/trace/events/tcp.h
@@ -154,6 +154,13 @@ DEFINE_EVENT(tcp_event_sk, tcp_receive_reset,
 	TP_ARGS(sk)
 );
 
+DEFINE_EVENT(tcp_event_sk, tcp_destroy_sock,
+
+	TP_PROTO(const struct sock *sk),
+
+	TP_ARGS(sk)
+);
+
 #endif /* _TRACE_TCP_H */
 
 /* This part must be outside protection */
diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c
index aa99d9d..736753a 100644
--- a/net/ipv4/tcp_ipv4.c
+++ b/net/ipv4/tcp_ipv4.c
@@ -1865,6 +1865,8 @@ void tcp_v4_destroy_sock(struct sock *sk)
 {
 	struct tcp_sock *tp = tcp_sk(sk);
 
+	trace_tcp_destroy_sock(sk);
+
 	tcp_clear_xmit_timers(sk);
 
 	tcp_cleanup_congestion_control(sk);
-- 
2.9.5

^ permalink raw reply related

* [PATCH v2 net-next] tcp: Enable TFO without a cookie on a per-socket basis
From: Christoph Paasch @ 2017-10-20 21:13 UTC (permalink / raw)
  To: David Miller; +Cc: netdev, Eric Dumazet, Yuchung Cheng

We already allow to enable TFO without a cookie by using the
fastopen-sysctl and setting it to TFO_SERVER_COOKIE_NOT_REQD (0x200).
This is safe to do in certain environments where we know that there
isn't a malicous host (aka., data-centers).

A server however might be talking to both sides (public Internet and
data-center). So, this server would want to enable cookie-less TFO for
the connections that go to the data-center while enforcing cookies for
the traffic from the Internet.

This patch exposes a socket-option to enable this (protected by
CAP_NET_ADMIN).

Signed-off-by: Christoph Paasch <cpaasch@apple.com>
---

Notes:
    v2: * Rename to fastopen_no_cookie and TCP_FASTOPEN_NO_COOKIE
        * Add per-route attribute for fastopen_no_cookie
        * Get rid of the capability check

 include/linux/tcp.h            |  3 ++-
 include/net/tcp.h              |  3 ++-
 include/uapi/linux/rtnetlink.h |  2 ++
 include/uapi/linux/tcp.h       |  1 +
 net/ipv4/tcp.c                 | 12 ++++++++++++
 net/ipv4/tcp_fastopen.c        | 14 +++++++++++---
 net/ipv4/tcp_input.c           |  2 +-
 7 files changed, 31 insertions(+), 6 deletions(-)

diff --git a/include/linux/tcp.h b/include/linux/tcp.h
index 1d2c44e09e31..173a7c2f9636 100644
--- a/include/linux/tcp.h
+++ b/include/linux/tcp.h
@@ -215,7 +215,8 @@ struct tcp_sock {
 	u8	chrono_type:2,	/* current chronograph type */
 		rate_app_limited:1,  /* rate_{delivered,interval_us} limited? */
 		fastopen_connect:1, /* FASTOPEN_CONNECT sockopt */
-		unused:4;
+		fastopen_no_cookie:1, /* Allow send/recv SYN+data without a cookie */
+		unused:3;
 	u8	nonagle     : 4,/* Disable Nagle algorithm?             */
 		thin_lto    : 1,/* Use linear timeouts for thin streams */
 		unused1	    : 1,
diff --git a/include/net/tcp.h b/include/net/tcp.h
index 1efe8365cb28..020b20c3f50a 100644
--- a/include/net/tcp.h
+++ b/include/net/tcp.h
@@ -1562,7 +1562,8 @@ int tcp_fastopen_reset_cipher(struct net *net, struct sock *sk,
 void tcp_fastopen_add_skb(struct sock *sk, struct sk_buff *skb);
 struct sock *tcp_try_fastopen(struct sock *sk, struct sk_buff *skb,
 			      struct request_sock *req,
-			      struct tcp_fastopen_cookie *foc);
+			      struct tcp_fastopen_cookie *foc,
+			      const struct dst_entry *dst);
 void tcp_fastopen_init_key_once(struct net *net);
 bool tcp_fastopen_cookie_check(struct sock *sk, u16 *mss,
 			     struct tcp_fastopen_cookie *cookie);
diff --git a/include/uapi/linux/rtnetlink.h b/include/uapi/linux/rtnetlink.h
index dab7dad9e01a..fe6679268901 100644
--- a/include/uapi/linux/rtnetlink.h
+++ b/include/uapi/linux/rtnetlink.h
@@ -430,6 +430,8 @@ enum {
 #define RTAX_QUICKACK RTAX_QUICKACK
 	RTAX_CC_ALGO,
 #define RTAX_CC_ALGO RTAX_CC_ALGO
+	RTAX_FASTOPEN_NO_COOKIE,
+#define RTAX_FASTOPEN_NO_COOKIE RTAX_FASTOPEN_NO_COOKIE
 	__RTAX_MAX
 };
 
diff --git a/include/uapi/linux/tcp.h b/include/uapi/linux/tcp.h
index 69c7493e42f8..d67e1d40c6d6 100644
--- a/include/uapi/linux/tcp.h
+++ b/include/uapi/linux/tcp.h
@@ -120,6 +120,7 @@ enum {
 #define TCP_ULP			31	/* Attach a ULP to a TCP connection */
 #define TCP_MD5SIG_EXT		32	/* TCP MD5 Signature with extensions */
 #define TCP_FASTOPEN_KEY	33	/* Set the key for Fast Open (cookie) */
+#define TCP_FASTOPEN_NO_COOKIE	34	/* Enable TFO without a TFO cookie */
 
 struct tcp_repair_opt {
 	__u32	opt_code;
diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c
index 8b1fa4dd4538..a3d46a781abd 100644
--- a/net/ipv4/tcp.c
+++ b/net/ipv4/tcp.c
@@ -2832,6 +2832,14 @@ static int do_tcp_setsockopt(struct sock *sk, int level,
 			err = -EOPNOTSUPP;
 		}
 		break;
+	case TCP_FASTOPEN_NO_COOKIE:
+		if (val > 1 || val < 0)
+			err = -EINVAL;
+		else if (!((1 << sk->sk_state) & (TCPF_CLOSE | TCPF_LISTEN)))
+			err = -EINVAL;
+		else
+			tp->fastopen_no_cookie = 1;
+		break;
 	case TCP_TIMESTAMP:
 		if (!tp->repair)
 			err = -EPERM;
@@ -3252,6 +3260,10 @@ static int do_tcp_getsockopt(struct sock *sk, int level,
 		val = tp->fastopen_connect;
 		break;
 
+	case TCP_FASTOPEN_NO_COOKIE:
+		val = tp->fastopen_no_cookie;
+		break;
+
 	case TCP_TIMESTAMP:
 		val = tcp_time_stamp_raw() + tp->tsoffset;
 		break;
diff --git a/net/ipv4/tcp_fastopen.c b/net/ipv4/tcp_fastopen.c
index 21075ce19cb6..e704bd86fdf9 100644
--- a/net/ipv4/tcp_fastopen.c
+++ b/net/ipv4/tcp_fastopen.c
@@ -316,7 +316,8 @@ static bool tcp_fastopen_queue_check(struct sock *sk)
  */
 struct sock *tcp_try_fastopen(struct sock *sk, struct sk_buff *skb,
 			      struct request_sock *req,
-			      struct tcp_fastopen_cookie *foc)
+			      struct tcp_fastopen_cookie *foc,
+			      const struct dst_entry *dst)
 {
 	bool syn_data = TCP_SKB_CB(skb)->end_seq != TCP_SKB_CB(skb)->seq + 1;
 	int tcp_fastopen = sock_net(sk)->ipv4.sysctl_tcp_fastopen;
@@ -333,7 +334,9 @@ struct sock *tcp_try_fastopen(struct sock *sk, struct sk_buff *skb,
 		return NULL;
 	}
 
-	if (syn_data && (tcp_fastopen & TFO_SERVER_COOKIE_NOT_REQD))
+	if (syn_data && ((tcp_fastopen & TFO_SERVER_COOKIE_NOT_REQD) ||
+			 tcp_sk(sk)->fastopen_no_cookie ||
+			 (dst && dst_metric(dst, RTAX_FASTOPEN_NO_COOKIE))))
 		goto fastopen;
 
 	if (foc->len >= 0 &&  /* Client presents or requests a cookie */
@@ -370,6 +373,7 @@ bool tcp_fastopen_cookie_check(struct sock *sk, u16 *mss,
 			       struct tcp_fastopen_cookie *cookie)
 {
 	unsigned long last_syn_loss = 0;
+	const struct dst_entry *dst;
 	int syn_loss = 0;
 
 	tcp_fastopen_cache_get(sk, mss, cookie, &syn_loss, &last_syn_loss);
@@ -387,7 +391,11 @@ bool tcp_fastopen_cookie_check(struct sock *sk, u16 *mss,
 		return false;
 	}
 
-	if (sock_net(sk)->ipv4.sysctl_tcp_fastopen & TFO_CLIENT_NO_COOKIE) {
+	dst = __sk_dst_get(sk);
+
+	if ((sock_net(sk)->ipv4.sysctl_tcp_fastopen & TFO_CLIENT_NO_COOKIE) ||
+	    tcp_sk(sk)->fastopen_no_cookie ||
+	    (dst && dst_metric(dst, RTAX_FASTOPEN_NO_COOKIE))) {
 		cookie->len = -1;
 		return true;
 	}
diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c
index b2390bfdc68f..a6cf6407f780 100644
--- a/net/ipv4/tcp_input.c
+++ b/net/ipv4/tcp_input.c
@@ -6329,7 +6329,7 @@ int tcp_conn_request(struct request_sock_ops *rsk_ops,
 	tcp_openreq_init_rwin(req, sk, dst);
 	if (!want_cookie) {
 		tcp_reqsk_record_syn(sk, req, skb);
-		fastopen_sk = tcp_try_fastopen(sk, skb, req, &foc);
+		fastopen_sk = tcp_try_fastopen(sk, skb, req, &foc, dst);
 	}
 	if (fastopen_sk) {
 		af_ops->send_synack(fastopen_sk, dst, &fl, req,
-- 
2.14.1

^ permalink raw reply related

* [PATCH net-next 2/2] ibmvnic: Fix failover error path for non-fatal resets
From: John Allen @ 2017-10-20 21:03 UTC (permalink / raw)
  To: netdev, Thomas Falcon, Nathan Fontenot
In-Reply-To: <9bafaca4-75e7-ba82-8eea-35a69c61b6db@linux.vnet.ibm.com>



For all non-fatal reset conditions, the hypervisor will send a failover when
we attempt to initialize the crq and the vnic client is expected to handle
that failover instead of the existing non-fatal reset. To handle this, we
need to return from init with a return code that indicates that we have hit
this case.

Signed-off-by: John Allen <jallen@linux.vnet.ibm.com>
---
diff --git a/drivers/net/ethernet/ibm/ibmvnic.c b/drivers/net/ethernet/ibm/ibmvnic.c
index ebbb083..c914d5a 100644
--- a/drivers/net/ethernet/ibm/ibmvnic.c
+++ b/drivers/net/ethernet/ibm/ibmvnic.c
@@ -1452,7 +1452,7 @@ static int do_reset(struct ibmvnic_adapter *adapter,

 		rc = ibmvnic_init(adapter);
 		if (rc)
-			return 0;
+			return IBMVNIC_INIT_FAILED;

 		/* If the adapter was in PROBE state prior to the reset,
 		 * exit here.
@@ -1555,7 +1555,7 @@ static void __ibmvnic_reset(struct work_struct *work)
 	while (rwi) {
 		rc = do_reset(adapter, rwi, reset_state);
 		kfree(rwi);
-		if (rc)
+		if (rc && rc != IBMVNIC_INIT_FAILED)
 			break;

 		rwi = get_next_rwi(adapter);
diff --git a/drivers/net/ethernet/ibm/ibmvnic.h b/drivers/net/ethernet/ibm/ibmvnic.h
index 5347a7c..46eed65 100644
--- a/drivers/net/ethernet/ibm/ibmvnic.h
+++ b/drivers/net/ethernet/ibm/ibmvnic.h
@@ -30,6 +30,8 @@
 #define IBMVNIC_DRIVER_VERSION	"1.0.1"
 #define IBMVNIC_INVALID_MAP	-1
 #define IBMVNIC_STATS_TIMEOUT	1
+#define IBMVNIC_INIT_FAILED	2
+
 /* basic structures plus 100 2k buffers */
 #define IBMVNIC_IO_ENTITLEMENT_DEFAULT	610305

^ permalink raw reply related

* [PATCH net-next 1/2] ibmvnic: Update reset infrastructure to support tunable parameters
From: John Allen @ 2017-10-20 21:02 UTC (permalink / raw)
  To: netdev, Thomas Falcon, Nathan Fontenot
In-Reply-To: <9bafaca4-75e7-ba82-8eea-35a69c61b6db@linux.vnet.ibm.com>

Update ibmvnic reset infrastructure to include a new reset option that will
allow changing of tunable parameters. There currently is no way to request
different capabilities from the vnic server on the fly so this patch
achieves this by resetting the driver and attempting to log in with the
requested changes. If the reset operation fails, the old values of the
tunable parameters are stored in the "fallback" struct and we attempt to
login with the fallback values.

Signed-off-by: John Allen <jallen@linux.vnet.ibm.com>
---
diff --git a/drivers/net/ethernet/ibm/ibmvnic.c b/drivers/net/ethernet/ibm/ibmvnic.c
index 4bc14a9..36898b0 100644
--- a/drivers/net/ethernet/ibm/ibmvnic.c
+++ b/drivers/net/ethernet/ibm/ibmvnic.c
@@ -115,6 +115,7 @@ static union sub_crq *ibmvnic_next_scrq(struct ibmvnic_adapter *,
 static int init_sub_crq_irqs(struct ibmvnic_adapter *adapter);
 static int ibmvnic_init(struct ibmvnic_adapter *);
 static void release_crq_queue(struct ibmvnic_adapter *);
+static int __ibmvnic_set_mac(struct net_device *netdev, struct sockaddr *p);

 struct ibmvnic_stat {
 	char name[ETH_GSTRING_LEN];
@@ -910,6 +911,11 @@ static int ibmvnic_open(struct net_device *netdev)

 	mutex_lock(&adapter->reset_lock);

+	if (adapter->desired->mac) {
+		__ibmvnic_set_mac(netdev, adapter->desired->mac);
+		adapter->desired->mac = NULL;
+	}
+
 	if (adapter->state != VNIC_CLOSED) {
 		rc = ibmvnic_login(netdev);
 		if (rc) {
@@ -1372,7 +1378,7 @@ static void ibmvnic_set_multi(struct net_device *netdev)
 	}
 }

-static int ibmvnic_set_mac(struct net_device *netdev, void *p)
+static int __ibmvnic_set_mac(struct net_device *netdev, struct sockaddr *p)
 {
 	struct ibmvnic_adapter *adapter = netdev_priv(netdev);
 	struct sockaddr *addr = p;
@@ -1390,6 +1396,21 @@ static int ibmvnic_set_mac(struct net_device *netdev, void *p)
 	return 0;
 }

+static int ibmvnic_set_mac(struct net_device *netdev, void *p)
+{
+	struct ibmvnic_adapter *adapter = netdev_priv(netdev);
+	struct sockaddr *addr = p;
+
+	if (adapter->state != VNIC_OPEN) {
+		memcpy(adapter->desired->mac, addr, sizeof(struct sockaddr));
+		return 0;
+	}
+
+	__ibmvnic_set_mac(netdev, addr);
+
+	return 0;
+}
+
 /**
  * do_reset returns zero if we are able to keep processing reset events, or
  * non-zero if we hit a fatal error and must halt.
@@ -1416,6 +1437,13 @@ static int do_reset(struct ibmvnic_adapter *adapter,
 	if (rc)
 		return rc;

+	if (adapter->reset_reason == VNIC_RESET_CHANGE_PARAM ||
+	    adapter->wait_for_reset) {
+		release_resources(adapter);
+		release_sub_crqs(adapter);
+		release_crq_queue(adapter);
+	}
+
 	if (adapter->reset_reason != VNIC_RESET_NON_FATAL) {
 		/* remove the closed state so when we call open it appears
 		 * we are coming from the probed state.
@@ -1438,16 +1466,23 @@ static int do_reset(struct ibmvnic_adapter *adapter,
 			return 0;
 		}

-		rc = reset_tx_pools(adapter);
-		if (rc)
-			return rc;
+		if (adapter->reset_reason == VNIC_RESET_CHANGE_PARAM ||
+		    adapter->wait_for_reset) {
+			rc = init_resources(adapter);
+			if (rc)
+				return rc;
+		} else {
+			rc = reset_tx_pools(adapter);
+			if (rc)
+				return rc;

-		rc = reset_rx_pools(adapter);
-		if (rc)
-			return rc;
+			rc = reset_rx_pools(adapter);
+			if (rc)
+				return rc;

-		if (reset_state == VNIC_CLOSED)
-			return 0;
+			if (reset_state == VNIC_CLOSED)
+				return 0;
+		}
 	}

 	rc = __ibmvnic_open(netdev);
@@ -1526,6 +1561,12 @@ static void __ibmvnic_reset(struct work_struct *work)
 		rwi = get_next_rwi(adapter);
 	}

+	if (adapter->wait_for_reset) {
+		adapter->wait_for_reset = false;
+		adapter->reset_done_rc = rc;
+		complete(&adapter->reset_done);
+	}
+
 	if (rc) {
 		netdev_dbg(adapter->netdev, "Reset failed\n");
 		free_all_rwi(adapter);
@@ -1705,9 +1746,42 @@ static void ibmvnic_netpoll_controller(struct net_device *dev)
 }
 #endif

+static int wait_for_reset(struct ibmvnic_adapter *adapter)
+{
+	adapter->fallback->mtu = adapter->req_mtu;
+	adapter->fallback->rx_queues = adapter->req_rx_queues;
+	adapter->fallback->tx_queues = adapter->req_tx_queues;
+	adapter->fallback->rx_entries = adapter->req_rx_add_entries_per_subcrq;
+	adapter->fallback->tx_entries = adapter->req_tx_entries_per_subcrq;
+
+	init_completion(&adapter->reset_done);
+	ibmvnic_reset(adapter, VNIC_RESET_CHANGE_PARAM);
+	adapter->wait_for_reset = true;
+	wait_for_completion(&adapter->reset_done);
+
+	if (adapter->reset_done_rc) {
+		adapter->desired->mtu = adapter->fallback->mtu;
+		adapter->desired->rx_queues = adapter->fallback->rx_queues;
+		adapter->desired->tx_queues = adapter->fallback->tx_queues;
+		adapter->desired->rx_entries = adapter->fallback->rx_entries;
+		adapter->desired->tx_entries = adapter->fallback->tx_entries;
+
+		init_completion(&adapter->reset_done);
+		ibmvnic_reset(adapter, VNIC_RESET_CHANGE_PARAM);
+		wait_for_completion(&adapter->reset_done);
+	}
+	adapter->wait_for_reset = false;
+
+	return adapter->reset_done_rc;
+}
+
 static int ibmvnic_change_mtu(struct net_device *netdev, int new_mtu)
 {
-	return -EOPNOTSUPP;
+	struct ibmvnic_adapter *adapter = netdev_priv(netdev);
+
+	adapter->desired->mtu = new_mtu + ETH_HLEN;
+
+	return wait_for_reset(adapter);
 }

 static const struct net_device_ops ibmvnic_netdev_ops = {
@@ -1795,6 +1869,27 @@ static void ibmvnic_get_ringparam(struct net_device *netdev,
 	ring->rx_jumbo_pending = 0;
 }

+static int ibmvnic_set_ringparam(struct net_device *netdev,
+				 struct ethtool_ringparam *ring)
+{
+	struct ibmvnic_adapter *adapter = netdev_priv(netdev);
+
+	if (ring->rx_pending > adapter->max_rx_add_entries_per_subcrq  ||
+	    ring->tx_pending > adapter->max_tx_entries_per_subcrq) {
+		netdev_err(netdev, "Invalid request.\n");
+		netdev_err(netdev, "Max tx buffers = %llu\n",
+			   adapter->max_rx_add_entries_per_subcrq);
+		netdev_err(netdev, "Max rx buffers = %llu\n",
+			   adapter->max_tx_entries_per_subcrq);
+		return -EINVAL;
+	}
+
+	adapter->desired->rx_entries = ring->rx_pending;
+	adapter->desired->tx_entries = ring->tx_pending;
+
+	return wait_for_reset(adapter);
+}
+
 static void ibmvnic_get_channels(struct net_device *netdev,
 				 struct ethtool_channels *channels)
 {
@@ -1810,6 +1905,17 @@ static void ibmvnic_get_channels(struct net_device *netdev,
 	channels->combined_count = 0;
 }

+static int ibmvnic_set_channels(struct net_device *netdev,
+				struct ethtool_channels *channels)
+{
+	struct ibmvnic_adapter *adapter = netdev_priv(netdev);
+
+	adapter->desired->rx_queues = channels->rx_count;
+	adapter->desired->tx_queues = channels->tx_count;
+
+	return wait_for_reset(adapter);
+}
+
 static void ibmvnic_get_strings(struct net_device *dev, u32 stringset, u8 *data)
 {
 	struct ibmvnic_adapter *adapter = netdev_priv(dev);
@@ -1906,7 +2012,9 @@ static void ibmvnic_get_ethtool_stats(struct net_device *dev,
 	.set_msglevel		= ibmvnic_set_msglevel,
 	.get_link		= ibmvnic_get_link,
 	.get_ringparam		= ibmvnic_get_ringparam,
+	.set_ringparam		= ibmvnic_set_ringparam,
 	.get_channels		= ibmvnic_get_channels,
+	.set_channels		= ibmvnic_set_channels,
 	.get_strings            = ibmvnic_get_strings,
 	.get_sset_count         = ibmvnic_get_sset_count,
 	.get_ethtool_stats	= ibmvnic_get_ethtool_stats,
@@ -2372,6 +2480,7 @@ static void ibmvnic_send_req_caps(struct ibmvnic_adapter *adapter, int retry)
 {
 	struct device *dev = &adapter->vdev->dev;
 	union ibmvnic_crq crq;
+	int max_entries;

 	if (!retry) {
 		/* Sub-CRQ entries are 32 byte long */
@@ -2383,21 +2492,60 @@ static void ibmvnic_send_req_caps(struct ibmvnic_adapter *adapter, int retry)
 			return;
 		}

-		/* Get the minimum between the queried max and the entries
-		 * that fit in our PAGE_SIZE
-		 */
-		adapter->req_tx_entries_per_subcrq =
-		    adapter->max_tx_entries_per_subcrq > entries_page ?
-		    entries_page : adapter->max_tx_entries_per_subcrq;
-		adapter->req_rx_add_entries_per_subcrq =
-		    adapter->max_rx_add_entries_per_subcrq > entries_page ?
-		    entries_page : adapter->max_rx_add_entries_per_subcrq;
-
-		adapter->req_tx_queues = adapter->opt_tx_comp_sub_queues;
-		adapter->req_rx_queues = adapter->opt_rx_comp_queues;
-		adapter->req_rx_add_queues = adapter->max_rx_add_queues;
+		if (adapter->desired->mtu)
+			adapter->req_mtu = adapter->desired->mtu;
+		else
+			adapter->req_mtu = adapter->netdev->mtu + ETH_HLEN;
+
+		if (!adapter->desired->tx_entries)
+			adapter->desired->tx_entries =
+					adapter->max_tx_entries_per_subcrq;
+		if (!adapter->desired->rx_entries)
+			adapter->desired->rx_entries =
+					adapter->max_rx_add_entries_per_subcrq;
+
+		max_entries = IBMVNIC_MAX_LTB_SIZE /
+			      (adapter->req_mtu + IBMVNIC_BUFFER_HLEN);
+
+		if ((adapter->req_mtu + IBMVNIC_BUFFER_HLEN) *
+			adapter->desired->tx_entries > IBMVNIC_MAX_LTB_SIZE) {
+			adapter->desired->tx_entries = max_entries;
+		}
+
+		if ((adapter->req_mtu + IBMVNIC_BUFFER_HLEN) *
+			adapter->desired->rx_entries > IBMVNIC_MAX_LTB_SIZE) {
+			adapter->desired->rx_entries = max_entries;
+		}

-		adapter->req_mtu = adapter->netdev->mtu + ETH_HLEN;
+		if (adapter->desired->tx_entries)
+			adapter->req_tx_entries_per_subcrq =
+					adapter->desired->tx_entries;
+		else
+			adapter->req_tx_entries_per_subcrq =
+					adapter->max_tx_entries_per_subcrq;
+
+		if (adapter->desired->rx_entries)
+			adapter->req_rx_add_entries_per_subcrq =
+					adapter->desired->rx_entries;
+		else
+			adapter->req_rx_add_entries_per_subcrq =
+					adapter->max_rx_add_entries_per_subcrq;
+
+		if (adapter->desired->tx_queues)
+			adapter->req_tx_queues =
+					adapter->desired->tx_queues;
+		else
+			adapter->req_tx_queues =
+					adapter->opt_tx_comp_sub_queues;
+
+		if (adapter->desired->rx_queues)
+			adapter->req_rx_queues =
+					adapter->desired->rx_queues;
+		else
+			adapter->req_rx_queues =
+					adapter->opt_rx_comp_queues;
+
+		adapter->req_rx_add_queues = adapter->max_rx_add_queues;
 	}

 	memset(&crq, 0, sizeof(crq));
@@ -3211,6 +3359,7 @@ static int handle_login_rsp(union ibmvnic_crq *login_rsp_crq,
 			    struct ibmvnic_adapter *adapter)
 {
 	struct device *dev = &adapter->vdev->dev;
+	struct net_device *netdev = adapter->netdev;
 	struct ibmvnic_login_rsp_buffer *login_rsp = adapter->login_rsp_buf;
 	struct ibmvnic_login_buffer *login = adapter->login_buf;
 	int i;
@@ -3230,6 +3379,8 @@ static int handle_login_rsp(union ibmvnic_crq *login_rsp_crq,
 		return 0;
 	}

+	netdev->mtu = adapter->req_mtu - ETH_HLEN;
+
 	netdev_dbg(adapter->netdev, "Login Response Buffer:\n");
 	for (i = 0; i < (adapter->login_rsp_buf_sz - 1) / 8 + 1; i++) {
 		netdev_dbg(adapter->netdev, "%016lx\n",
@@ -3785,7 +3936,7 @@ static int ibmvnic_init(struct ibmvnic_adapter *adapter)
 	unsigned long timeout = msecs_to_jiffies(30000);
 	int rc;

-	if (adapter->resetting) {
+	if (adapter->resetting && !adapter->wait_for_reset) {
 		rc = ibmvnic_reset_crq(adapter);
 		if (!rc)
 			rc = vio_enable_interrupts(adapter->vdev);
@@ -3819,7 +3970,7 @@ static int ibmvnic_init(struct ibmvnic_adapter *adapter)
 		return -1;
 	}

-	if (adapter->resetting)
+	if (adapter->resetting && !adapter->wait_for_reset)
 		rc = reset_sub_crq_queues(adapter);
 	else
 		rc = init_sub_crqs(adapter);
@@ -3870,6 +4021,11 @@ static int ibmvnic_probe(struct vio_dev *dev, const struct vio_device_id *id)
 	adapter->vdev = dev;
 	adapter->netdev = netdev;

+	adapter->desired = kzalloc(sizeof(*adapter->desired), GFP_KERNEL);
+	adapter->desired->mac = kzalloc(sizeof(*adapter->desired->mac),
+					GFP_KERNEL);
+	adapter->fallback = kzalloc(sizeof(*adapter->fallback), GFP_KERNEL);
+
 	ether_addr_copy(adapter->mac_addr, mac_addr_p);
 	ether_addr_copy(netdev->dev_addr, adapter->mac_addr);
 	netdev->irq = dev->irq;
@@ -3895,6 +4051,8 @@ static int ibmvnic_probe(struct vio_dev *dev, const struct vio_device_id *id)
 	} while (rc == EAGAIN);

 	netdev->mtu = adapter->req_mtu - ETH_HLEN;
+	netdev->min_mtu = adapter->min_mtu - ETH_HLEN;
+	netdev->max_mtu = adapter->max_mtu - ETH_HLEN;

 	rc = device_create_file(&dev->dev, &dev_attr_failover);
 	if (rc)
@@ -3909,6 +4067,9 @@ static int ibmvnic_probe(struct vio_dev *dev, const struct vio_device_id *id)
 	dev_info(&dev->dev, "ibmvnic registered\n");

 	adapter->state = VNIC_PROBED;
+
+	adapter->wait_for_reset = false;
+
 	return 0;

 ibmvnic_register_fail:
@@ -3932,6 +4093,11 @@ static int ibmvnic_remove(struct vio_dev *dev)
 	mutex_lock(&adapter->reset_lock);

 	release_resources(adapter);
+
+	kfree(adapter->desired->mac);
+	kfree(adapter->desired);
+	kfree(adapter->fallback);
+
 	release_sub_crqs(adapter);
 	release_crq_queue(adapter);

diff --git a/drivers/net/ethernet/ibm/ibmvnic.h b/drivers/net/ethernet/ibm/ibmvnic.h
index d02257c..5347a7c 100644
--- a/drivers/net/ethernet/ibm/ibmvnic.h
+++ b/drivers/net/ethernet/ibm/ibmvnic.h
@@ -38,7 +38,8 @@
 /* when changing this, update IBMVNIC_IO_ENTITLEMENT_DEFAULT */
 #define IBMVNIC_BUFFS_PER_POOL	100
 #define IBMVNIC_MAX_TX_QUEUES	5
-
+#define IBMVNIC_MAX_LTB_SIZE ((1 << (MAX_ORDER - 1)) * PAGE_SIZE)
+#define IBMVNIC_BUFFER_HLEN 500
 struct ibmvnic_login_buffer {
 	__be32 len;
 	__be32 version;
@@ -940,13 +941,23 @@ enum ibmvnic_reset_reason {VNIC_RESET_FAILOVER = 1,
 			   VNIC_RESET_MOBILITY,
 			   VNIC_RESET_FATAL,
 			   VNIC_RESET_NON_FATAL,
-			   VNIC_RESET_TIMEOUT};
+			   VNIC_RESET_TIMEOUT,
+			   VNIC_RESET_CHANGE_PARAM};

 struct ibmvnic_rwi {
 	enum ibmvnic_reset_reason reset_reason;
 	struct list_head list;
 };

+struct ibmvnic_tunables {
+	u64 rx_queues;
+	u64 tx_queues;
+	u64 rx_entries;
+	u64 tx_entries;
+	u64 mtu;
+	struct sockaddr *mac;
+};
+
 struct ibmvnic_adapter {
 	struct vio_dev *vdev;
 	struct net_device *netdev;
@@ -1007,6 +1018,10 @@ struct ibmvnic_adapter {
 	struct completion fw_done;
 	int fw_done_rc;

+	struct completion reset_done;
+	int reset_done_rc;
+	bool wait_for_reset;
+
 	/* partner capabilities */
 	u64 min_tx_queues;
 	u64 min_rx_queues;
@@ -1051,4 +1066,7 @@ struct ibmvnic_adapter {
 	struct work_struct ibmvnic_reset;
 	bool resetting;
 	bool napi_enabled, from_passive_init;
+
+	struct ibmvnic_tunables *desired;
+	struct ibmvnic_tunables *fallback;
 };

^ permalink raw reply related

* [PATCH net-next 0/2] ibmvnic: Tunable parameter support
From: John Allen @ 2017-10-20 21:00 UTC (permalink / raw)
  To: netdev, Thomas Falcon, Nathan Fontenot

This series implements support for changing tunable parameters such as the
mtu, number of tx/rx queues, and number of buffers per queue via ethtool
and ifconfig.

John Allen (2):
  ibmvnic: Update reset infrastructure to support tunable parameters
  ibmvnic: Fix failover error path for non-fatal resets

 drivers/net/ethernet/ibm/ibmvnic.c | 222 ++++++++++++++++++++++++++++++++-----
 drivers/net/ethernet/ibm/ibmvnic.h |  24 +++-
 2 files changed, 216 insertions(+), 30 deletions(-)

-- 
1.8.3.1

^ permalink raw reply

* Re: Get rid of RCU callbacks in TC filters?
From: Cong Wang @ 2017-10-20 20:52 UTC (permalink / raw)
  To: Paul E. McKenney
  Cc: Jamal Hadi Salim, Chris Mi, Linux Kernel Network Developers,
	Daniel Borkmann, Eric Dumazet, David Miller, Jiri Pirko
In-Reply-To: <CAM_iQpUL9xCrZCjCpcaBMyjSWEJ+1DsFMO6dwJVtVvz=zKJDxA@mail.gmail.com>

On Fri, Oct 20, 2017 at 1:31 PM, Cong Wang <xiyou.wangcong@gmail.com> wrote:
> Actually, I just tried this approach, this way makes the core tc filter
> code harder to wait for flying callbacks, currently rcu_barrier() is
> enough, with one more schedule_work() added we probably
> need flush_workqueue()... Huh, this also means I can't use the
> global workqueue so should add a new workqueue for tc filters.
>
> Good news is I seem to make it work without adding much code.
> Stay tuned. ;)

Hmm, lockdep already complains I have a deadlock when flushing
workqueue while hodling RTNL lock, because callbacks need RTNL
too... See the rcu_barrier() in tcf_block_put().

So this approach seems to be a dead end. Is there any way out?

Probably we have to convert call_rcu() to synchronize_rcu(),
but with batching of course.

^ permalink raw reply

* [PATCH] isdn/gigaset: Provide cardstate context for bas timer callbacks
From: Kees Cook @ 2017-10-20 20:47 UTC (permalink / raw)
  To: Paul Bolle
  Cc: Karsten Keil, David S. Miller, Johan Hovold, linux-kernel,
	gigaset307x-common, netdev

While the work callback uses the urb to find cardstate from bas_cardstate,
this may not be valid for timer callbacks. Instead, introduce a direct
pointer back to the cardstate from bas_cardstate for use in timer
callbacks.

Reported-by: Paul Bolle <pebolle@tiscali.nl>
Fixes: 4cfea08e6251 ("isdn/gigaset: Convert timers to use timer_setup()")
Cc: Paul Bolle <pebolle@tiscali.nl>
Cc: Karsten Keil <isdn@linux-pingi.de>
Cc: "David S. Miller" <davem@davemloft.net>
Cc: Johan Hovold <johan@kernel.org>
Cc: gigaset307x-common@lists.sourceforge.net
Cc: netdev@vger.kernel.org
Signed-off-by: Kees Cook <keescook@chromium.org>
---
 drivers/isdn/gigaset/bas-gigaset.c | 14 ++++++--------
 1 file changed, 6 insertions(+), 8 deletions(-)

diff --git a/drivers/isdn/gigaset/bas-gigaset.c b/drivers/isdn/gigaset/bas-gigaset.c
index c990c6bbffc2..20d0a080a2b0 100644
--- a/drivers/isdn/gigaset/bas-gigaset.c
+++ b/drivers/isdn/gigaset/bas-gigaset.c
@@ -89,6 +89,7 @@ static int start_cbsend(struct cardstate *);
 
 struct bas_cardstate {
 	struct usb_device	*udev;		/* USB device pointer */
+	struct cardstate	*cs;
 	struct usb_interface	*interface;	/* interface for this device */
 	unsigned char		minor;		/* starting minor number */
 
@@ -436,8 +437,7 @@ static void check_pending(struct bas_cardstate *ucs)
 static void cmd_in_timeout(struct timer_list *t)
 {
 	struct bas_cardstate *ucs = from_timer(ucs, t, timer_cmd_in);
-	struct urb *urb = ucs->urb_int_in;
-	struct cardstate *cs = urb->context;
+	struct cardstate *cs = ucs->cs;
 	int rc;
 
 	if (!ucs->rcvbuf_size) {
@@ -643,8 +643,7 @@ static void int_in_work(struct work_struct *work)
 static void int_in_resubmit(struct timer_list *t)
 {
 	struct bas_cardstate *ucs = from_timer(ucs, t, timer_int_in);
-	struct urb *urb = ucs->urb_int_in;
-	struct cardstate *cs = urb->context;
+	struct cardstate *cs = ucs->cs;
 	int rc;
 
 	if (ucs->retry_int_in++ >= BAS_RETRY) {
@@ -1446,8 +1445,7 @@ static void read_iso_tasklet(unsigned long data)
 static void req_timeout(struct timer_list *t)
 {
 	struct bas_cardstate *ucs = from_timer(ucs, t, timer_ctrl);
-	struct urb *urb = ucs->urb_int_in;
-	struct cardstate *cs = urb->context;
+	struct cardstate *cs = ucs->cs;
 	int pending;
 	unsigned long flags;
 
@@ -1843,8 +1841,7 @@ static void write_command_callback(struct urb *urb)
 static void atrdy_timeout(struct timer_list *t)
 {
 	struct bas_cardstate *ucs = from_timer(ucs, t, timer_atrdy);
-	struct urb *urb = ucs->urb_int_in;
-	struct cardstate *cs = urb->context;
+	struct cardstate *cs = ucs->cs;
 
 	dev_warn(cs->dev, "timeout waiting for HD_READY_SEND_ATDATA\n");
 
@@ -2217,6 +2214,7 @@ static int gigaset_initcshw(struct cardstate *cs)
 	}
 
 	spin_lock_init(&ucs->lock);
+	ucs->cs = cs;
 	timer_setup(&ucs->timer_ctrl, req_timeout, 0);
 	timer_setup(&ucs->timer_atrdy, atrdy_timeout, 0);
 	timer_setup(&ucs->timer_cmd_in, cmd_in_timeout, 0);
-- 
2.7.4


-- 
Kees Cook
Pixel Security

^ permalink raw reply related

* Re: Get rid of RCU callbacks in TC filters?
From: Cong Wang @ 2017-10-20 20:31 UTC (permalink / raw)
  To: Paul E. McKenney
  Cc: Jamal Hadi Salim, Chris Mi, Linux Kernel Network Developers,
	Daniel Borkmann, Eric Dumazet, David Miller, Jiri Pirko
In-Reply-To: <20171020165623.GM3521@linux.vnet.ibm.com>

On Fri, Oct 20, 2017 at 9:56 AM, Paul E. McKenney
<paulmck@linux.vnet.ibm.com> wrote:
> On Thu, Oct 19, 2017 at 08:26:01PM -0700, Cong Wang wrote:
>> On Wed, Oct 18, 2017 at 12:35 PM, Paul E. McKenney
>> <paulmck@linux.vnet.ibm.com> wrote:
>> > 5) Keep call_rcu(), but have the RCU callback schedule a workqueue.
>> > The workqueue could then use blocking primitives, for example, acquiring
>> > RTNL.
>>
>> Yeah, this could work too but we would get one more async...
>>
>> filter delete -> call_rcu() -> schedule_work() -> action destroy
>
> True, but on the other hand you get to hold RTNL.

I can get RTNL too with converting call_rcu() to synchronize_rcu().
;)

So this turns into the question again: if we mind synchronize_rcu()
on slow paths or not?

Actually, I just tried this approach, this way makes the core tc filter
code harder to wait for flying callbacks, currently rcu_barrier() is
enough, with one more schedule_work() added we probably
need flush_workqueue()... Huh, this also means I can't use the
global workqueue so should add a new workqueue for tc filters.

Good news is I seem to make it work without adding much code.
Stay tuned. ;)

>
>> > 6) As with #5, have the RCU callback schedule a workqueue, but aggregate
>> > workqueue scheduling using a timer.  This would reduce the number of
>> > RTNL acquisitions.
>>
>> Ouch, sounds like even one more async:
>>
>> filter delete -> call_rcu() -> schedule_work() -> timer -> flush_work()
>> -> action destroy
>>
>> :-(
>
> Indeed, the price of scalability and performance is often added
> asynchronous action at a distance.  But sometimes you can have
> scalability, performance, -and- synchronous action.  Not sure that this
> is one of those cases, but perhaps someone will come up with some trick
> that we are not yet seeing.
>
> And again, one benefit you get from the added asynchrony is the ability
> to acquire RTNL.  Another is increased batching, allowing the overhead
> of acquiring RTNL to be amortized over a larger number of updates.

Understood, my point is it might not be worthy to optimize a slow path
which already has RTNL lock...


>
>> > 7) As with #5, have the RCU callback schedule a workqueue, but have each
>> > iterator accumulate a list of things removed and do call_rcu() on the
>> > list.  This is an alternative way of aggregating to reduce the number
>> > of RTNL acquisitions.
>>
>> Yeah, this seems working too.
>>
>> > There are many other ways to skin this cat.
>>
>> We still have to pick one. :) Any preference? I want to keep it as simple
>> as possible, otherwise some day I would not understand it either.
>
> I must defer to the people who actually fully understand this code.

I understand that code, just not sure about which approach I should
pick.

I will keep you Cc'ed for any further change I make.

Thanks!

^ permalink raw reply

* Re: [PATCH 0/2] 9p: Fixes for hard-to-hit bugs
From: Al Viro @ 2017-10-20 20:11 UTC (permalink / raw)
  To: Tuomas Tynkkynen
  Cc: v9fs-developer, Eric Van Hensbergen, Ron Minnich,
	Latchesar Ionkov, David S. Miller, linux-kernel, netdev,
	linux-fsdevel
In-Reply-To: <1506431414.20647.0.camel@tuxera.com>

On Tue, Sep 26, 2017 at 04:10:14PM +0300, Tuomas Tynkkynen wrote:
> Hi Al,
> 
> On Wed, 2017-09-06 at 17:59 +0300, Tuomas Tynkkynen wrote:
> > These two patches fix two hard-to-hit (but really annoying) bugs in
> > 9p.
> > The first one was posted earlier in February (with one R-b), the
> > second
> > is a new one.
> > 
> > Both of these have had soaking in NixOS distribution kernels for
> > a couple of months with no ill effects.
> > 
> > Tuomas Tynkkynen (2):
> >   fs/9p: Compare qid.path in v9fs_test_inode
> >   net/9p: Switch to wait_event_killable()
> > 
> >  fs/9p/vfs_inode.c      |  3 +++
> >  fs/9p/vfs_inode_dotl.c |  3 +++
> >  net/9p/client.c        |  3 +--
> >  net/9p/trans_virtio.c  | 13 ++++++-------
> >  net/9p/trans_xen.c     |  4 ++--
> >  5 files changed, 15 insertions(+), 11 deletions(-)
> > 
> 
> Could you apply these? Thanks!

I can pick those, or, if you (or somebody else) are willing to actively
maintain a 9p tree, you could start sending straight to Linus - up to
you.

^ permalink raw reply

* Pls assist me to come and establish an industry in your country
From: Mariam Dim Deng @ 2017-10-20 19:59 UTC (permalink / raw)
  To: msmariamcook

Genuine offer

How are you today and your family, I am a citizen of Sudan but
currently staying in Burkina Faso. My name is Miss Mariam Dim Deng,
25years old originated from Sudan.
My late father Dr. Dominic Dim Deng was the former Minister for SPLA
Affair and Special Adviser to President Salva Kiir of South Sudan for
Decentralization. You can read more about the crash through the below
site:
http://news.bbc.co.uk/2/hi/africa/7380412.stm

I am the only survival daughter of my late father, I want to establish
an industry in your country.My father left the sum of eight million,
four hundred thousand dollars, in the bank, so you will help me to
receive the fund for investment in your country.
Please I want to disclose a joint business proposal to you, can you be
my partner and to direct me the way to establish an industry, please
contact me at email: m.dim.deng1@gmail.com

Your beloved Mariam Dim Den

^ permalink raw reply

* Re: [PATCH 0/2] 9p: Fixes for hard-to-hit bugs
From: Linus Torvalds @ 2017-10-20 19:40 UTC (permalink / raw)
  To: Tuomas Tynkkynen
  Cc: Al Viro, V9FS Developers, Eric Van Hensbergen, Ron Minnich,
	Latchesar Ionkov, David S. Miller, Linux Kernel Mailing List,
	Network Development, linux-fsdevel
In-Reply-To: <1508502868.17067.3.camel@tuxera.com>

On Fri, Oct 20, 2017 at 8:34 AM, Tuomas Tynkkynen <tuomas@tuxera.com> wrote:
> Al, Linus
>
> Can one of you please pick these patches? They've been on the list for
> a month now, with an ack from Latchesar Ionkov.

I  don't pick up patches from the list. They need to be actually sent
to me so that I feel like I'm supposed to take them.

It does seem like 9pfs is unmaintained. I think I got my last 9p pull
request in January 2016. Hmm.

          Linus

^ permalink raw reply

* Re: [PATCH v2 net] packet: avoid panic in packet_getsockopt()
From: Eric Dumazet @ 2017-10-20 19:25 UTC (permalink / raw)
  To: kbuild test robot
  Cc: Eric Dumazet, kbuild-all, David Miller, netdev, Willem de Bruijn,
	John Sperbeck
In-Reply-To: <201710210201.6l3IUwxu%fengguang.wu@intel.com>

On Fri, Oct 20, 2017 at 12:11 PM, kbuild test robot <lkp@intel.com> wrote:
> Hi Eric,
>
> [auto build test WARNING on net/master]
>
> url:    https://github.com/0day-ci/linux/commits/Eric-Dumazet/packet-avoid-panic-in-packet_getsockopt/20171021-003615
> reproduce:
>         # apt-get install sparse
>         make ARCH=x86_64 allmodconfig
>         make C=1 CF=-D__CHECK_ENDIAN__
>
>
> sparse warnings: (new ones prefixed by >>)
>

Thanks, this was mentioned in the commit changelog.

We will add rcu annotations in net-next.

^ permalink raw reply

* [PATCH] textsearch: fix typos in library helpers
From: Randy Dunlap @ 2017-10-20 19:15 UTC (permalink / raw)
  To: netdev@vger.kernel.org, David Miller

From: Randy Dunlap <rdunlap@infradead.org>

Fix spellos (typos) in textsearch library helpers.

Signed-off-by: Randy Dunlap <rdunlap@infradead.org>
---
 lib/ts_fsm.c |    2 +-
 lib/ts_kmp.c |    2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

--- lnx-414-rc5.orig/lib/ts_fsm.c
+++ lnx-414-rc5/lib/ts_fsm.c
@@ -11,7 +11,7 @@
  * ==========================================================================
  *
  *   A finite state machine consists of n states (struct ts_fsm_token)
- *   representing the pattern as a finite automation. The data is read
+ *   representing the pattern as a finite automaton. The data is read
  *   sequentially on an octet basis. Every state token specifies the number
  *   of recurrences and the type of value accepted which can be either a
  *   specific character or ctype based set of characters. The available
--- lnx-414-rc5.orig/lib/ts_kmp.c
+++ lnx-414-rc5/lib/ts_kmp.c
@@ -27,7 +27,7 @@
  *
  *   [1] Cormen, Leiserson, Rivest, Stein
  *       Introdcution to Algorithms, 2nd Edition, MIT Press
- *   [2] See finite automation theory
+ *   [2] See finite automaton theory
  */
 
 #include <linux/module.h>

^ permalink raw reply

* Re: [PATCH v2 net] packet: avoid panic in packet_getsockopt()
From: kbuild test robot @ 2017-10-20 19:11 UTC (permalink / raw)
  To: Eric Dumazet
  Cc: kbuild-all, David Miller, netdev, Willem de Bruijn, Eric Dumazet,
	John Sperbeck
In-Reply-To: <1508368492.31614.153.camel@edumazet-glaptop3.roam.corp.google.com>

Hi Eric,

[auto build test WARNING on net/master]

url:    https://github.com/0day-ci/linux/commits/Eric-Dumazet/packet-avoid-panic-in-packet_getsockopt/20171021-003615
reproduce:
        # apt-get install sparse
        make ARCH=x86_64 allmodconfig
        make C=1 CF=-D__CHECK_ENDIAN__


sparse warnings: (new ones prefixed by >>)


vim +3936 net/packet/af_packet.c

  3845	
  3846	static int packet_getsockopt(struct socket *sock, int level, int optname,
  3847				     char __user *optval, int __user *optlen)
  3848	{
  3849		int len;
  3850		int val, lv = sizeof(val);
  3851		struct sock *sk = sock->sk;
  3852		struct packet_sock *po = pkt_sk(sk);
  3853		void *data = &val;
  3854		union tpacket_stats_u st;
  3855		struct tpacket_rollover_stats rstats;
  3856		struct packet_rollover *rollover;
  3857	
  3858		if (level != SOL_PACKET)
  3859			return -ENOPROTOOPT;
  3860	
  3861		if (get_user(len, optlen))
  3862			return -EFAULT;
  3863	
  3864		if (len < 0)
  3865			return -EINVAL;
  3866	
  3867		switch (optname) {
  3868		case PACKET_STATISTICS:
  3869			spin_lock_bh(&sk->sk_receive_queue.lock);
  3870			memcpy(&st, &po->stats, sizeof(st));
  3871			memset(&po->stats, 0, sizeof(po->stats));
  3872			spin_unlock_bh(&sk->sk_receive_queue.lock);
  3873	
  3874			if (po->tp_version == TPACKET_V3) {
  3875				lv = sizeof(struct tpacket_stats_v3);
  3876				st.stats3.tp_packets += st.stats3.tp_drops;
  3877				data = &st.stats3;
  3878			} else {
  3879				lv = sizeof(struct tpacket_stats);
  3880				st.stats1.tp_packets += st.stats1.tp_drops;
  3881				data = &st.stats1;
  3882			}
  3883	
  3884			break;
  3885		case PACKET_AUXDATA:
  3886			val = po->auxdata;
  3887			break;
  3888		case PACKET_ORIGDEV:
  3889			val = po->origdev;
  3890			break;
  3891		case PACKET_VNET_HDR:
  3892			val = po->has_vnet_hdr;
  3893			break;
  3894		case PACKET_VERSION:
  3895			val = po->tp_version;
  3896			break;
  3897		case PACKET_HDRLEN:
  3898			if (len > sizeof(int))
  3899				len = sizeof(int);
  3900			if (len < sizeof(int))
  3901				return -EINVAL;
  3902			if (copy_from_user(&val, optval, len))
  3903				return -EFAULT;
  3904			switch (val) {
  3905			case TPACKET_V1:
  3906				val = sizeof(struct tpacket_hdr);
  3907				break;
  3908			case TPACKET_V2:
  3909				val = sizeof(struct tpacket2_hdr);
  3910				break;
  3911			case TPACKET_V3:
  3912				val = sizeof(struct tpacket3_hdr);
  3913				break;
  3914			default:
  3915				return -EINVAL;
  3916			}
  3917			break;
  3918		case PACKET_RESERVE:
  3919			val = po->tp_reserve;
  3920			break;
  3921		case PACKET_LOSS:
  3922			val = po->tp_loss;
  3923			break;
  3924		case PACKET_TIMESTAMP:
  3925			val = po->tp_tstamp;
  3926			break;
  3927		case PACKET_FANOUT:
  3928			val = (po->fanout ?
  3929			       ((u32)po->fanout->id |
  3930				((u32)po->fanout->type << 16) |
  3931				((u32)po->fanout->flags << 24)) :
  3932			       0);
  3933			break;
  3934		case PACKET_ROLLOVER_STATS:
  3935			rcu_read_lock();
> 3936			rollover = rcu_dereference(po->rollover);
  3937			if (rollover) {
  3938				rstats.tp_all = atomic_long_read(&rollover->num);
  3939				rstats.tp_huge = atomic_long_read(&rollover->num_huge);
  3940				rstats.tp_failed = atomic_long_read(&rollover->num_failed);
  3941				data = &rstats;
  3942				lv = sizeof(rstats);
  3943			}
  3944			rcu_read_unlock();
  3945			if (!rollover)
  3946				return -EINVAL;
  3947			break;
  3948		case PACKET_TX_HAS_OFF:
  3949			val = po->tp_tx_has_off;
  3950			break;
  3951		case PACKET_QDISC_BYPASS:
  3952			val = packet_use_direct_xmit(po);
  3953			break;
  3954		default:
  3955			return -ENOPROTOOPT;
  3956		}
  3957	
  3958		if (len > lv)
  3959			len = lv;
  3960		if (put_user(len, optlen))
  3961			return -EFAULT;
  3962		if (copy_to_user(optval, data, len))
  3963			return -EFAULT;
  3964		return 0;
  3965	}
  3966	

---
0-DAY kernel test infrastructure                Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all                   Intel Corporation

^ permalink raw reply

* Re: [RFC PATCH 5/5] selinux: Add SCTP support
From: Stephen Smalley @ 2017-10-20 19:00 UTC (permalink / raw)
  To: Richard Haines, selinux, netdev, linux-sctp,
	linux-security-module
  Cc: marcelo.leitner, nhorman, vyasevich, Paul Moore
In-Reply-To: <20171017135953.4419-1-richard_c_haines@btinternet.com>

On Tue, 2017-10-17 at 14:59 +0100, Richard Haines wrote:
> The SELinux SCTP implementation is explained in:
> Documentation/security/SELinux-sctp.txt
> 
> Signed-off-by: Richard Haines <richard_c_haines@btinternet.com>
> ---
>  Documentation/security/SELinux-sctp.txt | 108 +++++++++++++
>  security/selinux/hooks.c                | 268
> ++++++++++++++++++++++++++++++--
>  security/selinux/include/classmap.h     |   3 +-
>  security/selinux/include/netlabel.h     |   9 +-
>  security/selinux/include/objsec.h       |   5 +
>  security/selinux/netlabel.c             |  52 ++++++-
>  6 files changed, 427 insertions(+), 18 deletions(-)
>  create mode 100644 Documentation/security/SELinux-sctp.txt
> 
> diff --git a/Documentation/security/SELinux-sctp.txt
> b/Documentation/security/SELinux-sctp.txt
> new file mode 100644
> index 0000000..32e0255
> --- /dev/null
> +++ b/Documentation/security/SELinux-sctp.txt
> @@ -0,0 +1,108 @@
> +                               SCTP SELinux Support
> +                              ======================
> +
> +Security Hooks
> +===============
> +
> +The Documentation/security/LSM-sctp.txt document describes how the
> following
> +sctp security hooks are utilised:
> +    security_sctp_assoc_request()
> +    security_sctp_bind_connect()
> +    security_sctp_sk_clone()
> +
> +    security_inet_conn_established()
> +
> +
> +Policy Statements
> +==================
> +The following class and permissions to support SCTP are available
> within the
> +kernel:
> +    class sctp_socket inherits socket { node_bind }
> +
> +whenever the following policy capability is enabled:
> +    policycap extended_socket_class;
> +
> +The SELinux SCTP support adds the additional permissions that are
> explained
> +in the sections below:
> +    association bindx connectx
> +
> +If userspace tools have been updated, SCTP will support the portcon
> +statement as shown in the following example:
> +    portcon sctp 1024-1036 system_u:object_r:sctp_ports_t:s0
> +
> +
> +SCTP Bind, Connect and ASCONF Chunk Parameter Permission Checks
> +================================================================
> +The hook security_sctp_bind_connect() is called by SCTP to check
> permissions
> +required for ipv4/ipv6 addresses based on the @optname as follows:
> +
> +  ------------------------------------------------------------------
> +  |                      BINDX Permission Check                    |
> +  |       @optname             |         @address contains         |
> +  |----------------------------|-----------------------------------|
> +  | SCTP_SOCKOPT_BINDX_ADD     | One or more ipv4 / ipv6 addresses |
> +  ------------------------------------------------------------------
> +
> +  ------------------------------------------------------------------
> +  |                  BIND Permission Checks                        |
> +  |       @optname             |         @address contains         |
> +  |----------------------------|-----------------------------------|
> +  | SCTP_PRIMARY_ADDR          | Single ipv4 or ipv6 address       |
> +  | SCTP_SET_PEER_PRIMARY_ADDR | Single ipv4 or ipv6 address       |
> +  ------------------------------------------------------------------
> +
> +  ------------------------------------------------------------------
> +  |                 CONNECTX Permission Check                      |
> +  |       @optname             |         @address contains         |
> +  |----------------------------|-----------------------------------|
> +  | SCTP_SOCKOPT_CONNECTX      | One or more ipv4 / ipv6 addresses |
> +  ------------------------------------------------------------------
> +
> +  ------------------------------------------------------------------
> +  |                 CONNECT Permission Checks                      |
> +  |       @optname             |         @address contains         |
> +  |----------------------------|-----------------------------------|
> +  | SCTP_SENDMSG_CONNECT       | Single ipv4 or ipv6 address       |
> +  | SCTP_PARAM_ADD_IP          | One or more ipv4 / ipv6 addresses |
> +  | SCTP_PARAM_SET_PRIMARY     | Single ipv4 or ipv6 address       |
> +  ------------------------------------------------------------------
> +
> +SCTP Peer Labeling
> +===================
> +An SCTP socket will only have one peer label assigned to it. This
> will be
> +assigned during the establishment of the first association. Once the
> peer
> +label has been assigned, any new associations will have the
> "association"
> +permission validated by checking the socket peer sid against the
> received
> +packets peer sid to determine whether the association should be
> allowed or
> +denied.
> +
> +NOTES:
> +   1) If peer labeling is not enabled, then the peer context will
> always be
> +      SECINITSID_UNLABELED (unlabeled_t in Reference Policy).
> +
> +   2) As SCTP supports multiple endpoints with multi-homing on a
> single socket
> +      it is recommended that peer labels are consistent.
> +
> +   3) getpeercon(3) may be used by userspace to retrieve the sockets
> peer
> +       context.
> +
> +   4) If using NetLabel be aware that if a label is assigned to a
> specific
> +      interface, and that interface 'goes down', then the NetLabel
> service
> +      will remove the entry. Therefore ensure that the network
> startup scripts
> +      call netlabelctl(8) to set the required label (see netlabel-
> config(8)
> +      helper script for details).
> +
> +   5) The NetLabel SCTP peer labeling rules apply as discussed in
> the following
> +      set of posts tagged "netlabel" at: http://www.paul-moore.com/b
> log/t.
> +
> +   6) CIPSO is only supported for IPv4 addressing: socket(AF_INET,
> ...)
> +      CALIPSO is only supported for IPv6 addressing:
> socket(AF_INET6, ...)
> +
> +      Note the following when testing CIPSO/CALIPSO:
> +         a) CIPSO will send an ICMP packet if an SCTP packet cannot
> be
> +            delivered because of an invalid label.
> +         b) CALIPSO does not send an ICMP packet, just silently
> discards it.
> +
> +   7) IPSEC is not supported as rfc3554 - sctp/ipsec support has not
> been
> +      implemented in userspace (racoon(8) or ipsec_pluto(8)),
> although the
> +      kernel supports SCTP/IPSEC.
> diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
> index 33fd061..c3e9600 100644
> --- a/security/selinux/hooks.c
> +++ b/security/selinux/hooks.c
> @@ -67,6 +67,8 @@
>  #include <linux/tcp.h>
>  #include <linux/udp.h>
>  #include <linux/dccp.h>
> +#include <linux/sctp.h>
> +#include <net/sctp/structs.h>
>  #include <linux/quota.h>
>  #include <linux/un.h>		/* for Unix socket types */
>  #include <net/af_unix.h>	/* for Unix socket types */
> @@ -4119,6 +4121,23 @@ static int selinux_parse_skb_ipv4(struct
> sk_buff *skb,
>  		break;
>  	}
>  
> +#if IS_ENABLED(CONFIG_IP_SCTP)
> +	case IPPROTO_SCTP: {
> +		struct sctphdr _sctph, *sh;
> +
> +		if (ntohs(ih->frag_off) & IP_OFFSET)
> +			break;
> +
> +		offset += ihlen;
> +		sh = skb_header_pointer(skb, offset, sizeof(_sctph),
> &_sctph);
> +		if (sh == NULL)
> +			break;
> +
> +		ad->u.net->sport = sh->source;
> +		ad->u.net->dport = sh->dest;
> +		break;
> +	}
> +#endif
>  	default:
>  		break;
>  	}
> @@ -4192,6 +4211,19 @@ static int selinux_parse_skb_ipv6(struct
> sk_buff *skb,
>  		break;
>  	}
>  
> +#if IS_ENABLED(CONFIG_IP_SCTP)
> +	case IPPROTO_SCTP: {
> +		struct sctphdr _sctph, *sh;
> +
> +		sh = skb_header_pointer(skb, offset, sizeof(_sctph),
> &_sctph);
> +		if (sh == NULL)
> +			break;
> +
> +		ad->u.net->sport = sh->source;
> +		ad->u.net->dport = sh->dest;
> +		break;
> +	}
> +#endif
>  	/* includes fragments */
>  	default:
>  		break;
> @@ -4381,6 +4413,10 @@ static int selinux_socket_post_create(struct
> socket *sock, int family,
>  		sksec = sock->sk->sk_security;
>  		sksec->sclass = sclass;
>  		sksec->sid = sid;
> +		/* Allows detection of the first association on this
> socket */
> +		if (sksec->sclass == SECCLASS_SCTP_SOCKET)
> +			sksec->sctp_assoc_state = SCTP_ASSOC_UNSET;
> +

What prevents this from interleaving with selinux_sctp_assoc_request()
accesses to sctp_assoc_state?

>  		err = selinux_netlbl_socket_post_create(sock->sk,
> family);
>  	}
>  
> @@ -4401,11 +4437,7 @@ static int selinux_socket_bind(struct socket
> *sock, struct sockaddr *address, in
>  	if (err)
>  		goto out;
>  
> -	/*
> -	 * If PF_INET or PF_INET6, check name_bind permission for
> the port.
> -	 * Multiple address binding for SCTP is not supported yet:
> we just
> -	 * check the first address now.
> -	 */
> +	/* If PF_INET or PF_INET6, check name_bind permission for
> the port. */
>  	family = sk->sk_family;
>  	if (family == PF_INET || family == PF_INET6) {
>  		char *addrp;
> @@ -4417,7 +4449,13 @@ static int selinux_socket_bind(struct socket
> *sock, struct sockaddr *address, in
>  		unsigned short snum;
>  		u32 sid, node_perm;
>  
> -		if (family == PF_INET) {
> +		/*
> +		 * sctp_bindx(3) calls via
> selinux_sctp_bind_connect()
> +		 * that validates multiple binding addresses.
> Because of this
> +		 * need to check address->sa_family as it is
> possible to have
> +		 * sk->sk_family = PF_INET6 with addr->sa_family =
> AF_INET.
> +		 */
> +		if (family == PF_INET || address->sa_family ==
> AF_INET) {
>  			if (addrlen < sizeof(struct sockaddr_in)) {
>  				err = -EINVAL;
>  				goto out;
> @@ -4471,6 +4509,10 @@ static int selinux_socket_bind(struct socket
> *sock, struct sockaddr *address, in
>  			node_perm = DCCP_SOCKET__NODE_BIND;
>  			break;
>  
> +		case SECCLASS_SCTP_SOCKET:
> +			node_perm = SCTP_SOCKET__NODE_BIND;
> +			break;
> +
>  		default:
>  			node_perm = RAWIP_SOCKET__NODE_BIND;
>  			break;
> @@ -4485,7 +4527,7 @@ static int selinux_socket_bind(struct socket
> *sock, struct sockaddr *address, in
>  		ad.u.net->sport = htons(snum);
>  		ad.u.net->family = family;
>  
> -		if (family == PF_INET)
> +		if (family == PF_INET || address->sa_family ==
> AF_INET)
>  			ad.u.net->v4info.saddr = addr4-
> >sin_addr.s_addr;
>  		else
>  			ad.u.net->v6info.saddr = addr6->sin6_addr;
> @@ -4510,10 +4552,12 @@ static int selinux_socket_connect(struct
> socket *sock, struct sockaddr *address,
>  		return err;
>  
>  	/*
> -	 * If a TCP or DCCP socket, check name_connect permission
> for the port.
> +	 * If a TCP, DCCP or SCTP socket, check name_connect
> permission
> +	 * for the port.
>  	 */
>  	if (sksec->sclass == SECCLASS_TCP_SOCKET ||
> -	    sksec->sclass == SECCLASS_DCCP_SOCKET) {
> +	    sksec->sclass == SECCLASS_DCCP_SOCKET ||
> +	    sksec->sclass == SECCLASS_SCTP_SOCKET) {
>  		struct common_audit_data ad;
>  		struct lsm_network_audit net = {0,};
>  		struct sockaddr_in *addr4 = NULL;
> @@ -4521,7 +4565,14 @@ static int selinux_socket_connect(struct
> socket *sock, struct sockaddr *address,
>  		unsigned short snum;
>  		u32 sid, perm;
>  
> -		if (sk->sk_family == PF_INET) {
> +		/* sctp_connectx(3) calls via
> +		 *selinux_sctp_bind_connect() that validates
> multiple
> +		 * connect addresses. Because of this need to check
> +		 * address->sa_family as it is possible to have
> +		 * sk->sk_family = PF_INET6 with addr->sa_family =
> AF_INET.
> +		 */
> +		if (sk->sk_family == PF_INET ||
> +					address->sa_family ==
> AF_INET) {
>  			addr4 = (struct sockaddr_in *)address;
>  			if (addrlen < sizeof(struct sockaddr_in))
>  				return -EINVAL;
> @@ -4534,11 +4585,21 @@ static int selinux_socket_connect(struct
> socket *sock, struct sockaddr *address,
>  		}
>  
>  		err = sel_netport_sid(sk->sk_protocol, snum, &sid);
> +
>  		if (err)
>  			goto out;
>  
> -		perm = (sksec->sclass == SECCLASS_TCP_SOCKET) ?
> -		       TCP_SOCKET__NAME_CONNECT :
> DCCP_SOCKET__NAME_CONNECT;
> +		switch (sksec->sclass) {
> +		case SECCLASS_TCP_SOCKET:
> +			perm = TCP_SOCKET__NAME_CONNECT;
> +			break;
> +		case SECCLASS_DCCP_SOCKET:
> +			perm = DCCP_SOCKET__NAME_CONNECT;
> +			break;
> +		case SECCLASS_SCTP_SOCKET:
> +			perm = SCTP_SOCKET__NAME_CONNECT;
> +			break;
> +		}
>  
>  		ad.type = LSM_AUDIT_DATA_NET;
>  		ad.u.net = &net;
> @@ -4815,7 +4876,8 @@ static int
> selinux_socket_getpeersec_stream(struct socket *sock, char __user *op
>  	u32 peer_sid = SECSID_NULL;
>  
>  	if (sksec->sclass == SECCLASS_UNIX_STREAM_SOCKET ||
> -	    sksec->sclass == SECCLASS_TCP_SOCKET)
> +	    sksec->sclass == SECCLASS_TCP_SOCKET ||
> +	    sksec->sclass == SECCLASS_SCTP_SOCKET)
>  		peer_sid = sksec->peer_sid;
>  	if (peer_sid == SECSID_NULL)
>  		return -ENOPROTOOPT;
> @@ -4928,6 +4990,183 @@ static void selinux_sock_graft(struct sock
> *sk, struct socket *parent)
>  	sksec->sclass = isec->sclass;
>  }
>  
> +/* Called whenever SCTP receives an INIT or INIT_ACK chunk */
> +static int selinux_sctp_assoc_request(struct sctp_endpoint *ep,
> +				      struct sk_buff *skb,
> +				      int sctp_cid)
> +{
> +	struct sk_security_struct *sksec = ep->base.sk->sk_security;
> +	struct common_audit_data ad;
> +	struct lsm_network_audit net = {0,};
> +	u8 peerlbl_active;
> +	u32 peer_sid = SECINITSID_UNLABELED;
> +	u32 conn_sid;
> +	int err;
> +
> +	if (!selinux_policycap_extsockclass)
> +		return 0;
> +
> +	peerlbl_active = selinux_peerlbl_enabled();
> +
> +	if (peerlbl_active) {
> +		/* This will return peer_sid = SECSID_NULL if there
> are
> +		 * no peer labels, see
> security_net_peersid_resolve().
> +		 */
> +		err = selinux_skb_peerlbl_sid(skb, ep->base.sk-
> >sk_family,
> +					      &peer_sid);
> +
> +		if (err)
> +			return err;
> +
> +		if (peer_sid == SECSID_NULL)
> +			peer_sid = SECINITSID_UNLABELED;
> +	}
> +
> +	if (sksec->sctp_assoc_state == SCTP_ASSOC_UNSET) {
> +		sksec->sctp_assoc_state = SCTP_ASSOC_SET;
> +
> +		/* Here as first association on socket. As the peer
> SID
> +		 * was allowed by peer recv (and the netif/node
> checks),
> +		 * then it is approved by policy and used as the
> primary
> +		 * peer SID for getpeercon(3).
> +		 */
> +		sksec->peer_sid = peer_sid;
> +	} else if  (sksec->peer_sid != peer_sid) {
> +		/* Other association peer SIDs are checked to
> enforce
> +		 * consistency among the peer SIDs.
> +		 */
> +		ad.type = LSM_AUDIT_DATA_NET;
> +		ad.u.net = &net;
> +		ad.u.net->sk = ep->base.sk;
> +		err = avc_has_perm(sksec->peer_sid, peer_sid, sksec-
> >sclass,
> +				   SCTP_SOCKET__ASSOCIATION, &ad);
> +		if (err)
> +			return err;
> +	}
> +
> +	if (sctp_cid == SCTP_CID_INIT) {
> +		/* Have INIT when incoming connect(2),
> sctp_connectx(3)
> +		 * or sctp_sendmsg(3) (with no association already
> present),
> +		 * so compute the MLS component for the connection
> and store
> +		 * the information in ep. This will be used by SCTP
> TCP type
> +		 * sockets and peeled off connections as they cause
> a new
> +		 * socket to be generated. selinux_sctp_sk_clone()
> will then
> +		 * plug this into the new socket.
> +		 */
> +		err = selinux_conn_sid(sksec->sid, peer_sid,
> &conn_sid);
> +		if (err)
> +			return err;
> +
> +		ep->secid = conn_sid;
> +		ep->peer_secid = peer_sid;
> +
> +		/* Set any NetLabel labels including CIPSO/CALIPSO
> options. */
> +		return selinux_netlbl_sctp_assoc_request(ep, skb);
> +	}
> +
> +	return 0;
> +}
> +
> +/*
> + * Check if sctp IPv4/IPv6 addresses are valid for binding or
> connecting
> + * based on their @optname.
> + */
> +static int selinux_sctp_bind_connect(struct sock *sk, int optname,
> +				     struct sockaddr *address,
> +				     int addrlen)
> +{
> +	int len, err = 0, walk_size = 0;
> +	void *addr_buf;
> +	struct sockaddr *addr;
> +	struct socket *sock;
> +
> +	if (!selinux_policycap_extsockclass)
> +		return 0;
> +
> +	switch (optname) {
> +	case SCTP_SOCKOPT_BINDX_ADD:
> +		err = sock_has_perm(sk, SCTP_SOCKET__BINDX);
> +		break;
> +	case SCTP_SOCKOPT_CONNECTX:
> +		err = sock_has_perm(sk, SCTP_SOCKET__CONNECTX);
> +		break;
> +	/* These need SOCKET__BIND or SOCKET__CONNECT permissions
> that will
> +	 * be checked later.
> +	 */
> +	case SCTP_PRIMARY_ADDR:
> +	case SCTP_SET_PEER_PRIMARY_ADDR:
> +	case SCTP_PARAM_SET_PRIMARY:
> +	case SCTP_PARAM_ADD_IP:
> +	case SCTP_SENDMSG_CONNECT:
> +		break;
> +	default:
> +		err = -EINVAL;
> +	}
> +	if (err)
> +		return err;
> +
> +	/* Process one or more addresses that may be IPv4 or IPv6 */
> +	sock = sk->sk_socket;
> +	addr_buf = address;
> +
> +	while (walk_size < addrlen) {
> +		addr = addr_buf;
> +		switch (addr->sa_family) {
> +		case AF_INET:
> +			len = sizeof(struct sockaddr_in);
> +			break;
> +		case AF_INET6:
> +			len = sizeof(struct sockaddr_in6);
> +			break;
> +		default:
> +			return -EAFNOSUPPORT;
> +		}
> +
> +		err = -EINVAL;
> +		switch (optname) {
> +		/* Bind checks */
> +		case SCTP_PRIMARY_ADDR:
> +		case SCTP_SET_PEER_PRIMARY_ADDR:
> +		case SCTP_SOCKOPT_BINDX_ADD:
> +			err = selinux_socket_bind(sock, addr, len);
> +			break;
> +		/* Connect checks */
> +		case SCTP_SOCKOPT_CONNECTX:
> +		case SCTP_PARAM_SET_PRIMARY:
> +		case SCTP_PARAM_ADD_IP:
> +		case SCTP_SENDMSG_CONNECT:
> +			err = selinux_socket_connect(sock, addr,
> len);
> +			break;
> +		}
> +
> +		if (err)
> +			return err;
> +
> +		addr_buf += len;
> +		walk_size += len;
> +	}
> +	return 0;
> +}
> +
> +/* Called whenever a new socket is created by accept(2) or
> sctp_peeloff(3). */
> +static void selinux_sctp_sk_clone(struct sctp_endpoint *ep, struct
> sock *sk,
> +				  struct sock *newsk)
> +{
> +	struct sk_security_struct *sksec = sk->sk_security;
> +	struct sk_security_struct *newsksec = newsk->sk_security;
> +
> +	/* If policy does not support SECCLASS_SCTP_SOCKET then call
> +	 * the non-sctp clone version.
> +	 */
> +	if (!selinux_policycap_extsockclass)
> +		return selinux_sk_clone_security(sk, newsk);
> +
> +	newsksec->sid = ep->secid;
> +	newsksec->peer_sid = ep->peer_secid;
> +	newsksec->sclass = sksec->sclass;
> +	newsksec->nlbl_state = sksec->nlbl_state;
> +}
> +
>  static int selinux_inet_conn_request(struct sock *sk, struct sk_buff
> *skb,
>  				     struct request_sock *req)
>  {
> @@ -6416,6 +6655,9 @@ static struct security_hook_list
> selinux_hooks[] __lsm_ro_after_init = {
>  	LSM_HOOK_INIT(sk_clone_security, selinux_sk_clone_security),
>  	LSM_HOOK_INIT(sk_getsecid, selinux_sk_getsecid),
>  	LSM_HOOK_INIT(sock_graft, selinux_sock_graft),
> +	LSM_HOOK_INIT(sctp_assoc_request,
> selinux_sctp_assoc_request),
> +	LSM_HOOK_INIT(sctp_sk_clone, selinux_sctp_sk_clone),
> +	LSM_HOOK_INIT(sctp_bind_connect, selinux_sctp_bind_connect),
>  	LSM_HOOK_INIT(inet_conn_request, selinux_inet_conn_request),
>  	LSM_HOOK_INIT(inet_csk_clone, selinux_inet_csk_clone),
>  	LSM_HOOK_INIT(inet_conn_established,
> selinux_inet_conn_established),
> diff --git a/security/selinux/include/classmap.h
> b/security/selinux/include/classmap.h
> index b9fe343..b4b10da 100644
> --- a/security/selinux/include/classmap.h
> +++ b/security/selinux/include/classmap.h
> @@ -173,7 +173,8 @@ struct security_class_mapping secclass_map[] = {
>  	  { COMMON_CAP2_PERMS, NULL } },
>  	{ "sctp_socket",
>  	  { COMMON_SOCK_PERMS,
> -	    "node_bind", NULL } },
> +	    "node_bind", "name_connect", "association", "bindx",
> +	    "connectx", NULL } },
>  	{ "icmp_socket",
>  	  { COMMON_SOCK_PERMS,
>  	    "node_bind", NULL } },
> diff --git a/security/selinux/include/netlabel.h
> b/security/selinux/include/netlabel.h
> index 75686d5..835a0d6 100644
> --- a/security/selinux/include/netlabel.h
> +++ b/security/selinux/include/netlabel.h
> @@ -33,6 +33,7 @@
>  #include <linux/skbuff.h>
>  #include <net/sock.h>
>  #include <net/request_sock.h>
> +#include <net/sctp/structs.h>
>  
>  #include "avc.h"
>  #include "objsec.h"
> @@ -53,7 +54,8 @@ int selinux_netlbl_skbuff_getsid(struct sk_buff
> *skb,
>  int selinux_netlbl_skbuff_setsid(struct sk_buff *skb,
>  				 u16 family,
>  				 u32 sid);
> -
> +int selinux_netlbl_sctp_assoc_request(struct sctp_endpoint *ep,
> +				     struct sk_buff *skb);
>  int selinux_netlbl_inet_conn_request(struct request_sock *req, u16
> family);
>  void selinux_netlbl_inet_csk_clone(struct sock *sk, u16 family);
>  int selinux_netlbl_socket_post_create(struct sock *sk, u16 family);
> @@ -114,6 +116,11 @@ static inline int
> selinux_netlbl_conn_setsid(struct sock *sk,
>  	return 0;
>  }
>  
> +static inline int selinux_netlbl_sctp_assoc_request(struct
> sctp_endpoint *ep,
> +						    struct sk_buff
> *skb)
> +{
> +	return 0;
> +}
>  static inline int selinux_netlbl_inet_conn_request(struct
> request_sock *req,
>  						   u16 family)
>  {
> diff --git a/security/selinux/include/objsec.h
> b/security/selinux/include/objsec.h
> index 6ebc61e..660f270 100644
> --- a/security/selinux/include/objsec.h
> +++ b/security/selinux/include/objsec.h
> @@ -130,6 +130,11 @@ struct sk_security_struct {
>  	u32 sid;			/* SID of this object */
>  	u32 peer_sid;			/* SID of peer */
>  	u16 sclass;			/* sock security class */
> +
> +	enum {				/* SCTP association
> state */
> +		SCTP_ASSOC_UNSET = 0,
> +		SCTP_ASSOC_SET,
> +	} sctp_assoc_state;
>  };
>  
>  struct tun_security_struct {
> diff --git a/security/selinux/netlabel.c
> b/security/selinux/netlabel.c
> index aaba667..7d5aa15 100644
> --- a/security/selinux/netlabel.c
> +++ b/security/selinux/netlabel.c
> @@ -250,6 +250,7 @@ int selinux_netlbl_skbuff_setsid(struct sk_buff
> *skb,
>  	sk = skb_to_full_sk(skb);
>  	if (sk != NULL) {
>  		struct sk_security_struct *sksec = sk->sk_security;
> +
>  		if (sksec->nlbl_state != NLBL_REQSKB)
>  			return 0;
>  		secattr = selinux_netlbl_sock_getattr(sk, sid);
> @@ -271,6 +272,41 @@ int selinux_netlbl_skbuff_setsid(struct sk_buff
> *skb,
>  }
>  
>  /**
> + * selinux_netlbl_sctp_assoc_request - Label an incoming sctp
> association.
> + * @ep: incoming association endpoint.
> + * @skb: the packet.
> + *
> + * Description:
> + * A new incoming connection is represented by @ep, ......
> + * Returns zero on success, negative values on failure.
> + *
> + */
> +int selinux_netlbl_sctp_assoc_request(struct sctp_endpoint *ep,
> +				     struct sk_buff *skb)
> +{
> +	int rc;
> +	struct netlbl_lsm_secattr secattr;
> +	struct sk_security_struct *sksec = ep->base.sk->sk_security;
> +
> +	if (ep->base.sk->sk_family != PF_INET &&
> +				ep->base.sk->sk_family != PF_INET6)
> +		return 0;
> +
> +	netlbl_secattr_init(&secattr);
> +	rc = security_netlbl_sid_to_secattr(ep->secid, &secattr);
> +	if (rc != 0)
> +		goto assoc_request_return;
> +
> +	rc = netlbl_sctp_setattr(ep->base.sk, skb, &secattr);
> +	if (rc == 0)
> +		sksec->nlbl_state = NLBL_LABELED;
> +
> +assoc_request_return:
> +	netlbl_secattr_destroy(&secattr);
> +	return rc;
> +}
> +
> +/**
>   * selinux_netlbl_inet_conn_request - Label an incoming stream
> connection
>   * @req: incoming connection request socket
>   *
> @@ -481,7 +517,7 @@ int selinux_netlbl_socket_setsockopt(struct
> socket *sock,
>   */
>  int selinux_netlbl_socket_connect(struct sock *sk, struct sockaddr
> *addr)
>  {
> -	int rc;
> +	int rc, already_owned_by_user = 0;
>  	struct sk_security_struct *sksec = sk->sk_security;
>  	struct netlbl_lsm_secattr *secattr;
>  
> @@ -489,7 +525,16 @@ int selinux_netlbl_socket_connect(struct sock
> *sk, struct sockaddr *addr)
>  	    sksec->nlbl_state != NLBL_CONNLABELED)
>  		return 0;
>  
> -	lock_sock(sk);
> +	/* Note: When called via connect(2) this happens before the
> socket
> +	 * protocol layer connect operation and @sk is not locked,
> HOWEVER,
> +	 * when called by the SCTP protocol layer via
> sctp_connectx(3),
> +	 * sctp_sendmsg(3) or sendmsg(2), @sk is locked. Therefore
> check if
> +	 * @sk owned already.
> +	 */
> +	if (sock_owned_by_user(sk) && sksec->sclass ==
> SECCLASS_SCTP_SOCKET)
> +		already_owned_by_user = 1;
> +	else
> +		lock_sock(sk);

Conditional locking is generally considered harmful.  I'd split the
cases for the different callers, and use a common helper for both.

>  
>  	/* connected sockets are allowed to disconnect when the
> address family
>  	 * is set to AF_UNSPEC, if that is what is happening we want
> to reset
> @@ -510,6 +555,7 @@ int selinux_netlbl_socket_connect(struct sock
> *sk, struct sockaddr *addr)
>  		sksec->nlbl_state = NLBL_CONNLABELED;
>  
>  socket_connect_return:
> -	release_sock(sk);
> +	if (!already_owned_by_user)
> +		release_sock(sk);
>  	return rc;
>  }

^ permalink raw reply

* Re: [PATCH net] dccp/tcp: fix ireq->opt races
From: kbuild test robot @ 2017-10-20 18:34 UTC (permalink / raw)
  To: Eric Dumazet; +Cc: kbuild-all, David Miller, netdev, edumazet
In-Reply-To: <1508269854.31614.114.camel@edumazet-glaptop3.roam.corp.google.com>

Hi Eric,

[auto build test WARNING on net/master]

url:    https://github.com/0day-ci/linux/commits/Eric-Dumazet/dccp-tcp-fix-ireq-opt-races/20171021-001234
reproduce:
        # apt-get install sparse
        make ARCH=x86_64 allmodconfig
        make C=1 CF=-D__CHECK_ENDIAN__


sparse warnings: (new ones prefixed by >>)


vim +1954 net/ipv4/cipso_ipv4.c

446fda4f2 Paul Moore       2006-08-03  1898  
446fda4f2 Paul Moore       2006-08-03  1899  /**
389fb800a Paul Moore       2009-03-27  1900   * cipso_v4_req_setattr - Add a CIPSO option to a connection request socket
389fb800a Paul Moore       2009-03-27  1901   * @req: the connection request socket
389fb800a Paul Moore       2009-03-27  1902   * @doi_def: the CIPSO DOI to use
389fb800a Paul Moore       2009-03-27  1903   * @secattr: the specific security attributes of the socket
014ab19a6 Paul Moore       2008-10-10  1904   *
014ab19a6 Paul Moore       2008-10-10  1905   * Description:
389fb800a Paul Moore       2009-03-27  1906   * Set the CIPSO option on the given socket using the DOI definition and
389fb800a Paul Moore       2009-03-27  1907   * security attributes passed to the function.  Returns zero on success and
389fb800a Paul Moore       2009-03-27  1908   * negative values on failure.
014ab19a6 Paul Moore       2008-10-10  1909   *
014ab19a6 Paul Moore       2008-10-10  1910   */
389fb800a Paul Moore       2009-03-27  1911  int cipso_v4_req_setattr(struct request_sock *req,
389fb800a Paul Moore       2009-03-27  1912  			 const struct cipso_v4_doi *doi_def,
389fb800a Paul Moore       2009-03-27  1913  			 const struct netlbl_lsm_secattr *secattr)
014ab19a6 Paul Moore       2008-10-10  1914  {
389fb800a Paul Moore       2009-03-27  1915  	int ret_val = -EPERM;
389fb800a Paul Moore       2009-03-27  1916  	unsigned char *buf = NULL;
389fb800a Paul Moore       2009-03-27  1917  	u32 buf_len;
389fb800a Paul Moore       2009-03-27  1918  	u32 opt_len;
f6d8bd051 Eric Dumazet     2011-04-21  1919  	struct ip_options_rcu *opt = NULL;
389fb800a Paul Moore       2009-03-27  1920  	struct inet_request_sock *req_inet;
014ab19a6 Paul Moore       2008-10-10  1921  
389fb800a Paul Moore       2009-03-27  1922  	/* We allocate the maximum CIPSO option size here so we are probably
389fb800a Paul Moore       2009-03-27  1923  	 * being a little wasteful, but it makes our life _much_ easier later
389fb800a Paul Moore       2009-03-27  1924  	 * on and after all we are only talking about 40 bytes. */
389fb800a Paul Moore       2009-03-27  1925  	buf_len = CIPSO_V4_OPT_LEN_MAX;
389fb800a Paul Moore       2009-03-27  1926  	buf = kmalloc(buf_len, GFP_ATOMIC);
51456b291 Ian Morris       2015-04-03  1927  	if (!buf) {
389fb800a Paul Moore       2009-03-27  1928  		ret_val = -ENOMEM;
389fb800a Paul Moore       2009-03-27  1929  		goto req_setattr_failure;
389fb800a Paul Moore       2009-03-27  1930  	}
389fb800a Paul Moore       2009-03-27  1931  
389fb800a Paul Moore       2009-03-27  1932  	ret_val = cipso_v4_genopt(buf, buf_len, doi_def, secattr);
389fb800a Paul Moore       2009-03-27  1933  	if (ret_val < 0)
389fb800a Paul Moore       2009-03-27  1934  		goto req_setattr_failure;
389fb800a Paul Moore       2009-03-27  1935  	buf_len = ret_val;
389fb800a Paul Moore       2009-03-27  1936  
389fb800a Paul Moore       2009-03-27  1937  	/* We can't use ip_options_get() directly because it makes a call to
389fb800a Paul Moore       2009-03-27  1938  	 * ip_options_get_alloc() which allocates memory with GFP_KERNEL and
389fb800a Paul Moore       2009-03-27  1939  	 * we won't always have CAP_NET_RAW even though we _always_ want to
389fb800a Paul Moore       2009-03-27  1940  	 * set the IPOPT_CIPSO option. */
389fb800a Paul Moore       2009-03-27  1941  	opt_len = (buf_len + 3) & ~3;
389fb800a Paul Moore       2009-03-27  1942  	opt = kzalloc(sizeof(*opt) + opt_len, GFP_ATOMIC);
51456b291 Ian Morris       2015-04-03  1943  	if (!opt) {
389fb800a Paul Moore       2009-03-27  1944  		ret_val = -ENOMEM;
389fb800a Paul Moore       2009-03-27  1945  		goto req_setattr_failure;
389fb800a Paul Moore       2009-03-27  1946  	}
f6d8bd051 Eric Dumazet     2011-04-21  1947  	memcpy(opt->opt.__data, buf, buf_len);
f6d8bd051 Eric Dumazet     2011-04-21  1948  	opt->opt.optlen = opt_len;
f6d8bd051 Eric Dumazet     2011-04-21  1949  	opt->opt.cipso = sizeof(struct iphdr);
389fb800a Paul Moore       2009-03-27  1950  	kfree(buf);
389fb800a Paul Moore       2009-03-27  1951  	buf = NULL;
389fb800a Paul Moore       2009-03-27  1952  
389fb800a Paul Moore       2009-03-27  1953  	req_inet = inet_rsk(req);
389fb800a Paul Moore       2009-03-27 @1954  	opt = xchg(&req_inet->opt, opt);
f6d8bd051 Eric Dumazet     2011-04-21  1955  	if (opt)
4f9c8c1b0 Paul E. McKenney 2012-01-06  1956  		kfree_rcu(opt, rcu);
389fb800a Paul Moore       2009-03-27  1957  
389fb800a Paul Moore       2009-03-27  1958  	return 0;
389fb800a Paul Moore       2009-03-27  1959  
389fb800a Paul Moore       2009-03-27  1960  req_setattr_failure:
389fb800a Paul Moore       2009-03-27  1961  	kfree(buf);
389fb800a Paul Moore       2009-03-27  1962  	kfree(opt);
389fb800a Paul Moore       2009-03-27  1963  	return ret_val;
389fb800a Paul Moore       2009-03-27  1964  }
389fb800a Paul Moore       2009-03-27  1965  

:::::: The code at line 1954 was first introduced by commit
:::::: 389fb800ac8be2832efedd19978a2b8ced37eb61 netlabel: Label incoming TCP connections correctly in SELinux

:::::: TO: Paul Moore <paul.moore@hp.com>
:::::: CC: James Morris <jmorris@namei.org>

---
0-DAY kernel test infrastructure                Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all                   Intel Corporation

^ permalink raw reply

* [PATCH net-next 3/3] tun: do not arm flow_gc_timer in tun_flow_init()
From: Eric Dumazet @ 2017-10-20 18:29 UTC (permalink / raw)
  To: David S . Miller; +Cc: netdev, Eric Dumazet, Eric Dumazet, Jason Wang
In-Reply-To: <20171020182957.32729-1-edumazet@google.com>

Timer is properly armed on demand from tun_flow_update(),
so there is no need to arm it at tun init.

Signed-off-by: Eric Dumazet <edumazet@google.com>
---
 drivers/net/tun.c | 2 --
 1 file changed, 2 deletions(-)

diff --git a/drivers/net/tun.c b/drivers/net/tun.c
index 995887de5a98283382a631bcb8dfd874a4037ed3..2a2d058cdd403594e3f89c9a491ada17e3063506 100644
--- a/drivers/net/tun.c
+++ b/drivers/net/tun.c
@@ -1197,8 +1197,6 @@ static void tun_flow_init(struct tun_struct *tun)
 
 	tun->ageing_time = TUN_FLOW_EXPIRE;
 	setup_timer(&tun->flow_gc_timer, tun_flow_cleanup, (unsigned long)tun);
-	mod_timer(&tun->flow_gc_timer,
-		  round_jiffies_up(jiffies + tun->ageing_time));
 }
 
 static void tun_flow_uninit(struct tun_struct *tun)
-- 
2.15.0.rc0.271.g36b669edcc-goog

^ permalink raw reply related

* [PATCH net-next 2/3] tun: avoid extra timer schedule in tun_flow_cleanup()
From: Eric Dumazet @ 2017-10-20 18:29 UTC (permalink / raw)
  To: David S . Miller; +Cc: netdev, Eric Dumazet, Eric Dumazet, Jason Wang
In-Reply-To: <20171020182957.32729-1-edumazet@google.com>

If tun_flow_cleanup() deleted all flows, no need to
arm the timer again. It will be armed next time
tun_flow_update() is called.

Signed-off-by: Eric Dumazet <edumazet@google.com>
---
 drivers/net/tun.c | 9 ++++++---
 1 file changed, 6 insertions(+), 3 deletions(-)

diff --git a/drivers/net/tun.c b/drivers/net/tun.c
index f9541f7f9fb7592b50ac818702006f4f1042b448..995887de5a98283382a631bcb8dfd874a4037ed3 100644
--- a/drivers/net/tun.c
+++ b/drivers/net/tun.c
@@ -461,11 +461,14 @@ static void tun_flow_cleanup(unsigned long data)
 
 		hlist_for_each_entry_safe(e, n, &tun->flows[i], hash_link) {
 			unsigned long this_timer;
-			count++;
+
 			this_timer = e->updated + delay;
-			if (time_before_eq(this_timer, jiffies))
+			if (time_before_eq(this_timer, jiffies)) {
 				tun_flow_delete(tun, e);
-			else if (time_before(this_timer, next_timer))
+				continue;
+			}
+			count++;
+			if (time_before(this_timer, next_timer))
 				next_timer = this_timer;
 		}
 	}
-- 
2.15.0.rc0.271.g36b669edcc-goog

^ permalink raw reply related


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox