Skip to content

Commit

Permalink
Merge branch 'net-refcount_t'
Browse files Browse the repository at this point in the history
Elena Reshetova says:

====================
v3 net generic subsystem refcount conversions

Changes in v3:
Rebased on top of the net-next tree.

Changes in v2:
No changes in patches apart from rebases, but now 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 core network subsystem 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 patches contain only generic net pieces. Other changes will be sent separately.

The patches are fully independent and can be cherry-picked separately.
The big patches, such as conversions for sock structure, need a very detailed
look from maintainers: refcount managing is quite complex in them and while
it seems that they would benefit from the change, extra checking is needed.
The biggest corner issue is the fact that refcount_inc() does not increment
from zero.

If there are no objections to the patches, please merge them via respective trees.

* The respective change is currently merged into -next as
  "locking/refcount: Create unchecked atomic_t implementation".
====================

Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
David S. Miller committed Jul 1, 2017
2 parents 574a602 + fb5c2c1 commit 0b58e6d
Show file tree
Hide file tree
Showing 105 changed files with 321 additions and 322 deletions.
2 changes: 1 addition & 1 deletion crypto/algif_aead.c
Original file line number Diff line number Diff line change
Expand Up @@ -877,7 +877,7 @@ static void aead_sock_destruct(struct sock *sk)
unsigned int ivlen = crypto_aead_ivsize(
crypto_aead_reqtfm(&ctx->aead_req));

WARN_ON(atomic_read(&sk->sk_refcnt) != 0);
WARN_ON(refcount_read(&sk->sk_refcnt) != 0);
aead_put_sgl(sk);
sock_kzfree_s(sk, ctx->iv, ivlen);
sock_kfree_s(sk, ctx, ctx->len);
Expand Down
12 changes: 1 addition & 11 deletions drivers/atm/fore200e.c
Original file line number Diff line number Diff line change
Expand Up @@ -924,12 +924,7 @@ fore200e_tx_irq(struct fore200e* fore200e)
else {
dev_kfree_skb_any(entry->skb);
}
#if 1
/* race fixed by the above incarnation mechanism, but... */
if (atomic_read(&sk_atm(vcc)->sk_wmem_alloc) < 0) {
atomic_set(&sk_atm(vcc)->sk_wmem_alloc, 0);
}
#endif

/* check error condition */
if (*entry->status & STATUS_ERROR)
atomic_inc(&vcc->stats->tx_err);
Expand Down Expand Up @@ -1130,13 +1125,9 @@ fore200e_push_rpd(struct fore200e* fore200e, struct atm_vcc* vcc, struct rpd* rp
return -ENOMEM;
}

ASSERT(atomic_read(&sk_atm(vcc)->sk_wmem_alloc) >= 0);

vcc->push(vcc, skb);
atomic_inc(&vcc->stats->rx);

ASSERT(atomic_read(&sk_atm(vcc)->sk_wmem_alloc) >= 0);

return 0;
}

Expand Down Expand Up @@ -1572,7 +1563,6 @@ fore200e_send(struct atm_vcc *vcc, struct sk_buff *skb)
unsigned long flags;

ASSERT(vcc);
ASSERT(atomic_read(&sk_atm(vcc)->sk_wmem_alloc) >= 0);
ASSERT(fore200e);
ASSERT(fore200e_vcc);

Expand Down
2 changes: 1 addition & 1 deletion drivers/atm/he.c
Original file line number Diff line number Diff line change
Expand Up @@ -2395,7 +2395,7 @@ he_close(struct atm_vcc *vcc)
* TBRQ, the host issues the close command to the adapter.
*/

