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/procattr.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/procattr.c')
| -rw-r--r-- | security/apparmor/procattr.c | 141 |
1 files changed, 141 insertions, 0 deletions
diff --git a/security/apparmor/procattr.c b/security/apparmor/procattr.c new file mode 100644 index 000000000..c07b6e8fd --- /dev/null +++ b/security/apparmor/procattr.c @@ -0,0 +1,141 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * AppArmor security module + * + * This file contains AppArmor /proc/<pid>/attr/ interface functions + * + * Copyright (C) 1998-2008 Novell/SUSE + * Copyright 2009-2010 Canonical Ltd. + */ + +#include "include/apparmor.h" +#include "include/cred.h" +#include "include/policy.h" +#include "include/policy_ns.h" +#include "include/domain.h" +#include "include/procattr.h" + + +/** + * aa_getprocattr - Return the label information for @label + * @label: the label to print label info about (NOT NULL) + * @string: Returns - string containing the label info (NOT NULL) + * @newline: indicates that a newline should be added + * + * Requires: label != NULL && string != NULL + * + * Creates a string containing the label information for @label. + * + * Returns: size of string placed in @string else error code on failure + */ +int aa_getprocattr(struct aa_label *label, char **string, bool newline) +{ + struct aa_ns *ns = labels_ns(label); + struct aa_ns *current_ns = aa_get_current_ns(); + int len; + + if (!aa_ns_visible(current_ns, ns, true)) { + aa_put_ns(current_ns); + return -EACCES; + } + + len = aa_label_snxprint(NULL, 0, current_ns, label, + FLAG_SHOW_MODE | FLAG_VIEW_SUBNS | + FLAG_HIDDEN_UNCONFINED); + AA_BUG(len < 0); + + *string = kmalloc(len + 2, GFP_KERNEL); + if (!*string) { + aa_put_ns(current_ns); + return -ENOMEM; + } + + len = aa_label_snxprint(*string, len + 2, current_ns, label, + FLAG_SHOW_MODE | FLAG_VIEW_SUBNS | + FLAG_HIDDEN_UNCONFINED); + if (len < 0) { + kfree(*string); + *string = NULL; + aa_put_ns(current_ns); + return len; + } + + if (newline) + (*string)[len++] = '\n'; + (*string)[len] = 0; + + aa_put_ns(current_ns); + return len; +} + +/** + * split_token_from_name - separate a string of form <token>^<name> + * @op: operation being checked + * @args: string to parse (NOT NULL) + * @token: stores returned parsed token value (NOT NULL) + * + * Returns: start position of name after token else NULL on failure + */ +static char *split_token_from_name(const char *op, char *args, u64 *token) +{ + char *name; + + *token = simple_strtoull(args, &name, 16); + if ((name == args) || *name != '^') { + AA_ERROR("%s: Invalid input '%s'", op, args); + return ERR_PTR(-EINVAL); + } + + name++; /* skip ^ */ + if (!*name) + name = NULL; + return name; +} + +/** + * aa_setprocattr_changehat - handle procattr interface to change_hat + * @args: args received from writing to /proc/<pid>/attr/current (NOT NULL) + * @size: size of the args + * @flags: set of flags governing behavior + * + * Returns: %0 or error code if change_hat fails + */ +int aa_setprocattr_changehat(char *args, size_t size, int flags) +{ + char *hat; + u64 token; + const char *hats[16]; /* current hard limit on # of names */ + int count = 0; + + hat = split_token_from_name(OP_CHANGE_HAT, args, &token); + if (IS_ERR(hat)) + return PTR_ERR(hat); + + if (!hat && !token) { + AA_ERROR("change_hat: Invalid input, NULL hat and NULL magic"); + return -EINVAL; + } + + if (hat) { + /* set up hat name vector, args guaranteed null terminated + * at args[size] by setprocattr. + * + * If there are multiple hat names in the buffer each is + * separated by a \0. Ie. userspace writes them pre tokenized + */ + char *end = args + size; + for (count = 0; (hat < end) && count < 16; ++count) { + char *next = hat + strlen(hat) + 1; + hats[count] = hat; + AA_DEBUG(DEBUG_DOMAIN, + "%s: (pid %d) Magic 0x%llx count %d hat '%s'\n" + , __func__, current->pid, token, count, hat); + hat = next; + } + } else + AA_DEBUG(DEBUG_DOMAIN, + "%s: (pid %d) Magic 0x%llx count %d Hat '%s'\n", + __func__, current->pid, token, count, "<NULL>"); + + return aa_change_hat(hats, count, token, flags); +} |
