diff options
Diffstat (limited to 'net/core')
| -rw-r--r-- | net/core/dev.c | 40 | ||||
| -rw-r--r-- | net/core/dst.c | 1 | ||||
| -rw-r--r-- | net/core/fib_rules.c | 21 | ||||
| -rw-r--r-- | net/core/filter.c | 87 | ||||
| -rw-r--r-- | net/core/iovec.c | 20 | ||||
| -rw-r--r-- | net/core/net-sysfs.c | 26 | ||||
| -rw-r--r-- | net/core/net_namespace.c | 4 | ||||
| -rw-r--r-- | net/core/pktgen.c | 41 | ||||
| -rw-r--r-- | net/core/request_sock.c | 4 | ||||
| -rw-r--r-- | net/core/rtnetlink.c | 9 | ||||
| -rw-r--r-- | net/core/sock.c | 63 | ||||
| -rw-r--r-- | net/core/sysctl_net_core.c | 3 | ||||
| -rw-r--r-- | net/core/timestamping.c | 6 | 
13 files changed, 180 insertions, 145 deletions
| diff --git a/net/core/dev.c b/net/core/dev.c index 78b5a89b0f4..0dd54a69dac 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -1685,10 +1685,10 @@ EXPORT_SYMBOL(netif_device_attach);  static bool can_checksum_protocol(unsigned long features, __be16 protocol)  { -	return ((features & NETIF_F_GEN_CSUM) || -		((features & NETIF_F_IP_CSUM) && +	return ((features & NETIF_F_NO_CSUM) || +		((features & NETIF_F_V4_CSUM) &&  		 protocol == htons(ETH_P_IP)) || -		((features & NETIF_F_IPV6_CSUM) && +		((features & NETIF_F_V6_CSUM) &&  		 protocol == htons(ETH_P_IPV6)) ||  		((features & NETIF_F_FCOE_CRC) &&  		 protocol == htons(ETH_P_FCOE))); @@ -1696,22 +1696,18 @@ static bool can_checksum_protocol(unsigned long features, __be16 protocol)  static bool dev_can_checksum(struct net_device *dev, struct sk_buff *skb)  { +	__be16 protocol = skb->protocol;  	int features = dev->features; -	if (vlan_tx_tag_present(skb)) +	if (vlan_tx_tag_present(skb)) {  		features &= dev->vlan_features; - -	if (can_checksum_protocol(features, skb->protocol)) -		return true; - -	if (skb->protocol == htons(ETH_P_8021Q)) { +	} else if (protocol == htons(ETH_P_8021Q)) {  		struct vlan_ethhdr *veh = (struct vlan_ethhdr *)skb->data; -		if (can_checksum_protocol(dev->features & dev->vlan_features, -					  veh->h_vlan_encapsulated_proto)) -			return true; +		protocol = veh->h_vlan_encapsulated_proto; +		features &= dev->vlan_features;  	} -	return false; +	return can_checksum_protocol(features, protocol);  }  /** @@ -2135,7 +2131,7 @@ static struct netdev_queue *dev_pick_tx(struct net_device *dev,  	} else {  		struct sock *sk = skb->sk;  		queue_index = sk_tx_queue_get(sk); -		if (queue_index < 0) { +		if (queue_index < 0 || queue_index >= dev->real_num_tx_queues) {  			queue_index = 0;  			if (dev->real_num_tx_queues > 1) @@ -2213,7 +2209,7 @@ static inline int __dev_xmit_skb(struct sk_buff *skb, struct Qdisc *q,  }  static DEFINE_PER_CPU(int, xmit_recursion); -#define RECURSION_LIMIT 3 +#define RECURSION_LIMIT 10  /**   *	dev_queue_xmit - transmit a buffer @@ -2413,7 +2409,7 @@ EXPORT_SYMBOL(__skb_get_rxhash);  #ifdef CONFIG_RPS  /* One global table that all flow-based protocols share. */ -struct rps_sock_flow_table *rps_sock_flow_table __read_mostly; +struct rps_sock_flow_table __rcu *rps_sock_flow_table __read_mostly;  EXPORT_SYMBOL(rps_sock_flow_table);  /* @@ -2425,7 +2421,7 @@ static int get_rps_cpu(struct net_device *dev, struct sk_buff *skb,  		       struct rps_dev_flow **rflowp)  {  	struct netdev_rx_queue *rxqueue; -	struct rps_map *map = NULL; +	struct rps_map *map;  	struct rps_dev_flow_table *flow_table;  	struct rps_sock_flow_table *sock_flow_table;  	int cpu = -1; @@ -2444,15 +2440,15 @@ static int get_rps_cpu(struct net_device *dev, struct sk_buff *skb,  	} else  		rxqueue = dev->_rx; -	if (rxqueue->rps_map) { -		map = rcu_dereference(rxqueue->rps_map); -		if (map && map->len == 1) { +	map = rcu_dereference(rxqueue->rps_map); +	if (map) { +		if (map->len == 1) {  			tcpu = map->cpus[0];  			if (cpu_online(tcpu))  				cpu = tcpu;  			goto done;  		} -	} else if (!rxqueue->rps_flow_table) { +	} else if (!rcu_dereference_raw(rxqueue->rps_flow_table)) {  		goto done;  	} @@ -5416,7 +5412,7 @@ void netdev_run_todo(void)  		/* paranoia */  		BUG_ON(netdev_refcnt_read(dev));  		WARN_ON(rcu_dereference_raw(dev->ip_ptr)); -		WARN_ON(dev->ip6_ptr); +		WARN_ON(rcu_dereference_raw(dev->ip6_ptr));  		WARN_ON(dev->dn_ptr);  		if (dev->destructor) diff --git a/net/core/dst.c b/net/core/dst.c index 8abe628b79f..b99c7c7ffce 100644 --- a/net/core/dst.c +++ b/net/core/dst.c @@ -370,6 +370,7 @@ static int dst_dev_event(struct notifier_block *this, unsigned long event,  static struct notifier_block dst_dev_notifier = {  	.notifier_call	= dst_dev_event, +	.priority = -10, /* must be called after other network notifiers */  };  void __init dst_init(void) diff --git a/net/core/fib_rules.c b/net/core/fib_rules.c index 1bc3f253ba6..82a4369ae15 100644 --- a/net/core/fib_rules.c +++ b/net/core/fib_rules.c @@ -351,12 +351,12 @@ static int fib_nl_newrule(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg)  		list_for_each_entry(r, &ops->rules_list, list) {  			if (r->pref == rule->target) { -				rule->ctarget = r; +				RCU_INIT_POINTER(rule->ctarget, r);  				break;  			}  		} -		if (rule->ctarget == NULL) +		if (rcu_dereference_protected(rule->ctarget, 1) == NULL)  			unresolved = 1;  	} else if (rule->action == FR_ACT_GOTO)  		goto errout_free; @@ -373,6 +373,11 @@ static int fib_nl_newrule(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg)  	fib_rule_get(rule); +	if (last) +		list_add_rcu(&rule->list, &last->list); +	else +		list_add_rcu(&rule->list, &ops->rules_list); +  	if (ops->unresolved_rules) {  		/*  		 * There are unresolved goto rules in the list, check if @@ -381,7 +386,7 @@ static int fib_nl_newrule(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg)  		list_for_each_entry(r, &ops->rules_list, list) {  			if (r->action == FR_ACT_GOTO &&  			    r->target == rule->pref) { -				BUG_ON(r->ctarget != NULL); +				BUG_ON(rtnl_dereference(r->ctarget) != NULL);  				rcu_assign_pointer(r->ctarget, rule);  				if (--ops->unresolved_rules == 0)  					break; @@ -395,11 +400,6 @@ static int fib_nl_newrule(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg)  	if (unresolved)  		ops->unresolved_rules++; -	if (last) -		list_add_rcu(&rule->list, &last->list); -	else -		list_add_rcu(&rule->list, &ops->rules_list); -  	notify_rule_change(RTM_NEWRULE, rule, ops, nlh, NETLINK_CB(skb).pid);  	flush_route_cache(ops);  	rules_ops_put(ops); @@ -487,7 +487,7 @@ static int fib_nl_delrule(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg)  		 */  		if (ops->nr_goto_rules > 0) {  			list_for_each_entry(tmp, &ops->rules_list, list) { -				if (tmp->ctarget == rule) { +				if (rtnl_dereference(tmp->ctarget) == rule) {  					rcu_assign_pointer(tmp->ctarget, NULL);  					ops->unresolved_rules++;  				} @@ -545,7 +545,8 @@ static int fib_nl_fill_rule(struct sk_buff *skb, struct fib_rule *rule,  	frh->action = rule->action;  	frh->flags = rule->flags; -	if (rule->action == FR_ACT_GOTO && rule->ctarget == NULL) +	if (rule->action == FR_ACT_GOTO && +	    rcu_dereference_raw(rule->ctarget) == NULL)  		frh->flags |= FIB_RULE_UNRESOLVED;  	if (rule->iifname[0]) { diff --git a/net/core/filter.c b/net/core/filter.c index 7adf5035291..ae21a0d3c4a 100644 --- a/net/core/filter.c +++ b/net/core/filter.c @@ -89,8 +89,8 @@ int sk_filter(struct sock *sk, struct sk_buff *skb)  	rcu_read_lock_bh();  	filter = rcu_dereference_bh(sk->sk_filter);  	if (filter) { -		unsigned int pkt_len = sk_run_filter(skb, filter->insns, -				filter->len); +		unsigned int pkt_len = sk_run_filter(skb, filter->insns, filter->len); +  		err = pkt_len ? pskb_trim(skb, pkt_len) : -EPERM;  	}  	rcu_read_unlock_bh(); @@ -112,39 +112,41 @@ EXPORT_SYMBOL(sk_filter);   */  unsigned int sk_run_filter(struct sk_buff *skb, struct sock_filter *filter, int flen)  { -	struct sock_filter *fentry;	/* We walk down these */  	void *ptr;  	u32 A = 0;			/* Accumulator */  	u32 X = 0;			/* Index Register */  	u32 mem[BPF_MEMWORDS];		/* Scratch Memory Store */ +	unsigned long memvalid = 0;  	u32 tmp;  	int k;  	int pc; +	BUILD_BUG_ON(BPF_MEMWORDS > BITS_PER_LONG);  	/*  	 * Process array of filter instructions.  	 */  	for (pc = 0; pc < flen; pc++) { -		fentry = &filter[pc]; +		const struct sock_filter *fentry = &filter[pc]; +		u32 f_k = fentry->k;  		switch (fentry->code) {  		case BPF_S_ALU_ADD_X:  			A += X;  			continue;  		case BPF_S_ALU_ADD_K: -			A += fentry->k; +			A += f_k;  			continue;  		case BPF_S_ALU_SUB_X:  			A -= X;  			continue;  		case BPF_S_ALU_SUB_K: -			A -= fentry->k; +			A -= f_k;  			continue;  		case BPF_S_ALU_MUL_X:  			A *= X;  			continue;  		case BPF_S_ALU_MUL_K: -			A *= fentry->k; +			A *= f_k;  			continue;  		case BPF_S_ALU_DIV_X:  			if (X == 0) @@ -152,49 +154,49 @@ unsigned int sk_run_filter(struct sk_buff *skb, struct sock_filter *filter, int  			A /= X;  			continue;  		case BPF_S_ALU_DIV_K: -			A /= fentry->k; +			A /= f_k;  			continue;  		case BPF_S_ALU_AND_X:  			A &= X;  			continue;  		case BPF_S_ALU_AND_K: -			A &= fentry->k; +			A &= f_k;  			continue;  		case BPF_S_ALU_OR_X:  			A |= X;  			continue;  		case BPF_S_ALU_OR_K: -			A |= fentry->k; +			A |= f_k;  			continue;  		case BPF_S_ALU_LSH_X:  			A <<= X;  			continue;  		case BPF_S_ALU_LSH_K: -			A <<= fentry->k; +			A <<= f_k;  			continue;  		case BPF_S_ALU_RSH_X:  			A >>= X;  			continue;  		case BPF_S_ALU_RSH_K: -			A >>= fentry->k; +			A >>= f_k;  			continue;  		case BPF_S_ALU_NEG:  			A = -A;  			continue;  		case BPF_S_JMP_JA: -			pc += fentry->k; +			pc += f_k;  			continue;  		case BPF_S_JMP_JGT_K: -			pc += (A > fentry->k) ? fentry->jt : fentry->jf; +			pc += (A > f_k) ? fentry->jt : fentry->jf;  			continue;  		case BPF_S_JMP_JGE_K: -			pc += (A >= fentry->k) ? fentry->jt : fentry->jf; +			pc += (A >= f_k) ? fentry->jt : fentry->jf;  			continue;  		case BPF_S_JMP_JEQ_K: -			pc += (A == fentry->k) ? fentry->jt : fentry->jf; +			pc += (A == f_k) ? fentry->jt : fentry->jf;  			continue;  		case BPF_S_JMP_JSET_K: -			pc += (A & fentry->k) ? fentry->jt : fentry->jf; +			pc += (A & f_k) ? fentry->jt : fentry->jf;  			continue;  		case BPF_S_JMP_JGT_X:  			pc += (A > X) ? fentry->jt : fentry->jf; @@ -209,7 +211,7 @@ unsigned int sk_run_filter(struct sk_buff *skb, struct sock_filter *filter, int  			pc += (A & X) ? fentry->jt : fentry->jf;  			continue;  		case BPF_S_LD_W_ABS: -			k = fentry->k; +			k = f_k;  load_w:  			ptr = load_pointer(skb, k, 4, &tmp);  			if (ptr != NULL) { @@ -218,7 +220,7 @@ load_w:  			}  			break;  		case BPF_S_LD_H_ABS: -			k = fentry->k; +			k = f_k;  load_h:  			ptr = load_pointer(skb, k, 2, &tmp);  			if (ptr != NULL) { @@ -227,7 +229,7 @@ load_h:  			}  			break;  		case BPF_S_LD_B_ABS: -			k = fentry->k; +			k = f_k;  load_b:  			ptr = load_pointer(skb, k, 1, &tmp);  			if (ptr != NULL) { @@ -242,32 +244,34 @@ load_b:  			X = skb->len;  			continue;  		case BPF_S_LD_W_IND: -			k = X + fentry->k; +			k = X + f_k;  			goto load_w;  		case BPF_S_LD_H_IND: -			k = X + fentry->k; +			k = X + f_k;  			goto load_h;  		case BPF_S_LD_B_IND: -			k = X + fentry->k; +			k = X + f_k;  			goto load_b;  		case BPF_S_LDX_B_MSH: -			ptr = load_pointer(skb, fentry->k, 1, &tmp); +			ptr = load_pointer(skb, f_k, 1, &tmp);  			if (ptr != NULL) {  				X = (*(u8 *)ptr & 0xf) << 2;  				continue;  			}  			return 0;  		case BPF_S_LD_IMM: -			A = fentry->k; +			A = f_k;  			continue;  		case BPF_S_LDX_IMM: -			X = fentry->k; +			X = f_k;  			continue;  		case BPF_S_LD_MEM: -			A = mem[fentry->k]; +			A = (memvalid & (1UL << f_k)) ? +				mem[f_k] : 0;  			continue;  		case BPF_S_LDX_MEM: -			X = mem[fentry->k]; +			X = (memvalid & (1UL << f_k)) ? +				mem[f_k] : 0;  			continue;  		case BPF_S_MISC_TAX:  			X = A; @@ -276,14 +280,16 @@ load_b:  			A = X;  			continue;  		case BPF_S_RET_K: -			return fentry->k; +			return f_k;  		case BPF_S_RET_A:  			return A;  		case BPF_S_ST: -			mem[fentry->k] = A; +			memvalid |= 1UL << f_k; +			mem[f_k] = A;  			continue;  		case BPF_S_STX: -			mem[fentry->k] = X; +			memvalid |= 1UL << f_k; +			mem[f_k] = X;  			continue;  		default:  			WARN_ON(1); @@ -583,23 +589,16 @@ int sk_chk_filter(struct sock_filter *filter, int flen)  EXPORT_SYMBOL(sk_chk_filter);  /** - * 	sk_filter_rcu_release: Release a socket filter by rcu_head + * 	sk_filter_release_rcu - Release a socket filter by rcu_head   *	@rcu: rcu_head that contains the sk_filter to free   */ -static void sk_filter_rcu_release(struct rcu_head *rcu) +void sk_filter_release_rcu(struct rcu_head *rcu)  {  	struct sk_filter *fp = container_of(rcu, struct sk_filter, rcu); -	sk_filter_release(fp); -} - -static void sk_filter_delayed_uncharge(struct sock *sk, struct sk_filter *fp) -{ -	unsigned int size = sk_filter_len(fp); - -	atomic_sub(size, &sk->sk_omem_alloc); -	call_rcu_bh(&fp->rcu, sk_filter_rcu_release); +	kfree(fp);  } +EXPORT_SYMBOL(sk_filter_release_rcu);  /**   *	sk_attach_filter - attach a socket filter @@ -643,7 +642,7 @@ int sk_attach_filter(struct sock_fprog *fprog, struct sock *sk)  	rcu_assign_pointer(sk->sk_filter, fp);  	if (old_fp) -		sk_filter_delayed_uncharge(sk, old_fp); +		sk_filter_uncharge(sk, old_fp);  	return 0;  }  EXPORT_SYMBOL_GPL(sk_attach_filter); @@ -657,7 +656,7 @@ int sk_detach_filter(struct sock *sk)  					   sock_owned_by_user(sk));  	if (filter) {  		rcu_assign_pointer(sk->sk_filter, NULL); -		sk_filter_delayed_uncharge(sk, filter); +		sk_filter_uncharge(sk, filter);  		ret = 0;  	}  	return ret; diff --git a/net/core/iovec.c b/net/core/iovec.c index 72aceb1fe4f..c40f27e7d20 100644 --- a/net/core/iovec.c +++ b/net/core/iovec.c @@ -35,10 +35,9 @@   *	in any case.   */ -long verify_iovec(struct msghdr *m, struct iovec *iov, struct sockaddr *address, int mode) +int verify_iovec(struct msghdr *m, struct iovec *iov, struct sockaddr *address, int mode)  { -	int size, ct; -	long err; +	int size, ct, err;  	if (m->msg_namelen) {  		if (mode == VERIFY_READ) { @@ -62,14 +61,13 @@ long verify_iovec(struct msghdr *m, struct iovec *iov, struct sockaddr *address,  	err = 0;  	for (ct = 0; ct < m->msg_iovlen; ct++) { -		err += iov[ct].iov_len; -		/* -		 * Goal is not to verify user data, but to prevent returning -		 * negative value, which is interpreted as errno. -		 * Overflow is still possible, but it is harmless. -		 */ -		if (err < 0) -			return -EMSGSIZE; +		size_t len = iov[ct].iov_len; + +		if (len > INT_MAX - err) { +			len = INT_MAX - err; +			iov[ct].iov_len = len; +		} +		err += len;  	}  	return err; diff --git a/net/core/net-sysfs.c b/net/core/net-sysfs.c index b143173e3eb..7f902cad10f 100644 --- a/net/core/net-sysfs.c +++ b/net/core/net-sysfs.c @@ -598,7 +598,8 @@ static ssize_t store_rps_map(struct netdev_rx_queue *queue,  	}  	spin_lock(&rps_map_lock); -	old_map = queue->rps_map; +	old_map = rcu_dereference_protected(queue->rps_map, +					    lockdep_is_held(&rps_map_lock));  	rcu_assign_pointer(queue->rps_map, map);  	spin_unlock(&rps_map_lock); @@ -677,7 +678,8 @@ static ssize_t store_rps_dev_flow_table_cnt(struct netdev_rx_queue *queue,  		table = NULL;  	spin_lock(&rps_dev_flow_lock); -	old_table = queue->rps_flow_table; +	old_table = rcu_dereference_protected(queue->rps_flow_table, +					      lockdep_is_held(&rps_dev_flow_lock));  	rcu_assign_pointer(queue->rps_flow_table, table);  	spin_unlock(&rps_dev_flow_lock); @@ -705,16 +707,26 @@ static void rx_queue_release(struct kobject *kobj)  {  	struct netdev_rx_queue *queue = to_rx_queue(kobj);  	struct netdev_rx_queue *first = queue->first; +	struct rps_map *map; +	struct rps_dev_flow_table *flow_table; -	if (queue->rps_map) -		call_rcu(&queue->rps_map->rcu, rps_map_release); -	if (queue->rps_flow_table) -		call_rcu(&queue->rps_flow_table->rcu, -		    rps_dev_flow_table_release); +	map = rcu_dereference_raw(queue->rps_map); +	if (map) { +		RCU_INIT_POINTER(queue->rps_map, NULL); +		call_rcu(&map->rcu, rps_map_release); +	} + +	flow_table = rcu_dereference_raw(queue->rps_flow_table); +	if (flow_table) { +		RCU_INIT_POINTER(queue->rps_flow_table, NULL); +		call_rcu(&flow_table->rcu, rps_dev_flow_table_release); +	}  	if (atomic_dec_and_test(&first->count))  		kfree(first); +	else +		memset(kobj, 0, sizeof(*kobj));  }  static struct kobj_type rx_queue_ktype = { diff --git a/net/core/net_namespace.c b/net/core/net_namespace.c index c988e685433..3f860261c5e 100644 --- a/net/core/net_namespace.c +++ b/net/core/net_namespace.c @@ -42,7 +42,9 @@ static int net_assign_generic(struct net *net, int id, void *data)  	BUG_ON(!mutex_is_locked(&net_mutex));  	BUG_ON(id == 0); -	ng = old_ng = net->gen; +	old_ng = rcu_dereference_protected(net->gen, +					   lockdep_is_held(&net_mutex)); +	ng = old_ng;  	if (old_ng->len >= id)  		goto assign; diff --git a/net/core/pktgen.c b/net/core/pktgen.c index 2c0df0f95b3..33bc3823ac6 100644 --- a/net/core/pktgen.c +++ b/net/core/pktgen.c @@ -771,10 +771,10 @@ done:  static unsigned long num_arg(const char __user * user_buffer,  			     unsigned long maxlen, unsigned long *num)  { -	int i = 0; +	int i;  	*num = 0; -	for (; i < maxlen; i++) { +	for (i = 0; i < maxlen; i++) {  		char c;  		if (get_user(c, &user_buffer[i]))  			return -EFAULT; @@ -789,9 +789,9 @@ static unsigned long num_arg(const char __user * user_buffer,  static int strn_len(const char __user * user_buffer, unsigned int maxlen)  { -	int i = 0; +	int i; -	for (; i < maxlen; i++) { +	for (i = 0; i < maxlen; i++) {  		char c;  		if (get_user(c, &user_buffer[i]))  			return -EFAULT; @@ -846,7 +846,7 @@ static ssize_t pktgen_if_write(struct file *file,  {  	struct seq_file *seq = file->private_data;  	struct pktgen_dev *pkt_dev = seq->private; -	int i = 0, max, len; +	int i, max, len;  	char name[16], valstr[32];  	unsigned long value = 0;  	char *pg_result = NULL; @@ -860,13 +860,13 @@ static ssize_t pktgen_if_write(struct file *file,  		return -EINVAL;  	} -	max = count - i; -	tmp = count_trail_chars(&user_buffer[i], max); +	max = count; +	tmp = count_trail_chars(user_buffer, max);  	if (tmp < 0) {  		pr_warning("illegal format\n");  		return tmp;  	} -	i += tmp; +	i = tmp;  	/* Read variable name */ @@ -887,10 +887,11 @@ static ssize_t pktgen_if_write(struct file *file,  	i += len;  	if (debug) { -		char tb[count + 1]; -		if (copy_from_user(tb, user_buffer, count)) +		size_t copy = min_t(size_t, count, 1023); +		char tb[copy + 1]; +		if (copy_from_user(tb, user_buffer, copy))  			return -EFAULT; -		tb[count] = 0; +		tb[copy] = 0;  		printk(KERN_DEBUG "pktgen: %s,%lu  buffer -:%s:-\n", name,  		       (unsigned long)count, tb);  	} @@ -1764,7 +1765,7 @@ static ssize_t pktgen_thread_write(struct file *file,  {  	struct seq_file *seq = file->private_data;  	struct pktgen_thread *t = seq->private; -	int i = 0, max, len, ret; +	int i, max, len, ret;  	char name[40];  	char *pg_result; @@ -1773,12 +1774,12 @@ static ssize_t pktgen_thread_write(struct file *file,  		return -EINVAL;  	} -	max = count - i; -	len = count_trail_chars(&user_buffer[i], max); +	max = count; +	len = count_trail_chars(user_buffer, max);  	if (len < 0)  		return len; -	i += len; +	i = len;  	/* Read variable name */ @@ -1975,7 +1976,7 @@ static struct net_device *pktgen_dev_get_by_name(struct pktgen_dev *pkt_dev,  						 const char *ifname)  {  	char b[IFNAMSIZ+5]; -	int i = 0; +	int i;  	for (i = 0; ifname[i] != '@'; i++) {  		if (i == IFNAMSIZ) @@ -2519,8 +2520,8 @@ static void free_SAs(struct pktgen_dev *pkt_dev)  {  	if (pkt_dev->cflows) {  		/* let go of the SAs if we have them */ -		int i = 0; -		for (;  i < pkt_dev->cflows; i++) { +		int i; +		for (i = 0; i < pkt_dev->cflows; i++) {  			struct xfrm_state *x = pkt_dev->flows[i].x;  			if (x) {  				xfrm_state_put(x); @@ -2611,8 +2612,8 @@ static struct sk_buff *fill_packet_ipv4(struct net_device *odev,  	/* Update any of the values, used when we're incrementing various  	 * fields.  	 */ -	queue_map = pkt_dev->cur_queue_map;  	mod_cur_headers(pkt_dev); +	queue_map = pkt_dev->cur_queue_map;  	datalen = (odev->hard_header_len + 16) & ~0xf; @@ -2975,8 +2976,8 @@ static struct sk_buff *fill_packet_ipv6(struct net_device *odev,  	/* Update any of the values, used when we're incrementing various  	 * fields.  	 */ -	queue_map = pkt_dev->cur_queue_map;  	mod_cur_headers(pkt_dev); +	queue_map = pkt_dev->cur_queue_map;  	skb = __netdev_alloc_skb(odev,  				 pkt_dev->cur_pkt_size + 64 diff --git a/net/core/request_sock.c b/net/core/request_sock.c index 7552495aff7..fceeb37d716 100644 --- a/net/core/request_sock.c +++ b/net/core/request_sock.c @@ -45,9 +45,7 @@ int reqsk_queue_alloc(struct request_sock_queue *queue,  	nr_table_entries = roundup_pow_of_two(nr_table_entries + 1);  	lopt_size += nr_table_entries * sizeof(struct request_sock *);  	if (lopt_size > PAGE_SIZE) -		lopt = __vmalloc(lopt_size, -			GFP_KERNEL | __GFP_HIGHMEM | __GFP_ZERO, -			PAGE_KERNEL); +		lopt = vzalloc(lopt_size);  	else  		lopt = kzalloc(lopt_size, GFP_KERNEL);  	if (lopt == NULL) diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c index 8121268ddbd..841c287ef40 100644 --- a/net/core/rtnetlink.c +++ b/net/core/rtnetlink.c @@ -347,16 +347,17 @@ static size_t rtnl_link_get_size(const struct net_device *dev)  	if (!ops)  		return 0; -	size = nlmsg_total_size(sizeof(struct nlattr)) + /* IFLA_LINKINFO */ -	       nlmsg_total_size(strlen(ops->kind) + 1);	 /* IFLA_INFO_KIND */ +	size = nla_total_size(sizeof(struct nlattr)) + /* IFLA_LINKINFO */ +	       nla_total_size(strlen(ops->kind) + 1);  /* IFLA_INFO_KIND */  	if (ops->get_size)  		/* IFLA_INFO_DATA + nested data */ -		size += nlmsg_total_size(sizeof(struct nlattr)) + +		size += nla_total_size(sizeof(struct nlattr)) +  			ops->get_size(dev);  	if (ops->get_xstats_size) -		size += ops->get_xstats_size(dev);	/* IFLA_INFO_XSTATS */ +		/* IFLA_INFO_XSTATS */ +		size += nla_total_size(ops->get_xstats_size(dev));  	return size;  } diff --git a/net/core/sock.c b/net/core/sock.c index 11db43632df..e5af8d5d5b5 100644 --- a/net/core/sock.c +++ b/net/core/sock.c @@ -1009,6 +1009,36 @@ static void sock_copy(struct sock *nsk, const struct sock *osk)  #endif  } +/* + * caches using SLAB_DESTROY_BY_RCU should let .next pointer from nulls nodes + * un-modified. Special care is taken when initializing object to zero. + */ +static inline void sk_prot_clear_nulls(struct sock *sk, int size) +{ +	if (offsetof(struct sock, sk_node.next) != 0) +		memset(sk, 0, offsetof(struct sock, sk_node.next)); +	memset(&sk->sk_node.pprev, 0, +	       size - offsetof(struct sock, sk_node.pprev)); +} + +void sk_prot_clear_portaddr_nulls(struct sock *sk, int size) +{ +	unsigned long nulls1, nulls2; + +	nulls1 = offsetof(struct sock, __sk_common.skc_node.next); +	nulls2 = offsetof(struct sock, __sk_common.skc_portaddr_node.next); +	if (nulls1 > nulls2) +		swap(nulls1, nulls2); + +	if (nulls1 != 0) +		memset((char *)sk, 0, nulls1); +	memset((char *)sk + nulls1 + sizeof(void *), 0, +	       nulls2 - nulls1 - sizeof(void *)); +	memset((char *)sk + nulls2 + sizeof(void *), 0, +	       size - nulls2 - sizeof(void *)); +} +EXPORT_SYMBOL(sk_prot_clear_portaddr_nulls); +  static struct sock *sk_prot_alloc(struct proto *prot, gfp_t priority,  		int family)  { @@ -1021,19 +1051,12 @@ static struct sock *sk_prot_alloc(struct proto *prot, gfp_t priority,  		if (!sk)  			return sk;  		if (priority & __GFP_ZERO) { -			/* -			 * caches using SLAB_DESTROY_BY_RCU should let -			 * sk_node.next un-modified. Special care is taken -			 * when initializing object to zero. -			 */ -			if (offsetof(struct sock, sk_node.next) != 0) -				memset(sk, 0, offsetof(struct sock, sk_node.next)); -			memset(&sk->sk_node.pprev, 0, -			       prot->obj_size - offsetof(struct sock, -							 sk_node.pprev)); +			if (prot->clear_sk) +				prot->clear_sk(sk, prot->obj_size); +			else +				sk_prot_clear_nulls(sk, prot->obj_size);  		} -	} -	else +	} else  		sk = kmalloc(prot->obj_size, priority);  	if (sk != NULL) { @@ -1225,7 +1248,7 @@ struct sock *sk_clone(const struct sock *sk, const gfp_t priority)  		sock_reset_flag(newsk, SOCK_DONE);  		skb_queue_head_init(&newsk->sk_error_queue); -		filter = newsk->sk_filter; +		filter = rcu_dereference_protected(newsk->sk_filter, 1);  		if (filter != NULL)  			sk_filter_charge(newsk, filter); @@ -1653,10 +1676,10 @@ int __sk_mem_schedule(struct sock *sk, int size, int kind)  {  	struct proto *prot = sk->sk_prot;  	int amt = sk_mem_pages(size); -	int allocated; +	long allocated;  	sk->sk_forward_alloc += amt * SK_MEM_QUANTUM; -	allocated = atomic_add_return(amt, prot->memory_allocated); +	allocated = atomic_long_add_return(amt, prot->memory_allocated);  	/* Under limit. */  	if (allocated <= prot->sysctl_mem[0]) { @@ -1714,7 +1737,7 @@ suppress_allocation:  	/* Alas. Undo changes. */  	sk->sk_forward_alloc -= amt * SK_MEM_QUANTUM; -	atomic_sub(amt, prot->memory_allocated); +	atomic_long_sub(amt, prot->memory_allocated);  	return 0;  }  EXPORT_SYMBOL(__sk_mem_schedule); @@ -1727,12 +1750,12 @@ void __sk_mem_reclaim(struct sock *sk)  {  	struct proto *prot = sk->sk_prot; -	atomic_sub(sk->sk_forward_alloc >> SK_MEM_QUANTUM_SHIFT, +	atomic_long_sub(sk->sk_forward_alloc >> SK_MEM_QUANTUM_SHIFT,  		   prot->memory_allocated);  	sk->sk_forward_alloc &= SK_MEM_QUANTUM - 1;  	if (prot->memory_pressure && *prot->memory_pressure && -	    (atomic_read(prot->memory_allocated) < prot->sysctl_mem[0])) +	    (atomic_long_read(prot->memory_allocated) < prot->sysctl_mem[0]))  		*prot->memory_pressure = 0;  }  EXPORT_SYMBOL(__sk_mem_reclaim); @@ -2452,12 +2475,12 @@ static char proto_method_implemented(const void *method)  static void proto_seq_printf(struct seq_file *seq, struct proto *proto)  { -	seq_printf(seq, "%-9s %4u %6d  %6d   %-3s %6u   %-3s  %-10s " +	seq_printf(seq, "%-9s %4u %6d  %6ld   %-3s %6u   %-3s  %-10s "  			"%2c %2c %2c %2c %2c %2c %2c %2c %2c %2c %2c %2c %2c %2c %2c %2c %2c %2c %2c\n",  		   proto->name,  		   proto->obj_size,  		   sock_prot_inuse_get(seq_file_net(seq), proto), -		   proto->memory_allocated != NULL ? atomic_read(proto->memory_allocated) : -1, +		   proto->memory_allocated != NULL ? atomic_long_read(proto->memory_allocated) : -1L,  		   proto->memory_pressure != NULL ? *proto->memory_pressure ? "yes" : "no" : "NI",  		   proto->max_header,  		   proto->slab == NULL ? "no" : "yes", diff --git a/net/core/sysctl_net_core.c b/net/core/sysctl_net_core.c index 01eee5d984b..385b6095fdc 100644 --- a/net/core/sysctl_net_core.c +++ b/net/core/sysctl_net_core.c @@ -34,7 +34,8 @@ static int rps_sock_flow_sysctl(ctl_table *table, int write,  	mutex_lock(&sock_flow_mutex); -	orig_sock_table = rps_sock_flow_table; +	orig_sock_table = rcu_dereference_protected(rps_sock_flow_table, +					lockdep_is_held(&sock_flow_mutex));  	size = orig_size = orig_sock_table ? orig_sock_table->mask + 1 : 0;  	ret = proc_dointvec(&tmp, write, buffer, lenp, ppos); diff --git a/net/core/timestamping.c b/net/core/timestamping.c index 0ae6c22da85..c19bb4ee405 100644 --- a/net/core/timestamping.c +++ b/net/core/timestamping.c @@ -96,11 +96,13 @@ bool skb_defer_rx_timestamp(struct sk_buff *skb)  	struct phy_device *phydev;  	unsigned int type; -	skb_push(skb, ETH_HLEN); +	if (skb_headroom(skb) < ETH_HLEN) +		return false; +	__skb_push(skb, ETH_HLEN);  	type = classify(skb); -	skb_pull(skb, ETH_HLEN); +	__skb_pull(skb, ETH_HLEN);  	switch (type) {  	case PTP_CLASS_V1_IPV4: | 
