diff options
Diffstat (limited to 'lib')
-rw-r--r-- | lib/Kconfig.debug | 15 | ||||
-rw-r--r-- | lib/is_single_threaded.c | 61 |
2 files changed, 52 insertions, 24 deletions
diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug index 12327b2bb785..fbb87cf138c5 100644 --- a/lib/Kconfig.debug +++ b/lib/Kconfig.debug | |||
@@ -653,6 +653,21 @@ config DEBUG_NOTIFIERS | |||
653 | This is a relatively cheap check but if you care about maximum | 653 | This is a relatively cheap check but if you care about maximum |
654 | performance, say N. | 654 | performance, say N. |
655 | 655 | ||
656 | config DEBUG_CREDENTIALS | ||
657 | bool "Debug credential management" | ||
658 | depends on DEBUG_KERNEL | ||
659 | help | ||
660 | Enable this to turn on some debug checking for credential | ||
661 | management. The additional code keeps track of the number of | ||
662 | pointers from task_structs to any given cred struct, and checks to | ||
663 | see that this number never exceeds the usage count of the cred | ||
664 | struct. | ||
665 | |||
666 | Furthermore, if SELinux is enabled, this also checks that the | ||
667 | security pointer in the cred struct is never seen to be invalid. | ||
668 | |||
669 | If unsure, say N. | ||
670 | |||
656 | # | 671 | # |
657 | # Select this config option from the architecture Kconfig, if it | 672 | # Select this config option from the architecture Kconfig, if it |
658 | # it is preferred to always offer frame pointers as a config | 673 | # it is preferred to always offer frame pointers as a config |
diff --git a/lib/is_single_threaded.c b/lib/is_single_threaded.c index f1ed2fe76c65..bd2bea963364 100644 --- a/lib/is_single_threaded.c +++ b/lib/is_single_threaded.c | |||
@@ -12,34 +12,47 @@ | |||
12 | 12 | ||
13 | #include <linux/sched.h> | 13 | #include <linux/sched.h> |
14 | 14 | ||
15 | /** | 15 | /* |
16 | * is_single_threaded - Determine if a thread group is single-threaded or not | 16 | * Returns true if the task does not share ->mm with another thread/process. |
17 | * @p: A task in the thread group in question | ||
18 | * | ||
19 | * This returns true if the thread group to which a task belongs is single | ||
20 | * threaded, false if it is not. | ||
21 | */ | 17 | */ |
22 | bool is_single_threaded(struct task_struct *p) | 18 | bool current_is_single_threaded(void) |
23 | { | 19 | { |
24 | struct task_struct *g, *t; | 20 | struct task_struct *task = current; |
25 | struct mm_struct *mm = p->mm; | 21 | struct mm_struct *mm = task->mm; |
22 | struct task_struct *p, *t; | ||
23 | bool ret; | ||
26 | 24 | ||
27 | if (atomic_read(&p->signal->count) != 1) | 25 | if (atomic_read(&task->signal->live) != 1) |
28 | goto no; | 26 | return false; |
29 | 27 | ||
30 | if (atomic_read(&p->mm->mm_users) != 1) { | 28 | if (atomic_read(&mm->mm_users) == 1) |
31 | read_lock(&tasklist_lock); | 29 | return true; |
32 | do_each_thread(g, t) { | ||
33 | if (t->mm == mm && t != p) | ||
34 | goto no_unlock; | ||
35 | } while_each_thread(g, t); | ||
36 | read_unlock(&tasklist_lock); | ||
37 | } | ||
38 | 30 | ||
39 | return true; | 31 | ret = false; |
32 | rcu_read_lock(); | ||
33 | for_each_process(p) { | ||
34 | if (unlikely(p->flags & PF_KTHREAD)) | ||
35 | continue; | ||
36 | if (unlikely(p == task->group_leader)) | ||
37 | continue; | ||
38 | |||
39 | t = p; | ||
40 | do { | ||
41 | if (unlikely(t->mm == mm)) | ||
42 | goto found; | ||
43 | if (likely(t->mm)) | ||
44 | break; | ||
45 | /* | ||
46 | * t->mm == NULL. Make sure next_thread/next_task | ||
47 | * will see other CLONE_VM tasks which might be | ||
48 | * forked before exiting. | ||
49 | */ | ||
50 | smp_rmb(); | ||
51 | } while_each_thread(p, t); | ||
52 | } | ||
53 | ret = true; | ||
54 | found: | ||
55 | rcu_read_unlock(); | ||
40 | 56 | ||
41 | no_unlock: | 57 | return ret; |
42 | read_unlock(&tasklist_lock); | ||
43 | no: | ||
44 | return false; | ||
45 | } | 58 | } |