aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJohn Johansen <john.johansen@canonical.com>2017-05-29 12:16:04 -0700
committerJohn Johansen <john.johansen@canonical.com>2017-06-10 17:11:30 -0700
commitaa9aeea8d4c3dfb9297723c4340671ef88e372d3 (patch)
tree5e12bad66f4a0f98043c97b21e866e2edb7d18b3
parentapparmor: add fn to test if profile supports a given mediation class (diff)
downloadlinux-dev-aa9aeea8d4c3dfb9297723c4340671ef88e372d3.tar.xz
linux-dev-aa9aeea8d4c3dfb9297723c4340671ef88e372d3.zip
apparmor: add gerneric permissions struct and support fns
Signed-off-by: John Johansen <john.johansen@canonical.com>
-rw-r--r--security/apparmor/file.c30
-rw-r--r--security/apparmor/include/audit.h4
-rw-r--r--security/apparmor/include/perms.h34
-rw-r--r--security/apparmor/lib.c102
4 files changed, 153 insertions, 17 deletions
diff --git a/security/apparmor/file.c b/security/apparmor/file.c
index 44549db904b3..1ee656f66aa4 100644
--- a/security/apparmor/file.c
+++ b/security/apparmor/file.c
@@ -56,15 +56,15 @@ static void file_audit_cb(struct audit_buffer *ab, void *va)
struct common_audit_data *sa = va;
kuid_t fsuid = current_fsuid();
- if (aad(sa)->fs.request & AA_AUDIT_FILE_MASK) {
+ if (aad(sa)->request & AA_AUDIT_FILE_MASK) {
audit_log_format(ab, " requested_mask=");
- audit_file_mask(ab, aad(sa)->fs.request);
+ audit_file_mask(ab, aad(sa)->request);
}
- if (aad(sa)->fs.denied & AA_AUDIT_FILE_MASK) {
+ if (aad(sa)->denied & AA_AUDIT_FILE_MASK) {
audit_log_format(ab, " denied_mask=");
- audit_file_mask(ab, aad(sa)->fs.denied);
+ audit_file_mask(ab, aad(sa)->denied);
}
- if (aad(sa)->fs.request & AA_AUDIT_FILE_MASK) {
+ if (aad(sa)->request & AA_AUDIT_FILE_MASK) {
audit_log_format(ab, " fsuid=%d",
from_kuid(&init_user_ns, fsuid));
audit_log_format(ab, " ouid=%d",
@@ -100,7 +100,7 @@ int aa_audit_file(struct aa_profile *profile, struct file_perms *perms,
DEFINE_AUDIT_DATA(sa, LSM_AUDIT_DATA_TASK, op);
sa.u.tsk = NULL;
- aad(&sa)->fs.request = request;
+ aad(&sa)->request = request;
aad(&sa)->name = name;
aad(&sa)->fs.target = target;
aad(&sa)->fs.ouid = ouid;
@@ -115,30 +115,30 @@ int aa_audit_file(struct aa_profile *profile, struct file_perms *perms,
mask = 0xffff;
/* mask off perms that are not being force audited */
- aad(&sa)->fs.request &= mask;
+ aad(&sa)->request &= mask;
- if (likely(!aad(&sa)->fs.request))
+ if (likely(!aad(&sa)->request))
return 0;
type = AUDIT_APPARMOR_AUDIT;
} else {
/* only report permissions that were denied */
- aad(&sa)->fs.request = aad(&sa)->fs.request & ~perms->allow;
- AA_BUG(!aad(&sa)->fs.request);
+ aad(&sa)->request = aad(&sa)->request & ~perms->allow;
+ AA_BUG(!aad(&sa)->request);
- if (aad(&sa)->fs.request & perms->kill)
+ if (aad(&sa)->request & perms->kill)
type = AUDIT_APPARMOR_KILL;
/* quiet known rejects, assumes quiet and kill do not overlap */
- if ((aad(&sa)->fs.request & perms->quiet) &&
+ if ((aad(&sa)->request & perms->quiet) &&
AUDIT_MODE(profile) != AUDIT_NOQUIET &&
AUDIT_MODE(profile) != AUDIT_ALL)
- aad(&sa)->fs.request &= ~perms->quiet;
+ aad(&sa)->request &= ~perms->quiet;
- if (!aad(&sa)->fs.request)
+ if (!aad(&sa)->request)
return COMPLAIN_MODE(profile) ? 0 : aad(&sa)->error;
}
- aad(&sa)->fs.denied = aad(&sa)->fs.request & ~perms->allow;
+ aad(&sa)->denied = aad(&sa)->request & ~perms->allow;
return aa_audit(type, profile, &sa, file_audit_cb);
}
diff --git a/security/apparmor/include/audit.h b/security/apparmor/include/audit.h
index fdc4774318ba..1aeb8550fb82 100644
--- a/security/apparmor/include/audit.h
+++ b/security/apparmor/include/audit.h
@@ -107,14 +107,14 @@ struct apparmor_audit_data {
void *profile;
const char *name;
const char *info;
+ u32 request;
+ u32 denied;
union {
/* these entries require a custom callback fn */
struct {
struct aa_profile *peer;
struct {
const char *target;
- u32 request;
- u32 denied;
kuid_t ouid;
} fs;
};
diff --git a/security/apparmor/include/perms.h b/security/apparmor/include/perms.h
index 35e365e7aa75..6ef23212bd66 100644
--- a/security/apparmor/include/perms.h
+++ b/security/apparmor/include/perms.h
@@ -66,6 +66,40 @@
extern const char aa_file_perm_chrs[];
extern const char *aa_file_perm_names[];
+struct aa_perms {
+ u32 allow;
+ u32 audit; /* set only when allow is set */
+
+ u32 deny; /* explicit deny, or conflict if allow also set */
+ u32 quiet; /* set only when ~allow | deny */
+ u32 kill; /* set only when ~allow | deny */
+ u32 stop; /* set only when ~allow | deny */
+
+ u32 complain; /* accumulates only used when ~allow & ~deny */
+ u32 cond; /* set only when ~allow and ~deny */
+
+ u32 hide; /* set only when ~allow | deny */
+ u32 prompt; /* accumulates only used when ~allow & ~deny */
+
+ /* Reserved:
+ * u32 subtree; / * set only when allow is set * /
+ */
+ u16 xindex;
+};
+
+#define ALL_PERMS_MASK 0xffffffff
+
+extern struct aa_perms allperms;
+
+struct aa_profile;
+
void aa_perm_mask_to_str(char *str, const char *chrs, u32 mask);
+void aa_audit_perm_names(struct audit_buffer *ab, const char **names, u32 mask);
+void aa_audit_perm_mask(struct audit_buffer *ab, u32 mask, const char *chrs,
+ u32 chrsmask, const char **names, u32 namesmask);
+void aa_apply_modes_to_perms(struct aa_profile *profile,
+ struct aa_perms *perms);
+void aa_compute_perms(struct aa_dfa *dfa, unsigned int state,
+ struct aa_perms *perms);
#endif /* __AA_PERM_H */
diff --git a/security/apparmor/lib.c b/security/apparmor/lib.c
index 90d4631ddafe..a50913744823 100644
--- a/security/apparmor/lib.c
+++ b/security/apparmor/lib.c
@@ -24,6 +24,10 @@
#include "include/perms.h"
#include "include/policy.h"
+struct aa_perms allperms = { .allow = ALL_PERMS_MASK,
+ .quiet = ALL_PERMS_MASK,
+ .hide = ALL_PERMS_MASK };
+
/**
* aa_split_fqname - split a fqname into a profile and namespace name
* @fqname: a full qualified name in namespace profile format (NOT NULL)
@@ -188,6 +192,104 @@ void aa_perm_mask_to_str(char *str, const char *chrs, u32 mask)
*str = '\0';
}
+void aa_audit_perm_names(struct audit_buffer *ab, const char **names, u32 mask)
+{
+ const char *fmt = "%s";
+ unsigned int i, perm = 1;
+ bool prev = false;
+
+ for (i = 0; i < 32; perm <<= 1, i++) {
+ if (mask & perm) {
+ audit_log_format(ab, fmt, names[i]);
+ if (!prev) {
+ prev = true;
+ fmt = " %s";
+ }
+ }
+ }
+}
+
+void aa_audit_perm_mask(struct audit_buffer *ab, u32 mask, const char *chrs,
+ u32 chrsmask, const char **names, u32 namesmask)
+{
+ char str[33];
+
+ audit_log_format(ab, "\"");
+ if ((mask & chrsmask) && chrs) {
+ aa_perm_mask_to_str(str, chrs, mask & chrsmask);
+ mask &= ~chrsmask;
+ audit_log_format(ab, "%s", str);
+ if (mask & namesmask)
+ audit_log_format(ab, " ");
+ }
+ if ((mask & namesmask) && names)
+ aa_audit_perm_names(ab, names, mask & namesmask);
+ audit_log_format(ab, "\"");
+}
+
+/**
+ * aa_apply_modes_to_perms - apply namespace and profile flags to perms
+ * @profile: that perms where computed from
+ * @perms: perms to apply mode modifiers to
+ *
+ * TODO: split into profile and ns based flags for when accumulating perms
+ */
+void aa_apply_modes_to_perms(struct aa_profile *profile, struct aa_perms *perms)
+{
+ switch (AUDIT_MODE(profile)) {
+ case AUDIT_ALL:
+ perms->audit = ALL_PERMS_MASK;
+ /* fall through */
+ case AUDIT_NOQUIET:
+ perms->quiet = 0;
+ break;
+ case AUDIT_QUIET:
+ perms->audit = 0;
+ /* fall through */
+ case AUDIT_QUIET_DENIED:
+ perms->quiet = ALL_PERMS_MASK;
+ break;
+ }
+
+ if (KILL_MODE(profile))
+ perms->kill = ALL_PERMS_MASK;
+ else if (COMPLAIN_MODE(profile))
+ perms->complain = ALL_PERMS_MASK;
+/*
+ * TODO:
+ * else if (PROMPT_MODE(profile))
+ * perms->prompt = ALL_PERMS_MASK;
+ */
+}
+
+static u32 map_other(u32 x)
+{
+ return ((x & 0x3) << 8) | /* SETATTR/GETATTR */
+ ((x & 0x1c) << 18) | /* ACCEPT/BIND/LISTEN */
+ ((x & 0x60) << 19); /* SETOPT/GETOPT */
+}
+
+void aa_compute_perms(struct aa_dfa *dfa, unsigned int state,
+ struct aa_perms *perms)
+{
+ perms->deny = 0;
+ perms->kill = perms->stop = 0;
+ perms->complain = perms->cond = 0;
+ perms->hide = 0;
+ perms->prompt = 0;
+ perms->allow = dfa_user_allow(dfa, state);
+ perms->audit = dfa_user_audit(dfa, state);
+ perms->quiet = dfa_user_quiet(dfa, state);
+
+ /* for v5 perm mapping in the policydb, the other set is used
+ * to extend the general perm set
+ */
+ perms->allow |= map_other(dfa_other_allow(dfa, state));
+ perms->audit |= map_other(dfa_other_audit(dfa, state));
+ perms->quiet |= map_other(dfa_other_quiet(dfa, state));
+// perms->xindex = dfa_user_xindex(dfa, state);
+}
+
/**
* aa_policy_init - initialize a policy structure
* @policy: policy to initialize (NOT NULL)