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

Merge branch 'net-subsystem-misc-refcounter-conversions'



Elena Reshetova says:

====================
v2 net subsystem misc refcounter conversions

Changes in v2:
 * rebase on top of net-next
 * currently by default refcount_t = atomic_t (*) and uses all
   atomic standard operations unless CONFIG_REFCOUNT_FULL is enabled.
   This is a compromise for the systems that are critical on
   performance (such as net) and cannot accept even slight delay
   on the refcounter operations.

This series, for various misc network components, replaces atomic_t reference
counters with the new refcount_t type and API (see include/linux/refcount.h).
By doing this we prevent intentional or accidental
underflows or overflows that can led to use-after-free vulnerabilities.
These are the last networking-related conversions with the exception of
network drivers (to be send separately).

Please excuse the long patch set, but seems like breaking it up
won't save that much on CC list and most of the changes are
trivial.

The patches are fully independent and can be cherry-picked separately.
In order to try with refcount functionality enabled in run-time,
CONFIG_REFCOUNT_FULL must be enabled.

NOTE: automatic kernel builder for some reason doesn't like all my
network branches and regularly times out the builds on these branches.
Suggestion for "waiting a day for a good coverage" doesn't work, as
we have seen with generic network conversions. So please wait for the
full report from kernel test rebot before merging further up.
This has been compile-tested in 116 configs, but 71 timed out (including
all s390-related configs again). I am trying to see if they can fix
build coverage for me in meanwhile.

