diff options
| -rw-r--r-- | include/linux/netfilter/ipset/ip_set_getport.h | 10 | ||||
| -rw-r--r-- | net/ipv4/netfilter/ip_tables.c | 4 | ||||
| -rw-r--r-- | net/ipv4/netfilter/ipt_CLUSTERIP.c | 5 | ||||
| -rw-r--r-- | net/ipv6/netfilter/ip6_tables.c | 4 | ||||
| -rw-r--r-- | net/netfilter/ipset/ip_set_core.c | 22 | ||||
| -rw-r--r-- | net/netfilter/ipset/ip_set_hash_ipport.c | 34 | ||||
| -rw-r--r-- | net/netfilter/ipset/ip_set_hash_ipportip.c | 34 | ||||
| -rw-r--r-- | net/netfilter/ipset/ip_set_hash_ipportnet.c | 34 | ||||
| -rw-r--r-- | net/netfilter/ipset/ip_set_hash_netport.c | 30 | 
9 files changed, 73 insertions, 104 deletions
| diff --git a/include/linux/netfilter/ipset/ip_set_getport.h b/include/linux/netfilter/ipset/ip_set_getport.h index 3882a81a3b3c..5aebd170f899 100644 --- a/include/linux/netfilter/ipset/ip_set_getport.h +++ b/include/linux/netfilter/ipset/ip_set_getport.h @@ -18,4 +18,14 @@ static inline bool ip_set_get_ip6_port(const struct sk_buff *skb, bool src,  extern bool ip_set_get_ip_port(const struct sk_buff *skb, u8 pf, bool src,  				__be16 *port); +static inline bool ip_set_proto_with_ports(u8 proto) +{ +	switch (proto) { +	case IPPROTO_TCP: +	case IPPROTO_UDP: +		return true; +	} +	return false; +} +  #endif /*_IP_SET_GETPORT_H*/ diff --git a/net/ipv4/netfilter/ip_tables.c b/net/ipv4/netfilter/ip_tables.c index b09ed0d080f9..ffcea0d1678e 100644 --- a/net/ipv4/netfilter/ip_tables.c +++ b/net/ipv4/netfilter/ip_tables.c @@ -387,7 +387,7 @@ ipt_do_table(struct sk_buff *skb,  					verdict = (unsigned)(-v) - 1;  					break;  				} -				if (*stackptr == 0) { +				if (*stackptr <= origptr) {  					e = get_entry(table_base,  					    private->underflow[hook]);  					pr_debug("Underflow (this is normal) " @@ -427,10 +427,10 @@ ipt_do_table(struct sk_buff *skb,  			/* Verdict */  			break;  	} while (!acpar.hotdrop); -	xt_info_rdunlock_bh();  	pr_debug("Exiting %s; resetting sp from %u to %u\n",  		 __func__, *stackptr, origptr);  	*stackptr = origptr; +	xt_info_rdunlock_bh();  #ifdef DEBUG_ALLOW_ALL  	return NF_ACCEPT;  #else diff --git a/net/ipv4/netfilter/ipt_CLUSTERIP.c b/net/ipv4/netfilter/ipt_CLUSTERIP.c index 403ca57f6011..d609ac3cb9a4 100644 --- a/net/ipv4/netfilter/ipt_CLUSTERIP.c +++ b/net/ipv4/netfilter/ipt_CLUSTERIP.c @@ -664,8 +664,11 @@ static ssize_t clusterip_proc_write(struct file *file, const char __user *input,  	char buffer[PROC_WRITELEN+1];  	unsigned long nodenum; -	if (copy_from_user(buffer, input, PROC_WRITELEN)) +	if (size > PROC_WRITELEN) +		return -EIO; +	if (copy_from_user(buffer, input, size))  		return -EFAULT; +	buffer[size] = 0;  	if (*buffer == '+') {  		nodenum = simple_strtoul(buffer+1, NULL, 10); diff --git a/net/ipv6/netfilter/ip6_tables.c b/net/ipv6/netfilter/ip6_tables.c index c9598a9067d7..0b2af9b85cec 100644 --- a/net/ipv6/netfilter/ip6_tables.c +++ b/net/ipv6/netfilter/ip6_tables.c @@ -410,7 +410,7 @@ ip6t_do_table(struct sk_buff *skb,  					verdict = (unsigned)(-v) - 1;  					break;  				} -				if (*stackptr == 0) +				if (*stackptr <= origptr)  					e = get_entry(table_base,  					    private->underflow[hook]);  				else @@ -441,8 +441,8 @@ ip6t_do_table(struct sk_buff *skb,  			break;  	} while (!acpar.hotdrop); -	xt_info_rdunlock_bh();  	*stackptr = origptr; +	xt_info_rdunlock_bh();  #ifdef DEBUG_ALLOW_ALL  	return NF_ACCEPT; diff --git a/net/netfilter/ipset/ip_set_core.c b/net/netfilter/ipset/ip_set_core.c index 618a615acc9d..d6b48230a540 100644 --- a/net/netfilter/ipset/ip_set_core.c +++ b/net/netfilter/ipset/ip_set_core.c @@ -94,16 +94,28 @@ static int  find_set_type_get(const char *name, u8 family, u8 revision,  		  struct ip_set_type **found)  { +	struct ip_set_type *type; +	int err; +  	rcu_read_lock();  	*found = find_set_type(name, family, revision);  	if (*found) { -		int err = !try_module_get((*found)->me); -		rcu_read_unlock(); -		return err ? -EFAULT : 0; +		err = !try_module_get((*found)->me) ? -EFAULT : 0; +		goto unlock;  	} +	/* Make sure the type is loaded but we don't support the revision */ +	list_for_each_entry_rcu(type, &ip_set_type_list, list) +		if (STREQ(type->name, name)) { +			err = -IPSET_ERR_FIND_TYPE; +			goto unlock; +		}  	rcu_read_unlock();  	return try_to_load_type(name); + +unlock: +	rcu_read_unlock(); +	return err;  }  /* Find a given set type by name and family. @@ -116,7 +128,7 @@ find_set_type_minmax(const char *name, u8 family, u8 *min, u8 *max)  	struct ip_set_type *type;  	bool found = false; -	*min = *max = 0; +	*min = 255; *max = 0;  	rcu_read_lock();  	list_for_each_entry_rcu(type, &ip_set_type_list, list)  		if (STREQ(type->name, name) && @@ -124,7 +136,7 @@ find_set_type_minmax(const char *name, u8 family, u8 *min, u8 *max)  			found = true;  			if (type->revision < *min)  				*min = type->revision; -			else if (type->revision > *max) +			if (type->revision > *max)  				*max = type->revision;  		}  	rcu_read_unlock(); diff --git a/net/netfilter/ipset/ip_set_hash_ipport.c b/net/netfilter/ipset/ip_set_hash_ipport.c index adbe787ea5dc..b9214145d357 100644 --- a/net/netfilter/ipset/ip_set_hash_ipport.c +++ b/net/netfilter/ipset/ip_set_hash_ipport.c @@ -150,6 +150,7 @@ hash_ipport4_uadt(struct ip_set *set, struct nlattr *tb[],  	struct hash_ipport4_elem data = { };  	u32 ip, ip_to, p, port, port_to;  	u32 timeout = h->timeout; +	bool with_ports = false;  	int ret;  	if (unlikely(!tb[IPSET_ATTR_IP] || @@ -172,21 +173,15 @@ hash_ipport4_uadt(struct ip_set *set, struct nlattr *tb[],  	if (tb[IPSET_ATTR_PROTO]) {  		data.proto = nla_get_u8(tb[IPSET_ATTR_PROTO]); +		with_ports = ip_set_proto_with_ports(data.proto);  		if (data.proto == 0)  			return -IPSET_ERR_INVALID_PROTO;  	} else  		return -IPSET_ERR_MISSING_PROTO; -	switch (data.proto) { -	case IPPROTO_UDP: -	case IPPROTO_TCP: -	case IPPROTO_ICMP: -		break; -	default: +	if (!(with_ports || data.proto == IPPROTO_ICMP))  		data.port = 0; -		break; -	}  	if (tb[IPSET_ATTR_TIMEOUT]) {  		if (!with_timeout(h->timeout)) @@ -195,7 +190,6 @@ hash_ipport4_uadt(struct ip_set *set, struct nlattr *tb[],  	}  	if (adt == IPSET_TEST || -	    !(data.proto == IPPROTO_TCP || data.proto == IPPROTO_UDP) ||  	    !(tb[IPSET_ATTR_IP_TO] || tb[IPSET_ATTR_CIDR] ||  	      tb[IPSET_ATTR_PORT_TO])) {  		ret = adtfn(set, &data, timeout); @@ -219,13 +213,12 @@ hash_ipport4_uadt(struct ip_set *set, struct nlattr *tb[],  	} else  		ip_to = ip; -	port = ntohs(data.port); -	if (tb[IPSET_ATTR_PORT_TO]) { +	port_to = port = ntohs(data.port); +	if (with_ports && tb[IPSET_ATTR_PORT_TO]) {  		port_to = ip_set_get_h16(tb[IPSET_ATTR_PORT_TO]);  		if (port > port_to)  			swap(port, port_to); -	} else -		port_to = port; +	}  	for (; !before(ip_to, ip); ip++)  		for (p = port; p <= port_to; p++) { @@ -361,6 +354,7 @@ hash_ipport6_uadt(struct ip_set *set, struct nlattr *tb[],  	struct hash_ipport6_elem data = { };  	u32 port, port_to;  	u32 timeout = h->timeout; +	bool with_ports = false;  	int ret;  	if (unlikely(!tb[IPSET_ATTR_IP] || @@ -385,21 +379,15 @@ hash_ipport6_uadt(struct ip_set *set, struct nlattr *tb[],  	if (tb[IPSET_ATTR_PROTO]) {  		data.proto = nla_get_u8(tb[IPSET_ATTR_PROTO]); +		with_ports = ip_set_proto_with_ports(data.proto);  		if (data.proto == 0)  			return -IPSET_ERR_INVALID_PROTO;  	} else  		return -IPSET_ERR_MISSING_PROTO; -	switch (data.proto) { -	case IPPROTO_UDP: -	case IPPROTO_TCP: -	case IPPROTO_ICMPV6: -		break; -	default: +	if (!(with_ports || data.proto == IPPROTO_ICMPV6))  		data.port = 0; -		break; -	}  	if (tb[IPSET_ATTR_TIMEOUT]) {  		if (!with_timeout(h->timeout)) @@ -407,9 +395,7 @@ hash_ipport6_uadt(struct ip_set *set, struct nlattr *tb[],  		timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);  	} -	if (adt == IPSET_TEST || -	    !(data.proto == IPPROTO_TCP || data.proto == IPPROTO_UDP) || -	    !tb[IPSET_ATTR_PORT_TO]) { +	if (adt == IPSET_TEST || !with_ports || !tb[IPSET_ATTR_PORT_TO]) {  		ret = adtfn(set, &data, timeout);  		return ip_set_eexist(ret, flags) ? 0 : ret;  	} diff --git a/net/netfilter/ipset/ip_set_hash_ipportip.c b/net/netfilter/ipset/ip_set_hash_ipportip.c index 22e23abb86c6..4642872df6e1 100644 --- a/net/netfilter/ipset/ip_set_hash_ipportip.c +++ b/net/netfilter/ipset/ip_set_hash_ipportip.c @@ -154,6 +154,7 @@ hash_ipportip4_uadt(struct ip_set *set, struct nlattr *tb[],  	struct hash_ipportip4_elem data = { };  	u32 ip, ip_to, p, port, port_to;  	u32 timeout = h->timeout; +	bool with_ports = false;  	int ret;  	if (unlikely(!tb[IPSET_ATTR_IP] || !tb[IPSET_ATTR_IP2] || @@ -180,21 +181,15 @@ hash_ipportip4_uadt(struct ip_set *set, struct nlattr *tb[],  	if (tb[IPSET_ATTR_PROTO]) {  		data.proto = nla_get_u8(tb[IPSET_ATTR_PROTO]); +		with_ports = ip_set_proto_with_ports(data.proto);  		if (data.proto == 0)  			return -IPSET_ERR_INVALID_PROTO;  	} else  		return -IPSET_ERR_MISSING_PROTO; -	switch (data.proto) { -	case IPPROTO_UDP: -	case IPPROTO_TCP: -	case IPPROTO_ICMP: -		break; -	default: +	if (!(with_ports || data.proto == IPPROTO_ICMP))  		data.port = 0; -		break; -	}  	if (tb[IPSET_ATTR_TIMEOUT]) {  		if (!with_timeout(h->timeout)) @@ -203,7 +198,6 @@ hash_ipportip4_uadt(struct ip_set *set, struct nlattr *tb[],  	}  	if (adt == IPSET_TEST || -	    !(data.proto == IPPROTO_TCP || data.proto == IPPROTO_UDP) ||  	    !(tb[IPSET_ATTR_IP_TO] || tb[IPSET_ATTR_CIDR] ||  	      tb[IPSET_ATTR_PORT_TO])) {  		ret = adtfn(set, &data, timeout); @@ -227,13 +221,12 @@ hash_ipportip4_uadt(struct ip_set *set, struct nlattr *tb[],  	} else  		ip_to = ip; -	port = ntohs(data.port); -	if (tb[IPSET_ATTR_PORT_TO]) { +	port_to = port = ntohs(data.port); +	if (with_ports && tb[IPSET_ATTR_PORT_TO]) {  		port_to = ip_set_get_h16(tb[IPSET_ATTR_PORT_TO]);  		if (port > port_to)  			swap(port, port_to); -	} else -		port_to = port; +	}  	for (; !before(ip_to, ip); ip++)  		for (p = port; p <= port_to; p++) { @@ -375,6 +368,7 @@ hash_ipportip6_uadt(struct ip_set *set, struct nlattr *tb[],  	struct hash_ipportip6_elem data = { };  	u32 port, port_to;  	u32 timeout = h->timeout; +	bool with_ports = false;  	int ret;  	if (unlikely(!tb[IPSET_ATTR_IP] || !tb[IPSET_ATTR_IP2] || @@ -403,21 +397,15 @@ hash_ipportip6_uadt(struct ip_set *set, struct nlattr *tb[],  	if (tb[IPSET_ATTR_PROTO]) {  		data.proto = nla_get_u8(tb[IPSET_ATTR_PROTO]); +		with_ports = ip_set_proto_with_ports(data.proto);  		if (data.proto == 0)  			return -IPSET_ERR_INVALID_PROTO;  	} else  		return -IPSET_ERR_MISSING_PROTO; -	switch (data.proto) { -	case IPPROTO_UDP: -	case IPPROTO_TCP: -	case IPPROTO_ICMPV6: -		break; -	default: +	if (!(with_ports || data.proto == IPPROTO_ICMPV6))  		data.port = 0; -		break; -	}  	if (tb[IPSET_ATTR_TIMEOUT]) {  		if (!with_timeout(h->timeout)) @@ -425,9 +413,7 @@ hash_ipportip6_uadt(struct ip_set *set, struct nlattr *tb[],  		timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);  	} -	if (adt == IPSET_TEST || -	    !(data.proto == IPPROTO_TCP || data.proto == IPPROTO_UDP) || -	    !tb[IPSET_ATTR_PORT_TO]) { +	if (adt == IPSET_TEST || !with_ports || !tb[IPSET_ATTR_PORT_TO]) {  		ret = adtfn(set, &data, timeout);  		return ip_set_eexist(ret, flags) ? 0 : ret;  	} diff --git a/net/netfilter/ipset/ip_set_hash_ipportnet.c b/net/netfilter/ipset/ip_set_hash_ipportnet.c index 6033e8b54bbd..2cb84a54b7ad 100644 --- a/net/netfilter/ipset/ip_set_hash_ipportnet.c +++ b/net/netfilter/ipset/ip_set_hash_ipportnet.c @@ -174,6 +174,7 @@ hash_ipportnet4_uadt(struct ip_set *set, struct nlattr *tb[],  	struct hash_ipportnet4_elem data = { .cidr = HOST_MASK };  	u32 ip, ip_to, p, port, port_to;  	u32 timeout = h->timeout; +	bool with_ports = false;  	int ret;  	if (unlikely(!tb[IPSET_ATTR_IP] || !tb[IPSET_ATTR_IP2] || @@ -208,21 +209,15 @@ hash_ipportnet4_uadt(struct ip_set *set, struct nlattr *tb[],  	if (tb[IPSET_ATTR_PROTO]) {  		data.proto = nla_get_u8(tb[IPSET_ATTR_PROTO]); +		with_ports = ip_set_proto_with_ports(data.proto);  		if (data.proto == 0)  			return -IPSET_ERR_INVALID_PROTO;  	} else  		return -IPSET_ERR_MISSING_PROTO; -	switch (data.proto) { -	case IPPROTO_UDP: -	case IPPROTO_TCP: -	case IPPROTO_ICMP: -		break; -	default: +	if (!(with_ports || data.proto == IPPROTO_ICMP))  		data.port = 0; -		break; -	}  	if (tb[IPSET_ATTR_TIMEOUT]) {  		if (!with_timeout(h->timeout)) @@ -231,7 +226,6 @@ hash_ipportnet4_uadt(struct ip_set *set, struct nlattr *tb[],  	}  	if (adt == IPSET_TEST || -	    !(data.proto == IPPROTO_TCP || data.proto == IPPROTO_UDP) ||  	    !(tb[IPSET_ATTR_IP_TO] || tb[IPSET_ATTR_CIDR] ||  	      tb[IPSET_ATTR_PORT_TO])) {  		ret = adtfn(set, &data, timeout); @@ -255,13 +249,12 @@ hash_ipportnet4_uadt(struct ip_set *set, struct nlattr *tb[],  	} else  		ip_to = ip; -	port = ntohs(data.port); -	if (tb[IPSET_ATTR_PORT_TO]) { +	port_to = port = ntohs(data.port); +	if (with_ports && tb[IPSET_ATTR_PORT_TO]) {  		port_to = ip_set_get_h16(tb[IPSET_ATTR_PORT_TO]);  		if (port > port_to)  			swap(port, port_to); -	} else -		port_to = port; +	}  	for (; !before(ip_to, ip); ip++)  		for (p = port; p <= port_to; p++) { @@ -429,6 +422,7 @@ hash_ipportnet6_uadt(struct ip_set *set, struct nlattr *tb[],  	struct hash_ipportnet6_elem data = { .cidr = HOST_MASK };  	u32 port, port_to;  	u32 timeout = h->timeout; +	bool with_ports = false;  	int ret;  	if (unlikely(!tb[IPSET_ATTR_IP] || !tb[IPSET_ATTR_IP2] || @@ -465,21 +459,15 @@ hash_ipportnet6_uadt(struct ip_set *set, struct nlattr *tb[],  	if (tb[IPSET_ATTR_PROTO]) {  		data.proto = nla_get_u8(tb[IPSET_ATTR_PROTO]); +		with_ports = ip_set_proto_with_ports(data.proto);  		if (data.proto == 0)  			return -IPSET_ERR_INVALID_PROTO;  	} else  		return -IPSET_ERR_MISSING_PROTO; -	switch (data.proto) { -	case IPPROTO_UDP: -	case IPPROTO_TCP: -	case IPPROTO_ICMPV6: -		break; -	default: +	if (!(with_ports || data.proto == IPPROTO_ICMPV6))  		data.port = 0; -		break; -	}  	if (tb[IPSET_ATTR_TIMEOUT]) {  		if (!with_timeout(h->timeout)) @@ -487,9 +475,7 @@ hash_ipportnet6_uadt(struct ip_set *set, struct nlattr *tb[],  		timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);  	} -	if (adt == IPSET_TEST || -	    !(data.proto == IPPROTO_TCP || data.proto == IPPROTO_UDP) || -	    !tb[IPSET_ATTR_PORT_TO]) { +	if (adt == IPSET_TEST || !with_ports || !tb[IPSET_ATTR_PORT_TO]) {  		ret = adtfn(set, &data, timeout);  		return ip_set_eexist(ret, flags) ? 0 : ret;  	} diff --git a/net/netfilter/ipset/ip_set_hash_netport.c b/net/netfilter/ipset/ip_set_hash_netport.c index 34a165626ee9..8598676f2a05 100644 --- a/net/netfilter/ipset/ip_set_hash_netport.c +++ b/net/netfilter/ipset/ip_set_hash_netport.c @@ -170,6 +170,7 @@ hash_netport4_uadt(struct ip_set *set, struct nlattr *tb[],  	struct hash_netport4_elem data = { .cidr = HOST_MASK };  	u32 port, port_to;  	u32 timeout = h->timeout; +	bool with_ports = false;  	int ret;  	if (unlikely(!tb[IPSET_ATTR_IP] || @@ -198,21 +199,15 @@ hash_netport4_uadt(struct ip_set *set, struct nlattr *tb[],  	if (tb[IPSET_ATTR_PROTO]) {  		data.proto = nla_get_u8(tb[IPSET_ATTR_PROTO]); +		with_ports = ip_set_proto_with_ports(data.proto);  		if (data.proto == 0)  			return -IPSET_ERR_INVALID_PROTO;  	} else  		return -IPSET_ERR_MISSING_PROTO; -	switch (data.proto) { -	case IPPROTO_UDP: -	case IPPROTO_TCP: -	case IPPROTO_ICMP: -		break; -	default: +	if (!(with_ports || data.proto == IPPROTO_ICMP))  		data.port = 0; -		break; -	}  	if (tb[IPSET_ATTR_TIMEOUT]) {  		if (!with_timeout(h->timeout)) @@ -220,9 +215,7 @@ hash_netport4_uadt(struct ip_set *set, struct nlattr *tb[],  		timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);  	} -	if (adt == IPSET_TEST || -	    !(data.proto == IPPROTO_TCP || data.proto == IPPROTO_UDP) || -	    !tb[IPSET_ATTR_PORT_TO]) { +	if (adt == IPSET_TEST || !with_ports || !tb[IPSET_ATTR_PORT_TO]) {  		ret = adtfn(set, &data, timeout);  		return ip_set_eexist(ret, flags) ? 0 : ret;  	} @@ -390,6 +383,7 @@ hash_netport6_uadt(struct ip_set *set, struct nlattr *tb[],  	struct hash_netport6_elem data = { .cidr = HOST_MASK };  	u32 port, port_to;  	u32 timeout = h->timeout; +	bool with_ports = false;  	int ret;  	if (unlikely(!tb[IPSET_ATTR_IP] || @@ -418,21 +412,15 @@ hash_netport6_uadt(struct ip_set *set, struct nlattr *tb[],  	if (tb[IPSET_ATTR_PROTO]) {  		data.proto = nla_get_u8(tb[IPSET_ATTR_PROTO]); +		with_ports = ip_set_proto_with_ports(data.proto);  		if (data.proto == 0)  			return -IPSET_ERR_INVALID_PROTO;  	} else  		return -IPSET_ERR_MISSING_PROTO; -	switch (data.proto) { -	case IPPROTO_UDP: -	case IPPROTO_TCP: -	case IPPROTO_ICMPV6: -		break; -	default: +	if (!(with_ports || data.proto == IPPROTO_ICMPV6))  		data.port = 0; -		break; -	}  	if (tb[IPSET_ATTR_TIMEOUT]) {  		if (!with_timeout(h->timeout)) @@ -440,9 +428,7 @@ hash_netport6_uadt(struct ip_set *set, struct nlattr *tb[],  		timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);  	} -	if (adt == IPSET_TEST || -	    !(data.proto == IPPROTO_TCP || data.proto == IPPROTO_UDP) || -	    !tb[IPSET_ATTR_PORT_TO]) { +	if (adt == IPSET_TEST || !with_ports || !tb[IPSET_ATTR_PORT_TO]) {  		ret = adtfn(set, &data, timeout);  		return ip_set_eexist(ret, flags) ? 0 : ret;  	} | 
