diff mbox

[01/19] kernel: convert sighand_struct.count from atomic_t to refcount_t

Message ID 1487585948-6401-2-git-send-email-elena.reshetova@intel.com (mailing list archive)
State New, archived
Headers show

Commit Message

Reshetova, Elena Feb. 20, 2017, 10:18 a.m. UTC
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>
---
 fs/exec.c                 | 4 ++--
 include/linux/init_task.h | 2 +-
 include/linux/sched.h     | 3 ++-
 kernel/fork.c             | 8 ++++----
 4 files changed, 9 insertions(+), 8 deletions(-)

Comments

kernel test robot Feb. 20, 2017, 12:30 p.m. UTC | #1
Hi Elena,

[auto build test WARNING on next-20170220]
[cannot apply to linus/master linux/master tip/perf/core v4.9-rc8 v4.9-rc7 v4.9-rc6]
[if your patch is applied to the wrong git tree, please drop us a note to help improve the system]

url:    https://github.com/0day-ci/linux/commits/Elena-Reshetova/kernel-convert-sighand_struct-count-from-atomic_t-to-refcount_t/20170220-183434
config: blackfin-TCM-BF537_defconfig (attached as .config)
compiler: bfin-uclinux-gcc (GCC) 6.2.0
reproduce:
        wget https://git.kernel.org/cgit/linux/kernel/git/wfg/lkp-tests.git/plain/sbin/make.cross -O ~/bin/make.cross
        chmod +x ~/bin/make.cross
        # save the attached .config to linux build tree
        make.cross ARCH=blackfin 

All warnings (new ones prefixed by >>):

   In file included from include/asm-generic/bug.h:4:0,
                    from arch/blackfin/include/asm/bug.h:71,
                    from include/linux/bug.h:4,
                    from include/linux/mmdebug.h:4,
                    from include/linux/mm.h:8,
                    from fs/proc/task_nommu.c:2:
   fs/proc/task_nommu.c: In function 'task_mem':
   include/asm-generic/atomic.h:177:37: error: 'refcount_t {aka struct refcount_struct}' has no member named 'counter'
    #define atomic_read(v) READ_ONCE((v)->counter)
                                        ^
   include/linux/compiler.h:316:17: note: in definition of macro '__READ_ONCE'
     union { typeof(x) __val; char __c[1]; } __u;   \
                    ^
   include/asm-generic/atomic.h:177:24: note: in expansion of macro 'READ_ONCE'
    #define atomic_read(v) READ_ONCE((v)->counter)
                           ^~~~~~~~~
>> fs/proc/task_nommu.c:64:26: note: in expansion of macro 'atomic_read'
     if (current->sighand && atomic_read(&current->sighand->count) > 1)
                             ^~~~~~~~~~~
   include/asm-generic/atomic.h:177:37: error: 'refcount_t {aka struct refcount_struct}' has no member named 'counter'
    #define atomic_read(v) READ_ONCE((v)->counter)
                                        ^
   include/linux/compiler.h:318:22: note: in definition of macro '__READ_ONCE'
      __read_once_size(&(x), __u.__c, sizeof(x));  \
                         ^
   include/asm-generic/atomic.h:177:24: note: in expansion of macro 'READ_ONCE'
    #define atomic_read(v) READ_ONCE((v)->counter)
                           ^~~~~~~~~
>> fs/proc/task_nommu.c:64:26: note: in expansion of macro 'atomic_read'
     if (current->sighand && atomic_read(&current->sighand->count) > 1)
                             ^~~~~~~~~~~
   include/asm-generic/atomic.h:177:37: error: 'refcount_t {aka struct refcount_struct}' has no member named 'counter'
    #define atomic_read(v) READ_ONCE((v)->counter)
                                        ^
   include/linux/compiler.h:318:42: note: in definition of macro '__READ_ONCE'
      __read_once_size(&(x), __u.__c, sizeof(x));  \
                                             ^
   include/asm-generic/atomic.h:177:24: note: in expansion of macro 'READ_ONCE'
    #define atomic_read(v) READ_ONCE((v)->counter)
                           ^~~~~~~~~
