Commit 93b69d437effff11b1c37f330d3265c37ec2f84b

Authored by Kees Cook
1 parent b566650270

Yama: add RCU to drop read locking

Stop using spinlocks in the read path. Add RCU list to handle the readers.

Signed-off-by: Kees Cook <keescook@chromium.org>
Reviewed-by: Serge E. Hallyn <serge.hallyn@ubuntu.com>
Acked-by: John Johansen <john.johansen@canonical.com>

Showing 1 changed file with 24 additions and 23 deletions Side-by-side Diff

security/yama/yama_lsm.c
... ... @@ -30,6 +30,7 @@
30 30 struct task_struct *tracer;
31 31 struct task_struct *tracee;
32 32 struct list_head node;
  33 + struct rcu_head rcu;
33 34 };
34 35  
35 36 static LIST_HEAD(ptracer_relations);
36 37  
37 38  
38 39  
39 40  
40 41  
41 42  
... ... @@ -48,32 +49,31 @@
48 49 static int yama_ptracer_add(struct task_struct *tracer,
49 50 struct task_struct *tracee)
50 51 {
51   - int rc = 0;
52   - struct ptrace_relation *added;
53   - struct ptrace_relation *entry, *relation = NULL;
  52 + struct ptrace_relation *relation, *added;
54 53  
55 54 added = kmalloc(sizeof(*added), GFP_KERNEL);
56 55 if (!added)
57 56 return -ENOMEM;
58 57  
  58 + added->tracee = tracee;
  59 + added->tracer = tracer;
  60 +
59 61 spin_lock_bh(&ptracer_relations_lock);
60   - list_for_each_entry(entry, &ptracer_relations, node)
61   - if (entry->tracee == tracee) {
62   - relation = entry;
63   - break;
  62 + rcu_read_lock();
  63 + list_for_each_entry_rcu(relation, &ptracer_relations, node) {
  64 + if (relation->tracee == tracee) {
  65 + list_replace_rcu(&relation->node, &added->node);
  66 + kfree_rcu(relation, rcu);
  67 + goto out;
64 68 }
65   - if (!relation) {
66   - relation = added;
67   - relation->tracee = tracee;
68   - list_add(&relation->node, &ptracer_relations);
69 69 }
70   - relation->tracer = tracer;
71 70  
72   - spin_unlock_bh(&ptracer_relations_lock);
73   - if (added != relation)
74   - kfree(added);
  71 + list_add_rcu(&added->node, &ptracer_relations);
75 72  
76   - return rc;
  73 +out:
  74 + rcu_read_unlock();
  75 + spin_unlock_bh(&ptracer_relations_lock);
  76 + return 0;
77 77 }
78 78  
79 79 /**
80 80  
81 81  
82 82  
... ... @@ -84,15 +84,18 @@
84 84 static void yama_ptracer_del(struct task_struct *tracer,
85 85 struct task_struct *tracee)
86 86 {
87   - struct ptrace_relation *relation, *safe;
  87 + struct ptrace_relation *relation;
88 88  
89 89 spin_lock_bh(&ptracer_relations_lock);
90   - list_for_each_entry_safe(relation, safe, &ptracer_relations, node)
  90 + rcu_read_lock();
  91 + list_for_each_entry_rcu(relation, &ptracer_relations, node) {
91 92 if (relation->tracee == tracee ||
92 93 (tracer && relation->tracer == tracer)) {
93   - list_del(&relation->node);
94   - kfree(relation);
  94 + list_del_rcu(&relation->node);
  95 + kfree_rcu(relation, rcu);
95 96 }
  97 + }
  98 + rcu_read_unlock();
96 99 spin_unlock_bh(&ptracer_relations_lock);
97 100 }
98 101  
99 102  
... ... @@ -217,11 +220,10 @@
217 220 struct task_struct *parent = NULL;
218 221 bool found = false;
219 222  
220   - spin_lock_bh(&ptracer_relations_lock);
221 223 rcu_read_lock();
222 224 if (!thread_group_leader(tracee))
223 225 tracee = rcu_dereference(tracee->group_leader);
224   - list_for_each_entry(relation, &ptracer_relations, node)
  226 + list_for_each_entry_rcu(relation, &ptracer_relations, node)
225 227 if (relation->tracee == tracee) {
226 228 parent = relation->tracer;
227 229 found = true;
... ... @@ -231,7 +233,6 @@
231 233 if (found && (parent == NULL || task_is_descendant(parent, tracer)))
232 234 rc = 1;
233 235 rcu_read_unlock();
234   - spin_unlock_bh(&ptracer_relations_lock);
235 236  
236 237 return rc;
237 238 }