lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <CAP-5=fUfbMAKrLC_z04o9r0kGZ02tpHfv8cOecQAQaYPx44awA@mail.gmail.com>
Date: Thu, 18 Sep 2025 08:58:24 -0700
From: Ian Rogers <irogers@...gle.com>
To: Marco Elver <elver@...gle.com>
Cc: Peter Zijlstra <peterz@...radead.org>, Boqun Feng <boqun.feng@...il.com>, 
	Ingo Molnar <mingo@...nel.org>, Will Deacon <will@...nel.org>, 
	"David S. Miller" <davem@...emloft.net>, Luc Van Oostenryck <luc.vanoostenryck@...il.com>, 
	"Paul E. McKenney" <paulmck@...nel.org>, Alexander Potapenko <glider@...gle.com>, Arnd Bergmann <arnd@...db.de>, 
	Bart Van Assche <bvanassche@....org>, Bill Wendling <morbo@...gle.com>, Christoph Hellwig <hch@....de>, 
	Dmitry Vyukov <dvyukov@...gle.com>, Eric Dumazet <edumazet@...gle.com>, 
	Frederic Weisbecker <frederic@...nel.org>, Greg Kroah-Hartman <gregkh@...uxfoundation.org>, 
	Herbert Xu <herbert@...dor.apana.org.au>, Jann Horn <jannh@...gle.com>, 
	Joel Fernandes <joelagnelf@...dia.com>, Jonathan Corbet <corbet@....net>, 
	Josh Triplett <josh@...htriplett.org>, Justin Stitt <justinstitt@...gle.com>, 
	Kees Cook <kees@...nel.org>, Kentaro Takeda <takedakn@...data.co.jp>, 
	Lukas Bulwahn <lukas.bulwahn@...il.com>, Mark Rutland <mark.rutland@....com>, 
	Mathieu Desnoyers <mathieu.desnoyers@...icios.com>, Miguel Ojeda <ojeda@...nel.org>, 
	Nathan Chancellor <nathan@...nel.org>, Neeraj Upadhyay <neeraj.upadhyay@...nel.org>, 
	Nick Desaulniers <nick.desaulniers+lkml@...il.com>, Steven Rostedt <rostedt@...dmis.org>, 
	Tetsuo Handa <penguin-kernel@...ove.sakura.ne.jp>, Thomas Gleixner <tglx@...utronix.de>, 
	Thomas Graf <tgraf@...g.ch>, Uladzislau Rezki <urezki@...il.com>, Waiman Long <longman@...hat.com>, 
	kasan-dev@...glegroups.com, linux-crypto@...r.kernel.org, 
	linux-doc@...r.kernel.org, linux-kbuild@...r.kernel.org, 
	linux-kernel@...r.kernel.org, linux-mm@...ck.org, 
	linux-security-module@...r.kernel.org, linux-sparse@...r.kernel.org, 
	llvm@...ts.linux.dev, rcu@...r.kernel.org
Subject: Re: [PATCH v3 02/35] compiler-capability-analysis: Add infrastructure
 for Clang's capability analysis

