summaryrefslogtreecommitdiff
path: root/security/apparmor/include
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2017-07-05 11:26:35 -0700
committerLinus Torvalds <torvalds@linux-foundation.org>2017-07-05 11:26:35 -0700
commite24dd9ee5399747b71c1d982a484fc7601795f31 (patch)
tree14fcec8728916092a9f6dbeb0f2b8d5c5a4e5c9a /security/apparmor/include
parent7391786a64dcfe9c609a1f8e2204c1abf42ded23 (diff)
parentc4758fa59285fe4dbfeab4364a6957936d040fbf (diff)
Merge branch 'next' of git://git.kernel.org/pub/scm/linux/kernel/git/jmorris/linux-security
Pull security layer updates from James Morris: - a major update for AppArmor. From JJ: * several bug fixes and cleanups * the patch to add symlink support to securityfs that was floated on the list earlier and the apparmorfs changes that make use of securityfs symlinks * it introduces the domain labeling base code that Ubuntu has been carrying for several years, with several cleanups applied. And it converts the current mediation over to using the domain labeling base, which brings domain stacking support with it. This finally will bring the base upstream code in line with Ubuntu and provide a base to upstream the new feature work that Ubuntu carries. * This does _not_ contain any of the newer apparmor mediation features/controls (mount, signals, network, keys, ...) that Ubuntu is currently carrying, all of which will be RFC'd on top of this. - Notable also is the Infiniband work in SELinux, and the new file:map permission. From Paul: "While we're down to 21 patches for v4.13 (it was 31 for v4.12), the diffstat jumps up tremendously with over 2k of line changes. Almost all of these changes are the SELinux/IB work done by Daniel Jurgens; some other noteworthy changes include a NFS v4.2 labeling fix, a new file:map permission, and reporting of policy capabilities on policy load" There's also now genfscon labeling support for tracefs, which was lost in v4.1 with the separation from debugfs. - Smack incorporates a safer socket check in file_receive, and adds a cap_capable call in privilege check. - TPM as usual has a bunch of fixes and enhancements. - Multiple calls to security_add_hooks() can now be made for the same LSM, to allow LSMs to have hook declarations across multiple files. - IMA now supports different "ima_appraise=" modes (eg. log, fix) from the boot command line. * 'next' of git://git.kernel.org/pub/scm/linux/kernel/git/jmorris/linux-security: (126 commits) apparmor: put back designators in struct initialisers seccomp: Switch from atomic_t to recount_t seccomp: Adjust selftests to avoid double-join seccomp: Clean up core dump logic IMA: update IMA policy documentation to include pcr= option ima: Log the same audit cause whenever a file has no signature ima: Simplify policy_func_show. integrity: Small code improvements ima: fix get_binary_runtime_size() ima: use ima_parse_buf() to parse template data ima: use ima_parse_buf() to parse measurements headers ima: introduce ima_parse_buf() ima: Add cgroups2 to the defaults list ima: use memdup_user_nul ima: fix up #endif comments IMA: Correct Kconfig dependencies for hash selection ima: define is_ima_appraise_enabled() ima: define Kconfig IMA_APPRAISE_BOOTPARAM option ima: define a set of appraisal rules requiring file signatures ima: extend the "ima_policy" boot command line to support multiple policies ...
Diffstat (limited to 'security/apparmor/include')
-rw-r--r--security/apparmor/include/apparmor.h6
-rw-r--r--security/apparmor/include/apparmorfs.h67
-rw-r--r--security/apparmor/include/audit.h17
-rw-r--r--security/apparmor/include/capability.h8
-rw-r--r--security/apparmor/include/context.h201
-rw-r--r--security/apparmor/include/domain.h13
-rw-r--r--security/apparmor/include/file.h114
-rw-r--r--security/apparmor/include/ipc.h16
-rw-r--r--security/apparmor/include/label.h441
-rw-r--r--security/apparmor/include/lib.h120
-rw-r--r--security/apparmor/include/path.h7
-rw-r--r--security/apparmor/include/perms.h155
-rw-r--r--security/apparmor/include/policy.h131
-rw-r--r--security/apparmor/include/policy_ns.h21
-rw-r--r--security/apparmor/include/policy_unpack.h68
-rw-r--r--security/apparmor/include/procattr.h8
-rw-r--r--security/apparmor/include/resource.h6
17 files changed, 1125 insertions, 274 deletions
diff --git a/security/apparmor/include/apparmor.h b/security/apparmor/include/apparmor.h
index 1750cc0721c1..aaf893f4e4f5 100644
--- a/security/apparmor/include/apparmor.h
+++ b/security/apparmor/include/apparmor.h
@@ -4,7 +4,7 @@
* This file contains AppArmor basic global
*
* Copyright (C) 1998-2008 Novell/SUSE
- * Copyright 2009-2010 Canonical Ltd.
+ * Copyright 2009-2017 Canonical Ltd.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
@@ -27,8 +27,10 @@
#define AA_CLASS_NET 4
#define AA_CLASS_RLIMITS 5
#define AA_CLASS_DOMAIN 6
+#define AA_CLASS_PTRACE 9
+#define AA_CLASS_LABEL 16
-#define AA_CLASS_LAST AA_CLASS_DOMAIN
+#define AA_CLASS_LAST AA_CLASS_LABEL
/* Control parameters settable through module/boot flags */
extern enum audit_mode aa_g_audit;
diff --git a/security/apparmor/include/apparmorfs.h b/security/apparmor/include/apparmorfs.h
index 120a798b5bb0..bd689114bf93 100644
--- a/security/apparmor/include/apparmorfs.h
+++ b/security/apparmor/include/apparmorfs.h
@@ -17,49 +17,49 @@
extern struct path aa_null;
-enum aa_fs_type {
- AA_FS_TYPE_BOOLEAN,
- AA_FS_TYPE_STRING,
- AA_FS_TYPE_U64,
- AA_FS_TYPE_FOPS,
- AA_FS_TYPE_DIR,
+enum aa_sfs_type {
+ AA_SFS_TYPE_BOOLEAN,
+ AA_SFS_TYPE_STRING,
+ AA_SFS_TYPE_U64,
+ AA_SFS_TYPE_FOPS,
+ AA_SFS_TYPE_DIR,
};
-struct aa_fs_entry;
+struct aa_sfs_entry;
-struct aa_fs_entry {
+struct aa_sfs_entry {
const char *name;
struct dentry *dentry;
umode_t mode;
- enum aa_fs_type v_type;
+ enum aa_sfs_type v_type;
union {
bool boolean;
char *string;
unsigned long u64;
- struct aa_fs_entry *files;
+ struct aa_sfs_entry *files;
} v;
const struct file_operations *file_ops;
};
-extern const struct file_operations aa_fs_seq_file_ops;
+extern const struct file_operations aa_sfs_seq_file_ops;
-#define AA_FS_FILE_BOOLEAN(_name, _value) \
+#define AA_SFS_FILE_BOOLEAN(_name, _value) \
{ .name = (_name), .mode = 0444, \
- .v_type = AA_FS_TYPE_BOOLEAN, .v.boolean = (_value), \
- .file_ops = &aa_fs_seq_file_ops }
-#define AA_FS_FILE_STRING(_name, _value) \
+ .v_type = AA_SFS_TYPE_BOOLEAN, .v.boolean = (_value), \
+ .file_ops = &aa_sfs_seq_file_ops }
+#define AA_SFS_FILE_STRING(_name, _value) \
{ .name = (_name), .mode = 0444, \
- .v_type = AA_FS_TYPE_STRING, .v.string = (_value), \
- .file_ops = &aa_fs_seq_file_ops }
-#define AA_FS_FILE_U64(_name, _value) \
+ .v_type = AA_SFS_TYPE_STRING, .v.string = (_value), \
+ .file_ops = &aa_sfs_seq_file_ops }
+#define AA_SFS_FILE_U64(_name, _value) \
{ .name = (_name), .mode = 0444, \
- .v_type = AA_FS_TYPE_U64, .v.u64 = (_value), \
- .file_ops = &aa_fs_seq_file_ops }
-#define AA_FS_FILE_FOPS(_name, _mode, _fops) \
- { .name = (_name), .v_type = AA_FS_TYPE_FOPS, \
+ .v_type = AA_SFS_TYPE_U64, .v.u64 = (_value), \
+ .file_ops = &aa_sfs_seq_file_ops }
+#define AA_SFS_FILE_FOPS(_name, _mode, _fops) \
+ { .name = (_name), .v_type = AA_SFS_TYPE_FOPS, \
.mode = (_mode), .file_ops = (_fops) }
-#define AA_FS_DIR(_name, _value) \
- { .name = (_name), .v_type = AA_FS_TYPE_DIR, .v.files = (_value) }
+#define AA_SFS_DIR(_name, _value) \
+ { .name = (_name), .v_type = AA_SFS_TYPE_DIR, .v.files = (_value) }
extern void __init aa_destroy_aafs(void);
@@ -74,6 +74,7 @@ enum aafs_ns_type {
AAFS_NS_LOAD,
AAFS_NS_REPLACE,
AAFS_NS_REMOVE,
+ AAFS_NS_REVISION,
AAFS_NS_COUNT,
AAFS_NS_MAX_COUNT,
AAFS_NS_SIZE,
@@ -102,16 +103,22 @@ enum aafs_prof_type {
#define ns_subload(X) ((X)->dents[AAFS_NS_LOAD])
#define ns_subreplace(X) ((X)->dents[AAFS_NS_REPLACE])
#define ns_subremove(X) ((X)->dents[AAFS_NS_REMOVE])
+#define ns_subrevision(X) ((X)->dents[AAFS_NS_REVISION])
#define prof_dir(X) ((X)->dents[AAFS_PROF_DIR])
#define prof_child_dir(X) ((X)->dents[AAFS_PROF_PROFS])
-void __aa_fs_profile_rmdir(struct aa_profile *profile);
-void __aa_fs_profile_migrate_dents(struct aa_profile *old,
+void __aa_bump_ns_revision(struct aa_ns *ns);
+void __aafs_profile_rmdir(struct aa_profile *profile);
+void __aafs_profile_migrate_dents(struct aa_profile *old,
struct aa_profile *new);
-int __aa_fs_profile_mkdir(struct aa_profile *profile, struct dentry *parent);
-void __aa_fs_ns_rmdir(struct aa_ns *ns);
-int __aa_fs_ns_mkdir(struct aa_ns *ns, struct dentry *parent,
- const char *name);
+int __aafs_profile_mkdir(struct aa_profile *profile, struct dentry *parent);
+void __aafs_ns_rmdir(struct aa_ns *ns);
+int __aafs_ns_mkdir(struct aa_ns *ns, struct dentry *parent, const char *name,
+ struct dentry *dent);
+
+struct aa_loaddata;
+void __aa_fs_remove_rawdata(struct aa_loaddata *rawdata);
+int __aa_fs_create_rawdata(struct aa_ns *ns, struct aa_loaddata *rawdata);
#endif /* __AA_APPARMORFS_H */
diff --git a/security/apparmor/include/audit.h b/security/apparmor/include/audit.h
index fdc4774318ba..c68839a44351 100644
--- a/security/apparmor/include/audit.h
+++ b/security/apparmor/include/audit.h
@@ -22,8 +22,7 @@
#include <linux/slab.h>
#include "file.h"
-
-struct aa_profile;
+#include "label.h"
extern const char *const audit_mode_names[];
#define AUDIT_MAX_INDEX 5
@@ -65,10 +64,12 @@ enum audit_type {
#define OP_GETATTR "getattr"
#define OP_OPEN "open"
+#define OP_FRECEIVE "file_receive"
#define OP_FPERM "file_perm"
#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"
@@ -91,6 +92,8 @@ enum audit_type {
#define OP_CHANGE_HAT "change_hat"
#define OP_CHANGE_PROFILE "change_profile"
#define OP_CHANGE_ONEXEC "change_onexec"
+#define OP_STACK "stack"
+#define OP_STACK_ONEXEC "stack_onexec"
#define OP_SETPROCATTR "setprocattr"
#define OP_SETRLIMIT "setrlimit"
@@ -102,19 +105,19 @@ enum audit_type {
struct apparmor_audit_data {
int error;
- const char *op;
int type;
- void *profile;
+ const char *op;
+ struct aa_label *label;
const char *name;
const char *info;
+ u32 request;
+ u32 denied;
union {
/* these entries require a custom callback fn */
struct {
- struct aa_profile *peer;
+ struct aa_label *peer;
struct {
const char *target;
- u32 request;
- u32 denied;
kuid_t ouid;
} fs;
};
diff --git a/security/apparmor/include/capability.h b/security/apparmor/include/capability.h
index fc3fa381d850..e0304e2aeb7f 100644
--- a/security/apparmor/include/capability.h
+++ b/security/apparmor/include/capability.h
@@ -19,11 +19,12 @@
#include "apparmorfs.h"
-struct aa_profile;
+struct aa_label;
/* aa_caps - confinement data for capabilities
* @allowed: capabilities mask
* @audit: caps that are to be audited
+ * @denied: caps that are explicitly denied
* @quiet: caps that should not be audited
* @kill: caps that when requested will result in the task being killed
* @extended: caps that are subject finer grained mediation
@@ -31,14 +32,15 @@ struct aa_profile;
struct aa_caps {
kernel_cap_t allow;
kernel_cap_t audit;
+ kernel_cap_t denied;
kernel_cap_t quiet;
kernel_cap_t kill;
kernel_cap_t extended;
};
-extern struct aa_fs_entry aa_fs_entry_caps[];
+extern struct aa_sfs_entry aa_sfs_entry_caps[];
-int aa_capable(struct aa_profile *profile, int cap, int audit);
+int aa_capable(struct aa_label *label, int cap, int audit);
static inline void aa_free_cap_rules(struct aa_caps *caps)
{
diff --git a/security/apparmor/include/context.h b/security/apparmor/include/context.h
index 5b18fedab4c8..6ae07e9aaa17 100644
--- a/security/apparmor/include/context.h
+++ b/security/apparmor/include/context.h
@@ -19,60 +19,28 @@
#include <linux/slab.h>
#include <linux/sched.h>
-#include "policy.h"
+#include "label.h"
#include "policy_ns.h"
#define cred_ctx(X) ((X)->security)
#define current_ctx() cred_ctx(current_cred())
-/* struct aa_file_ctx - the AppArmor context the file was opened in
- * @perms: the permission the file was opened with
- *
- * The file_ctx could currently be directly stored in file->f_security
- * as the profile reference is now stored in the f_cred. However the
- * ctx struct will expand in the future so we keep the struct.
- */
-struct aa_file_ctx {
- u16 allow;
-};
-
-/**
- * aa_alloc_file_context - allocate file_ctx
- * @gfp: gfp flags for allocation
- *
- * Returns: file_ctx or NULL on failure
- */
-static inline struct aa_file_ctx *aa_alloc_file_context(gfp_t gfp)
-{
- return kzalloc(sizeof(struct aa_file_ctx), gfp);
-}
-
-/**
- * aa_free_file_context - free a file_ctx
- * @ctx: file_ctx to free (MAYBE_NULL)
- */
-static inline void aa_free_file_context(struct aa_file_ctx *ctx)
-{
- if (ctx)
- kzfree(ctx);
-}
-
/**
* struct aa_task_ctx - primary label for confined tasks
- * @profile: the current profile (NOT NULL)
- * @exec: profile to transition to on next exec (MAYBE NULL)
- * @previous: profile the task may return to (MAYBE NULL)
- * @token: magic value the task must know for returning to @previous_profile
+ * @label: the current label (NOT NULL)
+ * @exec: label to transition to on next exec (MAYBE NULL)
+ * @previous: label the task may return to (MAYBE NULL)
+ * @token: magic value the task must know for returning to @previous
*
- * Contains the task's current profile (which could change due to
+ * Contains the task's current label (which could change due to
* change_hat). Plus the hat_magic needed during change_hat.
*
* TODO: make so a task can be confined by a stack of contexts
*/
struct aa_task_ctx {
- struct aa_profile *profile;
- struct aa_profile *onexec;
- struct aa_profile *previous;
+ struct aa_label *label;
+ struct aa_label *onexec;
+ struct aa_label *previous;
u64 token;
};
@@ -80,40 +48,51 @@ struct aa_task_ctx *aa_alloc_task_context(gfp_t flags);
void aa_free_task_context(struct aa_task_ctx *ctx);
void aa_dup_task_context(struct aa_task_ctx *new,
const struct aa_task_ctx *old);
-int aa_replace_current_profile(struct aa_profile *profile);
-int aa_set_current_onexec(struct aa_profile *profile);
-int aa_set_current_hat(struct aa_profile *profile, u64 token);
-int aa_restore_previous_profile(u64 cookie);
-struct aa_profile *aa_get_task_profile(struct task_struct *task);
+int aa_replace_current_label(struct aa_label *label);
+int aa_set_current_onexec(struct aa_label *label, bool stack);
+int aa_set_current_hat(struct aa_label *label, u64 token);
+int aa_restore_previous_label(u64 cookie);
+struct aa_label *aa_get_task_label(struct task_struct *task);
/**
- * aa_cred_profile - obtain cred's profiles
- * @cred: cred to obtain profiles from (NOT NULL)
+ * aa_cred_raw_label - obtain cred's label
+ * @cred: cred to obtain label from (NOT NULL)
*
- * Returns: confining profile
+ * Returns: confining label
*
* does NOT increment reference count
*/
-static inline struct aa_profile *aa_cred_profile(const struct cred *cred)
+static inline struct aa_label *aa_cred_raw_label(const struct cred *cred)
{
struct aa_task_ctx *ctx = cred_ctx(cred);
- AA_BUG(!ctx || !ctx->profile);
- return ctx->profile;
+ AA_BUG(!ctx || !ctx->label);
+ return ctx->label;
+}
+
+/**
+ * aa_get_newest_cred_label - obtain the newest label on a cred
+ * @cred: cred to obtain label from (NOT NULL)
+ *
+ * Returns: newest version of confining label
+ */
+static inline struct aa_label *aa_get_newest_cred_label(const struct cred *cred)
+{
+ return aa_get_newest_label(aa_cred_raw_label(cred));
}
/**
- * __aa_task_profile - retrieve another task's profile
+ * __aa_task_raw_label - retrieve another task's label
* @task: task to query (NOT NULL)
*
- * Returns: @task's profile without incrementing its ref count
+ * Returns: @task's label without incrementing its ref count
*
* If @task != current needs to be called in RCU safe critical section
*/
-static inline struct aa_profile *__aa_task_profile(struct task_struct *task)
+static inline struct aa_label *__aa_task_raw_label(struct task_struct *task)
{
- return aa_cred_profile(__task_cred(task));
+ return aa_cred_raw_label(__task_cred(task));
}
/**
@@ -124,50 +103,114 @@ static inline struct aa_profile *__aa_task_profile(struct task_struct *task)
*/
static inline bool __aa_task_is_confined(struct task_struct *task)
{
- return !unconfined(__aa_task_profile(task));
+ return !unconfined(__aa_task_raw_label(task));
}
/**
- * __aa_current_profile - find the current tasks confining profile
+ * aa_current_raw_label - find the current tasks confining label
*
- * Returns: up to date confining profile or the ns unconfined profile (NOT NULL)
+ * Returns: up to date confining label or the ns unconfined label (NOT NULL)
*
* This fn will not update the tasks cred to the most up to date version
- * of the profile so it is safe to call when inside of locks.
+ * of the label so it is safe to call when inside of locks.
*/
-static inline struct aa_profile *__aa_current_profile(void)
+static inline struct aa_label *aa_current_raw_label(void)
{
- return aa_cred_profile(current_cred());
+ return aa_cred_raw_label(current_cred());
}
/**
- * aa_current_profile - find the current tasks confining profile and do updates
+ * aa_get_current_label - get the newest version of the current tasks label
+ *
+ * Returns: newest version of confining label (NOT NULL)
*
- * Returns: up to date confining profile or the ns unconfined profile (NOT NULL)
+ * This fn will not update the tasks cred, so it is safe inside of locks
*
- * This fn will update the tasks cred structure if the profile has been
- * replaced. Not safe to call inside locks
+ * The returned reference must be put with aa_put_label()
*/
-static inline struct aa_profile *aa_current_profile(void)
+static inline struct aa_label *aa_get_current_label(void)
{
- const struct aa_task_ctx *ctx = current_ctx();
- struct aa_profile *profile;
+ struct aa_label *l = aa_current_raw_label();
- AA_BUG(!ctx || !ctx->profile);
+ if (label_is_stale(l))
+ return aa_get_newest_label(l);
+ return aa_get_label(l);
+}
+
+#define __end_current_label_crit_section(X) end_current_label_crit_section(X)
- if (profile_is_stale(ctx->profile)) {
- profile = aa_get_newest_profile(ctx->profile);
- aa_replace_current_profile(profile);
- aa_put_profile(profile);
- ctx = current_ctx();
+/**
+ * end_label_crit_section - put a reference found with begin_current_label..
+ * @label: label reference to put
+ *
+ * Should only be used with a reference obtained with
+ * begin_current_label_crit_section and never used in situations where the
+ * task cred may be updated
+ */
+static inline void end_current_label_crit_section(struct aa_label *label)
+{
+ if (label != aa_current_raw_label())
+ aa_put_label(label);
+}
+
+/**
+ * __begin_current_label_crit_section - current's confining label
+ *
+ * Returns: up to date confining label or the ns unconfined label (NOT NULL)
+ *
+ * safe to call inside locks
+ *
+ * The returned reference must be put with __end_current_label_crit_section()
+ * This must NOT be used if the task cred could be updated within the
+ * critical section between __begin_current_label_crit_section() ..
+ * __end_current_label_crit_section()
+ */
+static inline struct aa_label *__begin_current_label_crit_section(void)
+{
+ struct aa_label *label = aa_current_raw_label();
+
+ if (label_is_stale(label))
+ label = aa_get_newest_label(label);
+
+ return label;
+}
+
+/**
+ * begin_current_label_crit_section - current's confining label and update it
+ *
+ * Returns: up to date confining label or the ns unconfined label (NOT NULL)
+ *
+ * Not safe to call inside locks
+ *
+ * The returned reference must be put with end_current_label_crit_section()
+ * This must NOT be used if the task cred could be updated within the
+ * critical section between begin_current_label_crit_section() ..
+ * end_current_label_crit_section()
+ */
+static inline struct aa_label *begin_current_label_crit_section(void)
+{
+ struct aa_label *label = aa_current_raw_label();
+
+ if (label_is_stale(label)) {
+ label = aa_get_newest_label(label);
+ if (aa_replace_current_label(label) == 0)
+ /* task cred will keep the reference */
+ aa_put_label(label);
}
- return ctx->profile;
+ return label;
}
static inline struct aa_ns *aa_get_current_ns(void)
{
- return aa_get_ns(__aa_current_profile()->ns);
+ struct aa_label *label;
+ struct aa_ns *ns;
+
+ label = __begin_current_label_crit_section();
+ ns = aa_get_ns(labels_ns(label));
+ __end_current_label_crit_section(label);
+
+ return ns;
}
/**
@@ -176,8 +219,8 @@ static inline struct aa_ns *aa_get_current_ns(void)
*/
static inline void aa_clear_task_ctx_trans(struct aa_task_ctx *ctx)
{
- aa_put_profile(ctx->previous);
- aa_put_profile(ctx->onexec);
+ aa_put_label(ctx->previous);
+ aa_put_label(ctx->onexec);
ctx->previous = NULL;
ctx->onexec = NULL;
ctx->token = 0;
diff --git a/security/apparmor/include/domain.h b/security/apparmor/include/domain.h
index 30544729878a..bab5810b6e9a 100644
--- a/security/apparmor/include/domain.h
+++ b/security/apparmor/include/domain.h
@@ -23,14 +23,17 @@ struct aa_domain {
char **table;
};
+#define AA_CHANGE_NOFLAGS 0
+#define AA_CHANGE_TEST 1
+#define AA_CHANGE_CHILD 2
+#define AA_CHANGE_ONEXEC 4
+#define AA_CHANGE_STACK 8
+
int apparmor_bprm_set_creds(struct linux_binprm *bprm);
int apparmor_bprm_secureexec(struct linux_binprm *bprm);
-void apparmor_bprm_committing_creds(struct linux_binprm *bprm);
-void apparmor_bprm_committed_creds(struct linux_binprm *bprm);
void aa_free_domain_entries(struct aa_domain *domain);
-int aa_change_hat(const char *hats[], int count, u64 token, bool permtest);
-int aa_change_profile(const char *fqname, bool onexec, bool permtest,
- bool stack);
+int aa_change_hat(const char *hats[], int count, u64 token, int flags);
+int aa_change_profile(const char *fqname, int flags);
#endif /* __AA_DOMAIN_H */
diff --git a/security/apparmor/include/file.h b/security/apparmor/include/file.h
index 38f821bf49b6..001e40073ff9 100644
--- a/security/apparmor/include/file.h
+++ b/security/apparmor/include/file.h
@@ -15,38 +15,73 @@
#ifndef __AA_FILE_H
#define __AA_FILE_H
+#include <linux/spinlock.h>
+
#include "domain.h"
#include "match.h"
+#include "perms.h"
struct aa_profile;
struct path;
-/*
- * We use MAY_EXEC, MAY_WRITE, MAY_READ, MAY_APPEND and the following flags
- * for profile permissions
- */
-#define AA_MAY_CREATE 0x0010
-#define AA_MAY_DELETE 0x0020
-#define AA_MAY_META_WRITE 0x0040
-#define AA_MAY_META_READ 0x0080
-
-#define AA_MAY_CHMOD 0x0100
-#define AA_MAY_CHOWN 0x0200
-#define AA_MAY_LOCK 0x0400
-#define AA_EXEC_MMAP 0x0800
-
-#define AA_MAY_LINK 0x1000
-#define AA_LINK_SUBSET AA_MAY_LOCK /* overlaid */
-#define AA_MAY_ONEXEC 0x40000000 /* exec allows onexec */
-#define AA_MAY_CHANGE_PROFILE 0x80000000
-#define AA_MAY_CHANGEHAT 0x80000000 /* ctrl auditing only */
+#define mask_mode_t(X) (X & (MAY_EXEC | MAY_WRITE | MAY_READ | MAY_APPEND))
#define AA_AUDIT_FILE_MASK (MAY_READ | MAY_WRITE | MAY_EXEC | MAY_APPEND |\
AA_MAY_CREATE | AA_MAY_DELETE | \
- AA_MAY_META_READ | AA_MAY_META_WRITE | \
+ AA_MAY_GETATTR | AA_MAY_SETATTR | \
AA_MAY_CHMOD | AA_MAY_CHOWN | AA_MAY_LOCK | \
AA_EXEC_MMAP | AA_MAY_LINK)
+#define file_ctx(X) ((struct aa_file_ctx *)(X)->f_security)
+
+/* struct aa_file_ctx - the AppArmor context the file was opened in
+ * @lock: lock to update the ctx
+ * @label: label currently cached on the ctx
+ * @perms: the permission the file was opened with
+ */
+struct aa_file_ctx {
+ spinlock_t lock;
+ struct aa_label __rcu *label;
+ u32 allow;
+};
+
+/**
+ * aa_alloc_file_ctx - allocate file_ctx
+ * @label: initial label of task creating the file
+ * @gfp: gfp flags for allocation
+ *
+ * Returns: file_ctx or NULL on failure
+ */
+static inline struct aa_file_ctx *aa_alloc_file_ctx(struct aa_label *label,
+ gfp_t gfp)
+{
+ struct aa_file_ctx *ctx;
+
+ ctx = kzalloc(sizeof(struct aa_file_ctx), gfp);
+ if (ctx) {
+ spin_lock_init(&ctx->lock);
+ rcu_assign_pointer(ctx->label, aa_get_label(label));
+ }
+ return ctx;
+}
+
+/**
+ * aa_free_file_ctx - free a file_ctx
+ * @ctx: file_ctx to free (MAYBE_NULL)
+ */
+static inline void aa_free_file_ctx(struct aa_file_ctx *ctx)
+{
+ if (ctx) {
+ aa_put_label(rcu_access_pointer(ctx->label));
+ kzfree(ctx);
+ }
+}
+
+static inline struct aa_label *aa_get_file_label(struct aa_file_ctx *ctx)
+{
+ return aa_get_label_rcu(&ctx->label);
+}
+
/*
* The xindex is broken into 3 parts
* - index - an index into either the exec name table or the variable table
@@ -75,25 +110,6 @@ struct path_cond {
umode_t mode;
};
-/* struct file_perms - file permission
- * @allow: mask of permissions that are allowed
- * @audit: mask of permissions to force an audit message for
- * @quiet: mask of permissions to quiet audit messages for
- * @kill: mask of permissions that when matched will kill the task
- * @xindex: exec transition index if @allow contains MAY_EXEC
- *
- * The @audit and @queit mask should be mutually exclusive.
- */
-struct file_perms {
- u32 allow;
- u32 audit;
- u32 quiet;
- u32 kill;
- u16 xindex;
-};
-
-extern struct file_perms nullperms;
-
#define COMBINED_PERM_MASK(X) ((X).allow | (X).audit | (X).quiet | (X).kill)
/* FIXME: split perms from dfa and match this to description
@@ -144,9 +160,10 @@ static inline u16 dfa_map_xindex(u16 mask)
#define dfa_other_xindex(dfa, state) \
dfa_map_xindex((ACCEPT_TABLE(dfa)[state] >> 14) & 0x3fff)
-int aa_audit_file(struct aa_profile *profile, struct file_perms *perms,
+int aa_audit_file(struct aa_profile *profile, struct aa_perms *perms,
const char *op, u32 request, const char *name,
- const char *target, kuid_t ouid, const char *info, int error);
+ const char *target, struct aa_label *tlabel, kuid_t ouid,
+ const char *info, int error);
/**
* struct aa_file_rules - components used for file rule permissions
@@ -167,20 +184,27 @@ struct aa_file_rules {
/* TODO: add delegate table */
};
+struct aa_perms aa_compute_fperms(struct aa_dfa *dfa, unsigned int state,
+ struct path_cond *cond);
unsigned int aa_str_perms(struct aa_dfa *dfa, unsigned int start,
const char *name, struct path_cond *cond,
- struct file_perms *perms);
+ struct aa_perms *perms);
-int aa_path_perm(const char *op, struct aa_profile *profile,
+int __aa_path_perm(const char *op, struct aa_profile *profile,
+ const char *name, u32 request, struct path_cond *cond,
+ int flags, struct aa_perms *perms);
+int aa_path_perm(const char *op, struct aa_label *label,
const struct path *path, int flags, u32 request,
struct path_cond *cond);
-int aa_path_link(struct aa_profile *profile, struct dentry *old_dentry,
+int aa_path_link(struct aa_label *label, struct dentry *old_dentry,
const struct path *new_dir, struct dentry *new_dentry);
-int aa_file_perm(const char *op, struct aa_profile *profile, struct file *file,
+int aa_file_perm(const char *op, struct aa_label *label, 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/include/ipc.h b/security/apparmor/include/ipc.h
index 288ca76e2fb1..656fdb81c8a0 100644
--- a/security/apparmor/include/ipc.h
+++ b/security/apparmor/include/ipc.h
@@ -4,7 +4,7 @@
* This file contains AppArmor ipc mediation function definitions.
*
* Copyright (C) 1998-2008 Novell/SUSE
- * Copyright 2009-2010 Canonical Ltd.
+ * Copyright 2009-2017 Canonical Ltd.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
@@ -19,10 +19,16 @@
struct aa_profile;
-int aa_may_ptrace(struct aa_profile *tracer, struct aa_profile *tracee,
- unsigned int mode);
+#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
-int aa_ptrace(struct task_struct *tracer, struct task_struct *tracee,
- unsigned int mode);
+#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);
#endif /* __AA_IPC_H */
diff --git a/security/apparmor/include/label.h b/security/apparmor/include/label.h
new file mode 100644
index 000000000000..9a283b722755
--- /dev/null
+++ b/security/apparmor/include/label.h
@@ -0,0 +1,441 @@
+/*
+ * AppArmor security module
+ *
+ * This file contains AppArmor label definitions
+ *
+ * Copyright 2017 Canonical Ltd.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, version 2 of the
+ * License.
+ */
+
+#ifndef __AA_LABEL_H
+#define __AA_LABEL_H
+
+#include <linux/atomic.h>
+#include <linux/audit.h>
+#include <linux/rbtree.h>
+#include <linux/rcupdate.h>
+
+#include "apparmor.h"
+#include "lib.h"
+
+struct aa_ns;
+
+#define LOCAL_VEC_ENTRIES 8
+#define DEFINE_VEC(T, V) \
+ struct aa_ ## T *(_ ## V ## _localtmp)[LOCAL_VEC_ENTRIES]; \
+ struct aa_ ## T **(V)
+
+#define vec_setup(T, V, N, GFP) \
+({ \
+ if ((N) <= LOCAL_VEC_ENTRIES) { \
+ typeof(N) i; \
+ (V) = (_ ## V ## _localtmp); \
+ for (i = 0; i < (N); i++) \
+ (V)[i] = NULL; \
+ } else \
+ (V) = kzalloc(sizeof(struct aa_ ## T *) * (N), (GFP)); \
+ (V) ? 0 : -ENOMEM; \
+})
+
+#define vec_cleanup(T, V, N) \
+do { \
+ int i; \
+ for (i = 0; i < (N); i++) { \
+ if (!IS_ERR_OR_NULL((V)[i])) \
+ aa_put_ ## T((V)[i]); \
+ } \
+ if ((V) != _ ## V ## _localtmp) \
+ kfree(V); \
+} while (0)
+
+#define vec_last(VEC, SIZE) ((VEC)[(SIZE) - 1])
+#define vec_ns(VEC, SIZE) (vec_last((VEC), (SIZE))->ns)
+#define vec_labelset(VEC, SIZE) (&vec_ns((VEC), (SIZE))->labels)
+#define cleanup_domain_vec(V, L) cleanup_label_vec((V), (L)->size)
+
+struct aa_profile;
+#define VEC_FLAG_TERMINATE 1
+int aa_vec_unique(struct aa_profile **vec, int n, int flags);
+struct aa_label *aa_vec_find_or_create_label(struct aa_profile **vec, int len,
+ gfp_t gfp);
+#define aa_sort_and_merge_vec(N, V) \
+ aa_sort_and_merge_profiles((N), (struct aa_profile **)(V))
+
+
+/* struct aa_labelset - set of labels for a namespace
+ *
+ * Labels are reference counted; aa_labelset does not contribute to label
+ * reference counts. Once a label's last refcount is put it is removed from
+ * the set.
+ */
+struct aa_labelset {
+ rwlock_t lock;
+
+ struct rb_root root;
+};
+
+#define __labelset_for_each(LS, N) \
+ for ((N) = rb_first(&(LS)->root); (N); (N) = rb_next(N))
+
+void aa_labelset_destroy(struct aa_labelset *ls);
+void aa_labelset_init(struct aa_labelset *ls);
+
+
+enum label_flags {
+ FLAG_HAT = 1, /* profile is a hat */
+ FLAG_UNCONFINED = 2, /* label unconfined only if all */
+ FLAG_NULL = 4, /* profile is null learning profile */
+ FLAG_IX_ON_NAME_ERROR = 8, /* fallback to ix on name lookup fail */
+ FLAG_IMMUTIBLE = 0x10, /* don't allow changes/replacement */
+ FLAG_USER_DEFINED = 0x20, /* user based profile - lower privs */
+ FLAG_NO_LIST_REF = 0x40, /* list doesn't keep profile ref */
+ FLAG_NS_COUNT = 0x80, /* carries NS ref count */
+ FLAG_IN_TREE = 0x100, /* label is in tree */
+ FLAG_PROFILE = 0x200, /* label is a profile */
+ FLAG_EXPLICIT = 0x400, /* explicit static label */
+ FLAG_STALE = 0x800, /* replaced/removed */
+ FLAG_RENAMED = 0x1000, /* label has renaming in it */
+ FLAG_REVOKED = 0x2000, /* label has revocation in it */
+
+ /* These flags must correspond with PATH_flags */
+ /* TODO: add new path flags */
+};
+
+struct aa_label;
+struct aa_proxy {
+ struct kref count;
+ struct aa_label __rcu *label;
+};
+
+struct label_it {
+ int i, j;
+};
+
+/* struct aa_label - lazy labeling struct
+ * @count: ref count of active users
+ * @node: rbtree position
+ * @rcu: rcu callback struct
+ * @proxy: is set to the label that replaced this label
+ * @hname: text representation of the label (MAYBE_NULL)
+ * @flags: stale and other flags - values may change under label set lock
+ * @secid: secid that references this label
+ * @size: number of entries in @ent[]
+ * @ent: set of profiles for label, actual size determined by @size
+ */
+struct aa_label {
+ struct kref count;
+ struct rb_node node;
+ struct rcu_head rcu;
+ struct aa_proxy *proxy;
+ __counted char *hname;
+ long flags;
+ u32 secid;
+ int size;
+ struct aa_profile *vec[];
+};
+
+#define last_error(E, FN) \
+do { \
+ int __subE = (FN); \
+ if (__subE) \
+ (E) = __subE; \
+} while (0)
+
+#define label_isprofile(X) ((X)->flags & FLAG_PROFILE)
+#define label_unconfined(X) ((X)->flags & FLAG_UNCONFINED)
+#define unconfined(X) label_unconfined(X)
+#define label_is_stale(X) ((X)->flags & FLAG_STALE)
+#define __label_make_stale(X) ((X)->flags |= FLAG_STALE)
+#define labels_ns(X) (vec_ns(&((X)->vec[0]), (X)->size))
+#define labels_set(X) (&labels_ns(X)->labels)
+#define labels_profile(X) ((X)->vec[(X)->size - 1])
+
+
+int aa_label_next_confined(struct aa_label *l, int i);
+
+/* for each profile in a label */
+#define label_for_each(I, L, P) \
+ for ((I).i = 0; ((P) = (L)->vec[(I).i]); ++((I).i))
+
+/* assumes break/goto ended label_for_each */
+#define label_for_each_cont(I, L, P) \
+ for (++((I).i); ((P) = (L)->vec[(I).i]); ++((I).i))
+
+#define next_comb(I, L1, L2) \
+do { \
+ (I).j++; \
+ if ((I).j >= (L2)->size) { \
+ (I).i++; \
+ (I).j = 0; \
+ } \
+} while (0)
+
+
+/* for each combination of P1 in L1, and P2 in L2 */
+#define label_for_each_comb(I, L1, L2, P1, P2) \
+for ((I).i = (I).j = 0; \
+ ((P1) = (L1)->vec[(I).i]) && ((P2) = (L2)->vec[(I).j]); \
+ (I) = next_comb(I, L1, L2))
+
+#define fn_for_each_comb(L1, L2, P1, P2, FN) \
+({ \
+ struct label_it i; \
+ int __E = 0; \
+ label_for_each_comb(i, (L1), (L2), (P1), (P2)) { \
+ last_error(__E, (FN)); \
+ } \
+ __E; \
+})
+
+/* for each profile that is enforcing confinement in a label */
+#define label_for_each_confined(I, L, P) \
+ for ((I).i = aa_label_next_confined((L), 0); \
+ ((P) = (L)->vec[(I).i]); \
+ (I).i = aa_label_next_confined((L), (I).i + 1))
+
+#define label_for_each_in_merge(I, A, B, P) \
+ for ((I).i = (I).j = 0; \
+ ((P) = aa_label_next_in_merge(&(I), (A), (B))); \
+ )
+
+#define label_for_each_not_in_set(I, SET, SUB, P) \
+ for ((I).i = (I).j = 0; \
+ ((P) = __aa_label_next_not_in_set(&(I), (SET), (SUB))); \
+ )
+
+#define next_in_ns(i, NS, L) \
+({ \
+ typeof(i) ___i = (i); \
+ while ((L)->vec[___i] && (L)->vec[___i]->ns != (NS)) \
+ (___i)++; \
+ (___i); \
+})
+
+#define label_for_each_in_ns(I, NS, L, P) \
+ for ((I).i = next_in_ns(0, (NS), (L)); \
+ ((P) = (L)->vec[(I).i]); \
+ (I).i = next_in_ns((I).i + 1, (NS), (L)))
+
+#define fn_for_each_in_ns(L, P, FN) \
+({ \
+ struct label_it __i; \
+ struct aa_ns *__ns = labels_ns(L); \
+ int __E = 0; \
+ label_for_each_in_ns(__i, __ns, (L), (P)) { \
+ last_error(__E, (FN)); \
+ } \
+ __E; \
+})
+
+
+#define fn_for_each_XXX(L, P, FN, ...) \
+({ \
+ struct label_it i; \
+ int __E = 0; \
+ label_for_each ## __VA_ARGS__(i, (L), (P)) { \
+ last_error(__E, (FN)); \
+ } \
+ __E; \
+})
+
+#define fn_for_each(L, P, FN) fn_for_each_XXX(L, P, FN)
+#define fn_for_each_confined(L, P, FN) fn_for_each_XXX(L, P, FN, _confined)
+
+#define fn_for_each2_XXX(L1, L2, P, FN, ...) \
+({ \
+ struct label_it i; \
+ int __E = 0; \
+ label_for_each ## __VA_ARGS__(i, (L1), (L2), (P)) { \
+ last_error(__E, (FN)); \
+ } \
+ __E; \
+})
+
+#define fn_for_each_in_merge(L1, L2, P, FN) \
+ fn_for_each2_XXX((L1), (L2), P, FN, _in_merge)
+#define fn_for_each_not_in_set(L1, L2, P, FN) \
+ fn_for_each2_XXX((L1), (L2), P, FN, _not_in_set)
+
+#define LABEL_MEDIATES(L, C) \
+({ \
+ struct aa_profile *profile; \
+ struct label_it i; \
+ int ret = 0; \
+ label_for_each(i, (L), profile) { \
+ if (PROFILE_MEDIATES(profile, (C))) { \
+ ret = 1; \
+ break; \
+ } \
+ } \
+ ret; \
+})
+
+
+void aa_labelset_destroy(struct aa_labelset *ls);
+void aa_labelset_init(struct aa_labelset *ls);
+void __aa_labelset_update_subtree(struct aa_ns *ns);
+
+void aa_label_free(struct aa_label *label);
+void aa_label_kref(struct kref *kref);
+bool aa_label_init(struct aa_label *label, int size);
+struct aa_label *aa_label_alloc(int size, struct aa_proxy *proxy, gfp_t gfp);
+
+bool aa_label_is_subset(struct aa_label *set, struct aa_label *sub);
+struct aa_profile *__aa_label_next_not_in_set(struct label_it *I,
+ struct aa_label *set,
+ struct aa_label *sub);
+bool aa_label_remove(struct aa_label *label);
+struct aa_label *aa_label_insert(struct aa_labelset *ls, struct aa_label *l);
+bool aa_label_replace(struct aa_label *old, struct aa_label *new);
+bool aa_label_make_newest(struct aa_labelset *ls, struct aa_label *old,
+ struct aa_label *new);
+
+struct aa_label *aa_label_find(struct aa_label *l);
+
+struct aa_profile *aa_label_next_in_merge(struct label_it *I,
+ struct aa_label *a,
+ struct aa_label *b);
+struct aa_label *aa_label_find_merge(struct aa_label *a, struct aa_label *b);
+struct aa_label *aa_label_merge(struct aa_label *a, struct aa_label *b,
+ gfp_t gfp);
+
+
+bool aa_update_label_name(struct aa_ns *ns, struct aa_label *label, gfp_t gfp);
+
+#define FLAGS_NONE 0
+#define FLAG_SHOW_MODE 1
+#define FLAG_VIEW_SUBNS 2
+#define FLAG_HIDDEN_UNCONFINED 4
+int aa_label_snxprint(char *str, size_t size, struct aa_ns *view,
+ struct aa_label *label, int flags);
+int aa_label_asxprint(char **strp, struct aa_ns *ns, struct aa_label *label,
+ int flags, gfp_t gfp);
+int aa_label_acntsxprint(char __counted **strp, struct aa_ns *ns,
+ struct aa_label *label, int flags, gfp_t gfp);
+void aa_label_xaudit(struct audit_buffer *ab, struct aa_ns *ns,
+ struct aa_label *label, int flags, gfp_t gfp);
+void aa_label_seq_xprint(struct seq_file *f, struct aa_ns *ns,
+ struct aa_label *label, int flags, gfp_t gfp);
+void aa_label_xprintk(struct aa_ns *ns, struct aa_label *label, int flags,
+ gfp_t gfp);
+void aa_label_audit(struct audit_buffer *ab, struct aa_label *label, gfp_t gfp);
+void aa_label_seq_print(struct seq_file *f, struct aa_label *label, gfp_t gfp);
+void aa_label_printk(struct aa_label *label, gfp_t gfp);
+
+struct aa_label *aa_label_parse(struct aa_label *base, const char *str,
+ gfp_t gfp, bool create, bool force_stack);
+
+
+struct aa_perms;
+int aa_label_match(struct aa_profile *profile, struct aa_label *label,
+ unsigned int state, bool subns, u32 request,
+ struct aa_perms *perms);
+
+
+/**
+ * __aa_get_label - get a reference count to uncounted label reference
+ * @l: reference to get a count on
+ *
+ * Returns: pointer to reference OR NULL if race is lost and reference is
+ * being repeated.
+ * Requires: lock held, and the return code MUST be checked
+ */
+static inline struct aa_label *__aa_get_label(struct aa_label *l)
+{
+ if (l && kref_get_unless_zero(&l->count))
+ return l;
+
+ return NULL;
+}
+
+static inline struct aa_label *aa_get_label(struct aa_label *l)
+{
+ if (l)
+ kref_get(&(l->count));
+
+ return l;
+}
+
+
+/**
+ * aa_get_label_rcu - increment refcount on a label that can be replaced
+ * @l: pointer to label that can be replaced (NOT NULL)
+ *
+ * Returns: pointer to a refcounted label.
+ * else NULL if no label
+ */
+static inline struct aa_label *aa_get_label_rcu(struct aa_label __rcu **l)
+{
+ struct aa_label *c;
+
+ rcu_read_lock();
+ do {
+ c = rcu_dereference(*l);
+ } while (c && !kref_get_unless_zero(&c->count));
+ rcu_read_unlock();
+
+ return c;
+}
+
+/**
+ * aa_get_newest_label - find the newest version of @l
+ * @l: the label to check for newer versions of
+ *
+ * Returns: refcounted newest version of @l taking into account
+ * replacement, renames and removals
+ * return @l.
+ */
+static inline struct aa_label *aa_get_newest_label(struct aa_label *l)
+{
+ if (!l)
+ return NULL;
+
+ if (label_is_stale(l)) {
+ struct aa_label *tmp;
+
+ AA_BUG(!l->proxy);
+ AA_BUG(!l->proxy->label);
+ /* BUG: only way this can happen is @l ref count and its
+ * replacement count have gone to 0 and are on their way
+ * to destruction. ie. we have a refcounting error
+ */
+ tmp = aa_get_label_rcu(&l->proxy->label);
+ AA_BUG(!tmp);
+
+ return tmp;
+ }
+
+ return aa_get_label(l);
+}
+
+static inline void aa_put_label(struct aa_label *l)
+{
+ if (l)
+ kref_put(&l->count, aa_label_kref);
+}
+
+
+struct aa_proxy *aa_alloc_proxy(struct aa_label *l, gfp_t gfp);
+void aa_proxy_kref(struct kref *kref);
+
+static inline struct aa_proxy *aa_get_proxy(struct aa_proxy *proxy)
+{
+ if (proxy)
+ kref_get(&(proxy->count));
+
+ return proxy;
+}
+
+static inline void aa_put_proxy(struct aa_proxy *proxy)
+{
+ if (proxy)
+ kref_put(&proxy->count, aa_proxy_kref);
+}
+
+void __aa_proxy_redirect(struct aa_label *orig, struct aa_label *new);
+
+#endif /* __AA_LABEL_H */
diff --git a/security/apparmor/include/lib.h b/security/apparmor/include/lib.h
index 550a700563b4..436b3a722357 100644
--- a/security/apparmor/include/lib.h
+++ b/security/apparmor/include/lib.h
@@ -60,6 +60,7 @@
extern int apparmor_initialized;
/* fn's in lib */
+const char *skipn_spaces(const char *str, size_t n);
char *aa_split_fqname(char *args, char **ns_name);
const char *aa_splitn_fqname(const char *fqname, size_t n, const char **ns_name,
size_t *ns_len);
@@ -99,6 +100,36 @@ static inline bool path_mediated_fs(struct dentry *dentry)
return !(dentry->d_sb->s_flags & MS_NOUSER);
}
+
+struct counted_str {
+ struct kref count;
+ char name[];
+};
+
+#define str_to_counted(str) \
+ ((struct counted_str *)(str - offsetof(struct counted_str, name)))
+
+#define __counted /* atm just a notation */
+
+void aa_str_kref(struct kref *kref);
+char *aa_str_alloc(int size, gfp_t gfp);
+
+
+static inline __counted char *aa_get_str(__counted char *str)
+{
+ if (str)
+ kref_get(&(str_to_counted(str)->count));
+
+ return str;
+}
+
+static inline void aa_put_str(__counted char *str)
+{
+ if (str)
+ kref_put(&str_to_counted(str)->count, aa_str_kref);
+}
+
+
/* struct aa_policy - common part of both namespaces and profiles
* @name: name of the object
* @hname - The hierarchical name
@@ -107,7 +138,7 @@ static inline bool path_mediated_fs(struct dentry *dentry)
*/
struct aa_policy {
const char *name;
- const char *hname;
+ __counted char *hname;
struct list_head list;
struct list_head profiles;
};
@@ -180,4 +211,89 @@ bool aa_policy_init(struct aa_policy *policy, const char *prefix,
const char *name, gfp_t gfp);
void aa_policy_destroy(struct aa_policy *policy);
-#endif /* AA_LIB_H */
+
+/*
+ * fn_label_build - abstract out the build of a label transition
+ * @L: label the transition is being computed for
+ * @P: profile parameter derived from L by this macro, can be passed to FN
+ * @GFP: memory allocation type to use
+ * @FN: fn to call for each profile transition. @P is set to the profile
+ *
+ * Returns: new label on success
+ * ERR_PTR if build @FN fails
+ * NULL if label_build fails due to low memory conditions
+ *
+ * @FN must return a label or ERR_PTR on failure. NULL is not allowed
+ */
+#define fn_label_build(L, P, GFP, FN) \
+({ \
+ __label__ __cleanup, __done; \
+ struct aa_label *__new_; \
+ \
+ if ((L)->size > 1) { \
+ /* TODO: add cache of transitions already done */ \
+ struct label_it __i; \
+ int __j, __k, __count; \
+ DEFINE_VEC(label, __lvec); \
+ DEFINE_VEC(profile, __pvec); \
+ if (vec_setup(label, __lvec, (L)->size, (GFP))) { \
+ __new_ = NULL; \
+ goto __done; \
+ } \
+ __j = 0; \
+ label_for_each(__i, (L), (P)) { \
+ __new_ = (FN); \
+ AA_BUG(!__new_); \
+ if (IS_ERR(__new_)) \
+ goto __cleanup; \
+ __lvec[__j++] = __new_; \
+ } \
+ for (__j = __count = 0; __j < (L)->size; __j++) \
+ __count += __lvec[__j]->size; \
+ if (!vec_setup(profile, __pvec, __count, (GFP))) { \
+ for (__j = __k = 0; __j < (L)->size; __j++) { \
+ label_for_each(__i, __lvec[__j], (P)) \
+ __pvec[__k++] = aa_get_profile(P); \
+ } \
+ __count -= aa_vec_unique(__pvec, __count, 0); \
+ if (__count > 1) { \
+ __new_ = aa_vec_find_or_create_label(__pvec,\
+ __count, (GFP)); \
+ /* only fails if out of Mem */ \
+ if (!__new_) \
+ __new_ = NULL; \
+ } else \
+ __new_ = aa_get_label(&__pvec[0]->label); \
+ vec_cleanup(profile, __pvec, __count); \
+ } else \
+ __new_ = NULL; \
+__cleanup: \
+ vec_cleanup(label, __lvec, (L)->size); \
+ } else { \
+ (P) = labels_profile(L); \
+ __new_ = (FN); \
+ } \
+__done: \
+ if (!__new_) \
+ AA_DEBUG("label build failed\n"); \
+ (__new_); \
+})
+
+
+#define __fn_build_in_ns(NS, P, NS_FN, OTHER_FN) \
+({ \
+ struct aa_label *__new; \
+ if ((P)->ns != (NS)) \
+ __new = (OTHER_FN); \
+ else \
+ __new = (NS_FN); \
+ (__new); \
+})
+
+#define fn_label_build_in_ns(L, P, GFP, NS_FN, OTHER_FN) \
+({ \
+ fn_label_build((L), (P), (GFP), \
+ __fn_build_in_ns(labels_ns(L), (P), (NS_FN), (OTHER_FN))); \
+})
+
+#endif /* __AA_LIB_H */
diff --git a/security/apparmor/include/path.h b/security/apparmor/include/path.h
index 0444fdde3918..05fb3305671e 100644
--- a/security/apparmor/include/path.h
+++ b/security/apparmor/include/path.h
@@ -23,11 +23,12 @@ enum path_flags {
PATH_CHROOT_NSCONNECT = 0x10, /* connect paths that are at ns root */
PATH_DELEGATE_DELETED = 0x08000, /* delegate deleted files */
- PATH_MEDIATE_DELETED = 0x10000, /* mediate deleted paths */
+ PATH_MEDIATE_DELETED = 0x10000, /* mediate deleted paths */
};
-int aa_path_name(const struct path *path, int flags, char **buffer,
- const char **name, const char **info);
+int aa_path_name(const struct path *path, int flags, char *buffer,
+ const char **name, const char **info,
+ const char *disconnected);
#define MAX_PATH_BUFFERS 2
diff --git a/security/apparmor/include/perms.h b/security/apparmor/include/perms.h
new file mode 100644
index 000000000000..2b27bb79aec4
--- /dev/null
+++ b/security/apparmor/include/perms.h
@@ -0,0 +1,155 @@
+/*
+ * AppArmor security module
+ *
+ * This file contains AppArmor basic permission sets definitions.
+ *
+ * Copyright 2017 Canonical Ltd.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, version 2 of the
+ * License.
+ */
+
+#ifndef __AA_PERM_H
+#define __AA_PERM_H
+
+#include <linux/fs.h>
+#include "label.h"
+
+#define AA_MAY_EXEC MAY_EXEC
+#define AA_MAY_WRITE MAY_WRITE
+#define AA_MAY_READ MAY_READ
+#define AA_MAY_APPEND MAY_APPEND
+
+#define AA_MAY_CREATE 0x0010
+#define AA_MAY_DELETE 0x0020
+#define AA_MAY_OPEN 0x0040
+#define AA_MAY_RENAME 0x0080 /* pair */
+
+#define AA_MAY_SETATTR 0x0100 /* meta write */
+#define AA_MAY_GETATTR 0x0200 /* meta read */
+#define AA_MAY_SETCRED 0x0400 /* security cred/attr */
+#define AA_MAY_GETCRED 0x0800
+
+#define AA_MAY_CHMOD 0x1000 /* pair */
+#define AA_MAY_CHOWN 0x2000 /* pair */
+#define AA_MAY_CHGRP 0x4000 /* pair */
+#define AA_MAY_LOCK 0x8000 /* LINK_SUBSET overlaid */
+
+#define AA_EXEC_MMAP 0x00010000
+#define AA_MAY_MPROT 0x00020000 /* extend conditions */
+#define AA_MAY_LINK 0x00040000 /* pair */
+#define AA_MAY_SNAPSHOT 0x00080000 /* pair */
+
+#define AA_MAY_DELEGATE
+#define AA_CONT_MATCH 0x08000000
+
+#define AA_MAY_STACK 0x10000000
+#define AA_MAY_ONEXEC 0x20000000 /* either stack or change_profile */
+#define AA_MAY_CHANGE_PROFILE 0x40000000
+#define AA_MAY_CHANGEHAT 0x80000000
+
+#define AA_LINK_SUBSET AA_MAY_LOCK /* overlaid */
+
+
+#define PERMS_CHRS_MASK (MAY_READ | MAY_WRITE | AA_MAY_CREATE | \
+ AA_MAY_DELETE | AA_MAY_LINK | AA_MAY_LOCK | \
+ AA_MAY_EXEC | AA_EXEC_MMAP | AA_MAY_APPEND)
+
+#define PERMS_NAMES_MASK (PERMS_CHRS_MASK | AA_MAY_OPEN | AA_MAY_RENAME | \
+ AA_MAY_SETATTR | AA_MAY_GETATTR | AA_MAY_SETCRED | \
+ AA_MAY_GETCRED | AA_MAY_CHMOD | AA_MAY_CHOWN | \
+ AA_MAY_CHGRP | AA_MAY_MPROT | AA_MAY_SNAPSHOT | \
+ AA_MAY_STACK | AA_MAY_ONEXEC | \
+ AA_MAY_CHANGE_PROFILE | AA_MAY_CHANGEHAT)
+
+extern const char aa_file_perm_chrs[];
+extern const char *aa_file_perm_names[];
+
+struct aa_perms {
+ u32 allow;
+ u32 audit; /* set only when allow is set */
+
+ u32 deny; /* explicit deny, or conflict if allow also set */
+ u32 quiet; /* set only when ~allow | deny */
+ u32 kill; /* set only when ~allow | deny */
+ u32 stop; /* set only when ~allow | deny */
+
+ u32 complain; /* accumulates only used when ~allow & ~deny */
+ u32 cond; /* set only when ~allow and ~deny */
+
+ u32 hide; /* set only when ~allow | deny */
+ u32 prompt; /* accumulates only used when ~allow & ~deny */
+
+ /* Reserved:
+ * u32 subtree; / * set only when allow is set * /
+ */
+ u16 xindex;
+};
+
+#define ALL_PERMS_MASK 0xffffffff
+extern struct aa_perms nullperms;
+extern struct aa_perms allperms;
+
+
+#define xcheck(FN1, FN2) \
+({ \
+ int e, error = FN1; \
+ e = FN2; \
+ if (e) \
+ error = e; \
+ error; \
+})
+
+
+/*
+ * TODO: update for labels pointing to labels instead of profiles
+ * TODO: optimize the walk, currently does subwalk of L2 for each P in L1
+ * gah this doesn't allow for label compound check!!!!
+ */
+#define xcheck_ns_profile_profile(P1, P2, FN, args...) \
+({ \
+ int ____e = 0; \
+ if (P1->ns == P2->ns) \
+ ____e = FN((P1), (P2), args); \
+ (____e); \
+})
+
+#define xcheck_ns_profile_label(P, L, FN, args...) \
+({ \
+ struct aa_profile *__p2; \
+ fn_for_each((L), __p2, \
+ xcheck_ns_profile_profile((P), __p2, (FN), args)); \
+})
+
+#define xcheck_ns_labels(L1, L2, FN, args...) \
+({ \
+ struct aa_profile *__p1; \
+ fn_for_each((L1), __p1, FN(__p1, (L2), args)); \
+})
+
+/* Do the cross check but applying FN at the profiles level */
+#define xcheck_labels_profiles(L1, L2, FN, args...) \
+ xcheck_ns_labels((L1), (L2), xcheck_ns_profile_label, (FN), args)
+
+
+void aa_perm_mask_to_str(char *str, const char *chrs, u32 mask);
+void aa_audit_perm_names(struct audit_buffer *ab, const char **names, u32 mask);
+void aa_audit_perm_mask(struct audit_buffer *ab, u32 mask, const char *chrs,
+ u32 chrsmask, const char **names, u32 namesmask);
+void aa_apply_modes_to_perms(struct aa_profile *profile,
+ struct aa_perms *perms);
+void aa_compute_perms(struct aa_dfa *dfa, unsigned int state,
+ struct aa_perms *perms);
+void aa_perms_accum(struct aa_perms *accum, struct aa_perms *addend);
+void aa_perms_accum_raw(struct aa_perms *accum, struct aa_perms *addend);
+void aa_profile_match_label(struct aa_profile *profile, struct aa_label *label,
+ int type, u32 request, struct aa_perms *perms);
+int aa_profile_label_perm(struct aa_profile *profile, struct aa_profile *target,
+ u32 request, int type, u32 *deny,
+ struct common_audit_data *sa);
+int aa_check_perms(struct aa_profile *profile, struct aa_perms *perms,
+ u32 request, struct common_audit_data *sa,
+ void (*cb)(struct audit_buffer *, void *));
+#endif /* __AA_PERM_H */
diff --git a/security/apparmor/include/policy.h b/security/apparmor/include/policy.h
index 67bc96afe541..17fe41a9cac3 100644
--- a/security/apparmor/include/policy.h
+++ b/security/apparmor/include/policy.h
@@ -29,6 +29,8 @@
#include "domain.h"
#include "file.h"
#include "lib.h"
+#include "label.h"
+#include "perms.h"
#include "resource.h"
@@ -47,9 +49,9 @@ extern const char *const aa_profile_mode_names[];
#define KILL_MODE(_profile) PROFILE_MODE((_profile), APPARMOR_KILL)
-#define PROFILE_IS_HAT(_profile) ((_profile)->flags & PFLAG_HAT)
+#define PROFILE_IS_HAT(_profile) ((_profile)->label.flags & FLAG_HAT)
-#define profile_is_stale(_profile) ((_profile)->flags & PFLAG_STALE)
+#define profile_is_stale(_profile) (label_is_stale(&(_profile)->label))
#define on_list_rcu(X) (!list_empty(X) && (X)->prev != LIST_POISON2)
@@ -66,22 +68,6 @@ enum profile_mode {
APPARMOR_UNCONFINED, /* profile set to unconfined */
};
-enum profile_flags {
- PFLAG_HAT = 1, /* profile is a hat */
- PFLAG_NULL = 4, /* profile is null learning profile */
- PFLAG_IX_ON_NAME_ERROR = 8, /* fallback to ix on name lookup fail */
- PFLAG_IMMUTABLE = 0x10, /* don't allow changes/replacement */
- PFLAG_USER_DEFINED = 0x20, /* user based profile - lower privs */
- PFLAG_NO_LIST_REF = 0x40, /* list doesn't keep profile ref */
- PFLAG_OLD_NULL_TRANS = 0x100, /* use // as the null transition */
- PFLAG_STALE = 0x200, /* profile replaced/removed */
- PFLAG_NS_COUNT = 0x400, /* carries NS ref count */
-
- /* These flags must correspond with PATH_flags */
- PFLAG_MEDIATE_DELETED = 0x10000, /* mediate instead delegate deleted */
-};
-
-struct aa_profile;
/* struct aa_policydb - match engine for a policy
* dfa: dfa pattern match
@@ -94,11 +80,6 @@ struct aa_policydb {
};
-struct aa_proxy {
- struct kref count;
- struct aa_profile __rcu *profile;
-};
-
/* struct aa_data - generic data structure
* key: name for retrieving this data
* size: size of data in bytes
@@ -115,19 +96,17 @@ struct aa_data {
/* struct aa_profile - basic confinement data
* @base - base components of the profile (name, refcount, lists, lock ...)
- * @count: reference count of the obj
- * @rcu: rcu head used when removing from @list
+ * @label - label this profile is an extension of
* @parent: parent of profile
* @ns: namespace the profile is in
- * @proxy: is set to the profile that replaced this profile
* @rename: optional profile name that this profile renamed
* @attach: human readable attachment string
* @xmatch: optional extended matching for unconfined executables names
* @xmatch_len: xmatch prefix len, used to determine xmatch priority
* @audit: the auditing mode of the profile
* @mode: the enforcement mode of the profile
- * @flags: flags controlling profile behavior
* @path_flags: flags controlling path generation behavior
+ * @disconnected: what to prepend if attach_disconnected is specified
* @size: the memory consumed by this profiles rules
* @policy: general match rules governing policy
* @file: The set of rules governing basic file access and domain transitions
@@ -143,8 +122,6 @@ struct aa_data {
* used to determine profile attachment against unconfined tasks. All other
* attachments are determined by profile X transition rules.
*
- * The @proxy struct is write protected by the profile lock.
- *
* Profiles have a hierarchy where hats and children profiles keep
* a reference to their parent.
*
@@ -154,12 +131,9 @@ struct aa_data {
*/
struct aa_profile {
struct aa_policy base;
- struct kref count;
- struct rcu_head rcu;
struct aa_profile __rcu *parent;
struct aa_ns *ns;
- struct aa_proxy *proxy;
const char *rename;
const char *attach;
@@ -167,8 +141,8 @@ struct aa_profile {
int xmatch_len;
enum audit_mode audit;
long mode;
- long flags;
u32 path_flags;
+ const char *disconnected;
int size;
struct aa_policydb policy;
@@ -181,17 +155,24 @@ struct aa_profile {
char *dirname;
struct dentry *dents[AAFS_PROF_SIZEOF];
struct rhashtable *data;
+ struct aa_label label;
};
extern enum profile_mode aa_g_profile_mode;
-void __aa_update_proxy(struct aa_profile *orig, struct aa_profile *new);
+#define AA_MAY_LOAD_POLICY AA_MAY_APPEND
+#define AA_MAY_REPLACE_POLICY AA_MAY_WRITE
+#define AA_MAY_REMOVE_POLICY AA_MAY_DELETE
+
+#define profiles_ns(P) ((P)->ns)
+#define name_is_shared(A, B) ((A)->hname && (A)->hname == (B)->hname)
void aa_add_profile(struct aa_policy *common, struct aa_profile *profile);
void aa_free_proxy_kref(struct kref *kref);
-struct aa_profile *aa_alloc_profile(const char *name, gfp_t gfp);
+struct aa_profile *aa_alloc_profile(const char *name, struct aa_proxy *proxy,
+ gfp_t gfp);
struct aa_profile *aa_new_null_profile(struct aa_profile *parent, bool hat,
const char *base, gfp_t gfp);
void aa_free_profile(struct aa_profile *profile);
@@ -200,21 +181,44 @@ struct aa_profile *aa_find_child(struct aa_profile *parent, const char *name);
struct aa_profile *aa_lookupn_profile(struct aa_ns *ns, const char *hname,
size_t n);
struct aa_profile *aa_lookup_profile(struct aa_ns *ns, const char *name);
-struct aa_profile *aa_fqlookupn_profile(struct aa_profile *base,
+struct aa_profile *aa_fqlookupn_profile(struct aa_label *base,
const char *fqname, size_t n);
struct aa_profile *aa_match_profile(struct aa_ns *ns, const char *name);
-ssize_t aa_replace_profiles(struct aa_ns *view, struct aa_profile *profile,
- bool noreplace, struct aa_loaddata *udata);
-ssize_t aa_remove_profiles(struct aa_ns *view, struct aa_profile *profile,
- char *name, size_t size);
+ssize_t aa_replace_profiles(struct aa_ns *view, struct aa_label *label,
+ u32 mask, struct aa_loaddata *udata);
+ssize_t aa_remove_profiles(struct aa_ns *view, struct aa_label *label,
+ char *name, size_t size);
void __aa_profile_list_release(struct list_head *head);
#define PROF_ADD 1
#define PROF_REPLACE 0
-#define unconfined(X) ((X)->mode == APPARMOR_UNCONFINED)
+#define profile_unconfined(X) ((X)->mode == APPARMOR_UNCONFINED)
+
+/**
+ * aa_get_newest_profile - simple wrapper fn to wrap the label version
+ * @p: profile (NOT NULL)
+ *
+ * Returns refcount to newest version of the profile (maybe @p)
+ *
+ * Requires: @p must be held with a valid refcount
+ */
+static inline struct aa_profile *aa_get_newest_profile(struct aa_profile *p)
+{
+ return labels_profile(aa_get_newest_label(&p->label));
+}
+#define PROFILE_MEDIATES(P, T) ((P)->policy.start[(T)])
+/* safe version of POLICY_MEDIATES for full range input */
+static inline unsigned int PROFILE_MEDIATES_SAFE(struct aa_profile *profile,
+ unsigned char class)
+{
+ if (profile->policy.dfa)
+ return aa_dfa_match_len(profile->policy.dfa,
+ profile->policy.start[0], &class, 1);
+ return 0;
+}
/**
* aa_get_profile - increment refcount on profile @p
@@ -226,7 +230,7 @@ void __aa_profile_list_release(struct list_head *head);
static inline struct aa_profile *aa_get_profile(struct aa_profile *p)
{
if (p)
- kref_get(&(p->count));
+ kref_get(&(p->label.count));
return p;
}
@@ -240,7 +244,7 @@ static inline struct aa_profile *aa_get_profile(struct aa_profile *p)
*/
static inline struct aa_profile *aa_get_profile_not0(struct aa_profile *p)
{
- if (p && kref_get_unless_zero(&p->count))
+ if (p && kref_get_unless_zero(&p->label.count))
return p;
return NULL;
@@ -260,53 +264,20 @@ static inline struct aa_profile *aa_get_profile_rcu(struct aa_profile __rcu **p)
rcu_read_lock();
do {
c = rcu_dereference(*p);
- } while (c && !kref_get_unless_zero(&c->count));
+ } while (c && !kref_get_unless_zero(&c->label.count));
rcu_read_unlock();
return c;
}
/**
- * aa_get_newest_profile - find the newest version of @profile
- * @profile: the profile to check for newer versions of
- *
- * Returns: refcounted newest version of @profile taking into account
- * replacement, renames and removals
- * return @profile.
- */
-static inline struct aa_profile *aa_get_newest_profile(struct aa_profile *p)
-{
- if (!p)
- return NULL;
-
- if (profile_is_stale(p))
- return aa_get_profile_rcu(&p->proxy->profile);
-
- return aa_get_profile(p);
-}
-
-/**
* aa_put_profile - decrement refcount on profile @p
* @p: profile (MAYBE NULL)
*/
static inline void aa_put_profile(struct aa_profile *p)
{
if (p)
- kref_put(&p->count, aa_free_profile_kref);
-}
-
-static inline struct aa_proxy *aa_get_proxy(struct aa_proxy *p)
-{
- if (p)
- kref_get(&(p->count));
-
- return p;
-}
-
-static inline void aa_put_proxy(struct aa_proxy *p)
-{
- if (p)
- kref_put(&p->count, aa_free_proxy_kref);
+ kref_put(&p->label.count, aa_label_kref);
}
static inline int AUDIT_MODE(struct aa_profile *profile)
@@ -319,7 +290,7 @@ static inline int AUDIT_MODE(struct aa_profile *profile)
bool policy_view_capable(struct aa_ns *ns);
bool policy_admin_capable(struct aa_ns *ns);
-int aa_may_manage_policy(struct aa_profile *profile, struct aa_ns *ns,
- const char *op);
+int aa_may_manage_policy(struct aa_label *label, struct aa_ns *ns,
+ u32 mask);
#endif /* __AA_POLICY_H */
diff --git a/security/apparmor/include/policy_ns.h b/security/apparmor/include/policy_ns.h
index 89cffddd7e75..9605f18624e2 100644
--- a/security/apparmor/include/policy_ns.h
+++ b/security/apparmor/include/policy_ns.h
@@ -19,6 +19,7 @@
#include "apparmor.h"
#include "apparmorfs.h"
+#include "label.h"
#include "policy.h"
@@ -68,6 +69,11 @@ struct aa_ns {
atomic_t uniq_null;
long uniq_id;
int level;
+ long revision;
+ wait_queue_head_t wait;
+
+ struct aa_labelset labels;
+ struct list_head rawdata_list;
struct dentry *dents[AAFS_NS_SIZEOF];
};
@@ -76,6 +82,8 @@ extern struct aa_ns *root_ns;
extern const char *aa_hidden_ns_name;
+#define ns_unconfined(NS) (&(NS)->unconfined->label)
+
bool aa_ns_visible(struct aa_ns *curr, struct aa_ns *view, bool subns);
const char *aa_ns_name(struct aa_ns *parent, struct aa_ns *child, bool subns);
void aa_free_ns(struct aa_ns *ns);
@@ -85,6 +93,8 @@ void aa_free_ns_kref(struct kref *kref);
struct aa_ns *aa_find_ns(struct aa_ns *root, const char *name);
struct aa_ns *aa_findn_ns(struct aa_ns *root, const char *name, size_t n);
+struct aa_ns *__aa_lookupn_ns(struct aa_ns *view, const char *hname, size_t n);
+struct aa_ns *aa_lookupn_ns(struct aa_ns *view, const char *name, size_t n);
struct aa_ns *__aa_find_or_create_ns(struct aa_ns *parent, const char *name,
struct dentry *dir);
struct aa_ns *aa_prepare_ns(struct aa_ns *root, const char *name);
@@ -144,4 +154,15 @@ static inline struct aa_ns *__aa_find_ns(struct list_head *head,
return __aa_findn_ns(head, name, strlen(name));
}
+static inline struct aa_ns *__aa_lookup_ns(struct aa_ns *base,
+ const char *hname)
+{
+ return __aa_lookupn_ns(base, hname, strlen(hname));
+}
+
+static inline struct aa_ns *aa_lookup_ns(struct aa_ns *view, const char *name)
+{
+ return aa_lookupn_ns(view, name, strlen(name));
+}
+
#endif /* AA_NAMESPACE_H */
diff --git a/security/apparmor/include/policy_unpack.h b/security/apparmor/include/policy_unpack.h
index 4c1319eebc42..be6cd69ac319 100644
--- a/security/apparmor/include/policy_unpack.h
+++ b/security/apparmor/include/policy_unpack.h
@@ -17,6 +17,8 @@
#include <linux/list.h>
#include <linux/kref.h>
+#include <linux/dcache.h>
+#include <linux/workqueue.h>
struct aa_load_ent {
struct list_head list;
@@ -36,26 +38,84 @@ struct aa_load_ent *aa_load_ent_alloc(void);
#define PACKED_MODE_KILL 2
#define PACKED_MODE_UNCONFINED 3
-/* struct aa_loaddata - buffer of policy load data set */
+struct aa_ns;
+
+enum {
+ AAFS_LOADDATA_ABI = 0,
+ AAFS_LOADDATA_REVISION,
+ AAFS_LOADDATA_HASH,
+ AAFS_LOADDATA_DATA,
+ AAFS_LOADDATA_DIR, /* must be last actual entry */
+ AAFS_LOADDATA_NDENTS /* count of entries */
+};
+
+/*
+ * struct aa_loaddata - buffer of policy raw_data set
+ *
+ * there is no loaddata ref for being on ns list, nor a ref from
+ * d_inode(@dentry) when grab a ref from these, @ns->lock must be held
+ * && __aa_get_loaddata() needs to be used, and the return value
+ * checked, if NULL the loaddata is already being reaped and should be
+ * considered dead.
+ */
struct aa_loaddata {
struct kref count;
+ struct list_head list;
+ struct work_struct work;
+ struct dentry *dents[AAFS_LOADDATA_NDENTS];
+ struct aa_ns *ns;
+ char *name;
size_t size;
+ long revision; /* the ns policy revision this caused */
int abi;
unsigned char *hash;
+
char data[];
};
int aa_unpack(struct aa_loaddata *udata, struct list_head *lh, const char **ns);
+/**
+ * __aa_get_loaddata - get a reference count to uncounted data reference
+ * @data: reference to get a count on
+ *
+ * Returns: pointer to reference OR NULL if race is lost and reference is
+ * being repeated.
+ * Requires: @data->ns->lock held, and the return code MUST be checked
+ *
+ * Use only from inode->i_private and @data->list found references
+ */
+static inline struct aa_loaddata *
+__aa_get_loaddata(struct aa_loaddata *data)
+{
+ if (data && kref_get_unless_zero(&(data->count)))
+ return data;
+
+ return NULL;
+}
+
+/**
+ * aa_get_loaddata - get a reference count from a counted data reference
+ * @data: reference to get a count on
+ *
+ * Returns: point to reference
+ * Requires: @data to have a valid reference count on it. It is a bug
+ * if the race to reap can be encountered when it is used.
+ */
static inline struct aa_loaddata *
aa_get_loaddata(struct aa_loaddata *data)
{
- if (data)
- kref_get(&(data->count));
- return data;
+ struct aa_loaddata *tmp = __aa_get_loaddata(data);
+
+ AA_BUG(data && !tmp);
+
+ return tmp;
}
+void __aa_loaddata_update(struct aa_loaddata *data, long revision);
+bool aa_rawdata_eq(struct aa_loaddata *l, struct aa_loaddata *r);
void aa_loaddata_kref(struct kref *kref);
+struct aa_loaddata *aa_loaddata_alloc(size_t size);
static inline void aa_put_loaddata(struct aa_loaddata *data)
{
if (data)
diff --git a/security/apparmor/include/procattr.h b/security/apparmor/include/procattr.h
index 6bd5f33d9533..c8fd99c9357d 100644
--- a/security/apparmor/include/procattr.h
+++ b/security/apparmor/include/procattr.h
@@ -15,11 +15,7 @@
#ifndef __AA_PROCATTR_H
#define __AA_PROCATTR_H
-#define AA_DO_TEST 1
-#define AA_ONEXEC 1
-
-int aa_getprocattr(struct aa_profile *profile, char **string);
-int aa_setprocattr_changehat(char *args, size_t size, int test);
-int aa_setprocattr_changeprofile(char *fqname, bool onexec, int test);
+int aa_getprocattr(struct aa_label *label, char **string);
+int aa_setprocattr_changehat(char *args, size_t size, int flags);
#endif /* __AA_PROCATTR_H */
diff --git a/security/apparmor/include/resource.h b/security/apparmor/include/resource.h
index d3f4cf027957..76f1586c9adb 100644
--- a/security/apparmor/include/resource.h
+++ b/security/apparmor/include/resource.h
@@ -34,13 +34,13 @@ struct aa_rlimit {
struct rlimit limits[RLIM_NLIMITS];
};
-extern struct aa_fs_entry aa_fs_entry_rlimit[];
+extern struct aa_sfs_entry aa_sfs_entry_rlimit[];
int aa_map_resource(int resource);
-int aa_task_setrlimit(struct aa_profile *profile, struct task_struct *,
+int aa_task_setrlimit(struct aa_label *label, struct task_struct *task,
unsigned int resource, struct rlimit *new_rlim);
-void __aa_transition_rlimits(struct aa_profile *old, struct aa_profile *new);
+void __aa_transition_rlimits(struct aa_label *old, struct aa_label *new);
static inline void aa_free_rlimit_rules(struct aa_rlimit *rlims)
{