* The respective change is currently merged into -next as
  "locking/refcount: Create unchecked atomic_t implementation".
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents bf72acef b6d52ede
......@@ -1034,11 +1034,11 @@ static bool vxlan_group_used(struct vxlan_net *vn, struct vxlan_dev *dev)
/* The vxlan_sock is only used by dev, leaving group has
* no effect on other vxlan devices.
*/
if (family == AF_INET && sock4 && atomic_read(&sock4->refcnt) == 1)
if (family == AF_INET && sock4 && refcount_read(&sock4->refcnt) == 1)
return false;
#if IS_ENABLED(CONFIG_IPV6)
sock6 = rtnl_dereference(dev->vn6_sock);
if (family == AF_INET6 && sock6 && atomic_read(&sock6->refcnt) == 1)
if (family == AF_INET6 && sock6 && refcount_read(&sock6->refcnt) == 1)
return false;
#endif
......@@ -1075,7 +1075,7 @@ static bool __vxlan_sock_release_prep(struct vxlan_sock *vs)
if (!vs)
return false;
if (!atomic_dec_and_test(&vs->refcnt))
if (!refcount_dec_and_test(&vs->refcnt))
return false;
vn = net_generic(sock_net(vs->sock->sk), vxlan_net_id);
......@@ -2825,7 +2825,7 @@ static struct vxlan_sock *vxlan_socket_create(struct net *net, bool ipv6,
}
vs->sock = sock;
atomic_set(&vs->refcnt, 1);
refcount_set(&vs->refcnt, 1);
vs->flags = (flags & VXLAN_F_RCV_FLAGS);
spin_lock(&vn->sock_lock);
......@@ -2860,7 +2860,7 @@ static int __vxlan_sock_add(struct vxlan_dev *vxlan, bool ipv6)
spin_lock(&vn->sock_lock);
vs = vxlan_find_sock(vxlan->net, ipv6 ? AF_INET6 : AF_INET,
vxlan->cfg.dst_port, vxlan->cfg.flags);
if (vs && !atomic_add_unless(&vs->refcnt, 1, 0)) {
if (vs && !refcount_inc_not_zero(&vs->refcnt)) {
spin_unlock(&vn->sock_lock);
return -EBUSY;
}
......
......@@ -11,6 +11,7 @@
#include <linux/uio.h>
#include <net/sock.h>
#include <linux/atomic.h>
#include <linux/refcount.h>
#include <uapi/linux/atmdev.h>
#ifdef CONFIG_PROC_FS
......@@ -158,7 +159,7 @@ struct atm_dev {
struct k_atm_dev_stats stats; /* statistics */
char signal; /* signal status (ATM_PHY_SIG_*) */
int link_rate; /* link rate (default: OC3) */
atomic_t refcnt; /* reference count */
refcount_t refcnt; /* reference count */
spinlock_t lock; /* protect internal members */
#ifdef CONFIG_PROC_FS
struct proc_dir_entry *proc_entry; /* proc entry */
......@@ -261,13 +262,13 @@ static inline int atm_may_send(struct atm_vcc *vcc,unsigned int size)
static inline void atm_dev_hold(struct atm_dev *dev)
{
atomic_inc(&dev->refcnt);
refcount_inc(&dev->refcnt);
}
static inline void atm_dev_put(struct atm_dev *dev)
{
if (atomic_dec_and_test(&dev->refcnt)) {
if (refcount_dec_and_test(&dev->refcnt)) {
BUG_ON(!test_bit(ATM_DF_REMOVED, &dev->flags));
if (dev->ops->dev_close)
dev->ops->dev_close(dev);
......
......@@ -13,6 +13,7 @@
#define _LINUX_SUNRPC_AUTH_GSS_H
#ifdef __KERNEL__
#include <linux/refcount.h>
#include <linux/sunrpc/auth.h>
#include <linux/sunrpc/svc.h>
#include <linux/sunrpc/gss_api.h>
......@@ -65,7 +66,7 @@ struct rpc_gss_init_res {
* the wire when communicating with a server. */
struct gss_cl_ctx {
atomic_t count;
refcount_t count;
enum rpc_gss_proc gc_proc;
u32 gc_seq;
spinlock_t gc_seq_lock;
......
......@@ -11,7 +11,7 @@
#include <linux/timer.h>
#include <linux/list.h>
#include <linux/slab.h>
#include <linux/atomic.h>
#include <linux/refcount.h>
#include <net/neighbour.h>
#include <net/sock.h>
......@@ -158,7 +158,7 @@ enum {
typedef struct ax25_uid_assoc {
struct hlist_node uid_node;
atomic_t refcount;
refcount_t refcount;
kuid_t uid;
ax25_address call;
} ax25_uid_assoc;
......@@ -167,11 +167,11 @@ typedef struct ax25_uid_assoc {
hlist_for_each_entry(__ax25, list, uid_node)
#define ax25_uid_hold(ax25) \
atomic_inc(&((ax25)->refcount))
refcount_inc(&((ax25)->refcount))
static inline void ax25_uid_put(ax25_uid_assoc *assoc)
{
if (atomic_dec_and_test(&assoc->refcount)) {
if (refcount_dec_and_test(&assoc->refcount)) {
kfree(assoc);
}
}
......@@ -185,7 +185,7 @@ typedef struct {
typedef struct ax25_route {
struct ax25_route *next;
atomic_t refcount;
refcount_t refcount;
ax25_address callsign;
struct net_device *dev;
ax25_digi *digipeat;
......@@ -194,14 +194,14 @@ typedef struct ax25_route {
static inline void ax25_hold_route(ax25_route *ax25_rt)
{
atomic_inc(&ax25_rt->refcount);
refcount_inc(&ax25_rt->refcount);
}
void __ax25_put_route(ax25_route *ax25_rt);
static inline void ax25_put_route(ax25_route *ax25_rt)
{
if (atomic_dec_and_test(&ax25_rt->refcount))
if (refcount_dec_and_test(&ax25_rt->refcount))
__ax25_put_route(ax25_rt);
}
......@@ -244,7 +244,7 @@ typedef struct ax25_cb {
unsigned char window;
struct timer_list timer, dtimer;
struct sock *sk; /* Backlink to socket */
atomic_t refcount;
refcount_t refcount;
} ax25_cb;
struct ax25_sock {
......@@ -266,11 +266,11 @@ static inline struct ax25_cb *sk_to_ax25(const struct sock *sk)
hlist_for_each_entry(__ax25, list, ax25_node)
#define ax25_cb_hold(__ax25) \
atomic_inc(&((__ax25)->refcount))
refcount_inc(&((__ax25)->refcount))
static __inline__ void ax25_cb_put(ax25_cb *ax25)
{
if (atomic_dec_and_test(&ax25->refcount)) {
if (refcount_dec_and_test(&ax25->refcount)) {
kfree(ax25->digipeat);
kfree(ax25);
}
......
......@@ -38,7 +38,7 @@
#include <linux/skbuff.h>
#include <net/netlabel.h>
#include <net/request_sock.h>
#include <linux/atomic.h>
#include <linux/refcount.h>
#include <asm/unaligned.h>
/* known doi values */
......@@ -57,7 +57,7 @@ struct calipso_doi {
u32 doi;
u32 type;
atomic_t refcount;
refcount_t refcount;
struct list_head list;
struct rcu_head rcu;
};
......
......@@ -2,6 +2,7 @@
#define _NET_DN_FIB_H
#include <linux/netlink.h>
#include <linux/refcount.h>
extern const struct nla_policy rtm_dn_policy[];
......@@ -28,7 +29,7 @@ struct dn_fib_info {
struct dn_fib_info *fib_next;
struct dn_fib_info *fib_prev;
int fib_treeref;
atomic_t fib_clntref;
refcount_t fib_clntref;
int fib_dead;
unsigned int fib_flags;
int fib_protocol;
......@@ -130,7 +131,7 @@ void dn_fib_free_info(struct dn_fib_info *fi);
static inline void dn_fib_info_put(struct dn_fib_info *fi)
{
if (atomic_dec_and_test(&fi->fib_clntref))
if (refcount_dec_and_test(&fi->fib_clntref))
dn_fib_free_info(fi);
}
......
......@@ -14,6 +14,7 @@
#include <linux/ipx.h>
#include <linux/list.h>
#include <linux/slab.h>
#include <linux/refcount.h>
struct ipx_address {
__be32 net;
......@@ -54,7 +55,7 @@ struct ipx_interface {
/* IPX address */
__be32 if_netnum;
unsigned char if_node[IPX_NODE_LEN];
atomic_t refcnt;
refcount_t refcnt;
/* physical device info */
struct net_device *if_dev;
......@@ -80,7 +81,7 @@ struct ipx_route {
unsigned char ir_routed;
unsigned char ir_router_node[IPX_NODE_LEN];
struct list_head node; /* node in ipx_routes list */
atomic_t refcnt;
refcount_t refcnt;
};
struct ipx_cb {
......@@ -139,7 +140,7 @@ const char *ipx_device_name(struct ipx_interface *intrfc);
static __inline__ void ipxitf_hold(struct ipx_interface *intrfc)
{
atomic_inc(&intrfc->refcnt);
refcount_inc(&intrfc->refcnt);
}
void ipxitf_down(struct ipx_interface *intrfc);
......@@ -157,18 +158,18 @@ int ipxrtr_ioctl(unsigned int cmd, void __user *arg);
static __inline__ void ipxitf_put(struct ipx_interface *intrfc)
{
if (atomic_dec_and_test(&intrfc->refcnt))
if (refcount_dec_and_test(&intrfc->refcnt))
ipxitf_down(intrfc);
}
static __inline__ void ipxrtr_hold(struct ipx_route *rt)
{
atomic_inc(&rt->refcnt);
refcount_inc(&rt->refcnt);
}
static __inline__ void ipxrtr_put(struct ipx_route *rt)
{
if (atomic_dec_and_test(&rt->refcnt))
if (refcount_dec_and_test(&rt->refcnt))
kfree(rt);
}
#endif /* _NET_INET_IPX_H_ */
#ifndef _LAPB_H
#define _LAPB_H
#include <linux/lapb.h>
#include <linux/refcount.h>
#define LAPB_HEADER_LEN 20 /* LAPB over Ethernet + a bit more */
......@@ -101,7 +102,7 @@ struct lapb_cb {
struct lapb_frame frmr_data;
unsigned char frmr_type;
atomic_t refcnt;
refcount_t refcnt;
};
/* lapb_iface.c */
......
......@@ -55,7 +55,7 @@ struct llc_sap {
unsigned char state;
unsigned char p_bit;
unsigned char f_bit;
atomic_t refcnt;
refcount_t refcnt;
int (*rcv_func)(struct sk_buff *skb,
struct net_device *dev,
struct packet_type *pt,
......@@ -113,14 +113,14 @@ struct llc_sap *llc_sap_open(unsigned char lsap,
struct net_device *orig_dev));
static inline void llc_sap_hold(struct llc_sap *sap)
{
atomic_inc(&sap->refcnt);
refcount_inc(&sap->refcnt);
}
void llc_sap_close(struct llc_sap *sap);
static inline void llc_sap_put(struct llc_sap *sap)
{
if (atomic_dec_and_test(&sap->refcnt))
if (refcount_dec_and_test(&sap->refcnt))
llc_sap_close(sap);
}
......
......@@ -11,6 +11,7 @@
#include <linux/list.h>
#include <linux/slab.h>
#include <net/sock.h>
#include <linux/refcount.h>
#define NR_NETWORK_LEN 15
#define NR_TRANSPORT_LEN 5
......@@ -93,7 +94,7 @@ struct nr_neigh {
unsigned short count;
unsigned int number;
unsigned char failed;
atomic_t refcount;
refcount_t refcount;
};
struct nr_route {
......@@ -109,7 +110,7 @@ struct nr_node {
unsigned char which;
unsigned char count;
struct nr_route routes[3];
atomic_t refcount;
refcount_t refcount;
spinlock_t node_lock;
};
......@@ -118,21 +119,21 @@ struct nr_node {
*********************************************************************/
#define nr_node_hold(__nr_node) \
atomic_inc(&((__nr_node)->refcount))
refcount_inc(&((__nr_node)->refcount))
static __inline__ void nr_node_put(struct nr_node *nr_node)
{
if (atomic_dec_and_test(&nr_node->refcount)) {
if (refcount_dec_and_test(&nr_node->refcount)) {
kfree(nr_node);
}
}
#define nr_neigh_hold(__nr_neigh) \
atomic_inc(&((__nr_neigh)->refcount))
refcount_inc(&((__nr_neigh)->refcount))
static __inline__ void nr_neigh_put(struct nr_neigh *nr_neigh)
{
if (atomic_dec_and_test(&nr_neigh->refcount)) {
if (refcount_dec_and_test(&nr_neigh->refcount)) {
if (nr_neigh->ax25)
ax25_cb_put(nr_neigh->ax25);
kfree(nr_neigh->digipeat);
......
......@@ -9,6 +9,7 @@
#include <linux/percpu.h>
#include <linux/dynamic_queue_limits.h>
#include <linux/list.h>
#include <linux/refcount.h>
#include <net/gen_stats.h>
#include <net/rtnetlink.h>
......@@ -95,7 +96,7 @@ struct Qdisc {
struct sk_buff *skb_bad_txq;
struct rcu_head rcu_head;
int padded;
atomic_t refcnt;
refcount_t refcnt;
spinlock_t busylock ____cacheline_aligned_in_smp;
};
......
......@@ -31,6 +31,7 @@
#define __sctp_auth_h__
#include <linux/list.h>
#include <linux/refcount.h>
struct sctp_endpoint;
struct sctp_association;
......@@ -53,7 +54,7 @@ struct sctp_hmac {
* over SCTP-AUTH
*/
struct sctp_auth_bytes {
atomic_t refcnt;
refcount_t refcnt;
__u32 len;
__u8 data[];
};
......@@ -76,7 +77,7 @@ static inline void sctp_auth_key_hold(struct sctp_auth_bytes *key)
if (!key)
return;
atomic_inc(&key->refcnt);
refcount_inc(&key->refcnt);
}
void sctp_auth_key_put(struct sctp_auth_bytes *key);
......
......@@ -496,7 +496,7 @@ struct sctp_datamsg {
/* Chunks waiting to be submitted to lower layer. */
struct list_head chunks;
/* Reference counting. */
atomic_t refcnt;
refcount_t refcnt;
/* When is this message no longer interesting to the peer? */
unsigned long expires_at;
/* Did the messenge fail to send? */
......@@ -524,7 +524,7 @@ int sctp_chunk_abandoned(struct sctp_chunk *);
struct sctp_chunk {
struct list_head list;
atomic_t refcnt;
refcount_t refcnt;
/* How many times this chunk have been sent, for prsctp RTX policy */
int sent_count;
......@@ -735,7 +735,7 @@ struct sctp_transport {
struct rhlist_head node;
/* Reference counting. */
atomic_t refcnt;
refcount_t refcnt;
/* RTO-Pending : A flag used to track if one of the DATA
* chunks sent to this address is currently being
* used to compute a RTT. If this flag is 0,
......@@ -1174,7 +1174,7 @@ struct sctp_ep_common {
* refcnt - Reference count access to this object.
* dead - Do not attempt to use this object.
*/
atomic_t refcnt;
refcount_t refcnt;
bool dead;
/* What socket does this endpoint belong to? */
......
......@@ -183,7 +183,7 @@ struct vxlan_sock {
struct hlist_node hlist;
struct socket *sock;
struct hlist_head vni_list[VNI_HASH_SIZE];
atomic_t refcnt;
refcount_t refcnt;
u32 flags;
};
......
......@@ -11,6 +11,7 @@
#define _X25_H
#include <linux/x25.h>
#include <linux/slab.h>
#include <linux/refcount.h>
#include <net/sock.h>
#define X25_ADDR_LEN 16
......@@ -129,7 +130,7 @@ struct x25_route {
struct x25_address address;
unsigned int sigdigits;
struct net_device *dev;
atomic_t refcnt;
refcount_t refcnt;
};
struct x25_neigh {
......@@ -141,7 +142,7 @@ struct x25_neigh {
unsigned long t20;
struct timer_list t20timer;
unsigned long global_facil_mask;
atomic_t refcnt;
refcount_t refcnt;
};
struct x25_sock {
......@@ -242,12 +243,12 @@ void x25_link_free(void);
/* x25_neigh.c */
static __inline__ void x25_neigh_hold(struct x25_neigh *nb)
{
atomic_inc(&nb->refcnt);
refcount_inc(&nb->refcnt);
}
static __inline__ void x25_neigh_put(struct x25_neigh *nb)
{
if (atomic_dec_and_test(&nb->refcnt))
if (refcount_dec_and_test(&nb->refcnt))
kfree(nb);
}
......@@ -265,12 +266,12 @@ void x25_route_free(void);
static __inline__ void x25_route_hold(struct x25_route *rt)
{
atomic_inc(&rt->refcnt);
refcount_inc(&rt->refcnt);
}
static __inline__ void x25_route_put(struct x25_route *rt)
{
if (atomic_dec_and_test(&rt->refcnt))
if (refcount_dec_and_test(&rt->refcnt))
kfree(rt);
}
......
......@@ -13,6 +13,7 @@
#include <linux/mutex.h>
#include <linux/audit.h>
#include <linux/slab.h>
#include <linux/refcount.h>
#include <net/sock.h>
#include <net/dst.h>
......@@ -137,7 +138,7 @@ struct xfrm_state {
struct hlist_node bysrc;
struct hlist_node byspi;
atomic_t refcnt;
refcount_t refcnt;
spinlock_t lock;
struct xfrm_id id;
......@@ -559,7 +560,7 @@ struct xfrm_policy {
/* This lock only affects elements except for entry. */
rwlock_t lock;
atomic_t refcnt;
refcount_t refcnt;
struct timer_list timer;
struct flow_cache_object flo;
......@@ -815,14 +816,14 @@ static inline void xfrm_audit_state_icvfail(struct xfrm_state *x,
static inline void xfrm_pol_hold(struct xfrm_policy *policy)
{
if (likely(policy != NULL))
atomic_inc(&policy->refcnt);
refcount_inc(&policy->refcnt);
}
void xfrm_policy_destroy(struct xfrm_policy *policy);
static inline void xfrm_pol_put(struct xfrm_policy *policy)
{
if (atomic_dec_and_test(&policy->refcnt))
if (refcount_dec_and_test(&policy->refcnt))
xfrm_policy_destroy(policy);
}
......@@ -837,18 +838,18 @@ void __xfrm_state_destroy(struct xfrm_state *);
static inline void __xfrm_state_put(struct xfrm_state *x)
{
atomic_dec(&x->refcnt);
refcount_dec(&x->refcnt);
}
static inline void xfrm_state_put(struct xfrm_state *x)
{
if (atomic_dec_and_test(&x->refcnt))
if (refcount_dec_and_test(&x->refcnt))
__xfrm_state_destroy(x);
}
static inline void xfrm_state_hold(struct xfrm_state *x)
{
atomic_inc(&x->refcnt);
refcount_inc(&x->refcnt);
}
static inline bool addr_match(const void *token1, const void *token2,
......@@ -1029,7 +1030,7 @@ struct xfrm_offload {
};
struct sec_path {
atomic_t refcnt;
refcount_t refcnt;
int len;
int olen;
......@@ -1050,7 +1051,7 @@ static inline struct sec_path *
secpath_get(struct sec_path *sp)
{
if (sp)
atomic_inc(&sp->refcnt);
refcount_inc(&sp->refcnt);
return sp;
}
......@@ -1059,7 +1060,7 @@ void __secpath_destroy(struct sec_path *sp);
static inline void
secpath_put(struct sec_path *sp)
{
if (sp && atomic_dec_and_test(&sp->refcnt))
if (sp && refcount_dec_and_test(&sp->refcnt))
__secpath_destroy(sp);
}
......
......@@ -101,12 +101,12 @@ static void lec_vcc_close(struct lec_priv *priv, struct atm_vcc *vcc);
/* must be done under lec_arp_lock */
static inline void lec_arp_hold(struct lec_arp_table *entry)
{
atomic_inc(&entry->usage);
refcount_inc(&entry->usage);
}
static inline void lec_arp_put(struct lec_arp_table *entry)
{
if (atomic_dec_and_test(&entry->usage))
if (refcount_dec_and_test(&entry->usage))
kfree(entry);
}
......@@ -1564,7 +1564,7 @@ static struct lec_arp_table *make_entry(struct lec_priv *priv,
to_return->last_used = jiffies;
to_return->priv = priv;
skb_queue_head_init(&to_return->tx_wait);
atomic_set(&to_return->usage, 1);
refcount_set(&to_return->usage, 1);
return to_return;
}
......
......@@ -47,7 +47,7 @@ struct lec_arp_table {
* the length of the tlvs array
*/
struct sk_buff_head tx_wait; /* wait queue for outgoing packets */
atomic_t usage; /* usage count */
refcount_t usage; /* usage count */
};
/*
......
......@@ -40,7 +40,7 @@ static in_cache_entry *in_cache_get(__be32 dst_ip,
entry = client->in_cache;
while (entry != NULL) {
if (entry->ctrl_info.in_dst_ip == dst_ip) {
atomic_inc(&entry->use);
refcount_inc(&entry->use);
read_unlock_bh(&client->ingress_lock);
return entry;
}
......@@ -61,7 +61,7 @@ static in_cache_entry *in_cache_get_with_mask(__be32 dst_ip,
entry = client->in_cache;
while (entry != NULL) {
if ((entry->ctrl_info.in_dst_ip & mask) == (dst_ip & mask)) {
atomic_inc(&entry->use);