summaryrefslogtreecommitdiffstats
path: root/security/selinux/ss/ebitmap.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 /security/selinux/ss/ebitmap.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 'security/selinux/ss/ebitmap.h')
-rw-r--r--security/selinux/ss/ebitmap.h156
1 files changed, 156 insertions, 0 deletions
diff --git a/security/selinux/ss/ebitmap.h b/security/selinux/ss/ebitmap.h
new file mode 100644
index 000000000..ae05cc8e4
--- /dev/null
+++ b/security/selinux/ss/ebitmap.h
@@ -0,0 +1,156 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * An extensible bitmap is a bitmap that supports an
+ * arbitrary number of bits. Extensible bitmaps are
+ * used to represent sets of values, such as types,
+ * roles, categories, and classes.
+ *
+ * Each extensible bitmap is implemented as a linked
+ * list of bitmap nodes, where each bitmap node has
+ * an explicitly specified starting bit position within
+ * the total bitmap.
+ *
+ * Author : Stephen Smalley, <stephen.smalley.work@gmail.com>
+ */
+
+#ifndef _SS_EBITMAP_H_
+#define _SS_EBITMAP_H_
+
+#include <net/netlabel.h>
+
+#ifdef CONFIG_64BIT
+#define EBITMAP_NODE_SIZE 64
+#else
+#define EBITMAP_NODE_SIZE 32
+#endif
+
+#define EBITMAP_UNIT_NUMS \
+ ((EBITMAP_NODE_SIZE - sizeof(void *) - sizeof(u32)) / \
+ sizeof(unsigned long))
+#define EBITMAP_UNIT_SIZE BITS_PER_LONG
+#define EBITMAP_SIZE (EBITMAP_UNIT_NUMS * EBITMAP_UNIT_SIZE)
+#define EBITMAP_BIT 1UL
+#define EBITMAP_SHIFT_UNIT_SIZE(x) \
+ (((x) >> EBITMAP_UNIT_SIZE / 2) >> EBITMAP_UNIT_SIZE / 2)
+
+struct ebitmap_node {
+ struct ebitmap_node *next;
+ unsigned long maps[EBITMAP_UNIT_NUMS];
+ u32 startbit;
+};
+
+struct ebitmap {
+ struct ebitmap_node *node; /* first node in the bitmap */
+ u32 highbit; /* highest position in the total bitmap */
+};
+
+#define ebitmap_length(e) ((e)->highbit)
+
+static inline u32 ebitmap_start_positive(const struct ebitmap *e,
+ struct ebitmap_node **n)
+{
+ u32 ofs;
+
+ for (*n = e->node; *n; *n = (*n)->next) {
+ ofs = find_first_bit((*n)->maps, EBITMAP_SIZE);
+ if (ofs < EBITMAP_SIZE)
+ return (*n)->startbit + ofs;
+ }
+ return ebitmap_length(e);
+}
+
+static inline void ebitmap_init(struct ebitmap *e)
+{
+ memset(e, 0, sizeof(*e));
+}
+
+static inline u32 ebitmap_next_positive(const struct ebitmap *e,
+ struct ebitmap_node **n, u32 bit)
+{
+ u32 ofs;
+
+ ofs = find_next_bit((*n)->maps, EBITMAP_SIZE, bit - (*n)->startbit + 1);
+ if (ofs < EBITMAP_SIZE)
+ return ofs + (*n)->startbit;
+
+ for (*n = (*n)->next; *n; *n = (*n)->next) {
+ ofs = find_first_bit((*n)->maps, EBITMAP_SIZE);
+ if (ofs < EBITMAP_SIZE)
+ return ofs + (*n)->startbit;
+ }
+ return ebitmap_length(e);
+}
+
+#define EBITMAP_NODE_INDEX(node, bit) \
+ (((bit) - (node)->startbit) / EBITMAP_UNIT_SIZE)
+#define EBITMAP_NODE_OFFSET(node, bit) \
+ (((bit) - (node)->startbit) % EBITMAP_UNIT_SIZE)
+
+static inline int ebitmap_node_get_bit(const struct ebitmap_node *n, u32 bit)
+{
+ u32 index = EBITMAP_NODE_INDEX(n, bit);
+ u32 ofs = EBITMAP_NODE_OFFSET(n, bit);
+
+ BUG_ON(index >= EBITMAP_UNIT_NUMS);
+ if ((n->maps[index] & (EBITMAP_BIT << ofs)))
+ return 1;
+ return 0;
+}
+
+static inline void ebitmap_node_set_bit(struct ebitmap_node *n, u32 bit)
+{
+ u32 index = EBITMAP_NODE_INDEX(n, bit);
+ u32 ofs = EBITMAP_NODE_OFFSET(n, bit);
+
+ BUG_ON(index >= EBITMAP_UNIT_NUMS);
+ n->maps[index] |= (EBITMAP_BIT << ofs);
+}
+
+static inline void ebitmap_node_clr_bit(struct ebitmap_node *n, u32 bit)
+{
+ u32 index = EBITMAP_NODE_INDEX(n, bit);
+ u32 ofs = EBITMAP_NODE_OFFSET(n, bit);
+
+ BUG_ON(index >= EBITMAP_UNIT_NUMS);
+ n->maps[index] &= ~(EBITMAP_BIT << ofs);
+}
+
+#define ebitmap_for_each_positive_bit(e, n, bit) \
+ for ((bit) = ebitmap_start_positive(e, &(n)); \
+ (bit) < ebitmap_length(e); \
+ (bit) = ebitmap_next_positive(e, &(n), bit))
+
+bool ebitmap_equal(const struct ebitmap *e1, const struct ebitmap *e2);
+int ebitmap_cpy(struct ebitmap *dst, const struct ebitmap *src);
+int ebitmap_and(struct ebitmap *dst, const struct ebitmap *e1,
+ const struct ebitmap *e2);
+int ebitmap_contains(const struct ebitmap *e1, const struct ebitmap *e2,
+ u32 last_e2bit);
+u32 ebitmap_get_highest_set_bit(const struct ebitmap *e);
+int ebitmap_get_bit(const struct ebitmap *e, u32 bit);
+int ebitmap_set_bit(struct ebitmap *e, u32 bit, int value);
+void ebitmap_destroy(struct ebitmap *e);
+struct policy_file;
+int ebitmap_read(struct ebitmap *e, struct policy_file *fp);
+int ebitmap_write(const struct ebitmap *e, struct policy_file *fp);
+u32 ebitmap_hash(const struct ebitmap *e, u32 hash);
+
+#ifdef CONFIG_NETLABEL
+int ebitmap_netlbl_export(struct ebitmap *ebmap,
+ struct netlbl_lsm_catmap **catmap);
+int ebitmap_netlbl_import(struct ebitmap *ebmap,
+ struct netlbl_lsm_catmap *catmap);
+#else
+static inline int ebitmap_netlbl_export(struct ebitmap *ebmap,
+ struct netlbl_lsm_catmap **catmap)
+{
+ return -ENOMEM;
+}
+static inline int ebitmap_netlbl_import(struct ebitmap *ebmap,
+ struct netlbl_lsm_catmap *catmap)
+{
+ return -ENOMEM;
+}
+#endif
+
+#endif /* _SS_EBITMAP_H_ */