while (((tx_inuse = atomic_read(&sk_atm(vcc)->sk_wmem_alloc)) > 1) &&
while (((tx_inuse = refcount_read(&sk_atm(vcc)->sk_wmem_alloc)) > 1) &&
(retry < MAX_RETRY)) {
msleep(sleep);
if (sleep < 250)
Expand Down
4 changes: 2 additions & 2 deletions drivers/atm/idt77252.c
Original file line number Diff line number Diff line change
Expand Up @@ -724,7 +724,7 @@ push_on_scq(struct idt77252_dev *card, struct vc_map *vc, struct sk_buff *skb)
struct sock *sk = sk_atm(vcc);

vc->estimator->cells += (skb->len + 47) / 48;
if (atomic_read(&sk->sk_wmem_alloc) >
if (refcount_read(&sk->sk_wmem_alloc) >
(sk->sk_sndbuf >> 1)) {
u32 cps = vc->estimator->maxcps;

Expand Down Expand Up @@ -2009,7 +2009,7 @@ idt77252_send_oam(struct atm_vcc *vcc, void *cell, int flags)
atomic_inc(&vcc->stats->tx_err);
return -ENOMEM;
}
atomic_add(skb->truesize, &sk_atm(vcc)->sk_wmem_alloc);
refcount_add(skb->truesize, &sk_atm(vcc)->sk_wmem_alloc);

skb_put_data(skb, cell, 52);

Expand Down
4 changes: 2 additions & 2 deletions drivers/infiniband/hw/nes/nes_cm.c
Original file line number Diff line number Diff line change
Expand Up @@ -742,7 +742,7 @@ int schedule_nes_timer(struct nes_cm_node *cm_node, struct sk_buff *skb,

if (type == NES_TIMER_TYPE_SEND) {
new_send->seq_num = ntohl(tcp_hdr(skb)->seq);
atomic_inc(&new_send->skb->users);
refcount_inc(&new_send->skb->users);
spin_lock_irqsave(&cm_node->retrans_list_lock, flags);
cm_node->send_entry = new_send;
add_ref_cm_node(cm_node);
Expand Down Expand Up @@ -924,7 +924,7 @@ static void nes_cm_timer_tick(unsigned long pass)
flags);
break;
}
atomic_inc(&send_entry->skb->users);
refcount_inc(&send_entry->skb->users);
cm_packets_retrans++;
nes_debug(NES_DBG_CM, "Retransmitting send_entry %p "
"for node %p, jiffies = %lu, time to send = "
Expand Down
2 changes: 1 addition & 1 deletion drivers/isdn/mISDN/socket.c
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,7 @@ mISDN_sock_recvmsg(struct socket *sock, struct msghdr *msg, size_t len,
copied = skb->len + MISDN_HEADER_LEN;
if (len < copied) {
if (flags & MSG_PEEK)
atomic_dec(&skb->users);
refcount_dec(&skb->users);
else
skb_queue_head(&sk->sk_receive_queue, skb);
return -ENOSPC;
Expand Down
2 changes: 1 addition & 1 deletion drivers/net/rionet.c
Original file line number Diff line number Diff line change
Expand Up @@ -201,7 +201,7 @@ static int rionet_start_xmit(struct sk_buff *skb, struct net_device *ndev)
rionet_queue_tx_msg(skb, ndev,
nets[rnet->mport->id].active[i]);
if (count)
atomic_inc(&skb->users);
refcount_inc(&skb->users);
count++;
}
} else if (RIONET_MAC_MATCH(eth->h_dest)) {
Expand Down
26 changes: 13 additions & 13 deletions drivers/s390/net/ctcm_main.c
Original file line number Diff line number Diff line change
Expand Up @@ -483,7 +483,7 @@ static int ctcm_transmit_skb(struct channel *ch, struct sk_buff *skb)
spin_unlock_irqrestore(&ch->collect_lock, saveflags);
return -EBUSY;
} else {
atomic_inc(&skb->users);
refcount_inc(&skb->users);
header.length = l;
header.type = be16_to_cpu(skb->protocol);
header.unused = 0;
Expand All @@ -500,7 +500,7 @@ static int ctcm_transmit_skb(struct channel *ch, struct sk_buff *skb)
* Protect skb against beeing free'd by upper
* layers.
*/
atomic_inc(&skb->users);
refcount_inc(&skb->users);
ch->prof.txlen += skb->len;
header.length = skb->len + LL_HEADER_LENGTH;
header.type = be16_to_cpu(skb->protocol);
Expand All @@ -517,14 +517,14 @@ static int ctcm_transmit_skb(struct channel *ch, struct sk_buff *skb)
if (hi) {
nskb = alloc_skb(skb->len, GFP_ATOMIC | GFP_DMA);
if (!nskb) {
atomic_dec(&skb->users);
refcount_dec(&skb->users);
skb_pull(skb, LL_HEADER_LENGTH + 2);
ctcm_clear_busy(ch->netdev);
return -ENOMEM;
} else {
skb_put_data(nskb, skb->data, skb->len);
atomic_inc(&nskb->users);
atomic_dec(&skb->users);
refcount_inc(&nskb->users);
refcount_dec(&skb->users);
dev_kfree_skb_irq(skb);
skb = nskb;
}
Expand All @@ -542,7 +542,7 @@ static int ctcm_transmit_skb(struct channel *ch, struct sk_buff *skb)
* Remove our header. It gets added
* again on retransmit.
*/
atomic_dec(&skb->users);
refcount_dec(&skb->users);
skb_pull(skb, LL_HEADER_LENGTH + 2);
ctcm_clear_busy(ch->netdev);
return -ENOMEM;
Expand All @@ -553,7 +553,7 @@ static int ctcm_transmit_skb(struct channel *ch, struct sk_buff *skb)
ch->ccw[1].count = skb->len;
skb_copy_from_linear_data(skb,
skb_put(ch->trans_skb, skb->len), skb->len);
atomic_dec(&skb->users);
refcount_dec(&skb->users);
dev_kfree_skb_irq(skb);
ccw_idx = 0;
} else {
Expand Down Expand Up @@ -679,7 +679,7 @@ static int ctcmpc_transmit_skb(struct channel *ch, struct sk_buff *skb)

if ((fsm_getstate(ch->fsm) != CTC_STATE_TXIDLE) || grp->in_sweep) {
spin_lock_irqsave(&ch->collect_lock, saveflags);
atomic_inc(&skb->users);
refcount_inc(&skb->users);
p_header = kmalloc(PDU_HEADER_LENGTH, gfp_type());

if (!p_header) {
Expand Down Expand Up @@ -716,7 +716,7 @@ static int ctcmpc_transmit_skb(struct channel *ch, struct sk_buff *skb)
* Protect skb against beeing free'd by upper
* layers.
*/
atomic_inc(&skb->users);
refcount_inc(&skb->users);

/*
* IDAL support in CTCM is broken, so we have to
Expand All @@ -729,8 +729,8 @@ static int ctcmpc_transmit_skb(struct channel *ch, struct sk_buff *skb)
goto nomem_exit;
} else {
skb_put_data(nskb, skb->data, skb->len);
atomic_inc(&nskb->users);
atomic_dec(&skb->users);
refcount_inc(&nskb->users);
refcount_dec(&skb->users);
dev_kfree_skb_irq(skb);
skb = nskb;
}
Expand Down Expand Up @@ -810,7 +810,7 @@ static int ctcmpc_transmit_skb(struct channel *ch, struct sk_buff *skb)
ch->trans_skb->len = 0;
ch->ccw[1].count = skb->len;
skb_put_data(ch->trans_skb, skb->data, skb->len);
atomic_dec(&skb->users);
refcount_dec(&skb->users);
dev_kfree_skb_irq(skb);
ccw_idx = 0;
CTCM_PR_DBGDATA("%s(%s): trans_skb len: %04x\n"
Expand Down Expand Up @@ -855,7 +855,7 @@ static int ctcmpc_transmit_skb(struct channel *ch, struct sk_buff *skb)
"%s(%s): MEMORY allocation ERROR\n",
CTCM_FUNTAIL, ch->id);
rc = -ENOMEM;
atomic_dec(&skb->users);
refcount_dec(&skb->users);
dev_kfree_skb_any(skb);
fsm_event(priv->mpcg->fsm, MPCG_EVENT_INOP, dev);
done:
Expand Down
10 changes: 5 additions & 5 deletions drivers/s390/net/netiucv.c
Original file line number Diff line number Diff line change
Expand Up @@ -743,7 +743,7 @@ static void conn_action_txdone(fsm_instance *fi, int event, void *arg)
conn->prof.tx_pending--;
if (single_flag) {
if ((skb = skb_dequeue(&conn->commit_queue))) {
atomic_dec(&skb->users);
refcount_dec(&skb->users);
if (privptr) {
privptr->stats.tx_packets++;
privptr->stats.tx_bytes +=
Expand All @@ -766,7 +766,7 @@ static void conn_action_txdone(fsm_instance *fi, int event, void *arg)
txbytes += skb->len;
txpackets++;
stat_maxcq++;
atomic_dec(&skb->users);
refcount_dec(&skb->users);
dev_kfree_skb_any(skb);
}
if (conn->collect_len > conn->prof.maxmulti)
Expand Down Expand Up @@ -958,7 +958,7 @@ static void netiucv_purge_skb_queue(struct sk_buff_head *q)
struct sk_buff *skb;

while ((skb = skb_dequeue(q))) {
atomic_dec(&skb->users);
refcount_dec(&skb->users);
dev_kfree_skb_any(skb);
}
}
Expand Down Expand Up @@ -1176,7 +1176,7 @@ static int netiucv_transmit_skb(struct iucv_connection *conn,
IUCV_DBF_TEXT(data, 2,
"EBUSY from netiucv_transmit_skb\n");
} else {
atomic_inc(&skb->users);
refcount_inc(&skb->users);
skb_queue_tail(&conn->collect_queue, skb);
conn->collect_len += l;
rc = 0;
Expand Down Expand Up @@ -1245,7 +1245,7 @@ static int netiucv_transmit_skb(struct iucv_connection *conn,
} else {
if (copied)
dev_kfree_skb(skb);
atomic_inc(&nskb->users);
refcount_inc(&nskb->users);
skb_queue_tail(&conn->commit_queue, nskb);
}
}
Expand Down
4 changes: 2 additions & 2 deletions drivers/s390/net/qeth_core_main.c
Original file line number Diff line number Diff line change
Expand Up @@ -1242,7 +1242,7 @@ static void qeth_release_skbs(struct qeth_qdio_out_buffer *buf)
iucv->sk_txnotify(skb, TX_NOTIFY_GENERALERROR);
}
}
atomic_dec(&skb->users);
refcount_dec(&skb->users);
dev_kfree_skb_any(skb);
skb = skb_dequeue(&buf->skb_list);
}
Expand Down Expand Up @@ -3975,7 +3975,7 @@ static inline int qeth_fill_buffer(struct qeth_qdio_out_q *queue,
int flush_cnt = 0, hdr_len, large_send = 0;

buffer = buf->buffer;
atomic_inc(&skb->users);
refcount_inc(&skb->users);
skb_queue_tail(&buf->skb_list, skb);

/*check first on TSO ....*/
Expand Down
2 changes: 1 addition & 1 deletion include/linux/atmdev.h
Original file line number Diff line number Diff line change
Expand Up @@ -254,7 +254,7 @@ static inline void atm_return(struct atm_vcc *vcc,int truesize)

static inline int atm_may_send(struct atm_vcc *vcc,unsigned int size)
{
return (size + atomic_read(&sk_atm(vcc)->sk_wmem_alloc)) <
return (size + refcount_read(&sk_atm(vcc)->sk_wmem_alloc)) <
sk_atm(vcc)->sk_sndbuf;
}

Expand Down
3 changes: 2 additions & 1 deletion include/linux/igmp.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
#include <linux/skbuff.h>
#include <linux/timer.h>
#include <linux/in.h>
#include <linux/refcount.h>
#include <uapi/linux/igmp.h>

static inline struct igmphdr *igmp_hdr(const struct sk_buff *skb)
Expand Down Expand Up @@ -84,7 +85,7 @@ struct ip_mc_list {
struct ip_mc_list __rcu *next_hash;
struct timer_list timer;
int users;
atomic_t refcnt;
refcount_t refcnt;
spinlock_t lock;
char tm_running;
char reporter;
Expand Down
11 changes: 6 additions & 5 deletions include/linux/inetdevice.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
#include <linux/timer.h>
#include <linux/sysctl.h>
#include <linux/rtnetlink.h>
#include <linux/refcount.h>

struct ipv4_devconf {
void *sysctl;
Expand All @@ -22,7 +23,7 @@ struct ipv4_devconf {

struct in_device {
struct net_device *dev;
atomic_t refcnt;
refcount_t refcnt;
int dead;
struct in_ifaddr *ifa_list; /* IP ifaddr chain */

Expand Down Expand Up @@ -219,7 +220,7 @@ static inline struct in_device *in_dev_get(const struct net_device *dev)
rcu_read_lock();
in_dev = __in_dev_get_rcu(dev);
if (in_dev)
atomic_inc(&in_dev->refcnt);
refcount_inc(&in_dev->refcnt);
rcu_read_unlock();
return in_dev;
}
Expand All @@ -240,12 +241,12 @@ void in_dev_finish_destroy(struct in_device *idev);

static inline void in_dev_put(struct in_device *idev)
{
if (atomic_dec_and_test(&idev->refcnt))
if (refcount_dec_and_test(&idev->refcnt))
in_dev_finish_destroy(idev);
}

#define __in_dev_put(idev) atomic_dec(&(idev)->refcnt)
#define in_dev_hold(idev) atomic_inc(&(idev)->refcnt)
#define __in_dev_put(idev) refcount_dec(&(idev)->refcnt)
#define in_dev_hold(idev) refcount_inc(&(idev)->refcnt)

#endif /* __KERNEL__ */

Expand Down
3 changes: 2 additions & 1 deletion include/linux/netpoll.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
#include <linux/interrupt.h>
#include <linux/rcupdate.h>
#include <linux/list.h>
#include <linux/refcount.h>

union inet_addr {
__u32 all[4];
Expand All @@ -34,7 +35,7 @@ struct netpoll {
};

struct netpoll_info {
atomic_t refcnt;
refcount_t refcnt;

struct semaphore dev_lock;

Expand Down
Loading

0 comments on commit 0b58e6d

Please sign in to comment.