diff options
author | John Johansen <john.johansen@canonical.com> | 2017-06-09 11:58:42 -0700 |
---|---|---|
committer | John Johansen <john.johansen@canonical.com> | 2017-06-10 17:11:37 -0700 |
commit | 192ca6b55a866e838aee98d9cb6a0b5086467c03 (patch) | |
tree | eba93d671a1476432f357fa68e6842f548e2cb2f /security/apparmor | |
parent | 2835a13bbdc09d330eafdf5e67eb407c90c01ab7 (diff) | |
download | linux-192ca6b55a866e838aee98d9cb6a0b5086467c03.tar.bz2 |
apparmor: revalidate files during exec
Instead of running file revalidation lazily when read/write are called
copy selinux and revalidate the file table on exec. This avoids
extra mediation overhead in read/write and also prevents file handles
being passed through to a grand child unchecked.
Signed-off-by: John Johansen <john.johansen@canonical.com>
Diffstat (limited to 'security/apparmor')
-rw-r--r-- | security/apparmor/file.c | 72 | ||||
-rw-r--r-- | security/apparmor/include/audit.h | 1 | ||||
-rw-r--r-- | security/apparmor/include/file.h | 2 | ||||
-rw-r--r-- | security/apparmor/lsm.c | 6 |
4 files changed, 81 insertions, 0 deletions
diff --git a/security/apparmor/file.c b/security/apparmor/file.c index 2e128c2aa4dc..bf508791cc1f 100644 --- a/security/apparmor/file.c +++ b/security/apparmor/file.c @@ -12,8 +12,13 @@ * License. */ +#include <linux/tty.h> +#include <linux/fdtable.h> +#include <linux/file.h> + #include "include/apparmor.h" #include "include/audit.h" +#include "include/context.h" #include "include/file.h" #include "include/match.h" #include "include/path.h" @@ -445,3 +450,70 @@ int aa_file_perm(const char *op, struct aa_profile *profile, struct file *file, return aa_path_perm(op, profile, &file->f_path, PATH_DELEGATE_DELETED, request, &cond); } + +static void revalidate_tty(struct aa_profile *profile) +{ + struct tty_struct *tty; + int drop_tty = 0; + + tty = get_current_tty(); + if (!tty) + return; + + spin_lock(&tty->files_lock); + if (!list_empty(&tty->tty_files)) { + struct tty_file_private *file_priv; + struct file *file; + /* TODO: Revalidate access to controlling tty. */ + file_priv = list_first_entry(&tty->tty_files, + struct tty_file_private, list); + file = file_priv->file; + + if (aa_file_perm(OP_INHERIT, profile, file, + MAY_READ | MAY_WRITE)) + drop_tty = 1; + } + spin_unlock(&tty->files_lock); + tty_kref_put(tty); + + if (drop_tty) + no_tty(); +} + +static int match_file(const void *p, struct file *file, unsigned int fd) +{ + struct aa_profile *profile = (struct aa_profile *)p; + + if (aa_file_perm(OP_INHERIT, profile, file, + aa_map_file_to_perms(file))) + return fd + 1; + return 0; +} + + +/* based on selinux's flush_unauthorized_files */ +void aa_inherit_files(const struct cred *cred, struct files_struct *files) +{ + struct aa_profile *profile = aa_get_newest_cred_profile(cred); + struct file *devnull = NULL; + unsigned int n; + + revalidate_tty(profile); + + /* Revalidate access to inherited open files. */ + n = iterate_fd(files, 0, match_file, profile); + if (!n) /* none found? */ + goto out; + + devnull = dentry_open(&aa_null, O_RDWR, cred); + if (IS_ERR(devnull)) + devnull = NULL; + /* replace all the matching ones with this */ + do { + replace_fd(n - 1, devnull, 0); + } while ((n = iterate_fd(files, n, match_file, profile)) != 0); + if (devnull) + fput(devnull); +out: + aa_put_profile(profile); +} diff --git a/security/apparmor/include/audit.h b/security/apparmor/include/audit.h index 1aeb8550fb82..d548261dd1b7 100644 --- a/security/apparmor/include/audit.h +++ b/security/apparmor/include/audit.h @@ -69,6 +69,7 @@ enum audit_type { #define OP_FLOCK "file_lock" #define OP_FMMAP "file_mmap" #define OP_FMPROT "file_mprotect" +#define OP_INHERIT "file_inherit" #define OP_CREATE "create" #define OP_POST_CREATE "post_create" diff --git a/security/apparmor/include/file.h b/security/apparmor/include/file.h index 19c483850770..df76c208473a 100644 --- a/security/apparmor/include/file.h +++ b/security/apparmor/include/file.h @@ -186,6 +186,8 @@ int aa_path_link(struct aa_profile *profile, struct dentry *old_dentry, int aa_file_perm(const char *op, struct aa_profile *profile, struct file *file, u32 request); +void aa_inherit_files(const struct cred *cred, struct files_struct *files); + static inline void aa_free_file_rules(struct aa_file_rules *rules) { aa_put_dfa(rules->dfa); diff --git a/security/apparmor/lsm.c b/security/apparmor/lsm.c index 3c6fa9753675..7ba43c18687a 100644 --- a/security/apparmor/lsm.c +++ b/security/apparmor/lsm.c @@ -417,6 +417,10 @@ static int common_file_perm(const char *op, struct file *file, u32 mask) struct aa_profile *profile, *fprofile; int error = 0; + /* don't reaudit files closed during inheritance */ + if (file->f_path.dentry == aa_null.dentry) + return -EACCES; + fprofile = aa_cred_raw_profile(file->f_cred); AA_BUG(!fprofile); @@ -600,6 +604,8 @@ static void apparmor_bprm_committing_creds(struct linux_binprm *bprm) (unconfined(new_ctx->profile))) return; + aa_inherit_files(bprm->cred, current->files); + current->pdeath_signal = 0; /* reset soft limits and set hard limits for the new profile */ |