diff options
| author | Steven Rostedt <rostedt@goodmis.org> | 2026-09-02 09:55:01 -0400 |
|---|---|---|
| committer | Steven Rostedt <rostedt@goodmis.org> | 2026-09-02 11:08:21 -0400 |
| commit | 4617721c502b2ddaa4e324e86da4997edf738fa5 (patch) | |
| tree | 350aa83b47da0b574a814795392b20b0bed83cbc /security/apparmor/secid.c | |
| download | linux-stable-4617721c502b2ddaa4e324e86da4997edf738fa5.tar.gz linux-stable-4617721c502b2ddaa4e324e86da4997edf738fa5.zip | |
ftrace: Synchronize the initialization of ftrace_opsgrafted
There's some internal state that ftrace_ops needs to have set, but since
it can be declared outside of the ftrace.c code, it calls
ftrace_ops_init() on the ops in every global function. The issue is that
if two tasks call it on the same ops at the same time it is possible to
have the initialization of one corrupt the initialization of the other
call.
Create a ops_mutex to use to synchronize every initialization of the
ftrace_ops. The mutex is taken within checking the ftrace_ops flag that
states it was initializied but the flag is checked again after the mutex
has been taken. Checking first outside the mutex allows it to shortcut
having to take the mutex. But then the check needs to be done again after
the mute is taken in case of races.
Cc: stable@vger.kernel.org
Link: https://patch.msgid.link/20260902095501.6b59af20@gandalf.local.home
Fixes: f04f24fb7e48d ("ftrace, kprobes: Fix a deadlock on ftrace_regex_lock")
Reported-by: sashiko-bot@kernel.org
Close: https://lore.kernel.org/all/20260829025528.49A831F000E9@smtp.kernel.org/
Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
Diffstat (limited to 'security/apparmor/secid.c')
| -rw-r--r-- | security/apparmor/secid.c | 155 |
1 files changed, 155 insertions, 0 deletions
diff --git a/security/apparmor/secid.c b/security/apparmor/secid.c new file mode 100644 index 000000000..28caf66b9 --- /dev/null +++ b/security/apparmor/secid.c @@ -0,0 +1,155 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * AppArmor security module + * + * This file contains AppArmor security identifier (secid) manipulation fns + * + * Copyright 2009-2017 Canonical Ltd. + * + * AppArmor allocates a unique secid for every label used. If a label + * is replaced it receives the secid of the label it is replacing. + */ + +#include <linux/errno.h> +#include <linux/err.h> +#include <linux/gfp.h> +#include <linux/slab.h> +#include <linux/spinlock.h> +#include <linux/xarray.h> + +#include "include/cred.h" +#include "include/lib.h" +#include "include/secid.h" +#include "include/label.h" +#include "include/policy_ns.h" + +/* + * secids - do not pin labels with a refcount. They rely on the label + * properly updating/freeing them + */ +#define AA_FIRST_SECID 2 + +static DEFINE_XARRAY_FLAGS(aa_secids, XA_FLAGS_LOCK_IRQ | XA_FLAGS_TRACK_FREE); + +int apparmor_display_secid_mode; + +/* + * TODO: allow policy to reserve a secid range? + * TODO: add secid pinning + * TODO: use secid_update in label replace + */ + +/* + * see label for inverse aa_label_to_secid + */ +struct aa_label *aa_secid_to_label(u32 secid) +{ + return xa_load(&aa_secids, secid); +} + +static int apparmor_label_to_secctx(struct aa_label *label, + struct lsm_context *cp) +{ + /* TODO: cache secctx and ref count so we don't have to recreate */ + int flags = FLAG_VIEW_SUBNS | FLAG_HIDDEN_UNCONFINED | FLAG_ABS_ROOT; + int len; + + if (!label) + return -EINVAL; + + if (apparmor_display_secid_mode) + flags |= FLAG_SHOW_MODE; + + if (cp) + len = aa_label_asxprint(&cp->context, root_ns, label, + flags, GFP_ATOMIC); + else + len = aa_label_snxprint(NULL, 0, root_ns, label, flags); + + if (len < 0) + return -ENOMEM; + + if (cp) { + cp->len = len; + cp->id = LSM_ID_APPARMOR; + } + + return len; +} + +int apparmor_secid_to_secctx(u32 secid, struct lsm_context *cp) +{ + struct aa_label *label = aa_secid_to_label(secid); + + return apparmor_label_to_secctx(label, cp); +} + +int apparmor_lsmprop_to_secctx(struct lsm_prop *prop, struct lsm_context *cp) +{ + struct aa_label *label; + + label = prop->apparmor.label; + + return apparmor_label_to_secctx(label, cp); +} + +int apparmor_secctx_to_secid(const char *secdata, u32 seclen, u32 *secid) +{ + struct aa_label *label; + + label = aa_label_strn_parse(&root_ns->unconfined->label, secdata, + seclen, GFP_KERNEL, false, false); + if (IS_ERR(label)) + return PTR_ERR(label); + *secid = label->secid; + + return 0; +} + +void apparmor_release_secctx(struct lsm_context *cp) +{ + if (cp->id == LSM_ID_APPARMOR) { + kfree(cp->context); + cp->context = NULL; + cp->id = LSM_ID_UNDEF; + } +} + +/** + * aa_alloc_secid - allocate a new secid for a profile + * @label: the label to allocate a secid for + * @gfp: memory allocation flags + * + * Returns: 0 with @label->secid initialized + * <0 returns error with @label->secid set to AA_SECID_INVALID + */ +int aa_alloc_secid(struct aa_label *label, gfp_t gfp) +{ + unsigned long flags; + int ret; + + xa_lock_irqsave(&aa_secids, flags); + ret = __xa_alloc(&aa_secids, &label->secid, label, + XA_LIMIT(AA_FIRST_SECID, INT_MAX), gfp); + xa_unlock_irqrestore(&aa_secids, flags); + + if (ret < 0) { + label->secid = AA_SECID_INVALID; + return ret; + } + + return 0; +} + +/** + * aa_free_secid - free a secid + * @secid: secid to free + */ +void aa_free_secid(u32 secid) +{ + unsigned long flags; + + xa_lock_irqsave(&aa_secids, flags); + __xa_erase(&aa_secids, secid); + xa_unlock_irqrestore(&aa_secids, flags); +} |
