apparmor/kernel-patches/for-mainline/apparmor-link-pairs.diff
John Johansen e0a1668ffd - fix regression in link pairs where exec_unsafe was not being considered
in the link subset tests
- update fgetattr fuse patch to use fuse_update_atts
2007-12-11 15:37:19 +00:00

162 lines
5.7 KiB
Diff

Change link to use pairs to provide tighter control of how links
can be made. The permission subset test is controled by an
extra flag of the link perm, this allows for compatibility with
old style links which have a broad pair, but also allows for
pairs to not require the subset test when needed.
The pairs are stored as two matches in the dfa seperated by the
null transition. Both matches must be made and have the link
perm set. If the second match has the AA_LINK_SUBSET_TEST perm
set, then the subset test is done.
The link keyword can be used or just the link mask
User side these pairs are expressed as follows
link [link_mask] linkname -> [subset_mask] targetname,
[link_mask] linkname -> [subset_mask] targetname,
link /linkname -> /targetname, #link to targetname, link is perm subset
if user:group:other link specification is desired then a user:group:other
mask containing only the link perm in the appropriate positions can be
specified
eg.
link l:: /linkname -> /targetname, # links to targetname if owned by
or
l:: /linkname -> /targetname,
Both the linkname and the target support full AppArmor globbing.
link l:: /** -> /**, # allow any link to target owned by user
to override the default subset test
l:: /linkname -> px /targetname,
Traditional AA style links are still supported and are mapped by the
parser into the newer link pair for the kernel, with the LINK_SUBSET_TEST
bits set.
/linkname rwl,
is mapped to
link /linkname -> /**,
/linkname rw,
---
security/apparmor/apparmor.h | 4 +++
security/apparmor/main.c | 45 ++++++++++++++++++++++++++++++++-----------
2 files changed, 38 insertions(+), 11 deletions(-)
--- a/security/apparmor/apparmor.h
+++ b/security/apparmor/apparmor.h
@@ -34,6 +34,7 @@
AA_MAY_LOCK | AA_EXEC_MMAP | \
AA_EXEC_UNSAFE | AA_EXEC_MOD_0 | \
AA_EXEC_MOD_1)
+#define AA_LINK_SUBSET_TEST 0x0020
#define AA_EXEC_UNCONFINED 0
#define AA_EXEC_INHERIT AA_EXEC_MOD_0
@@ -59,6 +60,9 @@
#define AA_USER_EXEC_MODS (AA_EXEC_MODIFIERS << AA_USER_SHIFT)
#define AA_OTHER_EXEC_MODS (AA_EXEC_MODIFIERS << AA_OTHER_SHIFT)
+#define AA_USER_EXEC_UNSAFE (AA_EXEC_UNSAFE << AA_USER_SHIFT)
+#define AA_OTHER_EXEC_UNSAFE (AA_EXEC_UNSAFE << AA_OTHER_SHIFT)
+
#define AA_EXEC_BITS (AA_USER_EXEC | AA_OTHER_EXEC)
#define AA_ALL_EXEC_MODS (AA_USER_EXEC_MODS | \
--- a/security/apparmor/main.c
+++ b/security/apparmor/main.c
@@ -67,10 +67,27 @@ static int aa_link_denied(struct aa_prof
const char *target, int target_mode,
int *request_mask)
{
- int l_mode, t_mode, denied_mask;
+ unsigned int state;
+ int l_mode, t_mode, denied_mask = 0;
int link_mask = AA_MAY_LINK << target_mode;
- l_mode = aa_match(profile->file_rules, link);
+ *request_mask = link_mask;
+
+ l_mode = aa_match_state(profile->file_rules, DFA_START, link, &state);
+ if (l_mode & link_mask) {
+ int mode;
+ /* test to see if target can be paired with link */
+ state = aa_dfa_null_transition(profile->file_rules, state);
+ mode = aa_match_state(profile->file_rules, state, target,
+ NULL);
+
+ if (!(mode & link_mask))
+ denied_mask |= link_mask;
+ if (!(mode & (AA_LINK_SUBSET_TEST << target_mode)))
+ return denied_mask;
+ }
+
+ /* do link perm subset test */
t_mode = aa_match(profile->file_rules, target);
/* Ignore valid-profile-transition flags. */
@@ -79,23 +96,30 @@ static int aa_link_denied(struct aa_prof
*request_mask = l_mode | link_mask;
- /* Link always requires 'l' on the link, a subset for user:other
- * of the target's 'r', 'w', 'x', 'a', 'z', and 'm' permissions on
- * the link, and if the link has 'x', an exact match of all the
- * execute flags ('i', 'u', 'U', 'p', 'P').
+ /* Link always requires 'l' on the link for both parts of the pair.
+ * If a subset test is required a permission subset test of the
+ * perms for the link are done against the user:group:other of the
+ * target's 'r', 'w', 'x', 'a', 'z', and 'm' permissions.
+ *
+ * If the link has 'x', an exact match of all the execute flags
+ * ('i', 'u', 'p'). safe exec is treated as a subset of unsafe exec
*/
#define SUBSET_PERMS (AA_FILE_PERMS & ~AA_LINK_BITS)
- denied_mask = ~l_mode & link_mask;
+ denied_mask |= ~l_mode & link_mask;
if (l_mode & SUBSET_PERMS) {
denied_mask |= (l_mode & SUBSET_PERMS) & ~t_mode;
if (denied_mask & AA_EXEC_BITS)
denied_mask |= l_mode & AA_ALL_EXEC_MODS;
else if (l_mode & AA_EXEC_BITS) {
+ if (!(l_mode & AA_USER_EXEC_UNSAFE))
+ l_mode |= t_mode & AA_USER_EXEC_UNSAFE;
if (l_mode & AA_USER_EXEC &&
(l_mode & AA_USER_EXEC_MODS) !=
(t_mode & AA_USER_EXEC_MODS))
denied_mask |= AA_USER_EXEC |
(l_mode & AA_USER_EXEC_MODS);
+ if (!(l_mode & AA_OTHER_EXEC_UNSAFE))
+ l_mode |= t_mode & AA_OTHER_EXEC_UNSAFE;
if (l_mode & AA_OTHER_EXEC &&
(l_mode & AA_OTHER_EXEC_MODS) !=
(t_mode & AA_OTHER_EXEC_MODS))
@@ -703,15 +727,15 @@ int aa_link(struct aa_profile *profile,
struct dentry *link, struct vfsmount *link_mnt,
struct dentry *target, struct vfsmount *target_mnt)
{
- int error, check = 0;
+ int error;
struct aa_audit sa;
char *buffer = NULL, *buffer2 = NULL;
memset(&sa, 0, sizeof(sa));
sa.operation = "inode_link";
sa.gfp_mask = GFP_KERNEL;
- sa.name = aa_get_name(link, link_mnt, &buffer, check);
- sa.name2 = aa_get_name(target, target_mnt, &buffer2, check);
+ sa.name = aa_get_name(link, link_mnt, &buffer, 0);
+ sa.name2 = aa_get_name(target, target_mnt, &buffer2, 0);
if (IS_ERR(sa.name)) {
sa.error_code = PTR_ERR(sa.name);
@@ -723,7 +747,6 @@ int aa_link(struct aa_profile *profile,
}
if (sa.name && sa.name2) {
- sa.request_mask = AA_MAY_LINK;
sa.denied_mask = aa_link_denied(profile, sa.name, sa.name2,
aa_inode_mode(target->d_inode),
&sa.request_mask);