Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

net: convert sk_buff_fclones.fclone_ref 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 <elena.reshetova@intel.com>
Signed-off-by: Hans Liljestrand <ishkamiel@gmail.com>
Signed-off-by: Kees Cook <keescook@chromium.org>
Signed-off-by: David Windsor <dwindsor@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>

authored by

Reshetova, Elena and committed by
David S. Miller
2638595a 63354797

+7 -7
+2 -2
include/linux/skbuff.h
··· 915 915 916 916 struct sk_buff skb2; 917 917 918 - atomic_t fclone_ref; 918 + refcount_t fclone_ref; 919 919 }; 920 920 921 921 /** ··· 935 935 fclones = container_of(skb, struct sk_buff_fclones, skb1); 936 936 937 937 return skb->fclone == SKB_FCLONE_ORIG && 938 - atomic_read(&fclones->fclone_ref) > 1 && 938 + refcount_read(&fclones->fclone_ref) > 1 && 939 939 fclones->skb2.sk == sk; 940 940 } 941 941
+5 -5
net/core/skbuff.c
··· 268 268 269 269 kmemcheck_annotate_bitfield(&fclones->skb2, flags1); 270 270 skb->fclone = SKB_FCLONE_ORIG; 271 - atomic_set(&fclones->fclone_ref, 1); 271 + refcount_set(&fclones->fclone_ref, 1); 272 272 273 273 fclones->skb2.fclone = SKB_FCLONE_CLONE; 274 274 } ··· 629 629 * This test would have no chance to be true for the clone, 630 630 * while here, branch prediction will be good. 631 631 */ 632 - if (atomic_read(&fclones->fclone_ref) == 1) 632 + if (refcount_read(&fclones->fclone_ref) == 1) 633 633 goto fastpath; 634 634 break; 635 635 ··· 637 637 fclones = container_of(skb, struct sk_buff_fclones, skb2); 638 638 break; 639 639 } 640 - if (!atomic_dec_and_test(&fclones->fclone_ref)) 640 + if (!refcount_dec_and_test(&fclones->fclone_ref)) 641 641 return; 642 642 fastpath: 643 643 kmem_cache_free(skbuff_fclone_cache, fclones); ··· 1027 1027 return NULL; 1028 1028 1029 1029 if (skb->fclone == SKB_FCLONE_ORIG && 1030 - atomic_read(&fclones->fclone_ref) == 1) { 1030 + refcount_read(&fclones->fclone_ref) == 1) { 1031 1031 n = &fclones->skb2; 1032 - atomic_set(&fclones->fclone_ref, 2); 1032 + refcount_set(&fclones->fclone_ref, 2); 1033 1033 } else { 1034 1034 if (skb_pfmemalloc(skb)) 1035 1035 gfp_mask |= __GFP_MEMALLOC;