Skip to content

Commit 14afee4

Browse files
ereshetovadavem330
authored andcommitted
net: convert sock.sk_wmem_alloc from atomic_t to refcount_t
refcount_t type and corresponding API should be used instead of atomic_t when the variable is used as a reference counter. This allows to avoid accidental refcounter overflows that might lead to use-after-free situations. Signed-off-by: Elena Reshetova <[email protected]> Signed-off-by: Hans Liljestrand <[email protected]> Signed-off-by: Kees Cook <[email protected]> Signed-off-by: David Windsor <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 2638595 commit 14afee4

37 files changed

+74
-85
lines changed

drivers/atm/fore200e.c

Lines changed: 1 addition & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -924,12 +924,7 @@ fore200e_tx_irq(struct fore200e* fore200e)
924924
else {
925925
dev_kfree_skb_any(entry->skb);
926926
}
927-
#if 1
928-
/* race fixed by the above incarnation mechanism, but... */
929-
if (atomic_read(&sk_atm(vcc)->sk_wmem_alloc) < 0) {
930-
atomic_set(&sk_atm(vcc)->sk_wmem_alloc, 0);
931-
}
932-
#endif
927+
933928
/* check error condition */
934929
if (*entry->status & STATUS_ERROR)
935930
atomic_inc(&vcc->stats->tx_err);
@@ -1130,13 +1125,9 @@ fore200e_push_rpd(struct fore200e* fore200e, struct atm_vcc* vcc, struct rpd* rp
11301125
return -ENOMEM;
11311126
}
11321127

1133-
ASSERT(atomic_read(&sk_atm(vcc)->sk_wmem_alloc) >= 0);
1134-
11351128
vcc->push(vcc, skb);
11361129
atomic_inc(&vcc->stats->rx);
11371130

1138-
ASSERT(atomic_read(&sk_atm(vcc)->sk_wmem_alloc) >= 0);
1139-
11401131
return 0;
11411132
}
11421133

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

15741565
ASSERT(vcc);
1575-
ASSERT(atomic_read(&sk_atm(vcc)->sk_wmem_alloc) >= 0);
15761566
ASSERT(fore200e);
15771567
ASSERT(fore200e_vcc);
15781568

drivers/atm/he.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2395,7 +2395,7 @@ he_close(struct atm_vcc *vcc)
23952395
* TBRQ, the host issues the close command to the adapter.
23962396
*/
23972397

