{
ssize_t error;
struct aa_loaddata *data;
- struct aa_profile *profile = aa_current_profile();
+ struct aa_profile *profile;
+
+ profile = begin_current_profile_crit_section();
+
/* high level check about policy management - fine grained in
* below after unpack
*/
error = aa_replace_profiles(ns, profile, mask, data);
aa_put_loaddata(data);
}
+ end_current_profile_crit_section(profile);
return error;
}
ssize_t error;
struct aa_ns *ns = aa_get_ns(f->f_inode->i_private);
- profile = aa_current_profile();
+ profile = begin_current_profile_crit_section();
/* high level check about policy management - fine grained in
* below after unpack
*/
aa_put_loaddata(data);
}
out:
+ end_current_profile_crit_section(profile);
aa_put_ns(ns);
return error;
}
if (buf_len < sizeof(bytes) + sizeof(blocks))
return -EINVAL; /* not enough space */
- curr = aa_current_profile();
+ curr = begin_current_profile_crit_section();
profile = aa_fqlookupn_profile(curr, query, strnlen(query, query_len));
+ end_current_profile_crit_section(curr);
if (!profile)
return -ENOENT;
match_str = label_name + label_name_len + 1;
match_len = query_len - label_name_len - 1;
- curr = aa_current_profile();
+ curr = begin_current_profile_crit_section();
profile = aa_fqlookupn_profile(curr, label_name, label_name_len);
+ end_current_profile_crit_section(curr);
if (!profile)
return -ENOENT;
static int seq_ns_level_show(struct seq_file *seq, void *v)
{
- struct aa_ns *ns = aa_current_profile()->ns;
+ struct aa_profile *profile;
- seq_printf(seq, "%d\n", ns->level);
+ profile = begin_current_profile_crit_section();
+ seq_printf(seq, "%d\n", profile->ns->level);
+ end_current_profile_crit_section(profile);
return 0;
}
static int seq_ns_name_show(struct seq_file *seq, void *v)
{
- struct aa_ns *ns = aa_current_profile()->ns;
+ struct aa_profile *profile;
- seq_printf(seq, "%s\n", aa_ns_name(ns, ns, true));
+ profile = begin_current_profile_crit_section();
+ seq_printf(seq, "%s\n", aa_ns_name(profile->ns, profile->ns, true));
+ end_current_profile_crit_section(profile);
return 0;
}
{
struct aa_ns *ns, *parent;
/* TODO: improve permission check */
- struct aa_profile *profile = aa_current_profile();
+ struct aa_profile *profile = begin_current_profile_crit_section();
int error = aa_may_manage_policy(profile, NULL, AA_MAY_LOAD_POLICY);
-
+ end_current_profile_crit_section(profile);
if (error)
return error;
{
struct aa_ns *ns, *parent;
/* TODO: improve permission check */
- struct aa_profile *profile = aa_current_profile();
+ struct aa_profile *profile = begin_current_profile_crit_section();
int error = aa_may_manage_policy(profile, NULL, AA_MAY_LOAD_POLICY);
-
+ end_current_profile_crit_section(profile);
if (error)
return error;
static void *p_start(struct seq_file *f, loff_t *pos)
{
struct aa_profile *profile = NULL;
- struct aa_ns *root = aa_current_profile()->ns;
+ struct aa_ns *root = aa_get_current_ns();
loff_t l = *pos;
- f->private = aa_get_ns(root);
-
+ f->private = root;
/* find the first profile */
mutex_lock(&root->lock);
struct aa_profile *p;
rcu_read_lock();
- p = aa_get_profile(__aa_task_profile(task));
+ p = aa_get_newest_profile(__aa_task_raw_profile(task));
rcu_read_unlock();
return p;
/* released below */
cred = get_current_cred();
ctx = cred_ctx(cred);
- profile = aa_get_newest_profile(aa_cred_profile(cred));
+ profile = aa_get_newest_cred_profile(cred);
previous_profile = aa_get_newest_profile(ctx->previous);
if (unconfined(profile)) {
}
cred = get_current_cred();
- profile = aa_cred_profile(cred);
+ profile = aa_get_newest_cred_profile(cred);
/*
* Fail explicitly requested domain transitions if no_new_privs
fqname, GLOBAL_ROOT_UID, info, error);
aa_put_profile(target);
+ aa_put_profile(profile);
put_cred(cred);
return error;
/**
- * aa_cred_profile - obtain cred's profiles
+ * aa_cred_raw_profile - obtain cred's profiles
* @cred: cred to obtain profiles from (NOT NULL)
*
* Returns: confining profile
*
* does NOT increment reference count
*/
-static inline struct aa_profile *aa_cred_profile(const struct cred *cred)
+static inline struct aa_profile *aa_cred_raw_profile(const struct cred *cred)
{
struct aa_task_ctx *ctx = cred_ctx(cred);
}
/**
- * __aa_task_profile - retrieve another task's profile
+ * aa_get_newest_cred_profile - obtain the newest profile on a cred
+ * @cred: cred to obtain profile from (NOT NULL)
+ *
+ * Returns: newest version of confining profile
+ */
+static inline
+struct aa_profile *aa_get_newest_cred_profile(const struct cred *cred)
+{
+ return aa_get_newest_profile(aa_cred_raw_profile(cred));
+}
+
+/**
+ * __aa_task_raw_profile - retrieve another task's profile
* @task: task to query (NOT NULL)
*
* Returns: @task's profile 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_profile *__aa_task_raw_profile(struct task_struct *task)
{
- return aa_cred_profile(__task_cred(task));
+ return aa_cred_raw_profile(__task_cred(task));
}
/**
*/
static inline bool __aa_task_is_confined(struct task_struct *task)
{
- return !unconfined(__aa_task_profile(task));
+ return !unconfined(__aa_task_raw_profile(task));
}
/**
- * __aa_current_profile - find the current tasks confining profile
+ * aa_current_raw_profile - find the current tasks confining profile
*
* Returns: up to date confining profile or the ns unconfined profile (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.
*/
-static inline struct aa_profile *__aa_current_profile(void)
+static inline struct aa_profile *aa_current_raw_profile(void)
{
- return aa_cred_profile(current_cred());
+ return aa_cred_raw_profile(current_cred());
}
/**
- * aa_current_profile - find the current tasks confining profile and do updates
+ * aa_get_current_profile - get the newest version of the current tasks profile
*
- * Returns: up to date confining profile or the ns unconfined profile (NOT NULL)
+ * Returns: newest version of confining 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_profile()
*/
-static inline struct aa_profile *aa_current_profile(void)
+static inline struct aa_profile *aa_get_current_profile(void)
{
- const struct aa_task_ctx *ctx = current_ctx();
- struct aa_profile *profile;
+ struct aa_profile *p = aa_current_raw_profile();
- AA_BUG(!ctx || !ctx->profile);
+ if (profile_is_stale(p))
+ return aa_get_newest_profile(p);
+ return aa_get_profile(p);
+}
- if (profile_is_stale(ctx->profile)) {
- profile = aa_get_newest_profile(ctx->profile);
- aa_replace_current_profile(profile);
+#define __end_current_profile_crit_section(X) \
+ end_current_profile_crit_section(X)
+
+/**
+ * end_profile_crit_section - put a reference found with begin_current_profile..
+ * @profile: profile reference to put
+ *
+ * Should only be used with a reference obtained with
+ * begin_current_profile_crit_section and never used in situations where the
+ * task cred may be updated
+ */
+static inline void end_current_profile_crit_section(struct aa_profile *profile)
+{
+ if (profile != aa_current_raw_profile())
aa_put_profile(profile);
- ctx = current_ctx();
+}
+
+/**
+ * __begin_current_profile_crit_section - current's confining profile
+ *
+ * Returns: up to date confining profile or the ns unconfined profile (NOT NULL)
+ *
+ * safe to call inside locks
+ *
+ * The returned reference must be put with __end_current_profile_crit_section()
+ * This must NOT be used if the task cred could be updated within the
+ * critical section between __begin_current_profile_crit_section() ..
+ * __end_current_profile_crit_section()
+ */
+static inline struct aa_profile *__begin_current_profile_crit_section(void)
+{
+ struct aa_profile *profile = aa_current_raw_profile();
+
+ if (profile_is_stale(profile))
+ profile = aa_get_newest_profile(profile);
+
+ return profile;
+}
+
+/**
+ * begin_current_profile_crit_section - current's profile and update if needed
+ *
+ * Returns: up to date confining profile or the ns unconfined profile (NOT NULL)
+ *
+ * Not safe to call inside locks
+ *
+ * The returned reference must be put with end_current_profile_crit_section()
+ * This must NOT be used if the task cred could be updated within the
+ * critical section between begin_current_profile_crit_section() ..
+ * end_current_profile_crit_section()
+ */
+static inline struct aa_profile *begin_current_profile_crit_section(void)
+{
+ struct aa_profile *profile = aa_current_raw_profile();
+
+ if (profile_is_stale(profile)) {
+ profile = aa_get_newest_profile(profile);
+ if (aa_replace_current_profile(profile) == 0)
+ /* task cred will keep the reference */
+ aa_put_profile(profile);
}
- return ctx->profile;
+ return profile;
}
static inline struct aa_ns *aa_get_current_ns(void)
{
- return aa_get_ns(__aa_current_profile()->ns);
+ struct aa_profile *profile;
+ struct aa_ns *ns;
+
+ profile = __begin_current_profile_crit_section();
+ ns = aa_get_ns(profile->ns);
+ __end_current_profile_crit_section(profile);
+
+ return ns;
}
/**
rcu_read_lock();
cred = __task_cred(target);
- profile = aa_cred_profile(cred);
+ profile = aa_get_newest_cred_profile(cred);
/*
* cap_capget is stacked ahead of this and will
*permitted = cap_intersect(*permitted, profile->caps.allow);
}
rcu_read_unlock();
+ aa_put_profile(profile);
return 0;
}
struct aa_profile *profile;
int error = 0;
- profile = aa_cred_profile(cred);
+ profile = aa_get_newest_cred_profile(cred);
if (!unconfined(profile))
error = aa_capable(profile, cap, audit);
+ aa_put_profile(profile);
+
return error;
}
struct aa_profile *profile;
int error = 0;
- profile = __aa_current_profile();
+ profile = __begin_current_profile_crit_section();
if (!unconfined(profile))
error = aa_path_perm(op, profile, path, 0, mask, cond);
+ __end_current_profile_crit_section(profile);
return error;
}
if (!path_mediated_fs(old_dentry))
return 0;
- profile = aa_current_profile();
+ profile = begin_current_profile_crit_section();
if (!unconfined(profile))
error = aa_path_link(profile, old_dentry, new_dir, new_dentry);
+ end_current_profile_crit_section(profile);
+
return error;
}
if (!path_mediated_fs(old_dentry))
return 0;
- profile = aa_current_profile();
+ profile = begin_current_profile_crit_section();
if (!unconfined(profile)) {
struct path old_path = { .mnt = old_dir->mnt,
.dentry = old_dentry };
AA_MAY_CREATE, &cond);
}
+ end_current_profile_crit_section(profile);
+
return error;
}
return 0;
}
- profile = aa_cred_profile(cred);
+ profile = aa_get_newest_cred_profile(cred);
if (!unconfined(profile)) {
struct inode *inode = file_inode(file);
struct path_cond cond = { inode->i_uid, inode->i_mode };
/* todo cache full allowed permissions set and state */
fctx->allow = aa_map_file_to_perms(file);
}
+ aa_put_profile(profile);
return error;
}
static int apparmor_file_alloc_security(struct file *file)
{
+ int error = 0;
+
/* freed by apparmor_file_free_security */
+ struct aa_profile *profile = begin_current_profile_crit_section();
file->f_security = aa_alloc_file_context(GFP_KERNEL);
if (!file->f_security)
return -ENOMEM;
- return 0;
+ end_current_profile_crit_section(profile);
+ return error;
}
static void apparmor_file_free_security(struct file *file)
static int common_file_perm(const char *op, struct file *file, u32 mask)
{
struct aa_file_ctx *fctx = file->f_security;
- struct aa_profile *profile, *fprofile = aa_cred_profile(file->f_cred);
+ struct aa_profile *profile, *fprofile;
int error = 0;
+ fprofile = aa_cred_raw_profile(file->f_cred);
AA_BUG(!fprofile);
if (!file->f_path.mnt ||
!path_mediated_fs(file->f_path.dentry))
return 0;
- profile = __aa_current_profile();
+ profile = __begin_current_profile_crit_section();
/* revalidate access, if task is unconfined, or the cached cred
* doesn't match or if the request is for more permissions than
if (!unconfined(profile) && !unconfined(fprofile) &&
((fprofile != profile) || (mask & ~fctx->allow)))
error = aa_file_perm(op, profile, file, mask);
+ __end_current_profile_crit_section(profile);
return error;
}
return error;
fail:
- aad(&sa)->profile = aa_current_profile();
+ aad(&sa)->profile = begin_current_profile_crit_section();
aad(&sa)->info = name;
aad(&sa)->error = error = -EINVAL;
aa_audit_msg(AUDIT_APPARMOR_DENIED, &sa, NULL);
+ end_current_profile_crit_section(aad(&sa)->profile);
goto out;
}
*/
static void apparmor_bprm_committing_creds(struct linux_binprm *bprm)
{
- struct aa_profile *profile = __aa_current_profile();
+ struct aa_profile *profile = aa_current_raw_profile();
struct aa_task_ctx *new_ctx = cred_ctx(bprm->cred);
/* bail out if unconfined or not changing profile */
static int apparmor_task_setrlimit(struct task_struct *task,
unsigned int resource, struct rlimit *new_rlim)
{
- struct aa_profile *profile = __aa_current_profile();
+ struct aa_profile *profile = __begin_current_profile_crit_section();
int error = 0;
if (!unconfined(profile))
error = aa_task_setrlimit(profile, task, resource, new_rlim);
+ __end_current_profile_crit_section(profile);
return error;
}
const char *name, const char *info, struct aa_ext *e,
int error)
{
- struct aa_profile *profile = __aa_current_profile();
+ struct aa_profile *profile = aa_current_raw_profile();
DEFINE_AUDIT_DATA(sa, LSM_AUDIT_DATA_NONE, NULL);
if (e)
aad(&sa)->iface.pos = e->pos - e->start;
const char *mode_str = aa_profile_mode_names[profile->mode];
const char *ns_name = NULL;
struct aa_ns *ns = profile->ns;
- struct aa_ns *current_ns = __aa_current_profile()->ns;
+ struct aa_ns *current_ns = aa_get_current_ns();
char *s;
if (!aa_ns_visible(current_ns, ns, true))
else
sprintf(s, "%s (%s)\n", profile->base.hname, mode_str);
*string = str;
+ aa_put_ns(current_ns);
/* NOTE: len does not include \0 of string, not saved as part of file */
return len;
int error = 0;
rcu_read_lock();
- task_profile = aa_get_profile(aa_cred_profile(__task_cred(task)));
+ task_profile = aa_get_newest_cred_profile((__task_cred(task)));
rcu_read_unlock();
/* TODO: extend resource control to handle other (non current)