>> fs/proc/task_nommu.c:64:26: note: in expansion of macro 'atomic_read'
     if (current->sighand && atomic_read(&current->sighand->count) > 1)
                             ^~~~~~~~~~~
   include/asm-generic/atomic.h:177:37: error: 'refcount_t {aka struct refcount_struct}' has no member named 'counter'
    #define atomic_read(v) READ_ONCE((v)->counter)
                                        ^
   include/linux/compiler.h:320:30: note: in definition of macro '__READ_ONCE'
      __read_once_size_nocheck(&(x), __u.__c, sizeof(x)); \
                                 ^
   include/asm-generic/atomic.h:177:24: note: in expansion of macro 'READ_ONCE'
    #define atomic_read(v) READ_ONCE((v)->counter)
                           ^~~~~~~~~
>> fs/proc/task_nommu.c:64:26: note: in expansion of macro 'atomic_read'
     if (current->sighand && atomic_read(&current->sighand->count) > 1)
                             ^~~~~~~~~~~
   include/asm-generic/atomic.h:177:37: error: 'refcount_t {aka struct refcount_struct}' has no member named 'counter'
    #define atomic_read(v) READ_ONCE((v)->counter)
                                        ^
   include/linux/compiler.h:320:50: note: in definition of macro '__READ_ONCE'
      __read_once_size_nocheck(&(x), __u.__c, sizeof(x)); \
                                                     ^
   include/asm-generic/atomic.h:177:24: note: in expansion of macro 'READ_ONCE'
    #define atomic_read(v) READ_ONCE((v)->counter)
                           ^~~~~~~~~
>> fs/proc/task_nommu.c:64:26: note: in expansion of macro 'atomic_read'
     if (current->sighand && atomic_read(&current->sighand->count) > 1)
                             ^~~~~~~~~~~

vim +/atomic_read +64 fs/proc/task_nommu.c

