Tag summary
+ Features - Replace zero-length array with flexible-array - add a valid state flags check - add consistency check between state and dfa diff encode flags - add apparmor subdir to proc attr interface - fail unpack if profile mode is unknown - add outofband transition and use it in xattr match - ensure that dfa state tables have entries + Cleanups - Use true and false for bool variable - Remove semicolon - Clean code by removing redundant instructions - Replace two seq_printf() calls by seq_puts() in aa_label_seq_xprint() - remove duplicate check of xattrs on profile attachment - remove useless aafs_create_symlink + Bug fixes - Fix memory leak of profile proxy - fix introspection of of task mode for unconfined tasks - fix nnp subset test for unconfined - check/put label on apparmor_sk_clone_security() -----BEGIN PGP SIGNATURE----- iQIzBAABCgAdFiEE7cSDD705q2rFEEf7BS82cBjVw9gFAl7dUf4ACgkQBS82cBjV w9j8rA//R3qbVeiN3SJtxLhiF3AAdP2cVbZ/mAhQLwYObI6flb1bliiahJHRf8Ey FaVb4srOH8NlmzNINZehXOvD3UDwX/sbpw8h0Y0JolO+v1m3UXkt/eRoMt6gRz7I jtaImY1/V+G4O5rV5fGA1HQI8Geg+W9Abt32d16vyKIIpnBS/Pfv8ppM0NcHCZ4G e8935T/dMNK5K0Y7HNb1nMjyzEr0LtEXvXznBOrGVpCtDQ45m0/NBvAqpfhuKsVm FE5Na8rgtiB9sU72LaoNXNr8Y5LVgkXPmBr/e1FqZtF01XEarKb7yJDGOLrLpp1o rGYpY9DQSBT/ZZrwMaLFqCd1XtnN1BAmhlM6TXfnm25ArEnQ49ReHFc7ZHZRSTZz LWVBD6atZbapvqckk1SU49eCLuGs5wmRj/CmwdoQUbZ+aOfR68zF+0PANbP5xDo4 862MmeMsm8JHndeCelpZQRbhtXt0t9MDzwMBevKhxV9hbpt4g8DcnC5tNUc9AnJi qJDsMkytYhazIW+/4MsnLTo9wzhqzXq5kBeE++Xl7vDE/V+d5ocvQg73xtwQo9sx LzMlh3cPmBvOnlpYfnONZP8pJdjDAuESsi/H5+RKQL3cLz7NX31CLWR8dXLBHy80 Dvxqvy84Cf7buigqwSzgAGKjDI5HmeOECAMjpLbEB2NS9xxQYuk= =U7d2 -----END PGP SIGNATURE----- Merge tag 'apparmor-pr-2020-06-07' of git://git.kernel.org/pub/scm/linux/kernel/git/jj/linux-apparmor Pull apparmor updates from John Johansen: "Features: - Replace zero-length array with flexible-array - add a valid state flags check - add consistency check between state and dfa diff encode flags - add apparmor subdir to proc attr interface - fail unpack if profile mode is unknown - add outofband transition and use it in xattr match - ensure that dfa state tables have entries Cleanups: - Use true and false for bool variable - Remove semicolon - Clean code by removing redundant instructions - Replace two seq_printf() calls by seq_puts() in aa_label_seq_xprint() - remove duplicate check of xattrs on profile attachment - remove useless aafs_create_symlink Bug fixes: - Fix memory leak of profile proxy - fix introspection of of task mode for unconfined tasks - fix nnp subset test for unconfined - check/put label on apparmor_sk_clone_security()" * tag 'apparmor-pr-2020-06-07' of git://git.kernel.org/pub/scm/linux/kernel/git/jj/linux-apparmor: apparmor: Fix memory leak of profile proxy apparmor: fix introspection of of task mode for unconfined tasks apparmor: check/put label on apparmor_sk_clone_security() apparmor: Use true and false for bool variable security/apparmor/label.c: Clean code by removing redundant instructions apparmor: Replace zero-length array with flexible-array apparmor: ensure that dfa state tables have entries apparmor: remove duplicate check of xattrs on profile attachment. apparmor: add outofband transition and use it in xattr match apparmor: fail unpack if profile mode is unknown apparmor: fix nnp subset test for unconfined apparmor: remove useless aafs_create_symlink apparmor: add proc subdir to attrs apparmor: add consistency check between state and dfa diff encode flags apparmor: add a valid state flags check AppArmor: Remove semicolon apparmor: Replace two seq_printf() calls by seq_puts() in aa_label_seq_xprint()
This commit is contained in:
commit
a2b447066c
|
@ -2778,6 +2778,15 @@ static const struct pid_entry smack_attr_dir_stuff[] = {
|
|||
LSM_DIR_OPS(smack);
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_SECURITY_APPARMOR
|
||||
static const struct pid_entry apparmor_attr_dir_stuff[] = {
|
||||
ATTR("apparmor", "current", 0666),
|
||||
ATTR("apparmor", "prev", 0444),
|
||||
ATTR("apparmor", "exec", 0666),
|
||||
};
|
||||
LSM_DIR_OPS(apparmor);
|
||||
#endif
|
||||
|
||||
static const struct pid_entry attr_dir_stuff[] = {
|
||||
ATTR(NULL, "current", 0666),
|
||||
ATTR(NULL, "prev", 0444),
|
||||
|
@ -2789,6 +2798,10 @@ static const struct pid_entry attr_dir_stuff[] = {
|
|||
DIR("smack", 0555,
|
||||
proc_smack_attr_dir_inode_ops, proc_smack_attr_dir_ops),
|
||||
#endif
|
||||
#ifdef CONFIG_SECURITY_APPARMOR
|
||||
DIR("apparmor", 0555,
|
||||
proc_apparmor_attr_dir_inode_ops, proc_apparmor_attr_dir_ops),
|
||||
#endif
|
||||
};
|
||||
|
||||
static int proc_attr_dir_readdir(struct file *file, struct dir_context *ctx)
|
||||
|
|
|
@ -340,38 +340,6 @@ static struct dentry *aafs_create_dir(const char *name, struct dentry *parent)
|
|||
NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
*
|
||||
|
@ -624,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);
|
||||
}
|
||||
|
||||
|
@ -840,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))
|
||||
|
@ -1763,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);
|
||||
|
@ -2364,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),
|
||||
{ }
|
||||
};
|
||||
|
||||
|
|
|
@ -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 */
|
||||
|
@ -926,7 +914,8 @@ int apparmor_bprm_creds_for_exec(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;
|
||||
|
@ -1204,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;
|
||||
|
@ -1225,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;
|
||||
|
@ -1420,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;
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
Loading…
Reference in New Issue