diff options
author | John Johansen <john.johansen@canonical.com> | 2017-06-09 14:38:35 -0700 |
---|---|---|
committer | John Johansen <john.johansen@canonical.com> | 2017-06-10 17:11:42 -0700 |
commit | 290f458a4f16f9cf6cb6562b249e69fe1c3c3a07 (patch) | |
tree | 41b1a79cb019d8fbbb1b07c28e5d926656728ccd | |
parent | b2d09ae449cedc6f276ac485c013d22a97d36992 (diff) |
apparmor: allow ptrace checks to be finer grained than just capability
Signed-off-by: John Johansen <john.johansen@canonical.com>
-rw-r--r-- | security/apparmor/apparmorfs.c | 6 | ||||
-rw-r--r-- | security/apparmor/include/ipc.h | 6 | ||||
-rw-r--r-- | security/apparmor/ipc.c | 56 |
3 files changed, 68 insertions, 0 deletions
diff --git a/security/apparmor/apparmorfs.c b/security/apparmor/apparmorfs.c index d24100f8fd98..d1a6ce499776 100644 --- a/security/apparmor/apparmorfs.c +++ b/security/apparmor/apparmorfs.c @@ -2086,6 +2086,11 @@ static struct aa_sfs_entry aa_sfs_entry_file[] = { { } }; +static struct aa_sfs_entry aa_sfs_entry_ptrace[] = { + AA_SFS_FILE_STRING("mask", "read trace"), + { } +}; + static struct aa_sfs_entry aa_sfs_entry_domain[] = { AA_SFS_FILE_BOOLEAN("change_hat", 1), AA_SFS_FILE_BOOLEAN("change_hatv", 1), @@ -2125,6 +2130,7 @@ static struct aa_sfs_entry aa_sfs_entry_features[] = { AA_SFS_FILE_U64("capability", VFS_CAP_FLAGS_MASK), AA_SFS_DIR("rlimit", aa_sfs_entry_rlimit), AA_SFS_DIR("caps", aa_sfs_entry_caps), + AA_SFS_DIR("ptrace", aa_sfs_entry_ptrace), AA_SFS_DIR("query", aa_sfs_entry_query), { } }; diff --git a/security/apparmor/include/ipc.h b/security/apparmor/include/ipc.h index fb3e751e6eed..656fdb81c8a0 100644 --- a/security/apparmor/include/ipc.h +++ b/security/apparmor/include/ipc.h @@ -21,6 +21,12 @@ struct aa_profile; #define AA_PTRACE_TRACE MAY_WRITE #define AA_PTRACE_READ MAY_READ +#define AA_MAY_BE_TRACED AA_MAY_APPEND +#define AA_MAY_BE_READ AA_MAY_CREATE +#define PTRACE_PERM_SHIFT 2 + +#define AA_PTRACE_PERM_MASK (AA_PTRACE_READ | AA_PTRACE_TRACE | \ + AA_MAY_BE_READ | AA_MAY_BE_TRACED) int aa_may_ptrace(struct aa_label *tracer, struct aa_label *tracee, u32 request); diff --git a/security/apparmor/ipc.c b/security/apparmor/ipc.c index f81649369f05..11e66b5bbc42 100644 --- a/security/apparmor/ipc.c +++ b/security/apparmor/ipc.c @@ -21,20 +21,76 @@ #include "include/policy.h" #include "include/ipc.h" +/** + * audit_ptrace_mask - convert mask to permission string + * @buffer: buffer to write string to (NOT NULL) + * @mask: permission mask to convert + */ +static void audit_ptrace_mask(struct audit_buffer *ab, u32 mask) +{ + switch (mask) { + case MAY_READ: + audit_log_string(ab, "read"); + break; + case MAY_WRITE: + audit_log_string(ab, "trace"); + break; + case AA_MAY_BE_READ: + audit_log_string(ab, "readby"); + break; + case AA_MAY_BE_TRACED: + audit_log_string(ab, "tracedby"); + break; + } +} + /* call back to audit ptrace fields */ static void audit_ptrace_cb(struct audit_buffer *ab, void *va) { struct common_audit_data *sa = va; + if (aad(sa)->request & AA_PTRACE_PERM_MASK) { + audit_log_format(ab, " requested_mask="); + audit_ptrace_mask(ab, aad(sa)->request); + + if (aad(sa)->denied & AA_PTRACE_PERM_MASK) { + audit_log_format(ab, " denied_mask="); + audit_ptrace_mask(ab, aad(sa)->denied); + } + } audit_log_format(ab, " peer="); aa_label_xaudit(ab, labels_ns(aad(sa)->label), aad(sa)->peer, FLAGS_NONE, GFP_ATOMIC); } +/* TODO: conditionals */ +static int profile_ptrace_perm(struct aa_profile *profile, + struct aa_profile *peer, u32 request, + struct common_audit_data *sa) +{ + struct aa_perms perms = { }; + + /* need because of peer in cross check */ + if (profile_unconfined(profile) || + !PROFILE_MEDIATES(profile, AA_CLASS_PTRACE)) + return 0; + + aad(sa)->peer = &peer->label; + aa_profile_match_label(profile, &peer->label, AA_CLASS_PTRACE, request, + &perms); + aa_apply_modes_to_perms(profile, &perms); + return aa_check_perms(profile, &perms, request, sa, audit_ptrace_cb); +} + static int cross_ptrace_perm(struct aa_profile *tracer, struct aa_profile *tracee, u32 request, struct common_audit_data *sa) { + if (PROFILE_MEDIATES(tracer, AA_CLASS_PTRACE)) + return xcheck(profile_ptrace_perm(tracer, tracee, request, sa), + profile_ptrace_perm(tracee, tracer, + request << PTRACE_PERM_SHIFT, + sa)); /* policy uses the old style capability check for ptrace */ if (profile_unconfined(tracer) || tracer == tracee) return 0; |