^1da177e Linus Torvalds    2005-04-16  48  
^1da177e Linus Torvalds    2005-04-16  49  	if (atomic_read(&mm->mm_count) > 1)
^1da177e Linus Torvalds    2005-04-16  50  		sbytes += kobjsize(mm);
^1da177e Linus Torvalds    2005-04-16  51  	else
^1da177e Linus Torvalds    2005-04-16  52  		bytes += kobjsize(mm);
^1da177e Linus Torvalds    2005-04-16  53  	
498052bb Al Viro           2009-03-30  54  	if (current->fs && current->fs->users > 1)
^1da177e Linus Torvalds    2005-04-16  55  		sbytes += kobjsize(current->fs);
^1da177e Linus Torvalds    2005-04-16  56  	else
^1da177e Linus Torvalds    2005-04-16  57  		bytes += kobjsize(current->fs);
^1da177e Linus Torvalds    2005-04-16  58  
^1da177e Linus Torvalds    2005-04-16  59  	if (current->files && atomic_read(&current->files->count) > 1)
^1da177e Linus Torvalds    2005-04-16  60  		sbytes += kobjsize(current->files);
^1da177e Linus Torvalds    2005-04-16  61  	else
^1da177e Linus Torvalds    2005-04-16  62  		bytes += kobjsize(current->files);
^1da177e Linus Torvalds    2005-04-16  63  
^1da177e Linus Torvalds    2005-04-16 @64  	if (current->sighand && atomic_read(&current->sighand->count) > 1)
^1da177e Linus Torvalds    2005-04-16  65  		sbytes += kobjsize(current->sighand);
^1da177e Linus Torvalds    2005-04-16  66  	else
^1da177e Linus Torvalds    2005-04-16  67  		bytes += kobjsize(current->sighand);
^1da177e Linus Torvalds    2005-04-16  68  
^1da177e Linus Torvalds    2005-04-16  69  	bytes += kobjsize(current); /* includes kernel stack */
^1da177e Linus Torvalds    2005-04-16  70  
df5f8314 Eric W. Biederman 2008-02-08  71  	seq_printf(m,
^1da177e Linus Torvalds    2005-04-16  72  		"Mem:\t%8lu bytes\n"

:::::: The code at line 64 was first introduced by commit
:::::: 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 Linux-2.6.12-rc2

:::::: TO: Linus Torvalds <torvalds@ppc970.osdl.org>
:::::: CC: Linus Torvalds <torvalds@ppc970.osdl.org>

---
0-DAY kernel test infrastructure                Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all                   Intel Corporation
kernel test robot Feb. 20, 2017, 12:42 p.m. UTC | #2
Hi Elena,

[auto build test ERROR on next-20170220]
[cannot apply to linus/master linux/master tip/perf/core v4.9-rc8 v4.9-rc7 v4.9-rc6]
[if your patch is applied to the wrong git tree, please drop us a note to help improve the system]

url:    https://github.com/0day-ci/linux/commits/Elena-Reshetova/kernel-convert-sighand_struct-count-from-atomic_t-to-refcount_t/20170220-183434
config: blackfin-BF561-EZKIT-SMP_defconfig (attached as .config)
compiler: bfin-uclinux-gcc (GCC) 6.2.0
reproduce:
        wget https://git.kernel.org/cgit/linux/kernel/git/wfg/lkp-tests.git/plain/sbin/make.cross -O ~/bin/make.cross
        chmod +x ~/bin/make.cross
        # save the attached .config to linux build tree
        make.cross ARCH=blackfin 

All errors (new ones prefixed by >>):

   In file included from include/linux/atomic.h:4:0,
                    from arch/blackfin/include/asm/spinlock.h:14,
                    from include/linux/spinlock.h:87,
                    from include/linux/mmzone.h:7,
                    from include/linux/gfp.h:5,
                    from include/linux/mm.h:9,
                    from fs/proc/task_nommu.c:2:
   fs/proc/task_nommu.c: In function 'task_mem':
>> arch/blackfin/include/asm/atomic.h:27:53: error: 'refcount_t {aka struct refcount_struct}' has no member named 'counter'
    #define atomic_read(v) __raw_uncached_fetch_asm(&(v)->counter)
                                                        ^
   fs/proc/task_nommu.c:64:26: note: in expansion of macro 'atomic_read'
     if (current->sighand && atomic_read(&current->sighand->count) > 1)
                             ^~~~~~~~~~~

vim +27 arch/blackfin/include/asm/atomic.h

d835b6c4 arch/blackfin/include/asm/atomic.h Peter Zijlstra 2015-04-23  21  
d835b6c4 arch/blackfin/include/asm/atomic.h Peter Zijlstra 2015-04-23  22  asmlinkage int __raw_atomic_and_asm(volatile int *ptr, int value);
d835b6c4 arch/blackfin/include/asm/atomic.h Peter Zijlstra 2015-04-23  23  asmlinkage int __raw_atomic_or_asm(volatile int *ptr, int value);
6b3087c6 arch/blackfin/include/asm/atomic.h Graf Yang      2009-01-07  24  asmlinkage int __raw_atomic_xor_asm(volatile int *ptr, int value);
6b3087c6 arch/blackfin/include/asm/atomic.h Graf Yang      2009-01-07  25  asmlinkage int __raw_atomic_test_asm(const volatile int *ptr, int value);
6b3087c6 arch/blackfin/include/asm/atomic.h Graf Yang      2009-01-07  26  
ae41f32e arch/blackfin/include/asm/atomic.h Mike Frysinger 2011-06-17 @27  #define atomic_read(v) __raw_uncached_fetch_asm(&(v)->counter)
1394f032 include/asm-blackfin/atomic.h      Bryan Wu       2007-05-06  28  
d835b6c4 arch/blackfin/include/asm/atomic.h Peter Zijlstra 2015-04-23  29  #define atomic_add_return(i, v) __raw_atomic_add_asm(&(v)->counter, i)
d835b6c4 arch/blackfin/include/asm/atomic.h Peter Zijlstra 2015-04-23  30  #define atomic_sub_return(i, v) __raw_atomic_add_asm(&(v)->counter, -(i))

:::::: The code at line 27 was first introduced by commit
:::::: ae41f32e16d8e87c84cb910a6a6aefb50318894d Blackfin: SMP: convert to common asm-generic/atomic.h

:::::: TO: Mike Frysinger <vapier@gentoo.org>
:::::: CC: Mike Frysinger <vapier@gentoo.org>

---
0-DAY kernel test infrastructure                Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all                   Intel Corporation
diff mbox

Patch

diff --git a/fs/exec.c b/fs/exec.c
index 698a860..3f78ff2 100644
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -1174,7 +1174,7 @@  static int de_thread(struct task_struct *tsk)
 	flush_itimer_signals();
 #endif
 
-	if (atomic_read(&oldsighand->count) != 1) {
+	if (refcount_read(&oldsighand->count) != 1) {
 		struct sighand_struct *newsighand;
 		/*
 		 * This ->sighand is shared with the CLONE_SIGHAND
@@ -1184,7 +1184,7 @@  static int de_thread(struct task_struct *tsk)
 		if (!newsighand)
 			return -ENOMEM;
 
-		atomic_set(&newsighand->count, 1);
+		refcount_set(&newsighand->count, 1);
 		memcpy(newsighand->action, oldsighand->action,
 		       sizeof(newsighand->action));
 
diff --git a/include/linux/init_task.h b/include/linux/init_task.h
index 3a85d61..1f160b2 100644
--- a/include/linux/init_task.h
+++ b/include/linux/init_task.h
@@ -82,7 +82,7 @@  extern struct fs_struct init_fs;
 extern struct nsproxy init_nsproxy;
 
 #define INIT_SIGHAND(sighand) {						\
-	.count		= ATOMIC_INIT(1), 				\
+	.count		= REFCOUNT_INIT(1), 				\
 	.action		= { { { .sa_handler = SIG_DFL, } }, },		\
 	.siglock	= __SPIN_LOCK_UNLOCKED(sighand.siglock),	\
 	.signalfd_wqh	= __WAIT_QUEUE_HEAD_INITIALIZER(sighand.signalfd_wqh),	\
diff --git a/include/linux/sched.h b/include/linux/sched.h
index 0f0d497..a0430aa 100644
--- a/include/linux/sched.h
+++ b/include/linux/sched.h
@@ -42,6 +42,7 @@  struct sched_param {
 #include <linux/seccomp.h>
 #include <linux/rcupdate.h>
 #include <linux/rculist.h>
+#include <linux/refcount.h>
 #include <linux/rtmutex.h>
 
 #include <linux/time.h>
@@ -527,7 +528,7 @@  static inline int get_dumpable(struct mm_struct *mm)
 #define MMF_INIT_MASK		(MMF_DUMPABLE_MASK | MMF_DUMP_FILTER_MASK)
 
 struct sighand_struct {
-	atomic_t		count;
+	refcount_t		count;
 	struct k_sigaction	action[_NSIG];
 	spinlock_t		siglock;
 	wait_queue_head_t	signalfd_wqh;
diff --git a/kernel/fork.c b/kernel/fork.c
index e96e256..9488f01 100644
--- a/kernel/fork.c
+++ b/kernel/fork.c
@@ -1285,7 +1285,7 @@  static int copy_sighand(unsigned long clone_flags, struct task_struct *tsk)
 	struct sighand_struct *sig;
 
 	if (clone_flags & CLONE_SIGHAND) {
-		atomic_inc(&current->sighand->count);
+		refcount_inc(&current->sighand->count);
 		return 0;
 	}
 	sig = kmem_cache_alloc(sighand_cachep, GFP_KERNEL);
@@ -1293,14 +1293,14 @@  static int copy_sighand(unsigned long clone_flags, struct task_struct *tsk)
 	if (!sig)
 		return -ENOMEM;
 
-	atomic_set(&sig->count, 1);
+	refcount_set(&sig->count, 1);
 	memcpy(sig->action, current->sighand->action, sizeof(sig->action));
 	return 0;
 }
 
 void __cleanup_sighand(struct sighand_struct *sighand)
 {
-	if (atomic_dec_and_test(&sighand->count)) {
+	if (refcount_dec_and_test(&sighand->count)) {
 		signalfd_cleanup(sighand);
 		/*
 		 * sighand_cachep is SLAB_DESTROY_BY_RCU so we can free it
@@ -2170,7 +2170,7 @@  static int check_unshare_flags(unsigned long unshare_flags)
 			return -EINVAL;
 	}
 	if (unshare_flags & (CLONE_SIGHAND | CLONE_VM)) {
-		if (atomic_read(&current->sighand->count) > 1)
+		if (refcount_read(&current->sighand->count) > 1)
 			return -EINVAL;
 	}
 	if (unshare_flags & CLONE_VM) {