Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit f9242b6b authored by David S. Miller's avatar David S. Miller
Browse files

inet: Sanitize inet{,6} protocol demux.



Don't pretend that inet_protos[] and inet6_protos[] are hashes, thay
are just a straight arrays.  Remove all unnecessary hash masking.

Document MAX_INET_PROTOS.

Use RAW_HTABLE_SIZE when appropriate.

Reported-by: default avatarBen Hutchings <bhutchings@solarflare.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 677a3d60
Loading
Loading
Loading
Loading
+5 −2
Original line number Diff line number Diff line
@@ -29,8 +29,11 @@
#include <linux/ipv6.h>
#endif

#define MAX_INET_PROTOS	256		/* Must be a power of 2		*/

/* This is one larger than the largest protocol value that can be
 * found in an ipv4 or ipv6 header.  Since in both cases the protocol
 * value is presented in a __u8, this is defined to be 256.
 */
#define MAX_INET_PROTOS		256

/* This is used to register protocols. */
struct net_protocol {
+12 −14
Original line number Diff line number Diff line
@@ -242,20 +242,18 @@ void build_ehash_secret(void)
}
EXPORT_SYMBOL(build_ehash_secret);

static inline int inet_netns_ok(struct net *net, int protocol)
static inline int inet_netns_ok(struct net *net, __u8 protocol)
{
	int hash;
	const struct net_protocol *ipprot;

	if (net_eq(net, &init_net))
		return 1;

	hash = protocol & (MAX_INET_PROTOS - 1);
	ipprot = rcu_dereference(inet_protos[hash]);

	if (ipprot == NULL)
	ipprot = rcu_dereference(inet_protos[protocol]);
	if (ipprot == NULL) {
		/* raw IP is OK */
		return 1;
	}
	return ipprot->netns_ok;
}

@@ -1216,8 +1214,8 @@ EXPORT_SYMBOL(inet_sk_rebuild_header);

static int inet_gso_send_check(struct sk_buff *skb)
{
	const struct iphdr *iph;
	const struct net_protocol *ops;
	const struct iphdr *iph;
	int proto;
	int ihl;
	int err = -EINVAL;
@@ -1236,7 +1234,7 @@ static int inet_gso_send_check(struct sk_buff *skb)
	__skb_pull(skb, ihl);
	skb_reset_transport_header(skb);
	iph = ip_hdr(skb);
	proto = iph->protocol & (MAX_INET_PROTOS - 1);
	proto = iph->protocol;
	err = -EPROTONOSUPPORT;

	rcu_read_lock();
@@ -1253,8 +1251,8 @@ static struct sk_buff *inet_gso_segment(struct sk_buff *skb,
	netdev_features_t features)
{
	struct sk_buff *segs = ERR_PTR(-EINVAL);
	struct iphdr *iph;
	const struct net_protocol *ops;
	struct iphdr *iph;
	int proto;
	int ihl;
	int id;
@@ -1286,7 +1284,7 @@ static struct sk_buff *inet_gso_segment(struct sk_buff *skb,
	skb_reset_transport_header(skb);
	iph = ip_hdr(skb);
	id = ntohs(iph->id);
	proto = iph->protocol & (MAX_INET_PROTOS - 1);
	proto = iph->protocol;
	segs = ERR_PTR(-EPROTONOSUPPORT);

	rcu_read_lock();
@@ -1340,7 +1338,7 @@ static struct sk_buff **inet_gro_receive(struct sk_buff **head,
			goto out;
	}

	proto = iph->protocol & (MAX_INET_PROTOS - 1);
	proto = iph->protocol;

	rcu_read_lock();
	ops = rcu_dereference(inet_protos[proto]);
@@ -1398,11 +1396,11 @@ static struct sk_buff **inet_gro_receive(struct sk_buff **head,

static int inet_gro_complete(struct sk_buff *skb)
{
	const struct net_protocol *ops;
	__be16 newlen = htons(skb->len - skb_network_offset(skb));
	struct iphdr *iph = ip_hdr(skb);
	int proto = iph->protocol & (MAX_INET_PROTOS - 1);
	const struct net_protocol *ops;
	int proto = iph->protocol;
	int err = -ENOSYS;
	__be16 newlen = htons(skb->len - skb_network_offset(skb));

	csum_replace2(&iph->check, iph->tot_len, newlen);
	iph->tot_len = newlen;
+4 −5
Original line number Diff line number Diff line
@@ -637,12 +637,12 @@ EXPORT_SYMBOL(icmp_send);

static void icmp_unreach(struct sk_buff *skb)
{
	const struct net_protocol *ipprot;
	const struct iphdr *iph;
	struct icmphdr *icmph;
	int hash, protocol;
	const struct net_protocol *ipprot;
	u32 info = 0;
	struct net *net;
	u32 info = 0;
	int protocol;

	net = dev_net(skb_dst(skb)->dev);

@@ -731,9 +731,8 @@ static void icmp_unreach(struct sk_buff *skb)
	 */
	raw_icmp_error(skb, protocol, info);

	hash = protocol & (MAX_INET_PROTOS - 1);
	rcu_read_lock();
	ipprot = rcu_dereference(inet_protos[hash]);
	ipprot = rcu_dereference(inet_protos[protocol]);
	if (ipprot && ipprot->err_handler)
		ipprot->err_handler(skb, info);
	rcu_read_unlock();
+2 −3
Original line number Diff line number Diff line
@@ -198,14 +198,13 @@ static int ip_local_deliver_finish(struct sk_buff *skb)
	rcu_read_lock();
	{
		int protocol = ip_hdr(skb)->protocol;
		int hash, raw;
		const struct net_protocol *ipprot;
		int raw;

	resubmit:
		raw = raw_local_deliver(skb, protocol);

		hash = protocol & (MAX_INET_PROTOS - 1);
		ipprot = rcu_dereference(inet_protos[hash]);
		ipprot = rcu_dereference(inet_protos[protocol]);
		if (ipprot != NULL) {
			int ret;

+3 −5
Original line number Diff line number Diff line
@@ -36,9 +36,7 @@ const struct net_protocol __rcu *inet_protos[MAX_INET_PROTOS] __read_mostly;

int inet_add_protocol(const struct net_protocol *prot, unsigned char protocol)
{
	int hash = protocol & (MAX_INET_PROTOS - 1);

	return !cmpxchg((const struct net_protocol **)&inet_protos[hash],
	return !cmpxchg((const struct net_protocol **)&inet_protos[protocol],
			NULL, prot) ? 0 : -1;
}
EXPORT_SYMBOL(inet_add_protocol);
@@ -49,9 +47,9 @@ EXPORT_SYMBOL(inet_add_protocol);

int inet_del_protocol(const struct net_protocol *prot, unsigned char protocol)
{
	int ret, hash = protocol & (MAX_INET_PROTOS - 1);
	int ret;

	ret = (cmpxchg((const struct net_protocol **)&inet_protos[hash],
	ret = (cmpxchg((const struct net_protocol **)&inet_protos[protocol],
		       prot, NULL) == prot) ? 0 : -1;

	synchronize_net();
Loading