apparmor: revalidate files during exec
authorJohn Johansen <john.johansen@canonical.com>
Fri, 9 Jun 2017 18:58:42 +0000 (11:58 -0700)
committerJohn Johansen <john.johansen@canonical.com>
Sun, 11 Jun 2017 00:11:37 +0000 (17:11 -0700)
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>
security/apparmor/file.c
security/apparmor/include/audit.h
security/apparmor/include/file.h
security/apparmor/lsm.c

index 2e128c2..bf50879 100644 (file)
  * 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);
+}
index 1aeb855..d548261 100644 (file)
@@ -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"
index 19c4838..df76c20 100644 (file)
@@ -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);
index 3c6fa97..7ba43c1 100644 (file)
@@ -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 */