lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Date:	Tue,  5 May 2015 18:59:53 -0700
From:	Andy Zhou <azhou@...ira.com>
To:	davem@...emloft.net
Cc:	netdev@...r.kernel.org, Andy Zhou <azhou@...ira.com>
Subject: [net-next fragmenation icmp 1/2] ipv4_fragment: Add a bit in IPCB to control ICMP generation

Currently, on fragmentation or defragmentation error, ICMP error message
can be generated. This is fine when they are used in a routing context,
but does not make sense when they are used in a bridging context, i.e.
netfilter for bridging.

This patch adds a bit in IPCB to control whether ICMP error message
should be generated.

IPV6 fragmentation and defragmentation functions are not reused by
bridge netfilter. Thus, this change is only required for IPV4.

Signed-off-by: Andy Zhou <azhou@...ira.com>
---
 include/net/inet_frag.h |  2 ++
 include/net/ip.h        |  1 +
 net/ipv4/ip_fragment.c  | 11 ++++++++++-
 net/ipv4/ip_output.c    |  5 +++--
 4 files changed, 16 insertions(+), 3 deletions(-)

diff --git a/include/net/inet_frag.h b/include/net/inet_frag.h
index 8d17655..1d57045 100644
--- a/include/net/inet_frag.h
+++ b/include/net/inet_frag.h
@@ -44,6 +44,7 @@ enum {
  * @meat: length of received fragments so far
  * @flags: fragment queue flags
  * @max_size: (ipv4 only) maximum received fragment size with IP_DF set
+ * @no_icmp:  Do not generate any fragmentation related icmp packet
  * @net: namespace that this frag belongs to
  */
 struct inet_frag_queue {
@@ -58,6 +59,7 @@ struct inet_frag_queue {
 	int			meat;
 	__u8			flags;
 	u16			max_size;
+	bool			no_icmp;
 	struct netns_frags	*net;
 };
 
diff --git a/include/net/ip.h b/include/net/ip.h
index d14af7e..8d81c865 100644
--- a/include/net/ip.h
+++ b/include/net/ip.h
@@ -45,6 +45,7 @@ struct inet_skb_parm {
 #define IPSKB_FRAG_COMPLETE	BIT(3)
 #define IPSKB_REROUTED		BIT(4)
 #define IPSKB_DOREDIRECT	BIT(5)
+#define IPSKB_NO_FRAG_ICMP	BIT(6)
 
 	u16			frag_max_size;
 };
diff --git a/net/ipv4/ip_fragment.c b/net/ipv4/ip_fragment.c
index cc1da6d..2f38d30 100644
--- a/net/ipv4/ip_fragment.c
+++ b/net/ipv4/ip_fragment.c
@@ -217,7 +217,8 @@ static void ip_expire(unsigned long arg)
 		/* Only an end host needs to send an ICMP
 		 * "Fragment Reassembly Timeout" message, per RFC792.
 		 */
-		if (qp->user == IP_DEFRAG_AF_PACKET ||
+		if (qp->q.no_icmp ||
+		    qp->user == IP_DEFRAG_AF_PACKET ||
 		    ((qp->user >= IP_DEFRAG_CONNTRACK_IN) &&
 		     (qp->user <= __IP_DEFRAG_CONNTRACK_IN_END) &&
 		     (skb_rtable(head)->rt_type != RTN_LOCAL)))
@@ -323,6 +324,7 @@ static int ip_frag_queue(struct ipq *qp, struct sk_buff *skb)
 	int ihl, end;
 	int err = -ENOENT;
 	u8 ecn;
+	bool no_icmp;
 
 	if (qp->q.flags & INET_FRAG_COMPLETE)
 		goto err;
@@ -340,6 +342,7 @@ static int ip_frag_queue(struct ipq *qp, struct sk_buff *skb)
 	offset &= IP_OFFSET;
 	offset <<= 3;		/* offset is in 8-byte chunks */
 	ihl = ip_hdrlen(skb);
+	no_icmp = IPCB(skb)->flags & IPSKB_NO_FRAG_ICMP;
 
 	/* Determine the position of this fragment. */
 	end = offset + skb->len - ihl;
@@ -478,6 +481,8 @@ found:
 	    skb->len + ihl > qp->q.max_size)
 		qp->q.max_size = skb->len + ihl;
 
+	qp->q.no_icmp = qp->q.no_icmp || no_icmp;
+
 	if (qp->q.flags == (INET_FRAG_FIRST_IN | INET_FRAG_LAST_IN) &&
 	    qp->q.meat == qp->q.len) {
 		unsigned long orefdst = skb->_skb_refdst;
@@ -608,6 +613,10 @@ static int ip_frag_reasm(struct ipq *qp, struct sk_buff *prev,
 	head->tstamp = qp->q.stamp;
 	IPCB(head)->frag_max_size = qp->q.max_size;
 
+	IPCB(head)->flags &= ~IPSKB_NO_FRAG_ICMP;
+	if (qp->q.no_icmp)
+		IPCB(head)->flags |= IPSKB_NO_FRAG_ICMP;
+
 	iph = ip_hdr(head);
 	/* max_size != 0 implies at least one fragment had IP_DF set */
 	iph->frag_off = qp->q.max_size ? htons(IP_DF) : 0;
diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c
index c65b93a..dfa425c 100644
--- a/net/ipv4/ip_output.c
+++ b/net/ipv4/ip_output.c
@@ -511,8 +511,9 @@ int ip_fragment(struct sock *sk, struct sk_buff *skb,
 		     (IPCB(skb)->frag_max_size &&
 		      IPCB(skb)->frag_max_size > mtu))) {
 		IP_INC_STATS(dev_net(dev), IPSTATS_MIB_FRAGFAILS);
-		icmp_send(skb, ICMP_DEST_UNREACH, ICMP_FRAG_NEEDED,
-			  htonl(mtu));
+		if (!(IPCB(skb)->flags & IPSKB_NO_FRAG_ICMP))
+			icmp_send(skb, ICMP_DEST_UNREACH, ICMP_FRAG_NEEDED,
+				  htonl(mtu));
 		kfree_skb(skb);
 		return -EMSGSIZE;
 	}
-- 
1.9.1

--
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to majordomo@...r.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Powered by blists - more mailing lists