2398-
while (((tx_inuse = atomic_read(&sk_atm(vcc)->sk_wmem_alloc)) > 1) &&
2398+
while (((tx_inuse = refcount_read(&sk_atm(vcc)->sk_wmem_alloc)) > 1) &&
23992399
(retry < MAX_RETRY)) {
24002400
msleep(sleep);
24012401
if (sleep < 250)

drivers/atm/idt77252.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -724,7 +724,7 @@ push_on_scq(struct idt77252_dev *card, struct vc_map *vc, struct sk_buff *skb)
724724
struct sock *sk = sk_atm(vcc);
725725

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

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

20142014
skb_put_data(skb, cell, 52);
20152015

include/linux/atmdev.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -254,7 +254,7 @@ static inline void atm_return(struct atm_vcc *vcc,int truesize)
254254

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

include/net/sock.h

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -390,7 +390,7 @@ struct sock {
390390

391391
/* ===== cache line for TX ===== */
392392
int sk_wmem_queued;
393-
atomic_t sk_wmem_alloc;
393+
refcount_t sk_wmem_alloc;
394394
unsigned long sk_tsq_flags;
395395
struct sk_buff *sk_send_head;
396396
struct sk_buff_head sk_write_queue;
@@ -1911,7 +1911,7 @@ static inline int skb_copy_to_page_nocache(struct sock *sk, struct iov_iter *fro
19111911
*/
19121912
static inline int sk_wmem_alloc_get(const struct sock *sk)
19131913
{
1914-
return atomic_read(&sk->sk_wmem_alloc) - 1;
1914+
return refcount_read(&sk->sk_wmem_alloc) - 1;
19151915
}
19161916

19171917
/**
@@ -2055,7 +2055,7 @@ static inline unsigned long sock_wspace(struct sock *sk)
20552055
int amt = 0;
20562056

20572057
if (!(sk->sk_shutdown & SEND_SHUTDOWN)) {
2058-
amt = sk->sk_sndbuf - atomic_read(&sk->sk_wmem_alloc);
2058+
amt = sk->sk_sndbuf - refcount_read(&sk->sk_wmem_alloc);
20592059
if (amt < 0)
20602060
amt = 0;
20612061
}
@@ -2136,7 +2136,7 @@ bool sk_page_frag_refill(struct sock *sk, struct page_frag *pfrag);
21362136
*/
21372137
static inline bool sock_writeable(const struct sock *sk)
21382138
{
2139-
return atomic_read(&sk->sk_wmem_alloc) < (sk->sk_sndbuf >> 1);
2139+
return refcount_read(&sk->sk_wmem_alloc) < (sk->sk_sndbuf >> 1);
21402140
}
21412141

21422142
static inline gfp_t gfp_any(void)

net/atm/br2684.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -252,7 +252,7 @@ static int br2684_xmit_vcc(struct sk_buff *skb, struct net_device *dev,
252252

253253
ATM_SKB(skb)->vcc = atmvcc = brvcc->atmvcc;
254254
pr_debug("atm_skb(%p)->vcc(%p)->dev(%p)\n", skb, atmvcc, atmvcc->dev);
255-
atomic_add(skb->truesize, &sk_atm(atmvcc)->sk_wmem_alloc);
255+
refcount_add(skb->truesize, &sk_atm(atmvcc)->sk_wmem_alloc);
256256
ATM_SKB(skb)->atm_options = atmvcc->atm_options;
257257
dev->stats.tx_packets++;
258258
dev->stats.tx_bytes += skb->len;

net/atm/clip.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -381,7 +381,7 @@ static netdev_tx_t clip_start_xmit(struct sk_buff *skb,
381381
memcpy(here, llc_oui, sizeof(llc_oui));
382382
((__be16 *) here)[3] = skb->protocol;
383383
}
384-
atomic_add(skb->truesize, &sk_atm(vcc)->sk_wmem_alloc);
384+
refcount_add(skb->truesize, &sk_atm(vcc)->sk_wmem_alloc);
385385
ATM_SKB(skb)->atm_options = vcc->atm_options;
386386
entry->vccs->last_use = jiffies;
387387
pr_debug("atm_skb(%p)->vcc(%p)->dev(%p)\n", skb, vcc, vcc->dev);

net/atm/common.c

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -80,9 +80,9 @@ static void vcc_sock_destruct(struct sock *sk)
8080
printk(KERN_DEBUG "%s: rmem leakage (%d bytes) detected.\n",
8181
__func__, atomic_read(&sk->sk_rmem_alloc));
8282

83-
if (atomic_read(&sk->sk_wmem_alloc))
83+
if (refcount_read(&sk->sk_wmem_alloc))
8484
printk(KERN_DEBUG "%s: wmem leakage (%d bytes) detected.\n",
85-
__func__, atomic_read(&sk->sk_wmem_alloc));
85+
__func__, refcount_read(&sk->sk_wmem_alloc));
8686
}
8787

8888
static void vcc_def_wakeup(struct sock *sk)
@@ -101,7 +101,7 @@ static inline int vcc_writable(struct sock *sk)
101101
struct atm_vcc *vcc = atm_sk(sk);
102102

103103
return (vcc->qos.txtp.max_sdu +
104-
atomic_read(&sk->sk_wmem_alloc)) <= sk->sk_sndbuf;
104+
refcount_read(&sk->sk_wmem_alloc)) <= sk->sk_sndbuf;
105105
}
106106

107107
static void vcc_write_space(struct sock *sk)
@@ -156,7 +156,7 @@ int vcc_create(struct net *net, struct socket *sock, int protocol, int family, i
156156
memset(&vcc->local, 0, sizeof(struct sockaddr_atmsvc));
157157
memset(&vcc->remote, 0, sizeof(struct sockaddr_atmsvc));
158158
vcc->qos.txtp.max_sdu = 1 << 16; /* for meta VCs */
159-
atomic_set(&sk->sk_wmem_alloc, 1);
159+
refcount_set(&sk->sk_wmem_alloc, 1);
160160
atomic_set(&sk->sk_rmem_alloc, 0);
161161
vcc->push = NULL;
162162
vcc->pop = NULL;
@@ -630,7 +630,7 @@ int vcc_sendmsg(struct socket *sock, struct msghdr *m, size_t size)
630630
goto out;
631631
}
632632
pr_debug("%d += %d\n", sk_wmem_alloc_get(sk), skb->truesize);
633-
atomic_add(skb->truesize, &sk->sk_wmem_alloc);
633+
refcount_add(skb->truesize, &sk->sk_wmem_alloc);
634634

635635
skb->dev = NULL; /* for paths shared with net_device interfaces */
636636
ATM_SKB(skb)->atm_options = vcc->atm_options;

net/atm/lec.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -181,7 +181,7 @@ lec_send(struct atm_vcc *vcc, struct sk_buff *skb)
181181
ATM_SKB(skb)->vcc = vcc;
182182
ATM_SKB(skb)->atm_options = vcc->atm_options;
183183

184-
atomic_add(skb->truesize, &sk_atm(vcc)->sk_wmem_alloc);
184+
refcount_add(skb->truesize, &sk_atm(vcc)->sk_wmem_alloc);
185185
if (vcc->send(vcc, skb) < 0) {
186186
dev->stats.tx_dropped++;
187187
return;
@@ -345,7 +345,7 @@ static int lec_atm_send(struct atm_vcc *vcc, struct sk_buff *skb)
345345
int i;
346346
char *tmp; /* FIXME */
347347

348-
atomic_sub(skb->truesize, &sk_atm(vcc)->sk_wmem_alloc);
348+
WARN_ON(refcount_sub_and_test(skb->truesize, &sk_atm(vcc)->sk_wmem_alloc));
349349
mesg = (struct atmlec_msg *)skb->data;
350350
tmp = skb->data;
351351
tmp += sizeof(struct atmlec_msg);

net/atm/mpc.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -555,7 +555,7 @@ static int send_via_shortcut(struct sk_buff *skb, struct mpoa_client *mpc)
555555
sizeof(struct llc_snap_hdr));
556556
}
557557

558-
atomic_add(skb->truesize, &sk_atm(entry->shortcut)->sk_wmem_alloc);
558+
refcount_add(skb->truesize, &sk_atm(entry->shortcut)->sk_wmem_alloc);
559559
ATM_SKB(skb)->atm_options = entry->shortcut->atm_options;
560560
entry->shortcut->send(entry->shortcut, skb);
561561
entry->packets_fwded++;
@@ -911,7 +911,7 @@ static int msg_from_mpoad(struct atm_vcc *vcc, struct sk_buff *skb)
911911

912912
struct mpoa_client *mpc = find_mpc_by_vcc(vcc);
913913
struct k_message *mesg = (struct k_message *)skb->data;
914-
atomic_sub(skb->truesize, &sk_atm(vcc)->sk_wmem_alloc);
914+
WARN_ON(refcount_sub_and_test(skb->truesize, &sk_atm(vcc)->sk_wmem_alloc));
915915

916916
if (mpc == NULL) {
917917
pr_info("no mpc found\n");

0 commit comments

Comments
 (0)