Skip to content

Commit

Permalink
Merge tag 'apparmor-pr-2020-06-07' of git://git.kernel.org/pub/scm/li…
Browse files Browse the repository at this point in the history
…nux/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()
  • Loading branch information
torvalds committed Jun 7, 2020
2 parents 8b8c704 + 3622ad2 commit a2b4470
Show file tree
Hide file tree
Showing 12 changed files with 198 additions and 119 deletions.
13 changes: 13 additions & 0 deletions fs/proc/base.c
Original file line number Diff line number Diff line change
Expand Up @@ -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),
Expand All @@ -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)
Expand Down
56 changes: 13 additions & 43 deletions security/apparmor/apparmorfs.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
*
Expand Down Expand Up @@ -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);
}

Expand Down Expand Up @@ -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))
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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),
{ }
};

Expand Down
39 changes: 14 additions & 25 deletions security/apparmor/domain.c
Original file line number Diff line number Diff line change
Expand Up @@ -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++) {
Expand All @@ -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);
Expand All @@ -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
Expand Down Expand Up @@ -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 = {};
Expand Down Expand Up @@ -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 */
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand All @@ -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;
Expand Down Expand Up @@ -1420,7 +1409,7 @@ int aa_change_profile(const char *fqname, 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;
Expand Down
12 changes: 6 additions & 6 deletions security/apparmor/file.c
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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,
Expand Down
2 changes: 2 additions & 0 deletions security/apparmor/include/label.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
11 changes: 11 additions & 0 deletions security/apparmor/include/match.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
Expand Down Expand Up @@ -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];
};

Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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 */
Loading

0 comments on commit a2b4470

Please sign in to comment.