diff options
Diffstat (limited to 'net/netlink')
| -rw-r--r-- | net/netlink/af_netlink.c | 47 | ||||
| -rw-r--r-- | net/netlink/af_netlink.h | 1 | 
2 files changed, 36 insertions, 12 deletions
| diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c index 930d17fa906c..6bb9f3cde0b0 100644 --- a/net/netlink/af_netlink.c +++ b/net/netlink/af_netlink.c @@ -574,11 +574,6 @@ static int netlink_insert(struct sock *sk, u32 portid)  	if (nlk_sk(sk)->bound)  		goto err; -	err = -ENOMEM; -	if (BITS_PER_LONG > 32 && -	    unlikely(atomic_read(&table->hash.nelems) >= UINT_MAX)) -		goto err; -  	nlk_sk(sk)->portid = portid;  	sock_hold(sk); @@ -993,7 +988,7 @@ static int netlink_bind(struct socket *sock, struct sockaddr *addr,  	struct netlink_sock *nlk = nlk_sk(sk);  	struct sockaddr_nl *nladdr = (struct sockaddr_nl *)addr;  	int err = 0; -	long unsigned int groups = nladdr->nl_groups; +	unsigned long groups = nladdr->nl_groups;  	bool bound;  	if (addr_len < sizeof(struct sockaddr_nl)) @@ -1011,9 +1006,7 @@ static int netlink_bind(struct socket *sock, struct sockaddr *addr,  			return err;  	} -	if (nlk->ngroups == 0) -		groups = 0; -	else if (nlk->ngroups < 8*sizeof(groups)) +	if (nlk->ngroups < BITS_PER_LONG)  		groups &= (1UL << nlk->ngroups) - 1;  	bound = nlk->bound; @@ -1713,6 +1706,13 @@ static int netlink_setsockopt(struct socket *sock, int level, int optname,  			nlk->flags &= ~NETLINK_F_EXT_ACK;  		err = 0;  		break; +	case NETLINK_DUMP_STRICT_CHK: +		if (val) +			nlk->flags |= NETLINK_F_STRICT_CHK; +		else +			nlk->flags &= ~NETLINK_F_STRICT_CHK; +		err = 0; +		break;  	default:  		err = -ENOPROTOOPT;  	} @@ -1806,6 +1806,15 @@ static int netlink_getsockopt(struct socket *sock, int level, int optname,  			return -EFAULT;  		err = 0;  		break; +	case NETLINK_DUMP_STRICT_CHK: +		if (len < sizeof(int)) +			return -EINVAL; +		len = sizeof(int); +		val = nlk->flags & NETLINK_F_STRICT_CHK ? 1 : 0; +		if (put_user(len, optlen) || put_user(val, optval)) +			return -EFAULT; +		err = 0; +		break;  	default:  		err = -ENOPROTOOPT;  	} @@ -2178,6 +2187,7 @@ EXPORT_SYMBOL(__nlmsg_put);  static int netlink_dump(struct sock *sk)  {  	struct netlink_sock *nlk = nlk_sk(sk); +	struct netlink_ext_ack extack = {};  	struct netlink_callback *cb;  	struct sk_buff *skb = NULL;  	struct nlmsghdr *nlh; @@ -2229,8 +2239,11 @@ static int netlink_dump(struct sock *sk)  	skb_reserve(skb, skb_tailroom(skb) - alloc_size);  	netlink_skb_set_owner_r(skb, sk); -	if (nlk->dump_done_errno > 0) +	if (nlk->dump_done_errno > 0) { +		cb->extack = &extack;  		nlk->dump_done_errno = cb->dump(skb, cb); +		cb->extack = NULL; +	}  	if (nlk->dump_done_errno > 0 ||  	    skb_tailroom(skb) < nlmsg_total_size(sizeof(nlk->dump_done_errno))) { @@ -2244,7 +2257,8 @@ static int netlink_dump(struct sock *sk)  	}  	nlh = nlmsg_put_answer(skb, cb, NLMSG_DONE, -			       sizeof(nlk->dump_done_errno), NLM_F_MULTI); +			       sizeof(nlk->dump_done_errno), +			       NLM_F_MULTI | cb->answer_flags);  	if (WARN_ON(!nlh))  		goto errout_skb; @@ -2253,6 +2267,12 @@ static int netlink_dump(struct sock *sk)  	memcpy(nlmsg_data(nlh), &nlk->dump_done_errno,  	       sizeof(nlk->dump_done_errno)); +	if (extack._msg && nlk->flags & NETLINK_F_EXT_ACK) { +		nlh->nlmsg_flags |= NLM_F_ACK_TLVS; +		if (!nla_put_string(skb, NLMSGERR_ATTR_MSG, extack._msg)) +			nlmsg_end(skb, nlh); +	} +  	if (sk_filter(sk, skb))  		kfree_skb(skb);  	else @@ -2279,9 +2299,9 @@ int __netlink_dump_start(struct sock *ssk, struct sk_buff *skb,  			 const struct nlmsghdr *nlh,  			 struct netlink_dump_control *control)  { +	struct netlink_sock *nlk, *nlk2;  	struct netlink_callback *cb;  	struct sock *sk; -	struct netlink_sock *nlk;  	int ret;  	refcount_inc(&skb->users); @@ -2315,6 +2335,9 @@ int __netlink_dump_start(struct sock *ssk, struct sk_buff *skb,  	cb->min_dump_alloc = control->min_dump_alloc;  	cb->skb = skb; +	nlk2 = nlk_sk(NETLINK_CB(skb).sk); +	cb->strict_check = !!(nlk2->flags & NETLINK_F_STRICT_CHK); +  	if (control->start) {  		ret = control->start(cb);  		if (ret) diff --git a/net/netlink/af_netlink.h b/net/netlink/af_netlink.h index 962de7b3c023..5f454c8de6a4 100644 --- a/net/netlink/af_netlink.h +++ b/net/netlink/af_netlink.h @@ -15,6 +15,7 @@  #define NETLINK_F_LISTEN_ALL_NSID	0x10  #define NETLINK_F_CAP_ACK		0x20  #define NETLINK_F_EXT_ACK		0x40 +#define NETLINK_F_STRICT_CHK		0x80  #define NLGRPSZ(x)	(ALIGN(x, sizeof(unsigned long) * 8) / 8)  #define NLGRPLONGS(x)	(NLGRPSZ(x)/sizeof(unsigned long)) |