From cb1459f2a503d23d029439ab2a39aa36de96155f Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Thu, 12 Sep 2024 13:51:39 +0000 Subject: [PATCH] Revert "jump_label: Prevent key->enabled int overflow" This reverts commit 550cb996916e40e814679f818f282fc28b6eab94 which is commit eb8c507296f6038d46010396d91b42a05c3b64d9 upstream. It breaks the Android kernel abi and can be brought back in the future in an abi-safe way if it is really needed. Bug: 161946584 Change-Id: Ibfe863eab77b6e07e72bd50022cd994ee15d75dc Signed-off-by: Greg Kroah-Hartman --- include/linux/jump_label.h | 21 +++----------- kernel/jump_label.c | 56 ++++++++------------------------------ 2 files changed, 16 insertions(+), 61 deletions(-) diff --git a/include/linux/jump_label.h b/include/linux/jump_label.h index 9fa735b4cb94..27c9ce32d9fc 100644 --- a/include/linux/jump_label.h +++ b/include/linux/jump_label.h @@ -247,10 +247,9 @@ extern bool arch_jump_label_transform_queue(struct jump_entry *entry, enum jump_label_type type); extern void arch_jump_label_transform_apply(void); extern int jump_label_text_reserved(void *start, void *end); -extern bool static_key_slow_inc(struct static_key *key); -extern bool static_key_fast_inc_not_disabled(struct static_key *key); +extern void static_key_slow_inc(struct static_key *key); extern void static_key_slow_dec(struct static_key *key); -extern bool static_key_slow_inc_cpuslocked(struct static_key *key); +extern void static_key_slow_inc_cpuslocked(struct static_key *key); extern void static_key_slow_dec_cpuslocked(struct static_key *key); extern int static_key_count(struct static_key *key); extern void static_key_enable(struct static_key *key); @@ -302,23 +301,11 @@ static __always_inline bool static_key_true(struct static_key *key) return false; } -static inline bool static_key_fast_inc_not_disabled(struct static_key *key) +static inline void static_key_slow_inc(struct static_key *key) { - int v; - STATIC_KEY_CHECK_USE(key); - /* - * Prevent key->enabled getting negative to follow the same semantics - * as for CONFIG_JUMP_LABEL=y, see kernel/jump_label.c comment. - */ - v = atomic_read(&key->enabled); - do { - if (v < 0 || (v + 1) < 0) - return false; - } while (!likely(atomic_try_cmpxchg(&key->enabled, &v, v + 1))); - return true; + atomic_inc(&key->enabled); } -#define static_key_slow_inc(key) static_key_fast_inc_not_disabled(key) static inline void static_key_slow_dec(struct static_key *key) { diff --git a/kernel/jump_label.c b/kernel/jump_label.c index d9c822bbffb8..4d6c6f5f60db 100644 --- a/kernel/jump_label.c +++ b/kernel/jump_label.c @@ -113,40 +113,9 @@ int static_key_count(struct static_key *key) } EXPORT_SYMBOL_GPL(static_key_count); -/* - * static_key_fast_inc_not_disabled - adds a user for a static key - * @key: static key that must be already enabled - * - * The caller must make sure that the static key can't get disabled while - * in this function. It doesn't patch jump labels, only adds a user to - * an already enabled static key. - * - * Returns true if the increment was done. Unlike refcount_t the ref counter - * is not saturated, but will fail to increment on overflow. - */ -bool static_key_fast_inc_not_disabled(struct static_key *key) +void static_key_slow_inc_cpuslocked(struct static_key *key) { - int v; - STATIC_KEY_CHECK_USE(key); - /* - * Negative key->enabled has a special meaning: it sends - * static_key_slow_inc() down the slow path, and it is non-zero - * so it counts as "enabled" in jump_label_update(). Note that - * atomic_inc_unless_negative() checks >= 0, so roll our own. - */ - v = atomic_read(&key->enabled); - do { - if (v <= 0 || (v + 1) < 0) - return false; - } while (!likely(atomic_try_cmpxchg(&key->enabled, &v, v + 1))); - - return true; -} -EXPORT_SYMBOL_GPL(static_key_fast_inc_not_disabled); - -bool static_key_slow_inc_cpuslocked(struct static_key *key) -{ lockdep_assert_cpus_held(); /* @@ -155,9 +124,15 @@ bool static_key_slow_inc_cpuslocked(struct static_key *key) * jump_label_update() process. At the same time, however, * the jump_label_update() call below wants to see * static_key_enabled(&key) for jumps to be updated properly. + * + * So give a special meaning to negative key->enabled: it sends + * static_key_slow_inc() down the slow path, and it is non-zero + * so it counts as "enabled" in jump_label_update(). Note that + * atomic_inc_unless_negative() checks >= 0, so roll our own. */ - if (static_key_fast_inc_not_disabled(key)) - return true; + for (int v = atomic_read(&key->enabled); v > 0; ) + if (likely(atomic_try_cmpxchg(&key->enabled, &v, v + 1))) + return; jump_label_lock(); if (atomic_read(&key->enabled) == 0) { @@ -169,23 +144,16 @@ bool static_key_slow_inc_cpuslocked(struct static_key *key) */ atomic_set_release(&key->enabled, 1); } else { - if (WARN_ON_ONCE(!static_key_fast_inc_not_disabled(key))) { - jump_label_unlock(); - return false; - } + atomic_inc(&key->enabled); } jump_label_unlock(); - return true; } -bool static_key_slow_inc(struct static_key *key) +void static_key_slow_inc(struct static_key *key) { - bool ret; - cpus_read_lock(); - ret = static_key_slow_inc_cpuslocked(key); + static_key_slow_inc_cpuslocked(key); cpus_read_unlock(); - return ret; } EXPORT_SYMBOL_GPL(static_key_slow_inc);