SMACK: Add missing rcu_read_lock/unlock for process capability walk.
Subsystems (2)
PATCH 1/1 SMACK: Add missing rcu_read_lock/unlock for process capability walk.
From: Andi Kleen <[email protected]>
smk_access_entry does a RCU list walk for a list shared with other threads. It relies on the caller doing rcu_read_lock(). One caller forgot to do to this, which could lead to races on preemptible kernels.
Move the rcu_read_lock() into smk_access_entry instead.
--- security/smack/smack_access.c | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-)
security/smack/smack_access.c +2 -2
@@ -92,6 +92,7 @@ int smk_access_entry(char *subject_label, char *object_label,int may = -ENOENT ;struct smack_rule *srp; +rcu_read_lock ();list_for_each_entry_rcu (srp, rule_list, list) {if (srp->smk_subject == subject_label ||strcmp (srp->smk_subject, subject_label) ==0 ) {
@@ -102,6 +103,7 @@ int smk_access_entry(char *subject_label, char *object_label, } } } +rcu_read_unlock ();return may; }
@@ -184,9 +186,7 @@ int smk_access_flags(char *subject_label, char *object_label, int request,* good. A negative response from smk_access_entry() * indicates there is no entry for this pair. */ -rcu_read_lock (); may =smk_access_entry (subject_label, object_label, &smack_rule_list); -rcu_read_unlock ();if (may >0 && (request & may) == request) goto out_audit;
Signature · 1 line
1.7.4.2
Quoted 8 lines · Andi Kleen
From: Andi Kleen <[email protected]>
smk_access_entrydoes a RCU list walk for a list shared with other threads. It relies on the caller doingrcu_read_lock(). One caller forgot to do to this, which could lead to races on preemptible kernels.Move the
rcu_read_lock()intosmk_access_entryinstead.
The lock was moved out of smk_access_entry in support of the processing done in the smack_mmap_file() hook. Where do you see a potential race, and which caller "forgot" to do the lock?
Thank you.
Quoted 35 lines
Signed-off-by Andi Kleen <[email protected]>--- security/smack/smack_access.c | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-)security/smack/smack_access.c +2
-2@@ -92,6 +92,7 @@ int smk_access_entry(char *subject_label, char *object_label,int may = -ENOENT ;struct smack_rule *srp; +rcu_read_lock ();list_for_each_entry_rcu (srp, rule_list, list) {if (srp->smk_subject == subject_label ||strcmp (srp->smk_subject, subject_label) ==0 ) {@@ -102,6 +103,7 @@ int smk_access_entry(char *subject_label, char *object_label, } } } +rcu_read_unlock ();return may; }@@ -184,9 +186,7 @@ int smk_access_flags(char *subject_label, char *object_label, int request,* good. A negative response from smk_access_entry() * indicates there is no entry for this pair. */ -rcu_read_lock (); may =smk_access_entry (subject_label, object_label, &smack_rule_list); -rcu_read_unlock ();if (may >0 && (request & may) == request) goto out_audit;
Quoted 8 lines · Casey Schaufler
Quoted 7 lines · Andi Kleen
From: Andi Kleen <[email protected]>
smk_access_entrydoes a RCU list walk for a list shared with other threads. It relies on the caller doingrcu_read_lock(). One caller forgot to do to this, which could lead to races on preemptible kernels.
Quoted 7 lines
Quoted 1 line
Move the
rcu_read_lock()intosmk_access_entryinstead.Nacked-by Casey Schaufler <[email protected]>The lock was moved out of
smk_access_entryin support of the processing done in thesmack_mmap_file()hook. Where do you see a potential race, and which caller "forgot" to do the lock?
There are two callers and only one takes it.
The one that doesn't take it is smk_curacc.
I checked the callers of that and there is no rcu_read_lock() in those
As far as I understand the cred which holds this list is shared between threads and other threads can modify it. Which means it needs RCU read lock protection.
-Andi
Casey Schaufler
maintainerQuoted 9 lines · Andi Kleen
Quoted 8 lines · Casey Schaufler
Quoted 7 lines · Andi Kleen
From: Andi Kleen <[email protected]>
smk_access_entrydoes a RCU list walk for a list shared with other threads. It relies on the caller doingrcu_read_lock(). One caller forgot to do to this, which could lead to races on preemptible kernels.
Quoted 7 lines
Quoted 6 lines
Quoted 1 line
Move the
rcu_read_lock()intosmk_access_entryinstead.Nacked-by Casey Schaufler <[email protected]>The lock was moved out of
smk_access_entryin support of the processing done in thesmack_mmap_file()hook. Where do you see a potential race, and which caller "forgot" to do the lock?There are two callers and only one takes it.
There are two callers in smack_access.c.
There are four more in smack_lsm.c
Quoted 1 line
The one that doesn't take it is
smk_curacc.
The call in smk_curacc() is using the task local list, not the system list.
Quoted 5 lines
I checked the callers of that and there is no
rcu_read_lock()in thoseAs far as I understand the cred which holds this list is shared between threads and other threads can modify it. Which means it needs RCU read lock protection.
The global list, yes. The task specific list, no. Modifying the local list is like any other modification of the cred structure and requires the cred be copied.
Moving the lock into smk_access_entry() would introduce a potential deadlock in smack_mmap_file. There is a bit of convolution in the mmap hook that requires looking at the list in a way that does not allow the locking to be embedded where it used to be.
Quoted 8 lines
-Andi
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
Quoted 3 lines
The global list, yes. The task specific list, no. Modifying the local list is like any other modification of the cred structure and requires the cred be copied.
But you still need to free it eventually right? And that freeing will need RCU on the reader.
Quoted 5 lines
Moving the lock into
smk_access_entry()would introduce a potential deadlock insmack_mmap_file. There is a bit of convolution in the mmap hook that requires looking at the list in a way that does not allow the locking to be embedded where it used to be.
rcu_read_lock() is just a per task counter and nests fine and never deadlocks.
-Andi
Casey Schaufler
maintainerQuoted 5 lines · Andi Kleen
Quoted 3 lines
The global list, yes. The task specific list, no. Modifying the local list is like any other modification of the cred structure and requires the cred be copied.
But you still need to free it eventually right? And that freeing will need RCU on the reader.
Entries are never freed from the global list. Someone is working on a patch to do that, but is running into - wait for it - locking issues.
Entries on the local lists are only freed when the task exits.
Quoted 10 lines · Casey Schaufler
Quoted 5 lines · Andi Kleen
Quoted 3 lines
The global list, yes. The task specific list, no. Modifying the local list is like any other modification of the cred structure and requires the cred be copied.
But you still need to free it eventually right? And that freeing will need RCU on the reader.
Entries are never freed from the global list. Someone is working on a patch to do that, but is running into - wait for it - locking issues.
Then why do you use rcu_read_lock() at all?
You can drop all the rcu_read_lock()s and probably the other *_rcu list accesses then. And my patch is indeed not needed.
Quoted 1 line
Entries on the local lists are only freed when the task exits.
You mean the last user of the cred?
-Andi
Signature · 1 line
[email protected] -- Speaking for myself only.
Casey Schaufler
maintainerQuoted 11 lines · Andi Kleen
Quoted 9 lines · Casey Schaufler
Quoted 5 lines · Andi Kleen
Quoted 3 lines
The global list, yes. The task specific list, no. Modifying the local list is like any other modification of the cred structure and requires the cred be copied.
But you still need to free it eventually right? And that freeing will need RCU on the reader.
Entries are never freed from the global list. Someone is working on a patch to do that, but is running into - wait for it - locking issues.
Then why do you use
rcu_read_lock()at all?
Because the entries can be modified in place.
Quoted 5 lines
You can drop all the rcu_read_lock()s and probably the other
*_rculist accesses then. And my patch is indeed not needed.Quoted 1 line
Entries on the local lists are only freed when the task exits.
You mean the last user of the cred?
Yes.
Quoted 2 lines
-Andi