summaryrefslogtreecommitdiff
path: root/security/apparmor
diff options
context:
space:
mode:
Diffstat (limited to 'security/apparmor')
-rw-r--r--security/apparmor/apparmorfs.c59
-rw-r--r--security/apparmor/audit.c3
-rw-r--r--security/apparmor/domain.c49
-rw-r--r--security/apparmor/file.c12
-rw-r--r--security/apparmor/include/domain.h2
-rw-r--r--security/apparmor/include/label.h2
-rw-r--r--security/apparmor/include/match.h11
-rw-r--r--security/apparmor/label.c60
-rw-r--r--security/apparmor/lsm.c9
-rw-r--r--security/apparmor/match.c58
-rw-r--r--security/apparmor/path.c2
-rw-r--r--security/apparmor/policy.c1
-rw-r--r--security/apparmor/policy_unpack.c58
13 files changed, 195 insertions, 131 deletions
diff --git a/security/apparmor/apparmorfs.c b/security/apparmor/apparmorfs.c
index 280741fc0f5f..5fd4a64e431f 100644
--- a/security/apparmor/apparmorfs.c
+++ b/security/apparmor/apparmorfs.c
@@ -341,38 +341,6 @@ static struct dentry *aafs_create_dir(const char *name, struct dentry *parent)
}
/**
- * aafs_create_symlink - create a symlink in the apparmorfs filesystem
- * @name: name of dentry to create
- * @parent: parent directory for this dentry
- * @target: if symlink, symlink target string
- * @private: private data
- * @iops: struct of inode_operations that should be used
- *
- * If @target parameter is %NULL, then the @iops parameter needs to be
- * setup to handle .readlink and .get_link inode_operations.
- */
-static struct dentry *aafs_create_symlink(const char *name,
- struct dentry *parent,
- const char *target,
- void *private,
- const struct inode_operations *iops)
-{
- struct dentry *dent;
- char *link = NULL;
-
- if (target) {
- if (!link)
- return ERR_PTR(-ENOMEM);
- }
- dent = aafs_create(name, S_IFLNK | 0444, parent, private, link, NULL,
- iops);
- if (IS_ERR(dent))
- kfree(link);
-
- return dent;
-}
-
-/**
* aafs_remove - removes a file or directory from the apparmorfs filesystem
*
* @dentry: dentry of the file/directory/symlink to removed.
@@ -454,7 +422,7 @@ static ssize_t policy_update(u32 mask, const char __user *buf, size_t size,
*/
error = aa_may_manage_policy(label, ns, mask);
if (error)
- return error;
+ goto end_section;
data = aa_simple_write_to_buffer(buf, size, size, pos);
error = PTR_ERR(data);
@@ -462,6 +430,7 @@ static ssize_t policy_update(u32 mask, const char __user *buf, size_t size,
error = aa_replace_profiles(ns, label, mask, data);
aa_put_loaddata(data);
}
+end_section:
end_current_label_crit_section(label);
return error;
@@ -623,7 +592,7 @@ static __poll_t ns_revision_poll(struct file *file, poll_table *pt)
void __aa_bump_ns_revision(struct aa_ns *ns)
{
- WRITE_ONCE(ns->revision, ns->revision + 1);
+ WRITE_ONCE(ns->revision, READ_ONCE(ns->revision) + 1);
wake_up_interruptible(&ns->wait);
}
@@ -839,7 +808,7 @@ static ssize_t query_label(char *buf, size_t buf_len,
struct multi_transaction {
struct kref count;
ssize_t size;
- char data[0];
+ char data[];
};
#define MULTI_TRANSACTION_LIMIT (PAGE_SIZE - sizeof(struct multi_transaction))
@@ -1762,25 +1731,25 @@ int __aafs_profile_mkdir(struct aa_profile *profile, struct dentry *parent)
}
if (profile->rawdata) {
- dent = aafs_create_symlink("raw_sha1", dir, NULL,
- profile->label.proxy,
- &rawdata_link_sha1_iops);
+ dent = aafs_create("raw_sha1", S_IFLNK | 0444, dir,
+ profile->label.proxy, NULL, NULL,
+ &rawdata_link_sha1_iops);
if (IS_ERR(dent))
goto fail;
aa_get_proxy(profile->label.proxy);
profile->dents[AAFS_PROF_RAW_HASH] = dent;
- dent = aafs_create_symlink("raw_abi", dir, NULL,
- profile->label.proxy,
- &rawdata_link_abi_iops);
+ dent = aafs_create("raw_abi", S_IFLNK | 0444, dir,
+ profile->label.proxy, NULL, NULL,
+ &rawdata_link_abi_iops);
if (IS_ERR(dent))
goto fail;
aa_get_proxy(profile->label.proxy);
profile->dents[AAFS_PROF_RAW_ABI] = dent;
- dent = aafs_create_symlink("raw_data", dir, NULL,
- profile->label.proxy,
- &rawdata_link_data_iops);
+ dent = aafs_create("raw_data", S_IFLNK | 0444, dir,
+ profile->label.proxy, NULL, NULL,
+ &rawdata_link_data_iops);
if (IS_ERR(dent))
goto fail;
aa_get_proxy(profile->label.proxy);
@@ -2363,6 +2332,8 @@ static struct aa_sfs_entry aa_sfs_entry_versions[] = {
static struct aa_sfs_entry aa_sfs_entry_policy[] = {
AA_SFS_DIR("versions", aa_sfs_entry_versions),
AA_SFS_FILE_BOOLEAN("set_load", 1),
+ /* number of out of band transitions supported */
+ AA_SFS_FILE_U64("outofband", MAX_OOB_SUPPORTED),
{ }
};
diff --git a/security/apparmor/audit.c b/security/apparmor/audit.c
index 5a98661a8b46..597732503815 100644
--- a/security/apparmor/audit.c
+++ b/security/apparmor/audit.c
@@ -197,8 +197,9 @@ int aa_audit_rule_init(u32 field, u32 op, char *rulestr, void **vrule)
rule->label = aa_label_parse(&root_ns->unconfined->label, rulestr,
GFP_KERNEL, true, false);
if (IS_ERR(rule->label)) {
+ int err = PTR_ERR(rule->label);
aa_audit_rule_free(rule);
- return PTR_ERR(rule->label);
+ return err;
}
*vrule = rule;
diff --git a/security/apparmor/domain.c b/security/apparmor/domain.c
index 6ceb74e0f789..1c898055a476 100644
--- a/security/apparmor/domain.c
+++ b/security/apparmor/domain.c
@@ -320,8 +320,7 @@ static int aa_xattrs_match(const struct linux_binprm *bprm,
might_sleep();
/* transition from exec match to xattr set */
- state = aa_dfa_null_transition(profile->xmatch, state);
-
+ state = aa_dfa_outofband_transition(profile->xmatch, state);
d = bprm->file->f_path.dentry;
for (i = 0; i < profile->xattr_count; i++) {
@@ -330,7 +329,13 @@ static int aa_xattrs_match(const struct linux_binprm *bprm,
if (size >= 0) {
u32 perm;
- /* Check the xattr value, not just presence */
+ /*
+ * Check the xattr presence before value. This ensure
+ * that not present xattr can be distinguished from a 0
+ * length value or rule that matches any value
+ */
+ state = aa_dfa_null_transition(profile->xmatch, state);
+ /* Check xattr value */
state = aa_dfa_match_len(profile->xmatch, state, value,
size);
perm = dfa_user_allow(profile->xmatch, state);
@@ -340,7 +345,7 @@ static int aa_xattrs_match(const struct linux_binprm *bprm,
}
}
/* transition to next element */
- state = aa_dfa_null_transition(profile->xmatch, state);
+ state = aa_dfa_outofband_transition(profile->xmatch, state);
if (size < 0) {
/*
* No xattr match, so verify if transition to
@@ -620,8 +625,6 @@ static struct aa_label *profile_transition(struct aa_profile *profile,
bool *secure_exec)
{
struct aa_label *new = NULL;
- struct aa_profile *component;
- struct label_it i;
const char *info = NULL, *name = NULL, *target = NULL;
unsigned int state = profile->file.start;
struct aa_perms perms = {};
@@ -670,21 +673,6 @@ static struct aa_label *profile_transition(struct aa_profile *profile,
info = "profile transition not found";
/* remove MAY_EXEC to audit as failure */
perms.allow &= ~MAY_EXEC;
- } else {
- /* verify that each component's xattr requirements are
- * met, and fail execution otherwise
- */
- label_for_each(i, new, component) {
- if (aa_xattrs_match(bprm, component, state) <
- 0) {
- error = -EACCES;
- info = "required xattrs not present";
- perms.allow &= ~MAY_EXEC;
- aa_put_label(new);
- new = NULL;
- goto audit;
- }
- }
}
} else if (COMPLAIN_MODE(profile)) {
/* no exec permission - learning mode */
@@ -854,14 +842,14 @@ static struct aa_label *handle_onexec(struct aa_label *label,
}
/**
- * apparmor_bprm_set_creds - set the new creds on the bprm struct
+ * apparmor_bprm_creds_for_exec - Update the new creds on the bprm struct
* @bprm: binprm for the exec (NOT NULL)
*
* Returns: %0 or error on failure
*
* TODO: once the other paths are done see if we can't refactor into a fn
*/
-int apparmor_bprm_set_creds(struct linux_binprm *bprm)
+int apparmor_bprm_creds_for_exec(struct linux_binprm *bprm)
{
struct aa_task_ctx *ctx;
struct aa_label *label, *new = NULL;
@@ -875,9 +863,6 @@ int apparmor_bprm_set_creds(struct linux_binprm *bprm)
file_inode(bprm->file)->i_mode
};
- if (bprm->called_set_creds)
- return 0;
-
ctx = task_ctx(current);
AA_BUG(!cred_label(bprm->cred));
AA_BUG(!ctx);
@@ -929,7 +914,8 @@ int apparmor_bprm_set_creds(struct linux_binprm *bprm)
* aways results in a further reduction of permissions.
*/
if ((bprm->unsafe & LSM_UNSAFE_NO_NEW_PRIVS) &&
- !unconfined(label) && !aa_label_is_subset(new, ctx->nnp)) {
+ !unconfined(label) &&
+ !aa_label_is_unconfined_subset(new, ctx->nnp)) {
error = -EPERM;
info = "no new privs";
goto audit;
@@ -1207,7 +1193,7 @@ int aa_change_hat(const char *hats[], int count, u64 token, int flags)
* reduce restrictions.
*/
if (task_no_new_privs(current) && !unconfined(label) &&
- !aa_label_is_subset(new, ctx->nnp)) {
+ !aa_label_is_unconfined_subset(new, ctx->nnp)) {
/* not an apparmor denial per se, so don't log it */
AA_DEBUG("no_new_privs - change_hat denied");
error = -EPERM;
@@ -1228,7 +1214,7 @@ int aa_change_hat(const char *hats[], int count, u64 token, int flags)
* reduce restrictions.
*/
if (task_no_new_privs(current) && !unconfined(label) &&
- !aa_label_is_subset(previous, ctx->nnp)) {
+ !aa_label_is_unconfined_subset(previous, ctx->nnp)) {
/* not an apparmor denial per se, so don't log it */
AA_DEBUG("no_new_privs - change_hat denied");
error = -EPERM;
@@ -1328,6 +1314,7 @@ int aa_change_profile(const char *fqname, int flags)
ctx->nnp = aa_get_label(label);
if (!fqname || !*fqname) {
+ aa_put_label(label);
AA_DEBUG("no profile name");
return -EINVAL;
}
@@ -1346,8 +1333,6 @@ int aa_change_profile(const char *fqname, int flags)
op = OP_CHANGE_PROFILE;
}
- label = aa_get_current_label();
-
if (*fqname == '&') {
stack = true;
/* don't have label_parse() do stacking */
@@ -1424,7 +1409,7 @@ check:
* reduce restrictions.
*/
if (task_no_new_privs(current) && !unconfined(label) &&
- !aa_label_is_subset(new, ctx->nnp)) {
+ !aa_label_is_unconfined_subset(new, ctx->nnp)) {
/* not an apparmor denial per se, so don't log it */
AA_DEBUG("no_new_privs - change_hat denied");
error = -EPERM;
diff --git a/security/apparmor/file.c b/security/apparmor/file.c
index f1caf3674e1c..9a2d14b7c9f8 100644
--- a/security/apparmor/file.c
+++ b/security/apparmor/file.c
@@ -154,13 +154,13 @@ int aa_audit_file(struct aa_profile *profile, struct aa_perms *perms,
* is_deleted - test if a file has been completely unlinked
* @dentry: dentry of file to test for deletion (NOT NULL)
*
- * Returns: %1 if deleted else %0
+ * Returns: true if deleted else false
*/
static inline bool is_deleted(struct dentry *dentry)
{
if (d_unlinked(dentry) && d_backing_inode(dentry)->i_nlink == 0)
- return 1;
- return 0;
+ return true;
+ return false;
}
static int path_name(const char *op, struct aa_label *label,
@@ -353,15 +353,15 @@ int aa_path_perm(const char *op, struct aa_label *label,
* this is done as part of the subset test, where a hardlink must have
* a subset of permissions that the target has.
*
- * Returns: %1 if subset else %0
+ * Returns: true if subset else false
*/
static inline bool xindex_is_subset(u32 link, u32 target)
{
if (((link & ~AA_X_UNSAFE) != (target & ~AA_X_UNSAFE)) ||
((link & AA_X_UNSAFE) && !(target & AA_X_UNSAFE)))
- return 0;
+ return false;
- return 1;
+ return true;
}
static int profile_path_link(struct aa_profile *profile,
diff --git a/security/apparmor/include/domain.h b/security/apparmor/include/domain.h
index 21b875fe2d37..d14928fe1c6f 100644
--- a/security/apparmor/include/domain.h
+++ b/security/apparmor/include/domain.h
@@ -30,7 +30,7 @@ struct aa_domain {
struct aa_label *x_table_lookup(struct aa_profile *profile, u32 xindex,
const char **name);
-int apparmor_bprm_set_creds(struct linux_binprm *bprm);
+int apparmor_bprm_creds_for_exec(struct linux_binprm *bprm);
void aa_free_domain_entries(struct aa_domain *domain);
int aa_change_hat(const char *hats[], int count, u64 token, int flags);
diff --git a/security/apparmor/include/label.h b/security/apparmor/include/label.h
index 47942c4ba7ca..1e90384b1523 100644
--- a/security/apparmor/include/label.h
+++ b/security/apparmor/include/label.h
@@ -275,12 +275,14 @@ 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_destroy(struct aa_label *label);
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, gfp_t gfp);
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);
+bool aa_label_is_unconfined_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);
diff --git a/security/apparmor/include/match.h b/security/apparmor/include/match.h
index e23f4aadc1ff..884489590588 100644
--- a/security/apparmor/include/match.h
+++ b/security/apparmor/include/match.h
@@ -37,6 +37,10 @@
#define YYTH_MAGIC 0x1B5E783D
#define YYTH_FLAG_DIFF_ENCODE 1
+#define YYTH_FLAG_OOB_TRANS 2
+#define YYTH_FLAGS (YYTH_FLAG_DIFF_ENCODE | YYTH_FLAG_OOB_TRANS)
+
+#define MAX_OOB_SUPPORTED 1
struct table_set_header {
u32 th_magic; /* YYTH_MAGIC */
@@ -94,6 +98,7 @@ struct table_header {
struct aa_dfa {
struct kref count;
u16 flags;
+ u32 max_oob;
struct table_header *tables[YYTD_ID_TSIZE];
};
@@ -127,6 +132,8 @@ unsigned int aa_dfa_match(struct aa_dfa *dfa, unsigned int start,
const char *str);
unsigned int aa_dfa_next(struct aa_dfa *dfa, unsigned int state,
const char c);
+unsigned int aa_dfa_outofband_transition(struct aa_dfa *dfa,
+ unsigned int state);
unsigned int aa_dfa_match_until(struct aa_dfa *dfa, unsigned int start,
const char *str, const char **retpos);
unsigned int aa_dfa_matchn_until(struct aa_dfa *dfa, unsigned int start,
@@ -181,5 +188,9 @@ static inline void aa_put_dfa(struct aa_dfa *dfa)
#define MATCH_FLAG_DIFF_ENCODE 0x80000000
#define MARK_DIFF_ENCODE 0x40000000
+#define MATCH_FLAG_OOB_TRANSITION 0x20000000
+#define MATCH_FLAGS_MASK 0xff000000
+#define MATCH_FLAGS_VALID (MATCH_FLAG_DIFF_ENCODE | MATCH_FLAG_OOB_TRANSITION)
+#define MATCH_FLAGS_INVALID (MATCH_FLAGS_MASK & ~MATCH_FLAGS_VALID)
#endif /* __AA_MATCH_H */
diff --git a/security/apparmor/label.c b/security/apparmor/label.c
index 470693239e64..e68bcedca976 100644
--- a/security/apparmor/label.c
+++ b/security/apparmor/label.c
@@ -309,10 +309,8 @@ out:
}
-static void label_destroy(struct aa_label *label)
+void aa_label_destroy(struct aa_label *label)
{
- struct aa_label *tmp;
-
AA_BUG(!label);
if (!label_isprofile(label)) {
@@ -328,16 +326,13 @@ static void label_destroy(struct aa_label *label)
}
}
- if (rcu_dereference_protected(label->proxy->label, true) == label)
- rcu_assign_pointer(label->proxy->label, NULL);
-
+ if (label->proxy) {
+ if (rcu_dereference_protected(label->proxy->label, true) == label)
+ rcu_assign_pointer(label->proxy->label, NULL);
+ aa_put_proxy(label->proxy);
+ }
aa_free_secid(label->secid);
- tmp = rcu_dereference_protected(label->proxy->label, true);
- if (tmp == label)
- rcu_assign_pointer(label->proxy->label, NULL);
-
- aa_put_proxy(label->proxy);
label->proxy = (struct aa_proxy *) PROXY_POISON + 1;
}
@@ -346,7 +341,7 @@ void aa_label_free(struct aa_label *label)
if (!label)
return;
- label_destroy(label);
+ aa_label_destroy(label);
kfree(label);
}
@@ -550,6 +545,39 @@ bool aa_label_is_subset(struct aa_label *set, struct aa_label *sub)
return __aa_label_next_not_in_set(&i, set, sub) == NULL;
}
+/**
+ * aa_label_is_unconfined_subset - test if @sub is a subset of @set
+ * @set: label to test against
+ * @sub: label to test if is subset of @set
+ *
+ * This checks for subset but taking into account unconfined. IF
+ * @sub contains an unconfined profile that does not have a matching
+ * unconfined in @set then this will not cause the test to fail.
+ * Conversely we don't care about an unconfined in @set that is not in
+ * @sub
+ *
+ * Returns: true if @sub is special_subset of @set
+ * else false
+ */
+bool aa_label_is_unconfined_subset(struct aa_label *set, struct aa_label *sub)
+{
+ struct label_it i = { };
+ struct aa_profile *p;
+
+ AA_BUG(!set);
+ AA_BUG(!sub);
+
+ if (sub == set)
+ return true;
+
+ do {
+ p = __aa_label_next_not_in_set(&i, set, sub);
+ if (p && !profile_unconfined(p))
+ break;
+ } while (p);
+
+ return p == NULL;
+}
/**
@@ -1531,13 +1559,13 @@ static const char *label_modename(struct aa_ns *ns, struct aa_label *label,
label_for_each(i, label, profile) {
if (aa_ns_visible(ns, profile->ns, flags & FLAG_VIEW_SUBNS)) {
- if (profile->mode == APPARMOR_UNCONFINED)
+ count++;
+ if (profile == profile->ns->unconfined)
/* special case unconfined so stacks with
* unconfined don't report as mixed. ie.
* profile_foo//&:ns1:unconfined (mixed)
*/
continue;
- count++;
if (mode == -1)
mode = profile->mode;
else if (mode != profile->mode)
@@ -1749,13 +1777,13 @@ void aa_label_seq_xprint(struct seq_file *f, struct aa_ns *ns,
AA_DEBUG("label print error");
return;
}
- seq_printf(f, "%s", str);
+ seq_puts(f, str);
kfree(str);
} else if (display_mode(ns, label, flags))
seq_printf(f, "%s (%s)", label->hname,
label_modename(ns, label, flags));
else
- seq_printf(f, "%s", label->hname);
+ seq_puts(f, label->hname);
}
void aa_label_xprintk(struct aa_ns *ns, struct aa_label *label, int flags,
diff --git a/security/apparmor/lsm.c b/security/apparmor/lsm.c
index b621ad74f54a..ffeaee5ed968 100644
--- a/security/apparmor/lsm.c
+++ b/security/apparmor/lsm.c
@@ -804,7 +804,12 @@ static void apparmor_sk_clone_security(const struct sock *sk,
struct aa_sk_ctx *ctx = SK_CTX(sk);
struct aa_sk_ctx *new = SK_CTX(newsk);
+ if (new->label)
+ aa_put_label(new->label);
new->label = aa_get_label(ctx->label);
+
+ if (new->peer)
+ aa_put_label(new->peer);
new->peer = aa_get_label(ctx->peer);
}
@@ -1232,7 +1237,7 @@ static struct security_hook_list apparmor_hooks[] __lsm_ro_after_init = {
LSM_HOOK_INIT(cred_prepare, apparmor_cred_prepare),
LSM_HOOK_INIT(cred_transfer, apparmor_cred_transfer),
- LSM_HOOK_INIT(bprm_set_creds, apparmor_bprm_set_creds),
+ LSM_HOOK_INIT(bprm_creds_for_exec, apparmor_bprm_creds_for_exec),
LSM_HOOK_INIT(bprm_committing_creds, apparmor_bprm_committing_creds),
LSM_HOOK_INIT(bprm_committed_creds, apparmor_bprm_committed_creds),
@@ -1696,7 +1701,7 @@ static int __init alloc_buffers(void)
#ifdef CONFIG_SYSCTL
static int apparmor_dointvec(struct ctl_table *table, int write,
- void __user *buffer, size_t *lenp, loff_t *ppos)
+ void *buffer, size_t *lenp, loff_t *ppos)
{
if (!policy_admin_capable(NULL))
return -EPERM;
diff --git a/security/apparmor/match.c b/security/apparmor/match.c
index 525ce22dc0e9..3e9e1eaf990e 100644
--- a/security/apparmor/match.c
+++ b/security/apparmor/match.c
@@ -97,6 +97,9 @@ static struct table_header *unpack_table(char *blob, size_t bsize)
th.td_flags == YYTD_DATA8))
goto out;
+ /* if we have a table it must have some entries */
+ if (th.td_lolen == 0)
+ goto out;
tsize = table_size(th.td_lolen, th.td_flags);
if (bsize < tsize)
goto out;
@@ -198,10 +201,32 @@ static int verify_dfa(struct aa_dfa *dfa)
state_count = dfa->tables[YYTD_ID_BASE]->td_lolen;
trans_count = dfa->tables[YYTD_ID_NXT]->td_lolen;
+ if (state_count == 0)
+ goto out;
for (i = 0; i < state_count; i++) {
if (!(BASE_TABLE(dfa)[i] & MATCH_FLAG_DIFF_ENCODE) &&
(DEFAULT_TABLE(dfa)[i] >= state_count))
goto out;
+ if (BASE_TABLE(dfa)[i] & MATCH_FLAGS_INVALID) {
+ pr_err("AppArmor DFA state with invalid match flags");
+ goto out;
+ }
+ if ((BASE_TABLE(dfa)[i] & MATCH_FLAG_DIFF_ENCODE)) {
+ if (!(dfa->flags & YYTH_FLAG_DIFF_ENCODE)) {
+ pr_err("AppArmor DFA diff encoded transition state without header flag");
+ goto out;
+ }
+ }
+ if ((BASE_TABLE(dfa)[i] & MATCH_FLAG_OOB_TRANSITION)) {
+ if (base_idx(BASE_TABLE(dfa)[i]) < dfa->max_oob) {
+ pr_err("AppArmor DFA out of bad transition out of range");
+ goto out;
+ }
+ if (!(dfa->flags & YYTH_FLAG_OOB_TRANS)) {
+ pr_err("AppArmor DFA out of bad transition state without header flag");
+ goto out;
+ }
+ }
if (base_idx(BASE_TABLE(dfa)[i]) + 255 >= trans_count) {
pr_err("AppArmor DFA next/check upper bounds error\n");
goto out;
@@ -304,9 +329,23 @@ struct aa_dfa *aa_dfa_unpack(void *blob, size_t size, int flags)
goto fail;
dfa->flags = ntohs(*(__be16 *) (data + 12));
- if (dfa->flags != 0 && dfa->flags != YYTH_FLAG_DIFF_ENCODE)
+ if (dfa->flags & ~(YYTH_FLAGS))
goto fail;
+ /*
+ * TODO: needed for dfa to support more than 1 oob
+ * if (dfa->flags & YYTH_FLAGS_OOB_TRANS) {
+ * if (hsize < 16 + 4)
+ * goto fail;
+ * dfa->max_oob = ntol(*(__be32 *) (data + 16));
+ * if (dfa->max <= MAX_OOB_SUPPORTED) {
+ * pr_err("AppArmor DFA OOB greater than supported\n");
+ * goto fail;
+ * }
+ * }
+ */
+ dfa->max_oob = 1;
+
data += hsize;
size -= hsize;
@@ -495,6 +534,23 @@ unsigned int aa_dfa_next(struct aa_dfa *dfa, unsigned int state,
return state;
}
+unsigned int aa_dfa_outofband_transition(struct aa_dfa *dfa, unsigned int state)
+{
+ u16 *def = DEFAULT_TABLE(dfa);
+ u32 *base = BASE_TABLE(dfa);
+ u16 *next = NEXT_TABLE(dfa);
+ u16 *check = CHECK_TABLE(dfa);
+ u32 b = (base)[(state)];
+
+ if (!(b & MATCH_FLAG_OOB_TRANSITION))
+ return DFA_NOMATCH;
+
+ /* No Equivalence class remapping for outofband transitions */
+ match_char(state, def, base, next, check, -1);
+
+ return state;
+}
+
/**
* aa_dfa_match_until - traverse @dfa until accept state or end of input
* @dfa: the dfa to match @str against (NOT NULL)
diff --git a/security/apparmor/path.c b/security/apparmor/path.c
index c6da542de27b..b02dfdbff7cd 100644
--- a/security/apparmor/path.c
+++ b/security/apparmor/path.c
@@ -142,7 +142,7 @@ static int d_namespace_path(const struct path *path, char *buf, char **name,
error = PTR_ERR(res);
*name = buf;
goto out;
- };
+ }
} else if (!our_mnt(path->mnt))
connected = 0;
diff --git a/security/apparmor/policy.c b/security/apparmor/policy.c
index 269f2f53c0b1..af4f50fda9e3 100644
--- a/security/apparmor/policy.c
+++ b/security/apparmor/policy.c
@@ -242,6 +242,7 @@ void aa_free_profile(struct aa_profile *profile)
kzfree(profile->hash);
aa_put_loaddata(profile->rawdata);
+ aa_label_destroy(&profile->label);
kzfree(profile);
}
diff --git a/security/apparmor/policy_unpack.c b/security/apparmor/policy_unpack.c
index 2d743c004bc4..b67322abcc33 100644
--- a/security/apparmor/policy_unpack.c
+++ b/security/apparmor/policy_unpack.c
@@ -243,11 +243,11 @@ fail:
static bool unpack_X(struct aa_ext *e, enum aa_code code)
{
if (!inbounds(e, 1))
- return 0;
+ return false;
if (*(u8 *) e->pos != code)
- return 0;
+ return false;
e->pos++;
- return 1;
+ return true;
}
/**
@@ -261,10 +261,10 @@ static bool unpack_X(struct aa_ext *e, enum aa_code code)
* name element in the stream. If @name is NULL any name element will be
* skipped and only the typecode will be tested.
*
- * Returns 1 on success (both type code and name tests match) and the read
+ * Returns true on success (both type code and name tests match) and the read
* head is advanced past the headers
*
- * Returns: 0 if either match fails, the read head does not move
+ * Returns: false if either match fails, the read head does not move
*/
static bool unpack_nameX(struct aa_ext *e, enum aa_code code, const char *name)
{
@@ -289,11 +289,11 @@ static bool unpack_nameX(struct aa_ext *e, enum aa_code code, const char *name)
/* now check if type code matches */
if (unpack_X(e, code))
- return 1;
+ return true;
fail:
e->pos = pos;
- return 0;
+ return false;
}
static bool unpack_u8(struct aa_ext *e, u8 *data, const char *name)
@@ -306,12 +306,12 @@ static bool unpack_u8(struct aa_ext *e, u8 *data, const char *name)
if (data)
*data = get_unaligned((u8 *)e->pos);
e->pos += sizeof(u8);
- return 1;
+ return true;
}
fail:
e->pos = pos;
- return 0;
+ return false;
}
static bool unpack_u32(struct aa_ext *e, u32 *data, const char *name)
@@ -324,12 +324,12 @@ static bool unpack_u32(struct aa_ext *e, u32 *data, const char *name)
if (data)
*data = le32_to_cpu(get_unaligned((__le32 *) e->pos));
e->pos += sizeof(u32);
- return 1;
+ return true;
}
fail:
e->pos = pos;
- return 0;
+ return false;
}
static bool unpack_u64(struct aa_ext *e, u64 *data, const char *name)
@@ -342,12 +342,12 @@ static bool unpack_u64(struct aa_ext *e, u64 *data, const char *name)
if (data)
*data = le64_to_cpu(get_unaligned((__le64 *) e->pos));
e->pos += sizeof(u64);
- return 1;
+ return true;
}
fail:
e->pos = pos;
- return 0;
+ return false;
}
static size_t unpack_array(struct aa_ext *e, const char *name)
@@ -472,7 +472,7 @@ static struct aa_dfa *unpack_dfa(struct aa_ext *e)
* @e: serialized data extent information (NOT NULL)
* @profile: profile to add the accept table to (NOT NULL)
*
- * Returns: 1 if table successfully unpacked
+ * Returns: true if table successfully unpacked
*/
static bool unpack_trans_table(struct aa_ext *e, struct aa_profile *profile)
{
@@ -535,12 +535,12 @@ static bool unpack_trans_table(struct aa_ext *e, struct aa_profile *profile)
if (!unpack_nameX(e, AA_STRUCTEND, NULL))
goto fail;
}
- return 1;
+ return true;
fail:
aa_free_domain_entries(&profile->file.trans);
e->pos = saved_pos;
- return 0;
+ return false;
}
static bool unpack_xattrs(struct aa_ext *e, struct aa_profile *profile)
@@ -565,11 +565,11 @@ static bool unpack_xattrs(struct aa_ext *e, struct aa_profile *profile)
goto fail;
}
- return 1;
+ return true;
fail:
e->pos = pos;
- return 0;
+ return false;
}
static bool unpack_secmark(struct aa_ext *e, struct aa_profile *profile)
@@ -601,7 +601,7 @@ static bool unpack_secmark(struct aa_ext *e, struct aa_profile *profile)
goto fail;
}
- return 1;
+ return true;
fail:
if (profile->secmark) {
@@ -613,7 +613,7 @@ fail:
}
e->pos = pos;
- return 0;
+ return false;
}
static bool unpack_rlimits(struct aa_ext *e, struct aa_profile *profile)
@@ -643,11 +643,11 @@ static bool unpack_rlimits(struct aa_ext *e, struct aa_profile *profile)
if (!unpack_nameX(e, AA_STRUCTEND, NULL))
goto fail;
}
- return 1;
+ return true;
fail:
e->pos = pos;
- return 0;
+ return false;
}
static u32 strhash(const void *data, u32 len, u32 seed)
@@ -748,10 +748,14 @@ static struct aa_profile *unpack_profile(struct aa_ext *e, char **ns_name)
goto fail;
if (tmp == PACKED_MODE_COMPLAIN || (e->version & FORCE_COMPLAIN_FLAG))
profile->mode = APPARMOR_COMPLAIN;
+ else if (tmp == PACKED_MODE_ENFORCE)
+ profile->mode = APPARMOR_ENFORCE;
else if (tmp == PACKED_MODE_KILL)
profile->mode = APPARMOR_KILL;
else if (tmp == PACKED_MODE_UNCONFINED)
profile->mode = APPARMOR_UNCONFINED;
+ else
+ goto fail;
if (!unpack_u32(e, &tmp, NULL))
goto fail;
if (tmp)
@@ -990,8 +994,8 @@ static bool verify_xindex(int xindex, int table_size)
xtype = xindex & AA_X_TYPE_MASK;
index = xindex & AA_X_INDEX_MASK;
if (xtype == AA_X_TABLE && index >= table_size)
- return 0;
- return 1;
+ return false;
+ return true;
}
/* verify dfa xindexes are in range of transition tables */
@@ -1000,11 +1004,11 @@ static bool verify_dfa_xindex(struct aa_dfa *dfa, int table_size)
int i;
for (i = 0; i < dfa->tables[YYTD_ID_ACCEPT]->td_lolen; i++) {
if (!verify_xindex(dfa_user_xindex(dfa, i), table_size))
- return 0;
+ return false;
if (!verify_xindex(dfa_other_xindex(dfa, i), table_size))
- return 0;
+ return false;
}
- return 1;
+ return true;
}
/**