summaryrefslogtreecommitdiffstats
path: root/include/net/scm.h
diff options
context:
space:
mode:
authorSteven Rostedt <rostedt@goodmis.org>2026-09-02 09:55:01 -0400
committerSteven Rostedt <rostedt@goodmis.org>2026-09-02 11:08:21 -0400
commit4617721c502b2ddaa4e324e86da4997edf738fa5 (patch)
tree350aa83b47da0b574a814795392b20b0bed83cbc /include/net/scm.h
downloadlinux-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 'include/net/scm.h')
-rw-r--r--include/net/scm.h114
1 files changed, 114 insertions, 0 deletions
diff --git a/include/net/scm.h b/include/net/scm.h
new file mode 100644
index 000000000..86ae6bc10
--- /dev/null
+++ b/include/net/scm.h
@@ -0,0 +1,114 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef __LINUX_NET_SCM_H
+#define __LINUX_NET_SCM_H
+
+#include <linux/limits.h>
+#include <linux/net.h>
+#include <linux/cred.h>
+#include <linux/file.h>
+#include <linux/security.h>
+#include <linux/pid.h>
+#include <linux/nsproxy.h>
+#include <linux/sched/signal.h>
+#include <net/compat.h>
+
+/* Well, we should have at least one descriptor open
+ * to accept passed FDs 8)
+ */
+#define SCM_MAX_FD 253
+
+struct scm_creds {
+ u32 pid;
+ kuid_t uid;
+ kgid_t gid;
+};
+
+#ifdef CONFIG_UNIX
+struct unix_edge;
+#endif
+
+struct scm_fp_list {
+ short count;
+ short count_unix;
+ short max;
+#ifdef CONFIG_UNIX
+ bool inflight;
+ bool dead;
+ struct list_head vertices;
+ struct unix_edge *edges;
+#endif
+ struct user_struct *user;
+ struct file *fp[SCM_MAX_FD];
+};
+
+struct scm_cookie {
+ struct pid *pid; /* Skb credentials */
+ struct scm_fp_list *fp; /* Passed files */
+ struct scm_creds creds; /* Skb credentials */
+#ifdef CONFIG_SECURITY_NETWORK
+ u32 secid; /* Passed security ID */
+#endif
+};
+
+void scm_detach_fds(struct msghdr *msg, struct scm_cookie *scm, bool notrunc);
+void scm_detach_fds_compat(struct msghdr *msg, struct scm_cookie *scm, bool notrunc);
+int __scm_send(struct socket *sock, struct msghdr *msg, struct scm_cookie *scm);
+void __scm_destroy(struct scm_cookie *scm);
+struct scm_fp_list *scm_fp_dup(struct scm_fp_list *fpl);
+
+#ifdef CONFIG_SECURITY_NETWORK
+static __inline__ void unix_get_peersec_dgram(struct socket *sock, struct scm_cookie *scm)
+{
+ security_socket_getpeersec_dgram(sock, NULL, &scm->secid);
+}
+#else
+static __inline__ void unix_get_peersec_dgram(struct socket *sock, struct scm_cookie *scm)
+{ }
+#endif /* CONFIG_SECURITY_NETWORK */
+
+static __inline__ void scm_set_cred(struct scm_cookie *scm,
+ struct pid *pid, kuid_t uid, kgid_t gid)
+{
+ scm->pid = get_pid(pid);
+ scm->creds.pid = pid_vnr(pid);
+ scm->creds.uid = uid;
+ scm->creds.gid = gid;
+}
+
+static __inline__ void scm_destroy_cred(struct scm_cookie *scm)
+{
+ put_pid(scm->pid);
+ scm->pid = NULL;
+}
+
+static __inline__ void scm_destroy(struct scm_cookie *scm)
+{
+ scm_destroy_cred(scm);
+ if (scm->fp)
+ __scm_destroy(scm);
+}
+
+static __inline__ int scm_send(struct socket *sock, struct msghdr *msg,
+ struct scm_cookie *scm, bool forcecreds)
+{
+ memset(scm, 0, sizeof(*scm));
+ scm->creds.uid = INVALID_UID;
+ scm->creds.gid = INVALID_GID;
+ if (forcecreds)
+ scm_set_cred(scm, task_tgid(current), current_uid(), current_gid());
+ unix_get_peersec_dgram(sock, scm);
+ if (msg->msg_controllen <= 0)
+ return 0;
+ return __scm_send(sock, msg, scm);
+}
+
+void scm_recv(struct socket *sock, struct msghdr *msg,
+ struct scm_cookie *scm, int flags);
+void scm_recv_unix(struct socket *sock, struct msghdr *msg,
+ struct scm_cookie *scm, int flags);
+
+int scm_recv_one_fd(struct file *f, int __user *ufd, unsigned int flags,
+ bool notrunc);
+
+#endif /* __LINUX_NET_SCM_H */
+