diff options
author | John Johansen <john.johansen@canonical.com> | 2017-05-29 21:16:04 +0200 |
---|---|---|
committer | John Johansen <john.johansen@canonical.com> | 2017-06-11 02:11:30 +0200 |
commit | aa9aeea8d4c3dfb9297723c4340671ef88e372d3 (patch) | |
tree | 5e12bad66f4a0f98043c97b21e866e2edb7d18b3 | |
parent | apparmor: add fn to test if profile supports a given mediation class (diff) | |
download | linux-aa9aeea8d4c3dfb9297723c4340671ef88e372d3.tar.xz linux-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.c | 30 | ||||
-rw-r--r-- | security/apparmor/include/audit.h | 4 | ||||
-rw-r--r-- | security/apparmor/include/perms.h | 34 | ||||
-rw-r--r-- | security/apparmor/lib.c | 102 |
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) |