On Thu, Sep 18, 2025 at 7:05 AM Marco Elver <elver@...gle.com> wrote:
>
> Capability analysis is a C language extension, which enables statically
> checking that user-definable "capabilities" are acquired and released where
> required. An obvious application is lock-safety checking for the kernel's
> various synchronization primitives (each of which represents a "capability"),
> and checking that locking rules are not violated.
>
> Clang originally called the feature "Thread Safety Analysis" [1], with
> some terminology still using the thread-safety-analysis-only names. This
> was later changed and the feature became more flexible, gaining the
> ability to define custom "capabilities". Its foundations can be found in
> "capability systems", used to specify the permissibility of operations
> to depend on some capability being held (or not held).
>
> [1] https://clang.llvm.org/docs/ThreadSafetyAnalysis.html
> [2] https://www.cs.cornell.edu/talc/papers/capabilities.pdf
>
> Because the feature is not just able to express capabilities related to
> synchronization primitives, the naming chosen for the kernel departs
> from Clang's initial "Thread Safety" nomenclature and refers to the
> feature as "Capability Analysis" to avoid confusion. The implementation
> still makes references to the older terminology in some places, such as
> `-Wthread-safety` being the warning enabled option that also still
> appears in diagnostic messages.
>
> See more details in the kernel-doc documentation added in this and the
> subsequent changes.
>
> Clang version 22+ is required.
>
> Signed-off-by: Marco Elver <elver@...gle.com>
> ---
> v3:
> * Require Clang 22 or later (reentrant capabilities, basic alias analysis).
> * Rename __assert_cap/__asserts_cap -> __assume_cap/__assumes_cap (suggested by Peter).
> * Add __acquire_ret and __acquire_shared_ret helper macros - can be used
>   to define function-like macros that return objects which contains a
>   held capabilities. Works now because of capability alias analysis.
> * Add capability_unsafe_alias() helper, where the analysis rightfully
>   points out we're doing strange things with aliases but we don't care.
> * Support multi-argument attributes.
>
> v2:
> * New -Wthread-safety feature rename to -Wthread-safety-pointer (was
>   -Wthread-safety-addressof).
> * Introduce __capability_unsafe() function attribute.
> * Rename __var_guarded_by to simply __guarded_by. The initial idea was
>   to be explicit if the variable or pointed-to data is guarded by, but
>   having a shorter attribute name is likely better long-term.
> * Rename __ref_guarded_by to __pt_guarded_by (pointed-to guarded by).
> ---
>  Makefile                                     |   1 +
>  include/linux/compiler-capability-analysis.h | 449 ++++++++++++++++++-
>  lib/Kconfig.debug                            |  31 ++
>  scripts/Makefile.capability-analysis         |   7 +
>  scripts/Makefile.lib                         |  10 +
>  5 files changed, 491 insertions(+), 7 deletions(-)
>  create mode 100644 scripts/Makefile.capability-analysis
>
> diff --git a/Makefile b/Makefile
> index cf37b9407821..2c91730e513b 100644
> --- a/Makefile
> +++ b/Makefile
> @@ -1096,6 +1096,7 @@ include-$(CONFIG_RANDSTRUCT)      += scripts/Makefile.randstruct
>  include-$(CONFIG_KSTACK_ERASE) += scripts/Makefile.kstack_erase
>  include-$(CONFIG_AUTOFDO_CLANG)        += scripts/Makefile.autofdo
>  include-$(CONFIG_PROPELLER_CLANG)      += scripts/Makefile.propeller
> +include-$(CONFIG_WARN_CAPABILITY_ANALYSIS) += scripts/Makefile.capability-analysis
>  include-$(CONFIG_GCC_PLUGINS)  += scripts/Makefile.gcc-plugins
>
>  include $(addprefix $(srctree)/, $(include-y))
> diff --git a/include/linux/compiler-capability-analysis.h b/include/linux/compiler-capability-analysis.h
> index 7546ddb83f86..6f3f185478bc 100644
> --- a/include/linux/compiler-capability-analysis.h
> +++ b/include/linux/compiler-capability-analysis.h
> @@ -6,27 +6,462 @@
>  #ifndef _LINUX_COMPILER_CAPABILITY_ANALYSIS_H
>  #define _LINUX_COMPILER_CAPABILITY_ANALYSIS_H
>
> +#if defined(WARN_CAPABILITY_ANALYSIS)
> +
> +/*
> + * The below attributes are used to define new capability types. Internal only.
> + */
> +# define __cap_type(name)                      __attribute__((capability(#name)))
> +# define __reentrant_cap                       __attribute__((reentrant_capability))
> +# define __acquires_cap(...)                   __attribute__((acquire_capability(__VA_ARGS__)))
> +# define __acquires_shared_cap(...)            __attribute__((acquire_shared_capability(__VA_ARGS__)))
> +# define __try_acquires_cap(ret, var)          __attribute__((try_acquire_capability(ret, var)))
> +# define __try_acquires_shared_cap(ret, var)   __attribute__((try_acquire_shared_capability(ret, var)))
> +# define __releases_cap(...)                   __attribute__((release_capability(__VA_ARGS__)))
> +# define __releases_shared_cap(...)            __attribute__((release_shared_capability(__VA_ARGS__)))
> +# define __assumes_cap(...)                    __attribute__((assert_capability(__VA_ARGS__)))
> +# define __assumes_shared_cap(...)             __attribute__((assert_shared_capability(__VA_ARGS__)))
> +# define __returns_cap(var)                    __attribute__((lock_returned(var)))
> +
> +/*
> + * The below are used to annotate code being checked. Internal only.
> + */
> +# define __excludes_cap(...)           __attribute__((locks_excluded(__VA_ARGS__)))
> +# define __requires_cap(...)           __attribute__((requires_capability(__VA_ARGS__)))
> +# define __requires_shared_cap(...)    __attribute__((requires_shared_capability(__VA_ARGS__)))
> +
> +/**
> + * __guarded_by - struct member and globals attribute, declares variable
> + *                protected by capability
> + *
> + * Declares that the struct member or global variable must be guarded by the
> + * given capabilities. Read operations on the data require shared access,
> + * while write operations require exclusive access.
> + *
> + * .. code-block:: c
> + *
> + *     struct some_state {
> + *             spinlock_t lock;
> + *             long counter __guarded_by(&lock);
> + *     };
> + */
> +# define __guarded_by(...)             __attribute__((guarded_by(__VA_ARGS__)))
> +
> +/**
> + * __pt_guarded_by - struct member and globals attribute, declares pointed-to
> + *                   data is protected by capability
> + *
> + * Declares that the data pointed to by the struct member pointer or global
> + * pointer must be guarded by the given capabilities. Read operations on the
> + * data require shared access, while write operations require exclusive access.
> + *
> + * .. code-block:: c
> + *
> + *     struct some_state {
> + *             spinlock_t lock;
> + *             long *counter __pt_guarded_by(&lock);
> + *     };
> + */
> +# define __pt_guarded_by(...)          __attribute__((pt_guarded_by(__VA_ARGS__)))
> +
> +/**
> + * struct_with_capability() - declare or define a capability struct
> + * @name: struct name
> + *
> + * Helper to declare or define a struct type with capability of the same name.
> + *
> + * .. code-block:: c
> + *
> + *     struct_with_capability(my_handle) {
> + *             int foo;
> + *             long bar;
> + *     };
> + *
> + *     struct some_state {
> + *             ...
> + *     };
> + *     // ... declared elsewhere ...
> + *     struct_with_capability(some_state);
> + *
> + * Note: The implementation defines several helper functions that can acquire,
> + * release, and assert the capability.
> + */
> +# define struct_with_capability(name, ...)                                                             \
> +       struct __cap_type(name) __VA_ARGS__ name;                                                       \
> +       static __always_inline void __acquire_cap(const struct name *var)                               \
> +               __attribute__((overloadable)) __no_capability_analysis __acquires_cap(var) { }          \
> +       static __always_inline void __acquire_shared_cap(const struct name *var)                        \
> +               __attribute__((overloadable)) __no_capability_analysis __acquires_shared_cap(var) { }   \
> +       static __always_inline bool __try_acquire_cap(const struct name *var, bool ret)                 \
> +               __attribute__((overloadable)) __no_capability_analysis __try_acquires_cap(1, var)       \
> +       { return ret; }                                                                                 \
> +       static __always_inline bool __try_acquire_shared_cap(const struct name *var, bool ret)          \
> +               __attribute__((overloadable)) __no_capability_analysis __try_acquires_shared_cap(1, var) \
> +       { return ret; }                                                                                 \
> +       static __always_inline void __release_cap(const struct name *var)                               \
> +               __attribute__((overloadable)) __no_capability_analysis __releases_cap(var) { }          \
> +       static __always_inline void __release_shared_cap(const struct name *var)                        \
> +               __attribute__((overloadable)) __no_capability_analysis __releases_shared_cap(var) { }   \
> +       static __always_inline void __assume_cap(const struct name *var)                                \
> +               __attribute__((overloadable)) __assumes_cap(var) { }                                    \
> +       static __always_inline void __assume_shared_cap(const struct name *var)                         \
> +               __attribute__((overloadable)) __assumes_shared_cap(var) { }                             \
> +       struct name
> +
> +/**
> + * disable_capability_analysis() - disables capability analysis
> + *
> + * Disables capability analysis. Must be paired with a later
> + * enable_capability_analysis().
> + */
> +# define disable_capability_analysis()                         \
> +       __diag_push();                                          \
> +       __diag_ignore_all("-Wunknown-warning-option", "")       \
> +       __diag_ignore_all("-Wthread-safety", "")                \
> +       __diag_ignore_all("-Wthread-safety-pointer", "")
> +
> +/**
> + * enable_capability_analysis() - re-enables capability analysis
> + *
> + * Re-enables capability analysis. Must be paired with a prior
> + * disable_capability_analysis().
> + */
> +# define enable_capability_analysis() __diag_pop()
> +
> +/**
> + * __no_capability_analysis - function attribute, disables capability analysis
> + *
> + * Function attribute denoting that capability analysis is disabled for the
> + * whole function. Prefer use of `capability_unsafe()` where possible.
> + */
> +# define __no_capability_analysis      __attribute__((no_thread_safety_analysis))
> +
> +#else /* !WARN_CAPABILITY_ANALYSIS */
> +
> +# define __cap_type(name)
> +# define __reentrant_cap
> +# define __acquires_cap(...)
> +# define __acquires_shared_cap(...)
> +# define __try_acquires_cap(ret, var)
> +# define __try_acquires_shared_cap(ret, var)
> +# define __releases_cap(...)
> +# define __releases_shared_cap(...)
> +# define __assumes_cap(...)
> +# define __assumes_shared_cap(...)
> +# define __returns_cap(var)
> +# define __guarded_by(...)
> +# define __pt_guarded_by(...)
> +# define __excludes_cap(...)
> +# define __requires_cap(...)
> +# define __requires_shared_cap(...)
> +# define __acquire_cap(var)                    do { } while (0)
> +# define __acquire_shared_cap(var)             do { } while (0)
> +# define __try_acquire_cap(var, ret)           (ret)
> +# define __try_acquire_shared_cap(var, ret)    (ret)
> +# define __release_cap(var)                    do { } while (0)
> +# define __release_shared_cap(var)             do { } while (0)
> +# define __assume_cap(var)                     do { (void)(var); } while (0)
> +# define __assume_shared_cap(var)              do { (void)(var); } while (0)
> +# define struct_with_capability(name, ...)     struct __VA_ARGS__ name
> +# define disable_capability_analysis()
> +# define enable_capability_analysis()
> +# define __no_capability_analysis
> +
> +#endif /* WARN_CAPABILITY_ANALYSIS */
> +
> +/**
> + * capability_unsafe() - disable capability checking for contained code
> + *
> + * Disables capability checking for contained statements or expression.
> + *
> + * .. code-block:: c
> + *
> + *     struct some_data {
> + *             spinlock_t lock;
> + *             int counter __guarded_by(&lock);
> + *     };
> + *
> + *     int foo(struct some_data *d)
> + *     {
> + *             // ...
> + *             // other code that is still checked ...
> + *             // ...
> + *             return capability_unsafe(d->counter);
> + *     }
> + */
> +#define capability_unsafe(...)         \
> +({                                     \
> +       disable_capability_analysis();  \
> +       __VA_ARGS__;                    \
> +       enable_capability_analysis()    \
> +})
> +
> +/**
> + * __capability_unsafe() - function attribute, disable capability checking
> + * @comment: comment explaining why opt-out is safe
> + *
> + * Function attribute denoting that capability analysis is disabled for the
> + * whole function. Forces adding an inline comment as argument.
> + */
> +#define __capability_unsafe(comment) __no_capability_analysis
> +
> +/**
> + * capability_unsafe_alias() - helper to insert a capability "alias barrier"
> + * @p: pointer aliasing a capability or object containing capabilities
> + *
> + * No-op function that acts as a "capability alias barrier", where the analysis
> + * rightfully detects that we're switching aliases, but the switch is considered
> + * safe but beyond the analysis reasoning abilities.
> + *
> + * This should be inserted before the first use of such an alias.
> + *
> + * Implementation Note: The compiler ignores aliases that may be reassigned but
> + * their value cannot be determined (e.g. when passing a non-const pointer to an
> + * alias as a function argument).
> + */
> +#define capability_unsafe_alias(p) _capability_unsafe_alias((void **)&(p))
> +static inline void _capability_unsafe_alias(void **p) { }
> +
> +/**
> + * token_capability() - declare an abstract global capability instance
> + * @name: token capability name
> + *
> + * Helper that declares an abstract global capability instance @name that can be
> + * used as a token capability, but not backed by a real data structure (linker
> + * error if accidentally referenced). The type name is `__capability_@...e`.
> + */
> +#define token_capability(name, ...)                                    \
> +       struct_with_capability(__capability_##name, ##__VA_ARGS__) {};  \
> +       extern const struct __capability_##name *name
> +
> +/**
> + * token_capability_instance() - declare another instance of a global capability
> + * @cap: token capability previously declared with token_capability()
> + * @name: name of additional global capability instance
> + *
> + * Helper that declares an additional instance @name of the same token
> + * capability class @name. This is helpful where multiple related token
> + * capabilities are declared, as it also allows using the same underlying type
> + * (`__capability_@...`) as function arguments.
> + */
> +#define token_capability_instance(cap, name)           \
> +       extern const struct __capability_##cap *name
> +
> +/*
> + * Common keywords for static capability analysis. Both Clang's capability
> + * analysis and Sparse's context tracking are currently supported.
> + */
>  #ifdef __CHECKER__
>
>  /* Sparse context/lock checking support. */
>  # define __must_hold(x)                __attribute__((context(x,1,1)))
> +# define __must_not_hold(x)
>  # define __acquires(x)         __attribute__((context(x,0,1)))
>  # define __cond_acquires(x)    __attribute__((context(x,0,-1)))
>  # define __releases(x)         __attribute__((context(x,1,0)))
>  # define __acquire(x)          __context__(x,1)
>  # define __release(x)          __context__(x,-1)
>  # define __cond_lock(x, c)     ((c) ? ({ __acquire(x); 1; }) : 0)
> +/* For Sparse, there's no distinction between exclusive and shared locks. */
> +# define __must_hold_shared    __must_hold
> +# define __acquires_shared     __acquires
> +# define __cond_acquires_shared __cond_acquires
> +# define __releases_shared     __releases
> +# define __acquire_shared      __acquire
> +# define __release_shared      __release
> +# define __cond_lock_shared    __cond_acquire
>
>  #else /* !__CHECKER__ */
>
> -# define __must_hold(x)
> -# define __acquires(x)
> -# define __cond_acquires(x)
> -# define __releases(x)
> -# define __acquire(x)          (void)0
> -# define __release(x)          (void)0
> -# define __cond_lock(x, c)     (c)
> +/**
> + * __must_hold() - function attribute, caller must hold exclusive capability
> + * @x: capability instance pointer
> + *
> + * Function attribute declaring that the caller must hold the given capability
> + * instance @x exclusively.
> + */
> +# define __must_hold(x)                __requires_cap(x)
> +
> +/**
> + * __must_not_hold() - function attribute, caller must not hold capability
> + * @x: capability instance pointer
> + *
> + * Function attribute declaring that the caller must not hold the given
> + * capability instance @x.
> + */
> +# define __must_not_hold(x)    __excludes_cap(x)
> +
> +/**
> + * __acquires() - function attribute, function acquires capability exclusively
> + * @x: capability instance pointer
> + *
> + * Function attribute declaring that the function acquires the given
> + * capability instance @x exclusively, but does not release it.
> + */
> +# define __acquires(x)         __acquires_cap(x)
> +
> +/**
> + * __cond_acquires() - function attribute, function conditionally
> + *                     acquires a capability exclusively
> + * @x: capability instance pointer
> + *
> + * Function attribute declaring that the function conditionally acquires the
> + * given capability instance @x exclusively, but does not release it.
> + */
> +# define __cond_acquires(x)    __try_acquires_cap(1, x)
> +
> +/**
> + * __releases() - function attribute, function releases a capability exclusively
> + * @x: capability instance pointer
> + *
> + * Function attribute declaring that the function releases the given capability
> + * instance @x exclusively. The capability must be held on entry.
> + */
> +# define __releases(x)         __releases_cap(x)
> +
> +/**
> + * __acquire() - function to acquire capability exclusively
> + * @x: capability instance pointer
> + *
> + * No-op function that acquires the given capability instance @x exclusively.
> + */
> +# define __acquire(x)          __acquire_cap(x)
> +
> +/**
> + * __release() - function to release capability exclusively
> + * @x: capability instance pointer
> + *
> + * No-op function that releases the given capability instance @x.
> + */
> +# define __release(x)          __release_cap(x)
> +
> +/**
> + * __cond_lock() - function that conditionally acquires a capability
> + *                 exclusively
> + * @x: capability instance pinter
> + * @c: boolean expression
> + *
> + * Return: result of @c
> + *
> + * No-op function that conditionally acquires capability instance @x
> + * exclusively, if the boolean expression @c is true. The result of @c is the
> + * return value, to be able to create a capability-enabled interface; for
> + * example:
> + *
> + * .. code-block:: c
> + *
> + *     #define spin_trylock(l) __cond_lock(&lock, _spin_trylock(&lock))
> + */
> +# define __cond_lock(x, c)     __try_acquire_cap(x, c)
> +
> +/**
> + * __must_hold_shared() - function attribute, caller must hold shared capability
> + * @x: capability instance pointer
> + *
> + * Function attribute declaring that the caller must hold the given capability
> + * instance @x with shared access.
> + */
> +# define __must_hold_shared(x) __requires_shared_cap(x)
> +
> +/**
> + * __acquires_shared() - function attribute, function acquires capability shared
> + * @x: capability instance pointer
> + *
> + * Function attribute declaring that the function acquires the given
> + * capability instance @x with shared access, but does not release it.
> + */
> +# define __acquires_shared(x)  __acquires_shared_cap(x)
> +
> +/**
> + * __cond_acquires_shared() - function attribute, function conditionally
> + *                            acquires a capability shared
> + * @x: capability instance pointer
> + *
> + * Function attribute declaring that the function conditionally acquires the
> + * given capability instance @x with shared access, but does not release it.
> + */
> +# define __cond_acquires_shared(x) __try_acquires_shared_cap(1, x)
> +
> +/**
> + * __releases_shared() - function attribute, function releases a
> + *                       capability shared
> + * @x: capability instance pointer
> + *
> + * Function attribute declaring that the function releases the given capability
> + * instance @x with shared access. The capability must be held on entry.
> + */
> +# define __releases_shared(x)  __releases_shared_cap(x)
> +
> +/**
> + * __acquire_shared() - function to acquire capability shared
> + * @x: capability instance pointer
> + *
> + * No-op function that acquires the given capability instance @x with shared
> + * access.
> + */
> +# define __acquire_shared(x)   __acquire_shared_cap(x)
> +
> +/**
> + * __release_shared() - function to release capability shared
> + * @x: capability instance pointer
> + *
> + * No-op function that releases the given capability instance @x with shared
> + * access.
> + */
> +# define __release_shared(x)   __release_shared_cap(x)
> +
> +/**
> + * __cond_lock_shared() - function that conditionally acquires a capability
> + *                        shared
> + * @x: capability instance pinter
> + * @c: boolean expression
> + *
> + * Return: result of @c
> + *
> + * No-op function that conditionally acquires capability instance @x with shared
> + * access, if the boolean expression @c is true. The result of @c is the return
> + * value, to be able to create a capability-enabled interface.
> + */
> +# define __cond_lock_shared(x, c) __try_acquire_shared_cap(x, c)
>
>  #endif /* __CHECKER__ */
>
> +/**
> + * __acquire_ret() - helper to acquire capability of return value
> + * @call: call expression
> + * @ret_expr: acquire expression that uses __ret
> + */
> +#define __acquire_ret(call, ret_expr)          \
> +       ({                                      \
> +               __auto_type __ret = call;       \
> +               __acquire(ret_expr);            \
> +               __ret;                          \
> +       })
> +
> +/**
> + * __acquire_shared_ret() - helper to acquire capability shared of return value
> + * @call: call expression
> + * @ret_expr: acquire shared expression that uses __ret
> + */
> +#define __acquire_shared_ret(call, ret_expr)   \
> +       ({                                      \
> +               __auto_type __ret = call;       \
> +               __acquire_shared(ret_expr);     \
> +               __ret;                          \
> +       })
> +
> +/*
> + * Attributes to mark functions returning acquired capabilities. This is purely
> + * cosmetic to help readability, and should be used with the above macros as
> + * follows:
> + *
> + *   struct foo { spinlock_t lock; ... };
> + *   ...
> + *   #define myfunc(...) __acquire_ret(_myfunc(__VA_ARGS__), &__ret->lock)
> + *   struct foo *_myfunc(int bar) __acquires_ret;
> + *   ...
> + */
> +#define __acquires_ret         __no_capability_analysis
> +#define __acquires_shared_ret  __no_capability_analysis
> +
>  #endif /* _LINUX_COMPILER_CAPABILITY_ANALYSIS_H */
> diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug
> index dc0e0c6ed075..57e09615f88d 100644
> --- a/lib/Kconfig.debug
> +++ b/lib/Kconfig.debug
> @@ -613,6 +613,37 @@ config DEBUG_FORCE_WEAK_PER_CPU
>           To ensure that generic code follows the above rules, this
>           option forces all percpu variables to be defined as weak.
>
> +config WARN_CAPABILITY_ANALYSIS
> +       bool "Compiler capability-analysis warnings"
> +       depends on CC_IS_CLANG && CLANG_VERSION >= 220000
> +       # Branch profiling re-defines "if", which messes with the compiler's
> +       # ability to analyze __cond_acquires(..), resulting in false positives.
> +       depends on !TRACE_BRANCH_PROFILING

Err, wow! What and huh, and why? Crikes. I'm amazed you found such an
option exists. I must be very naive to have never heard of it and now
I wonder if it is needed and load bearing?

Ian


> +       default y
> +       help
> +         Capability analysis is a C language extension, which enables
> +         statically checking that user-definable "capabilities" are acquired
> +         and released where required.
> +
> +         Clang's name of the feature ("Thread Safety Analysis") refers to
> +         the original name of the feature; it was later expanded to be a
> +         generic "Capability Analysis" framework.
> +
> +         Requires Clang 22 or later.
> +
> +         Produces warnings by default. Select CONFIG_WERROR if you wish to
> +         turn these warnings into errors.
> +
> +config WARN_CAPABILITY_ANALYSIS_ALL
> +       bool "Enable capability analysis for all source files"
> +       depends on WARN_CAPABILITY_ANALYSIS
> +       depends on EXPERT && !COMPILE_TEST
> +       help
> +         Enable tree-wide capability analysis. This is likely to produce a
> +         large number of false positives - enable at your own risk.
> +
> +         If unsure, say N.
> +
>  endmenu # "Compiler options"
>
>  menu "Generic Kernel Debugging Instruments"
> diff --git a/scripts/Makefile.capability-analysis b/scripts/Makefile.capability-analysis
> new file mode 100644
> index 000000000000..e137751a4c9a
> --- /dev/null
> +++ b/scripts/Makefile.capability-analysis
> @@ -0,0 +1,7 @@
> +# SPDX-License-Identifier: GPL-2.0
> +
> +capability-analysis-cflags := -DWARN_CAPABILITY_ANALYSIS       \
> +       -fexperimental-late-parse-attributes -Wthread-safety    \
> +       -Wthread-safety-pointer -Wthread-safety-beta
> +
> +export CFLAGS_CAPABILITY_ANALYSIS := $(capability-analysis-cflags)
> diff --git a/scripts/Makefile.lib b/scripts/Makefile.lib
> index 1d581ba5df66..e0ac273bf9eb 100644
> --- a/scripts/Makefile.lib
> +++ b/scripts/Makefile.lib
> @@ -105,6 +105,16 @@ _c_flags += $(if $(patsubst n%,, \
>         -D__KCSAN_INSTRUMENT_BARRIERS__)
>  endif
>
> +#
> +# Enable capability analysis flags only where explicitly opted in.
> +# (depends on variables CAPABILITY_ANALYSIS_obj.o, CAPABILITY_ANALYSIS)
> +#
> +ifeq ($(CONFIG_WARN_CAPABILITY_ANALYSIS),y)
> +_c_flags += $(if $(patsubst n%,, \
> +               $(CAPABILITY_ANALYSIS_$(target-stem).o)$(CAPABILITY_ANALYSIS)$(if $(is-kernel-object),$(CONFIG_WARN_CAPABILITY_ANALYSIS_ALL))), \
> +               $(CFLAGS_CAPABILITY_ANALYSIS))
> +endif
> +
>  #
>  # Enable AutoFDO build flags except some files or directories we don't want to
>  # enable (depends on variables AUTOFDO_PROFILE_obj.o and AUTOFDO_PROFILE).
> --
> 2.51.0.384.g4c02a37b29-goog
>

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