apparmor/kernel-patches/for-mainline/owner-perm-set.diff
2007-11-19 23:18:48 +00:00

561 lines
17 KiB
Diff

---
security/apparmor/apparmor.h | 60 +++++++---
security/apparmor/apparmorfs.c | 2
security/apparmor/lsm.c | 2
security/apparmor/main.c | 193 +++++++++++++++++++++++------------
security/apparmor/match.c | 8 -
security/apparmor/module_interface.c | 3
6 files changed, 179 insertions(+), 89 deletions(-)
--- a/security/apparmor/apparmor.h
+++ b/security/apparmor/apparmor.h
@@ -26,22 +26,50 @@
#define AA_MAY_LINK 0x0010
#define AA_MAY_LOCK 0x0020
#define AA_EXEC_MMAP 0x0040
+#define AA_EXEC_UNSAFE 0x0080
+#define AA_EXEC_MOD_0 0x0100
+#define AA_EXEC_MOD_1 0x0200
+#define AA_BASE_PERMS (MAY_READ | MAY_WRITE | MAY_EXEC | \
+ MAY_APPEND | AA_MAY_LINK | \
+ AA_MAY_LOCK | AA_EXEC_MMAP | \
+ AA_EXEC_UNSAFE | AA_EXEC_MOD_0 | \
+ AA_EXEC_MOD_1)
-#define AA_CHANGE_PROFILE 0x04000000
-#define AA_EXEC_INHERIT 0x08000000
-#define AA_EXEC_UNCONFINED 0x10000000
-#define AA_EXEC_PROFILE 0x20000000
-#define AA_EXEC_UNSAFE 0x40000000
-
-#define AA_EXEC_MODIFIERS (AA_EXEC_INHERIT | \
- AA_EXEC_UNCONFINED | \
- AA_EXEC_PROFILE)
+#define AA_EXEC_UNCONFINED 0
+#define AA_EXEC_INHERIT AA_EXEC_MOD_0
+#define AA_EXEC_PROFILE AA_EXEC_MOD_1
+#define AA_EXEC_PIX (AA_EXEC_MOD_0 | AA_EXEC_MOD_1)
-#define AA_VALID_PERM_MASK (MAY_READ | MAY_WRITE | MAY_EXEC | \
- MAY_APPEND | AA_MAY_LINK | \
- AA_MAY_LOCK | \
- AA_EXEC_MODIFIERS | AA_EXEC_MMAP | \
- AA_EXEC_UNSAFE | AA_CHANGE_PROFILE)
+#define AA_EXEC_MODIFIERS (AA_EXEC_MOD_0 | AA_EXEC_MOD_1)
+
+#define AA_USER_SHIFT 0
+#define AA_OTHER_SHIFT 10
+
+#define AA_USER_PERMS (AA_BASE_PERMS << AA_USER_SHIFT)
+#define AA_OTHER_PERMS (AA_BASE_PERMS << AA_OTHER_SHIFT)
+
+#define AA_FILE_PERMS (AA_USER_PERMS | AA_OTHER_PERMS)
+
+#define AA_LINK_BITS ((AA_MAY_LINK << AA_USER_SHIFT) | \
+ (AA_MAY_LINK << AA_OTHER_SHIFT))
+
+#define AA_USER_EXEC (MAY_EXEC << AA_USER_SHIFT)
+#define AA_OTHER_EXEC (MAY_EXEC << AA_OTHER_SHIFT)
+
+#define AA_USER_EXEC_MODS (AA_EXEC_MODIFIERS << AA_USER_SHIFT)
+#define AA_OTHER_EXEC_MODS (AA_EXEC_MODIFIERS << AA_OTHER_SHIFT)
+
+#define AA_EXEC_BITS (AA_USER_EXEC | AA_OTHER_EXEC)
+
+#define AA_ALL_EXEC_MODS (AA_USER_EXEC_MODS | \
+ AA_OTHER_EXEC_MODS)
+
+/* shared permissions that are not duplicated in user:group:other */
+#define AA_CHANGE_PROFILE 0x40000000
+
+#define AA_SHARED_PERMS (AA_CHANGE_PROFILE)
+
+#define AA_VALID_PERM_MASK (AA_FILE_PERMS | AA_SHARED_PERMS)
#define AA_SECURE_EXEC_NEEDED 1
@@ -183,7 +211,7 @@ struct aa_audit {
const char *name;
const char *name2;
const char *name3;
- int requested_mask, denied_mask;
+ int request_mask, denied_mask;
struct iattr *iattr;
pid_t task, parent;
int family, type, protocol;
@@ -226,7 +254,7 @@ extern int aa_perm_dir(struct aa_profile
struct dentry *dentry, struct vfsmount *mnt,
int mask);
extern int aa_perm_path(struct aa_profile *, const char *operation,
- const char *name, int);
+ const char *name, int mask, uid_t uid);
extern int aa_link(struct aa_profile *profile,
struct dentry *link, struct vfsmount *link_mnt,
struct dentry *target, struct vfsmount *target_mnt);
--- a/security/apparmor/apparmorfs.c
+++ b/security/apparmor/apparmorfs.c
@@ -89,7 +89,7 @@ static struct file_operations apparmorfs
static ssize_t aa_matching_read(struct file *file, char __user *buf,
size_t size, loff_t *ppos)
{
- const char *matching = "pattern=aadfa perms=rwxamlz";
+ const char *matching = "pattern=aadfa perms=rwxamlz user:other";
return simple_read_from_buffer(buf, size, ppos, matching,
strlen(matching));
--- a/security/apparmor/lsm.c
+++ b/security/apparmor/lsm.c
@@ -199,7 +199,7 @@ static int apparmor_sysctl(struct ctl_ta
if (name && name - buffer >= 5) {
name -= 5;
memcpy(name, "/proc", 5);
- error = aa_perm_path(profile, "sysctl", name, mask);
+ error = aa_perm_path(profile, "sysctl", name, mask, 0);
}
free_page((unsigned long)buffer);
}
--- a/security/apparmor/main.c
+++ b/security/apparmor/main.c
@@ -31,6 +31,14 @@ static const char *capability_names[] =
struct aa_namespace *default_namespace;
+static int aa_inode_mode(struct inode *inode)
+{
+ /* if the inode doesn't exist the user is creating it */
+ if (!inode || current->fsuid == inode->i_uid)
+ return AA_USER_SHIFT;
+ return AA_OTHER_SHIFT;
+}
+
/**
* aa_file_denied - check for @mask access on a file
* @profile: profile to check against
@@ -51,39 +59,52 @@ static int aa_file_denied(struct aa_prof
* @profile: profile to check against
* @link: pathname of link being created
* @target: pathname of target to be linked to
+ * @target_mode: UGO shift for target inode
* @request_mask: the permissions subset valid only if link succeeds
* Return %0 on success, or else the permissions that the profile denies.
*/
static int aa_link_denied(struct aa_profile *profile, const char *link,
- const char *target, int *request_mask)
+ const char *target, int target_mode,
+ int *request_mask)
{
int l_mode, t_mode, denied_mask;
+ int link_mask = AA_MAY_LINK << target_mode;
l_mode = aa_match(profile->file_rules, link);
t_mode = aa_match(profile->file_rules, target);
/* Ignore valid-profile-transition flags. */
- l_mode &= ~AA_CHANGE_PROFILE;
- t_mode &= ~AA_CHANGE_PROFILE;
+ l_mode &= ~AA_SHARED_PERMS;
+ t_mode &= ~AA_SHARED_PERMS;
- *request_mask = l_mode | AA_MAY_LINK;
-
- /* Link always requires 'l' on the link, a subset 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').
- */
-#define RWXAZM (MAY_READ | MAY_WRITE | MAY_EXEC | MAY_APPEND | AA_MAY_LOCK | \
- AA_EXEC_MMAP)
- denied_mask = ~l_mode & AA_MAY_LINK;
- if (l_mode & RWXAZM)
- denied_mask |= (l_mode & ~ AA_MAY_LINK) & ~t_mode;
- else
- denied_mask |= t_mode | AA_MAY_LINK;
- if (denied_mask & AA_EXEC_MODIFIERS)
- denied_mask |= MAY_EXEC;
+ *request_mask = l_mode | link_mask;
-#undef RWXAZM
+ /* 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').
+ */
+#define SUBSET_PERMS (AA_FILE_PERMS & ~AA_LINK_BITS)
+ 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 &&
+ (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 &&
+ (l_mode & AA_OTHER_EXEC_MODS) !=
+ (t_mode & AA_OTHER_EXEC_MODS))
+ denied_mask |= AA_OTHER_EXEC |
+ (l_mode & AA_OTHER_EXEC_MODS);
+ }
+ } else
+ denied_mask |= t_mode | link_mask;
+#undef SUBSET_PERMS
return denied_mask;
}
@@ -173,7 +194,7 @@ static int aa_perm_dentry(struct aa_prof
char *buffer = NULL;
sa->name = aa_get_name(dentry, mnt, &buffer, check);
-
+ sa->request_mask <<= aa_inode_mode(dentry->d_inode);
if (IS_ERR(sa->name)) {
/*
* deleted files are given a pass on permission checks when
@@ -182,13 +203,13 @@ static int aa_perm_dentry(struct aa_prof
if (PTR_ERR(sa->name) == -ENOENT && (check & AA_CHECK_FD))
sa->denied_mask = 0;
else {
- sa->denied_mask = sa->requested_mask;
+ sa->denied_mask = sa->request_mask;
sa->error_code = PTR_ERR(sa->name);
}
sa->name = NULL;
} else
sa->denied_mask = aa_file_denied(profile, sa->name,
- sa->requested_mask);
+ sa->request_mask);
if (!sa->denied_mask)
sa->error_code = 0;
@@ -229,10 +250,10 @@ void free_default_namespace(void)
default_namespace = NULL;
}
-static void aa_audit_file_mask(struct audit_buffer *ab, const char *name,
- int mask)
+static void aa_audit_file_sub_mask(struct audit_buffer *ab, char *buffer,
+ int mask)
{
- char mask_str[10], *m = mask_str;
+ char *m = buffer;
if (mask & AA_EXEC_MMAP)
*m++ = 'm';
@@ -242,32 +263,58 @@ static void aa_audit_file_mask(struct au
*m++ = 'w';
else if (mask & MAY_APPEND)
*m++ = 'a';
- if (mask & (MAY_EXEC | AA_EXEC_MODIFIERS)) {
+ if (mask & MAY_EXEC) {
if (mask & AA_EXEC_UNSAFE) {
- if (mask & AA_EXEC_INHERIT)
- *m++ = 'i';
- if (mask & AA_EXEC_UNCONFINED)
+ switch(mask & AA_EXEC_MODIFIERS) {
+ case AA_EXEC_UNCONFINED:
*m++ = 'u';
- if (mask & AA_EXEC_PROFILE)
+ break;
+ case AA_EXEC_PIX:
+ *m++ = 'p';
+ /* fall through */
+ case AA_EXEC_INHERIT:
+ *m++ = 'i';
+ break;
+ case AA_EXEC_PROFILE:
*m++ = 'p';
+ break;
+ }
} else {
- if (mask & AA_EXEC_INHERIT)
- *m++ = 'I';
- if (mask & AA_EXEC_UNCONFINED)
+ switch(mask & AA_EXEC_MODIFIERS) {
+ case AA_EXEC_UNCONFINED:
*m++ = 'U';
- if (mask & AA_EXEC_PROFILE)
+ break;
+ case AA_EXEC_PIX:
*m++ = 'P';
+ /* fall through */
+ case AA_EXEC_INHERIT:
+ *m++ = 'I';
+ break;
+ case AA_EXEC_PROFILE:
+ *m++ = 'P';
+ break;
+ }
}
- if (mask & MAY_EXEC)
- *m++ = 'x';
+ *m++ = 'x';
}
if (mask & AA_MAY_LINK)
*m++ = 'l';
if (mask & AA_MAY_LOCK)
*m++ = 'k';
*m++ = '\0';
+}
+
+static void aa_audit_file_mask(struct audit_buffer *ab, const char *name,
+ int mask)
+{
+ char user[10], other[10];
- audit_log_format(ab, " %s=\"%s\"", name, mask_str);
+ aa_audit_file_sub_mask(ab, user,
+ (mask & AA_USER_PERMS) >> AA_USER_SHIFT);
+ aa_audit_file_sub_mask(ab, other,
+ (mask & AA_OTHER_PERMS) >> AA_OTHER_SHIFT);
+
+ audit_log_format(ab, " %s=\"%s::%s\"", name, user, other);
}
static const char *address_families[] = {
@@ -316,8 +363,8 @@ static int aa_audit_base(struct aa_profi
if (sa->info)
audit_log_format(ab, " info=\"%s\"", sa->info);
- if (sa->requested_mask)
- aa_audit_file_mask(ab, "requested_mask", sa->requested_mask);
+ if (sa->request_mask)
+ aa_audit_file_mask(ab, "request_mask", sa->request_mask);
if (sa->denied_mask)
aa_audit_file_mask(ab, "denied_mask", sa->denied_mask);
@@ -472,7 +519,7 @@ int aa_attr(struct aa_profile *profile,
sa.operation = "setattr";
sa.gfp_mask = GFP_KERNEL;
sa.iattr = iattr;
- sa.requested_mask = MAY_WRITE;
+ sa.request_mask = MAY_WRITE;
sa.error_code = -EACCES;
check = 0;
@@ -506,7 +553,7 @@ int aa_perm_xattr(struct aa_profile *pro
memset(&sa, 0, sizeof(sa));
sa.operation = operation;
sa.gfp_mask = GFP_KERNEL;
- sa.requested_mask = mask;
+ sa.request_mask = mask;
sa.error_code = -EACCES;
if (inode && S_ISDIR(inode->i_mode))
@@ -540,7 +587,7 @@ int aa_perm(struct aa_profile *profile,
memset(&sa, 0, sizeof(sa));
sa.operation = operation;
sa.gfp_mask = GFP_KERNEL;
- sa.requested_mask = mask;
+ sa.request_mask = mask;
sa.error_code = -EACCES;
error = aa_perm_dentry(profile, dentry, mnt, &sa, check);
@@ -569,24 +616,28 @@ int aa_perm_dir(struct aa_profile *profi
memset(&sa, 0, sizeof(sa));
sa.operation = operation;
sa.gfp_mask = GFP_KERNEL;
- sa.requested_mask = mask;
+ sa.request_mask = mask;
sa.error_code = -EACCES;
return aa_perm_dentry(profile, dentry, mnt, &sa, AA_CHECK_DIR);
}
int aa_perm_path(struct aa_profile *profile, const char *operation,
- const char *name, int mask)
+ const char *name, int mask, uid_t uid)
{
struct aa_audit sa;
memset(&sa, 0, sizeof(sa));
sa.operation = operation;
sa.gfp_mask = GFP_KERNEL;
- sa.requested_mask = mask;
+ sa.request_mask = mask;
sa.name = name;
+ if (current->fsuid == uid)
+ sa.request_mask = mask << AA_USER_SHIFT;
+ else
+ sa.request_mask = mask << AA_OTHER_SHIFT;
- sa.denied_mask = aa_file_denied(profile, name, mask);
+ sa.denied_mask = aa_file_denied(profile, name, sa.request_mask) ;
sa.error_code = sa.denied_mask ? -EACCES : 0;
return aa_audit(profile, &sa);
@@ -672,9 +723,10 @@ int aa_link(struct aa_profile *profile,
}
if (sa.name && sa.name2) {
- sa.requested_mask = AA_MAY_LINK;
+ sa.request_mask = AA_MAY_LINK;
sa.denied_mask = aa_link_denied(profile, sa.name, sa.name2,
- &sa.requested_mask);
+ aa_inode_mode(target->d_inode),
+ &sa.request_mask);
sa.error_code = sa.denied_mask ? -EACCES : 0;
}
@@ -818,7 +870,7 @@ aa_register_find(struct aa_profile *prof
__FUNCTION__, new_profile->name);
} else if (mandatory && profile) {
sa->info = "mandatory profile missing";
- sa->denied_mask = MAY_EXEC;
+ sa->denied_mask = sa->request_mask; /* shifted MAY_EXEC */
if (complain) {
aa_audit_hint(profile, sa);
new_profile =
@@ -829,7 +881,7 @@ aa_register_find(struct aa_profile *prof
}
} else {
/* Only way we can get into this code is if task
- * is unconfined.
+ * is unconfined, or pix.
*/
AA_DEBUG("%s: No profile found for exec image '%s'\n",
__FUNCTION__,
@@ -851,7 +903,7 @@ int aa_register(struct linux_binprm *bpr
char *buffer = NULL;
struct file *filp = bprm->file;
struct aa_profile *profile, *old_profile, *new_profile = NULL;
- int exec_mode = AA_EXEC_UNSAFE, complain = 0;
+ int exec_mode, complain = 0, shift;
struct aa_audit sa;
AA_DEBUG("%s\n", __FUNCTION__);
@@ -862,11 +914,14 @@ int aa_register(struct linux_binprm *bpr
return -ENOENT;
}
+ shift = aa_inode_mode(filp->f_dentry->d_inode);
+ exec_mode = AA_EXEC_UNSAFE << shift;
+
memset(&sa, 0, sizeof(sa));
sa.operation = "exec";
sa.gfp_mask = GFP_KERNEL;
sa.name = filename;
- sa.requested_mask = MAY_EXEC;
+ sa.request_mask = MAY_EXEC << shift;
repeat:
profile = aa_get_profile(current);
@@ -878,16 +933,16 @@ repeat:
*/
exec_mode = aa_match(profile->file_rules, filename);
- if (exec_mode & (MAY_EXEC | AA_EXEC_MODIFIERS)) {
- switch (exec_mode & (MAY_EXEC | AA_EXEC_MODIFIERS)) {
- case MAY_EXEC | AA_EXEC_INHERIT:
+ if (exec_mode & sa.request_mask) {
+ switch ((exec_mode >> shift) & AA_EXEC_MODIFIERS) {
+ case AA_EXEC_INHERIT:
AA_DEBUG("%s: INHERIT %s\n",
__FUNCTION__,
filename);
/* nothing to be done here */
goto cleanup;
- case MAY_EXEC | AA_EXEC_UNCONFINED:
+ case AA_EXEC_UNCONFINED:
AA_DEBUG("%s: UNCONFINED %s\n",
__FUNCTION__,
filename);
@@ -896,7 +951,7 @@ repeat:
new_profile = NULL;
break;
- case MAY_EXEC | AA_EXEC_PROFILE:
+ case AA_EXEC_PROFILE:
AA_DEBUG("%s: PROFILE %s\n",
__FUNCTION__,
filename);
@@ -905,6 +960,18 @@ repeat:
1, complain,
&sa);
break;
+ case AA_EXEC_PIX:
+ AA_DEBUG("%s: PROFILE %s\n",
+ __FUNCTION__,
+ filename);
+ new_profile = aa_register_find(profile,
+ filename,
+ 0, complain,
+ &sa);
+ if (!new_profile)
+ /* inherit - nothing to be done here */
+ goto cleanup;
+ break;
}
} else if (complain) {
@@ -914,9 +981,9 @@ repeat:
*/
new_profile =
aa_dup_profile(profile->ns->null_complain_profile);
- exec_mode |= AA_EXEC_UNSAFE;
+ exec_mode |= AA_EXEC_UNSAFE << shift;
} else {
- sa.denied_mask = MAY_EXEC;
+ sa.denied_mask = sa.request_mask;
aa_audit_reject(profile, &sa);
new_profile = ERR_PTR(-EPERM);
}
@@ -937,7 +1004,7 @@ repeat:
if (PTR_ERR(old_profile) == -ESTALE)
goto repeat;
if (PTR_ERR(old_profile) == -EPERM) {
- sa.denied_mask = MAY_EXEC;
+ sa.denied_mask = sa.request_mask;
sa.info = "unable to set profile due to ptrace";
sa.task = current->parent->pid;
aa_audit_reject(profile, &sa);
@@ -957,7 +1024,7 @@ repeat:
* Cases 2 and 3 are marked as requiring secure exec
* (unless policy specified "unsafe exec")
*/
- if (!(exec_mode & AA_EXEC_UNSAFE)) {
+ if (!(exec_mode & (AA_EXEC_UNSAFE << shift))) {
unsigned long bprm_flags;
bprm_flags = AA_SECURE_EXEC_NEEDED;
@@ -967,7 +1034,7 @@ repeat:
if (complain && new_profile &&
new_profile == new_profile->ns->null_complain_profile) {
- sa.requested_mask = 0;
+ sa.request_mask = 0;
sa.name = NULL;
sa.info = "set profile";
aa_audit_hint(new_profile, &sa);
--- a/security/apparmor/match.c
+++ b/security/apparmor/match.c
@@ -175,14 +175,8 @@ int verify_dfa(struct aa_dfa *dfa)
for (i = 0; i < state_count; i++) {
int mode = ACCEPT_TABLE(dfa)[i];
- if (mode & ~AA_VALID_PERM_MASK)
+ if (mode & ~AA_VALID_PERM_MASK) {
goto out;
-
- /* if MAY_EXEC, exactly one exec modifier must be set */
- if (mode & MAY_EXEC) {
- mode &= AA_EXEC_MODIFIERS;
- if (mode & (mode - 1))
- goto out;
}
}
--- a/security/apparmor/module_interface.c
+++ b/security/apparmor/module_interface.c
@@ -349,7 +349,8 @@ fail:
sa.operation = operation;
sa.gfp_mask = GFP_KERNEL;
sa.name = profile && profile->name ? profile->name : "unknown";
- sa.info = "failed to unpack profile";
+ if (!sa.info)
+ sa.info = "failed to unpack profile";
aa_audit_status(NULL, &sa);
if (profile)