summaryrefslogtreecommitdiffstats
path: root/security/apparmor
diff options
context:
space:
mode:
authorJohn Johansen <john.johansen@canonical.com>2017-06-09 20:58:42 +0200
committerJohn Johansen <john.johansen@canonical.com>2017-06-11 02:11:37 +0200
commit192ca6b55a866e838aee98d9cb6a0b5086467c03 (patch)
treeeba93d671a1476432f357fa68e6842f548e2cb2f /security/apparmor
parentapparmor: cleanup rename XXX_file_context() to XXX_file_ctx() (diff)
downloadlinux-192ca6b55a866e838aee98d9cb6a0b5086467c03.tar.xz
linux-192ca6b55a866e838aee98d9cb6a0b5086467c03.zip
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.c72
-rw-r--r--security/apparmor/include/audit.h1
-rw-r--r--security/apparmor/include/file.h2
-rw-r--r--security/apparmor/lsm.c6
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 */