diff options
author | Eric Paris <eparis@redhat.com> | 2011-04-25 16:26:29 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2011-04-25 21:16:32 -0400 |
commit | 9ade0cf440a1e5800dc68eef2e77b8d9d83a6dff (patch) | |
tree | 17a06970af5a26cd340b785a894f20f262335575 /security/selinux/hooks.c | |
parent | 1879fd6a26571fd4e8e1f4bb3e7537bc936b1fe7 (diff) |
SELINUX: Make selinux cache VFS RCU walks safe
Now that the security modules can decide whether they support the
dcache RCU walk or not it's possible to make selinux a bit more
RCU friendly. The SELinux AVC and security server access decision
code is RCU safe. A specific piece of the LSM audit code may not
be RCU safe.
This patch makes the VFS RCU walk retry if it would hit the non RCU
safe chunk of code. It will normally just work under RCU. This is
done simply by passing the VFS RCU state as a flag down into the
avc_audit() code and returning ECHILD there if it would have an issue.
Based-on-patch-by: Andi Kleen <ak@linux.intel.com>
Signed-off-by: Eric Paris <eparis@redhat.com>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'security/selinux/hooks.c')
-rw-r--r-- | security/selinux/hooks.c | 26 |
1 files changed, 13 insertions, 13 deletions
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index a73f4e463774..f7cf0ea6faea 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c | |||
@@ -1446,8 +1446,11 @@ static int task_has_capability(struct task_struct *tsk, | |||
1446 | } | 1446 | } |
1447 | 1447 | ||
1448 | rc = avc_has_perm_noaudit(sid, sid, sclass, av, 0, &avd); | 1448 | rc = avc_has_perm_noaudit(sid, sid, sclass, av, 0, &avd); |
1449 | if (audit == SECURITY_CAP_AUDIT) | 1449 | if (audit == SECURITY_CAP_AUDIT) { |
1450 | avc_audit(sid, sid, sclass, av, &avd, rc, &ad); | 1450 | int rc2 = avc_audit(sid, sid, sclass, av, &avd, rc, &ad, 0); |
1451 | if (rc2) | ||
1452 | return rc2; | ||
1453 | } | ||
1451 | return rc; | 1454 | return rc; |
1452 | } | 1455 | } |
1453 | 1456 | ||
@@ -1467,7 +1470,8 @@ static int task_has_system(struct task_struct *tsk, | |||
1467 | static int inode_has_perm(const struct cred *cred, | 1470 | static int inode_has_perm(const struct cred *cred, |
1468 | struct inode *inode, | 1471 | struct inode *inode, |
1469 | u32 perms, | 1472 | u32 perms, |
1470 | struct common_audit_data *adp) | 1473 | struct common_audit_data *adp, |
1474 | unsigned flags) | ||
1471 | { | 1475 | { |
1472 | struct inode_security_struct *isec; | 1476 | struct inode_security_struct *isec; |
1473 | struct common_audit_data ad; | 1477 | struct common_audit_data ad; |
@@ -1487,7 +1491,7 @@ static int inode_has_perm(const struct cred *cred, | |||
1487 | ad.u.fs.inode = inode; | 1491 | ad.u.fs.inode = inode; |
1488 | } | 1492 | } |
1489 | 1493 | ||
1490 | return avc_has_perm(sid, isec->sid, isec->sclass, perms, adp); | 1494 | return avc_has_perm_flags(sid, isec->sid, isec->sclass, perms, adp, flags); |
1491 | } | 1495 | } |
1492 | 1496 | ||
1493 | /* Same as inode_has_perm, but pass explicit audit data containing | 1497 | /* Same as inode_has_perm, but pass explicit audit data containing |
@@ -1504,7 +1508,7 @@ static inline int dentry_has_perm(const struct cred *cred, | |||
1504 | COMMON_AUDIT_DATA_INIT(&ad, FS); | 1508 | COMMON_AUDIT_DATA_INIT(&ad, FS); |
1505 | ad.u.fs.path.mnt = mnt; | 1509 | ad.u.fs.path.mnt = mnt; |
1506 | ad.u.fs.path.dentry = dentry; | 1510 | ad.u.fs.path.dentry = dentry; |
1507 | return inode_has_perm(cred, inode, av, &ad); | 1511 | return inode_has_perm(cred, inode, av, &ad, 0); |
1508 | } | 1512 | } |
1509 | 1513 | ||
1510 | /* Check whether a task can use an open file descriptor to | 1514 | /* Check whether a task can use an open file descriptor to |
@@ -1540,7 +1544,7 @@ static int file_has_perm(const struct cred *cred, | |||
1540 | /* av is zero if only checking access to the descriptor. */ | 1544 | /* av is zero if only checking access to the descriptor. */ |
1541 | rc = 0; | 1545 | rc = 0; |
1542 | if (av) | 1546 | if (av) |
1543 | rc = inode_has_perm(cred, inode, av, &ad); | 1547 | rc = inode_has_perm(cred, inode, av, &ad, 0); |
1544 | 1548 | ||
1545 | out: | 1549 | out: |
1546 | return rc; | 1550 | return rc; |
@@ -2103,7 +2107,7 @@ static inline void flush_unauthorized_files(const struct cred *cred, | |||
2103 | file = file_priv->file; | 2107 | file = file_priv->file; |
2104 | inode = file->f_path.dentry->d_inode; | 2108 | inode = file->f_path.dentry->d_inode; |
2105 | if (inode_has_perm(cred, inode, | 2109 | if (inode_has_perm(cred, inode, |
2106 | FILE__READ | FILE__WRITE, NULL)) { | 2110 | FILE__READ | FILE__WRITE, NULL, 0)) { |
2107 | drop_tty = 1; | 2111 | drop_tty = 1; |
2108 | } | 2112 | } |
2109 | } | 2113 | } |
@@ -2649,10 +2653,6 @@ static int selinux_inode_permission(struct inode *inode, int mask, unsigned flag | |||
2649 | if (!mask) | 2653 | if (!mask) |
2650 | return 0; | 2654 | return 0; |
2651 | 2655 | ||
2652 | /* May be droppable after audit */ | ||
2653 | if (flags & IPERM_FLAG_RCU) | ||
2654 | return -ECHILD; | ||
2655 | |||
2656 | COMMON_AUDIT_DATA_INIT(&ad, FS); | 2656 | COMMON_AUDIT_DATA_INIT(&ad, FS); |
2657 | ad.u.fs.inode = inode; | 2657 | ad.u.fs.inode = inode; |
2658 | 2658 | ||
@@ -2661,7 +2661,7 @@ static int selinux_inode_permission(struct inode *inode, int mask, unsigned flag | |||
2661 | 2661 | ||
2662 | perms = file_mask_to_av(inode->i_mode, mask); | 2662 | perms = file_mask_to_av(inode->i_mode, mask); |
2663 | 2663 | ||
2664 | return inode_has_perm(cred, inode, perms, &ad); | 2664 | return inode_has_perm(cred, inode, perms, &ad, flags); |
2665 | } | 2665 | } |
2666 | 2666 | ||
2667 | static int selinux_inode_setattr(struct dentry *dentry, struct iattr *iattr) | 2667 | static int selinux_inode_setattr(struct dentry *dentry, struct iattr *iattr) |
@@ -3209,7 +3209,7 @@ static int selinux_dentry_open(struct file *file, const struct cred *cred) | |||
3209 | * new inode label or new policy. | 3209 | * new inode label or new policy. |
3210 | * This check is not redundant - do not remove. | 3210 | * This check is not redundant - do not remove. |
3211 | */ | 3211 | */ |
3212 | return inode_has_perm(cred, inode, open_file_to_av(file), NULL); | 3212 | return inode_has_perm(cred, inode, open_file_to_av(file), NULL, 0); |
3213 | } | 3213 | } |
3214 | 3214 | ||
3215 | /* task security operations */ | 3215 | /* task security operations */ |