summaryrefslogtreecommitdiff
path: root/security/apparmor/policy_unpack.c
diff options
context:
space:
mode:
authorJohn Johansen <john.johansen@canonical.com>2017-05-09 10:08:41 +0300
committerJohn Johansen <john.johansen@canonical.com>2017-06-08 22:51:49 +0300
commit5d5182cae40115c03933989473288e54afb39c7c (patch)
treead17fd4482d130039eb61b62e9c32ef3fa283d04 /security/apparmor/policy_unpack.c
parent6623ec7c4dbe18a5a2878e2d888be70d08a91826 (diff)
downloadlinux-5d5182cae40115c03933989473288e54afb39c7c.tar.xz
apparmor: move to per loaddata files, instead of replicating in profiles
The loaddata sets cover more than just a single profile and should be tracked at the ns level. Move the load data files under the namespace and reference the files from the profiles via a symlink. Signed-off-by: John Johansen <john.johansen@canonical.com> Reviewed-by: Seth Arnold <seth.arnold@canonical.com> Reviewed-by: Kees Cook <keescook@chromium.org>
Diffstat (limited to 'security/apparmor/policy_unpack.c')
-rw-r--r--security/apparmor/policy_unpack.c61
1 files changed, 59 insertions, 2 deletions
diff --git a/security/apparmor/policy_unpack.c b/security/apparmor/policy_unpack.c
index 6bc1b10191fa..e521df1bd1fb 100644
--- a/security/apparmor/policy_unpack.c
+++ b/security/apparmor/policy_unpack.c
@@ -122,16 +122,73 @@ static int audit_iface(struct aa_profile *new, const char *ns_name,
return aa_audit(AUDIT_APPARMOR_STATUS, profile, &sa, audit_cb);
}
+void __aa_loaddata_update(struct aa_loaddata *data, long revision)
+{
+ AA_BUG(!data);
+ AA_BUG(!data->ns);
+ AA_BUG(!data->dents[AAFS_LOADDATA_REVISION]);
+ AA_BUG(!mutex_is_locked(&data->ns->lock));
+ AA_BUG(data->revision > revision);
+
+ data->revision = revision;
+ d_inode(data->dents[AAFS_LOADDATA_DIR])->i_mtime =
+ current_time(d_inode(data->dents[AAFS_LOADDATA_DIR]));
+ d_inode(data->dents[AAFS_LOADDATA_REVISION])->i_mtime =
+ current_time(d_inode(data->dents[AAFS_LOADDATA_REVISION]));
+}
+
+bool aa_rawdata_eq(struct aa_loaddata *l, struct aa_loaddata *r)
+{
+ if (l->size != r->size)
+ return false;
+ if (aa_g_hash_policy && memcmp(l->hash, r->hash, aa_hash_size()) != 0)
+ return false;
+ return memcmp(l->data, r->data, r->size) == 0;
+}
+
+/*
+ * need to take the ns mutex lock which is NOT safe most places that
+ * put_loaddata is called, so we have to delay freeing it
+ */
+static void do_loaddata_free(struct work_struct *work)
+{
+ struct aa_loaddata *d = container_of(work, struct aa_loaddata, work);
+ struct aa_ns *ns = aa_get_ns(d->ns);
+
+ if (ns) {
+ mutex_lock(&ns->lock);
+ __aa_fs_remove_rawdata(d);
+ mutex_unlock(&ns->lock);
+ aa_put_ns(ns);
+ }
+
+ kzfree(d->hash);
+ kfree(d->name);
+ kvfree(d);
+}
+
void aa_loaddata_kref(struct kref *kref)
{
struct aa_loaddata *d = container_of(kref, struct aa_loaddata, count);
if (d) {
- kzfree(d->hash);
- kvfree(d);
+ INIT_WORK(&d->work, do_loaddata_free);
+ schedule_work(&d->work);
}
}
+struct aa_loaddata *aa_loaddata_alloc(size_t size)
+{
+ struct aa_loaddata *d = kvzalloc(sizeof(*d) + size, GFP_KERNEL);
+
+ if (d == NULL)
+ return ERR_PTR(-ENOMEM);
+ kref_init(&d->count);
+ INIT_LIST_HEAD(&d->list);
+
+ return d;
+}
+
/* test if read will be in packed data bounds */
static bool inbounds(struct aa_ext *e, size_t size)
{