* [PATCH v3 1/9] Compiler Attributes: Add __must_init macro
2026-11-08 22:39 [PATCH v3 0/9] Add __must_init and require explicit kobj_type::release Ian Rogers
@ 2026-11-08 22:39 ` Ian Rogers
2026-11-08 22:39 ` [PATCH v3 2/9] powerpc/secvar: Add missing kobject release callback to secvar_ktype Ian Rogers
` (7 subsequent siblings)
8 siblings, 0 replies; 10+ messages in thread
From: Ian Rogers @ 2026-11-08 22:39 UTC (permalink / raw)
To: Danilo Krummrich, Greg Kroah-Hartman, Kees Cook, Miguel Ojeda,
Rafael J . Wysocki
Cc: Madhavan Srinivasan, Michael Ellerman, Nicholas Piggin,
Christophe Leroy, Nayna Jain, Srish Srinivasan, Mimi Zohar,
Yoshinori Sato, Rich Felker, John Paul Adrian Glaubitz,
Juergen Gross, Stefano Stabellini, Oleksandr Tyshchenko,
Nathan Chancellor, Nick Desaulniers, Viresh Kumar, Zhongqiu Han,
Alexander Aring, Felix Kuehling, Christian König,
Zhihao Cheng, Sumanth Korikkar, Bill Wendling, Justin Stitt,
driver-core, llvm, linux-hardening, linux-fsdevel, linux-doc,
linux-acpi, linux-pm, linuxppc-dev, linux-sh, linux-s390, gfs2,
xen-devel, linux-mtd, amd-gfx, dri-devel, linux-kernel,
Ian Rogers
Clang supports the 'require_explicit_initialization' attribute on struct
fields to indicate that a field must be initialized explicitly by the
user when the object is constructed. When an aggregate initializer or
uninitialized variable omits an annotated field, Clang emits a
-Wuninitialized-explicit-init warning (enabled by default).
Add the __must_init macro to include/linux/compiler_attributes.h (which
is included by include/linux/compiler_types.h and
include/linux/compiler.h) so kernel structs with error-prone
initialization (such as mandatory callbacks or cleanup handlers) can
enforce explicit initialization at compile time, as discussed at the
Linux Plumbers Conference. The shorter __must_init spelling, rather than
the attribute's full name, keeps annotated struct members readable and
was suggested by Greg Kroah-Hartman.
Note that Clang versions prior to the fix for
https://github.com/llvm/llvm-project/issues/232483 do not diagnose
file-scope objects declared without any initializer (initializers at
file scope that omit the field are diagnosed).
Also teach Sphinx (Documentation/conf.py), kernel-doc
(tools/lib/python/kdoc/xforms_lists.py), and checkpatch.pl about the new
attribute macro.
Link: https://lpc.events/event/20/contributions/2392/
Link: https://lore.kernel.org/lkml/2026101532-fantastic-deafness-e04c@gregkh/
Acked-by: Miguel Ojeda <ojeda@kernel.org>
Reviewed-by: Nick Desaulniers <ndesaulniers@google.com>
Reviewed-by: Nathan Chancellor <nathan@kernel.org>
Acked-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Reviewed-by: Kees Cook <kees@kernel.org>
Signed-off-by: Ian Rogers <irogers@google.com>
---
Documentation/conf.py | 1 +
include/linux/compiler_attributes.h | 12 ++++++++++++
scripts/checkpatch.pl | 1 +
tools/lib/python/kdoc/xforms_lists.py | 1 +
4 files changed, 15 insertions(+)
diff --git a/Documentation/conf.py b/Documentation/conf.py
index 5ab26ce89daf..baaa4035258c 100644
--- a/Documentation/conf.py
+++ b/Documentation/conf.py
@@ -203,6 +203,7 @@ c_id_attributes = [
"__noreturn",
"__packed",
"__pure",
+ "__must_init",
"__section",
"__always_unused",
"__maybe_unused",
diff --git a/include/linux/compiler_attributes.h b/include/linux/compiler_attributes.h
index 476c4c560d17..b9c0b56dd22e 100644
--- a/include/linux/compiler_attributes.h
+++ b/include/linux/compiler_attributes.h
@@ -322,6 +322,18 @@
*/
#define __pure __attribute__((__pure__))
+/*
+ * Optional: not supported by gcc
+ * Optional: only supported since clang >= 20.0
+ *
+ * clang: https://clang.llvm.org/docs/AttributeReference.html#require-explicit-initialization
+ */
+#if __has_attribute(__require_explicit_initialization__)
+# define __must_init __attribute__((__require_explicit_initialization__))
+#else
+# define __must_init
+#endif
+
/*
* gcc: https://gcc.gnu.org/onlinedocs/gcc/Common-Function-Attributes.html#index-section-function-attribute
* gcc: https://gcc.gnu.org/onlinedocs/gcc/Common-Variable-Attributes.html#index-section-variable-attribute
diff --git a/scripts/checkpatch.pl b/scripts/checkpatch.pl
index b8b64f720191..6a091c45b1a1 100755
--- a/scripts/checkpatch.pl
+++ b/scripts/checkpatch.pl
@@ -6888,6 +6888,7 @@ sub process {
"noreturn" => "__noreturn",
"packed" => "__packed",
"pure" => "__pure",
+ "require_explicit_initialization" => "__must_init",
"section" => "__section",
"used" => "__used",
"weak" => "__weak"
diff --git a/tools/lib/python/kdoc/xforms_lists.py b/tools/lib/python/kdoc/xforms_lists.py
index db23fb650ea8..42956b98aae3 100644
--- a/tools/lib/python/kdoc/xforms_lists.py
+++ b/tools/lib/python/kdoc/xforms_lists.py
@@ -36,6 +36,7 @@ class CTransforms:
(CMatch("CRYPTO_MINALIGN_ATTR"), ""),
(CMatch("__private"), ""),
(CMatch("__rcu"), ""),
+ (CMatch("__must_init"), ""),
(CMatch("____cacheline_aligned_in_smp"), ""),
(CMatch("____cacheline_aligned"), ""),
(CMatch("__cacheline_group_(?:begin|end)"), ""),
--
2.56.0.455.g6c5a503b38-goog
^ permalink raw reply [flat|nested] 10+ messages in thread* [PATCH v3 2/9] powerpc/secvar: Add missing kobject release callback to secvar_ktype
2026-11-08 22:39 [PATCH v3 0/9] Add __must_init and require explicit kobj_type::release Ian Rogers
2026-11-08 22:39 ` [PATCH v3 1/9] Compiler Attributes: Add __must_init macro Ian Rogers
@ 2026-11-08 22:39 ` Ian Rogers
2026-11-08 22:39 ` [PATCH v3 3/9] sh: sq: Add missing kobject release callback to ktype_percpu_entry Ian Rogers
` (6 subsequent siblings)
8 siblings, 0 replies; 10+ messages in thread
From: Ian Rogers @ 2026-11-08 22:39 UTC (permalink / raw)
To: Danilo Krummrich, Greg Kroah-Hartman, Kees Cook, Miguel Ojeda,
Rafael J . Wysocki
Cc: Madhavan Srinivasan, Michael Ellerman, Nicholas Piggin,
Christophe Leroy, Nayna Jain, Srish Srinivasan, Mimi Zohar,
Yoshinori Sato, Rich Felker, John Paul Adrian Glaubitz,
Juergen Gross, Stefano Stabellini, Oleksandr Tyshchenko,
Nathan Chancellor, Nick Desaulniers, Viresh Kumar, Zhongqiu Han,
Alexander Aring, Felix Kuehling, Christian König,
Zhihao Cheng, Sumanth Korikkar, Bill Wendling, Justin Stitt,
driver-core, llvm, linux-hardening, linux-fsdevel, linux-doc,
linux-acpi, linux-pm, linuxppc-dev, linux-sh, linux-s390, gfs2,
xen-devel, linux-mtd, amd-gfx, dri-devel, linux-kernel,
Ian Rogers
In add_var(), a struct kobject is dynamically allocated with
kzalloc_obj() and initialized with secvar_ktype. If kobject_add() or
sysfs_create_file() fails, kobject_put(kobj) is called to clean up.
However, secvar_ktype does not define a .release callback, which results
in a memory leak of kobj (and a pr_debug warning in kobject_cleanup()
when CONFIG_DEBUG_KOBJECT_RELEASE is enabled).
Provide a secvar_release() callback that calls kfree(kobj).
Fixes: bd5d9c743d38 ("powerpc: expose secure variables to userspace via sysfs")
Signed-off-by: Ian Rogers <irogers@google.com>
---
arch/powerpc/kernel/secvar-sysfs.c | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/arch/powerpc/kernel/secvar-sysfs.c b/arch/powerpc/kernel/secvar-sysfs.c
index 395399bbab2c..f3f6ac25ea78 100644
--- a/arch/powerpc/kernel/secvar-sysfs.c
+++ b/arch/powerpc/kernel/secvar-sysfs.c
@@ -126,7 +126,13 @@ static const struct attribute_group secvar_attr_group = {
};
__ATTRIBUTE_GROUPS(secvar_attr);
+static void secvar_release(struct kobject *kobj)
+{
+ kfree(kobj);
+}
+
static const struct kobj_type secvar_ktype = {
+ .release = secvar_release,
.sysfs_ops = &kobj_sysfs_ops,
.default_groups = secvar_attr_groups,
};
--
2.56.0.455.g6c5a503b38-goog
^ permalink raw reply [flat|nested] 10+ messages in thread* [PATCH v3 3/9] sh: sq: Add missing kobject release callback to ktype_percpu_entry
2026-11-08 22:39 [PATCH v3 0/9] Add __must_init and require explicit kobj_type::release Ian Rogers
2026-11-08 22:39 ` [PATCH v3 1/9] Compiler Attributes: Add __must_init macro Ian Rogers
2026-11-08 22:39 ` [PATCH v3 2/9] powerpc/secvar: Add missing kobject release callback to secvar_ktype Ian Rogers
@ 2026-11-08 22:39 ` Ian Rogers
2026-11-08 22:39 ` [PATCH v3 4/9] cpufreq: governor: Initialize kobj_type release callback statically Ian Rogers
` (5 subsequent siblings)
8 siblings, 0 replies; 10+ messages in thread
From: Ian Rogers @ 2026-11-08 22:39 UTC (permalink / raw)
To: Danilo Krummrich, Greg Kroah-Hartman, Kees Cook, Miguel Ojeda,
Rafael J . Wysocki
Cc: Madhavan Srinivasan, Michael Ellerman, Nicholas Piggin,
Christophe Leroy, Nayna Jain, Srish Srinivasan, Mimi Zohar,
Yoshinori Sato, Rich Felker, John Paul Adrian Glaubitz,
Juergen Gross, Stefano Stabellini, Oleksandr Tyshchenko,
Nathan Chancellor, Nick Desaulniers, Viresh Kumar, Zhongqiu Han,
Alexander Aring, Felix Kuehling, Christian König,
Zhihao Cheng, Sumanth Korikkar, Bill Wendling, Justin Stitt,
driver-core, llvm, linux-hardening, linux-fsdevel, linux-doc,
linux-acpi, linux-pm, linuxppc-dev, linux-sh, linux-s390, gfs2,
xen-devel, linux-mtd, amd-gfx, dri-devel, linux-kernel,
Ian Rogers
In sq_dev_add(), sq_kobject[cpu] is dynamically allocated with
kzalloc_obj() and initialized with ktype_percpu_entry. When
sq_dev_remove() calls kobject_put(kobj), the kobject is never freed
because ktype_percpu_entry lacks a .release callback.
Provide a sq_kobj_release() callback that calls kfree(kobj).
Fixes: d7c30c682a27 ("sh: Store Queue API rework.")
Signed-off-by: Ian Rogers <irogers@google.com>
---
arch/sh/kernel/cpu/sh4/sq.c | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/arch/sh/kernel/cpu/sh4/sq.c b/arch/sh/kernel/cpu/sh4/sq.c
index 908a8e09113b..f33864958487 100644
--- a/arch/sh/kernel/cpu/sh4/sq.c
+++ b/arch/sh/kernel/cpu/sh4/sq.c
@@ -331,7 +331,13 @@ static const struct sysfs_ops sq_sysfs_ops = {
.store = sq_sysfs_store,
};
+static void sq_kobj_release(struct kobject *kobj)
+{
+ kfree(kobj);
+}
+
static struct kobj_type ktype_percpu_entry = {
+ .release = sq_kobj_release,
.sysfs_ops = &sq_sysfs_ops,
.default_groups = sq_sysfs_groups,
};
--
2.56.0.455.g6c5a503b38-goog
^ permalink raw reply [flat|nested] 10+ messages in thread* [PATCH v3 4/9] cpufreq: governor: Initialize kobj_type release callback statically
2026-11-08 22:39 [PATCH v3 0/9] Add __must_init and require explicit kobj_type::release Ian Rogers
` (2 preceding siblings ...)
2026-11-08 22:39 ` [PATCH v3 3/9] sh: sq: Add missing kobject release callback to ktype_percpu_entry Ian Rogers
@ 2026-11-08 22:39 ` Ian Rogers
2026-11-08 22:39 ` [PATCH v3 5/9] dlm: Free dlm_ls in kobject release callback Ian Rogers
` (4 subsequent siblings)
8 siblings, 0 replies; 10+ messages in thread
From: Ian Rogers @ 2026-11-08 22:39 UTC (permalink / raw)
To: Danilo Krummrich, Greg Kroah-Hartman, Kees Cook, Miguel Ojeda,
Rafael J . Wysocki
Cc: Madhavan Srinivasan, Michael Ellerman, Nicholas Piggin,
Christophe Leroy, Nayna Jain, Srish Srinivasan, Mimi Zohar,
Yoshinori Sato, Rich Felker, John Paul Adrian Glaubitz,
Juergen Gross, Stefano Stabellini, Oleksandr Tyshchenko,
Nathan Chancellor, Nick Desaulniers, Viresh Kumar, Zhongqiu Han,
Alexander Aring, Felix Kuehling, Christian König,
Zhihao Cheng, Sumanth Korikkar, Bill Wendling, Justin Stitt,
driver-core, llvm, linux-hardening, linux-fsdevel, linux-doc,
linux-acpi, linux-pm, linuxppc-dev, linux-sh, linux-s390, gfs2,
xen-devel, linux-mtd, amd-gfx, dri-devel, linux-kernel,
Ian Rogers
Export cpufreq_dbs_data_release() and initialize .kobj_type.release
statically in the ondemand and conservative governors instead of
assigning it at runtime in cpufreq_dbs_governor_init().
This prepares for annotating struct kobj_type::release with
__must_init.
Reviewed-by: Zhongqiu Han <zhongqiu.han@oss.qualcomm.com>
Acked-by: Rafael J. Wysocki (Intel) <rafael@kernel.org> # cpufreq
Acked-by: Viresh Kumar <viresh.kumar@linaro.org>
Signed-off-by: Ian Rogers <irogers@google.com>
---
drivers/cpufreq/cpufreq_conservative.c | 5 ++++-
drivers/cpufreq/cpufreq_governor.c | 4 ++--
drivers/cpufreq/cpufreq_governor.h | 1 +
drivers/cpufreq/cpufreq_ondemand.c | 5 ++++-
4 files changed, 11 insertions(+), 4 deletions(-)
diff --git a/drivers/cpufreq/cpufreq_conservative.c b/drivers/cpufreq/cpufreq_conservative.c
index 02bfd46543e9..146a2353b1a2 100644
--- a/drivers/cpufreq/cpufreq_conservative.c
+++ b/drivers/cpufreq/cpufreq_conservative.c
@@ -318,7 +318,10 @@ static void cs_limits(struct cpufreq_policy *policy)
static struct dbs_governor cs_governor = {
.gov = CPUFREQ_DBS_GOVERNOR_INITIALIZER("conservative"),
- .kobj_type = { .default_groups = cs_groups },
+ .kobj_type = {
+ .release = cpufreq_dbs_data_release,
+ .default_groups = cs_groups,
+ },
.gov_dbs_update = cs_dbs_update,
.alloc = cs_alloc,
.free = cs_free,
diff --git a/drivers/cpufreq/cpufreq_governor.c b/drivers/cpufreq/cpufreq_governor.c
index f3bd3dbe7c41..f8b5aca09b6b 100644
--- a/drivers/cpufreq/cpufreq_governor.c
+++ b/drivers/cpufreq/cpufreq_governor.c
@@ -419,7 +419,7 @@ static void free_policy_dbs_info(struct policy_dbs_info *policy_dbs,
gov->free(policy_dbs);
}
-static void cpufreq_dbs_data_release(struct kobject *kobj)
+void cpufreq_dbs_data_release(struct kobject *kobj)
{
struct dbs_data *dbs_data = to_dbs_data(to_gov_attr_set(kobj));
struct dbs_governor *gov = dbs_data->gov;
@@ -427,6 +427,7 @@ static void cpufreq_dbs_data_release(struct kobject *kobj)
gov->exit(dbs_data);
kfree(dbs_data);
}
+EXPORT_SYMBOL_GPL(cpufreq_dbs_data_release);
int cpufreq_dbs_governor_init(struct cpufreq_policy *policy)
{
@@ -488,7 +489,6 @@ int cpufreq_dbs_governor_init(struct cpufreq_policy *policy)
policy->governor_data = policy_dbs;
gov->kobj_type.sysfs_ops = &governor_sysfs_ops;
- gov->kobj_type.release = cpufreq_dbs_data_release;
ret = kobject_init_and_add(&dbs_data->attr_set.kobj, &gov->kobj_type,
get_governor_parent_kobj(policy),
"%s", gov->gov.name);
diff --git a/drivers/cpufreq/cpufreq_governor.h b/drivers/cpufreq/cpufreq_governor.h
index 806d8fb4dff1..1026712bb79b 100644
--- a/drivers/cpufreq/cpufreq_governor.h
+++ b/drivers/cpufreq/cpufreq_governor.h
@@ -150,6 +150,7 @@ static inline struct dbs_governor *dbs_governor_of(struct cpufreq_policy *policy
}
/* Governor callback routines */
+void cpufreq_dbs_data_release(struct kobject *kobj);
int cpufreq_dbs_governor_init(struct cpufreq_policy *policy);
void cpufreq_dbs_governor_exit(struct cpufreq_policy *policy);
int cpufreq_dbs_governor_start(struct cpufreq_policy *policy);
diff --git a/drivers/cpufreq/cpufreq_ondemand.c b/drivers/cpufreq/cpufreq_ondemand.c
index 9942dbb38dae..7386d043c665 100644
--- a/drivers/cpufreq/cpufreq_ondemand.c
+++ b/drivers/cpufreq/cpufreq_ondemand.c
@@ -374,7 +374,10 @@ static struct od_ops od_ops = {
static struct dbs_governor od_dbs_gov = {
.gov = CPUFREQ_DBS_GOVERNOR_INITIALIZER("ondemand"),
- .kobj_type = { .default_groups = od_groups },
+ .kobj_type = {
+ .release = cpufreq_dbs_data_release,
+ .default_groups = od_groups,
+ },
.gov_dbs_update = od_dbs_update,
.alloc = od_alloc,
.free = od_free,
--
2.56.0.455.g6c5a503b38-goog
^ permalink raw reply [flat|nested] 10+ messages in thread* [PATCH v3 5/9] dlm: Free dlm_ls in kobject release callback
2026-11-08 22:39 [PATCH v3 0/9] Add __must_init and require explicit kobj_type::release Ian Rogers
` (3 preceding siblings ...)
2026-11-08 22:39 ` [PATCH v3 4/9] cpufreq: governor: Initialize kobj_type release callback statically Ian Rogers
@ 2026-11-08 22:39 ` Ian Rogers
2026-11-08 22:39 ` [PATCH v3 6/9] xen/sys-hypervisor: Add release callback to hyp_sysfs_kobj_type Ian Rogers
` (3 subsequent siblings)
8 siblings, 0 replies; 10+ messages in thread
From: Ian Rogers @ 2026-11-08 22:39 UTC (permalink / raw)
To: Danilo Krummrich, Greg Kroah-Hartman, Kees Cook, Miguel Ojeda,
Rafael J . Wysocki
Cc: Madhavan Srinivasan, Michael Ellerman, Nicholas Piggin,
Christophe Leroy, Nayna Jain, Srish Srinivasan, Mimi Zohar,
Yoshinori Sato, Rich Felker, John Paul Adrian Glaubitz,
Juergen Gross, Stefano Stabellini, Oleksandr Tyshchenko,
Nathan Chancellor, Nick Desaulniers, Viresh Kumar, Zhongqiu Han,
Alexander Aring, Felix Kuehling, Christian König,
Zhihao Cheng, Sumanth Korikkar, Bill Wendling, Justin Stitt,
driver-core, llvm, linux-hardening, linux-fsdevel, linux-doc,
linux-acpi, linux-pm, linuxppc-dev, linux-sh, linux-s390, gfs2,
xen-devel, linux-mtd, amd-gfx, dri-devel, linux-kernel,
Ian Rogers
struct dlm_ls embeds a struct kobject (ls_kobj), but dlm_ktype lacked a
.release callback and dlm freed the lockspace structure directly via
kfree(ls). With CONFIG_DEBUG_KOBJECT_RELEASE=y, freeing ls before the
delayed kobject release runs causes a use-after-free, and unloading the
module while the delayed release is pending results in an instruction
page fault.
Add a completion ls_kobj_done and dlm_ls_release() to complete it when
the last kobject reference is dropped, waiting for it in free_lockspace()
before kfree(ls) and in the new_lockspace() error path before module_put().
Also delete the kobject via kobject_del() before stopping dlm_recoverd
to close the window where concurrent sysfs writes could wake the stopped
recovery task.
Fixes: 3514faca19a6 ("kobject: remove struct kobj_type from struct kset")
Acked-by: Alexander Aring <aahringo@redhat.com>
Signed-off-by: Ian Rogers <irogers@google.com>
---
fs/dlm/dlm_internal.h | 1 +
fs/dlm/lockspace.c | 26 ++++++++++++++++++++------
2 files changed, 21 insertions(+), 6 deletions(-)
diff --git a/fs/dlm/dlm_internal.h b/fs/dlm/dlm_internal.h
index 74c2e77d1b55..95b3bff0cb57 100644
--- a/fs/dlm/dlm_internal.h
+++ b/fs/dlm/dlm_internal.h
@@ -576,6 +576,7 @@ struct dlm_ls {
int ls_create_count; /* create/release refcount */
unsigned long ls_flags; /* LSFL_ */
struct kobject ls_kobj;
+ struct completion ls_kobj_done;
struct xarray ls_lkbxa;
rwlock_t ls_lkbxa_lock;
diff --git a/fs/dlm/lockspace.c b/fs/dlm/lockspace.c
index a9c98b4f378f..2dccd080a10f 100644
--- a/fs/dlm/lockspace.c
+++ b/fs/dlm/lockspace.c
@@ -179,7 +179,15 @@ static const struct sysfs_ops dlm_attr_ops = {
.store = dlm_attr_store,
};
+static void dlm_ls_release(struct kobject *kobj)
+{
+ struct dlm_ls *ls = container_of(kobj, struct dlm_ls, ls_kobj);
+
+ complete(&ls->ls_kobj_done);
+}
+
static struct kobj_type dlm_ktype = {
+ .release = dlm_ls_release,
.default_groups = dlm_groups,
.sysfs_ops = &dlm_attr_ops,
};
@@ -355,6 +363,8 @@ static void free_lockspace(struct work_struct *work)
*/
rhashtable_free_and_destroy(&ls->ls_rsbtbl, rhash_free_rsb, NULL);
+ kobject_put(&ls->ls_kobj);
+ wait_for_completion(&ls->ls_kobj_done);
kfree(ls);
}
@@ -435,7 +445,10 @@ static int new_lockspace(const char *name, const char *cluster,
ls->ls_lvblen = lvblen;
atomic_set(&ls->ls_count, 0);
init_waitqueue_head(&ls->ls_count_wait);
+ init_completion(&ls->ls_kobj_done);
ls->ls_flags = 0;
+ ls->ls_kobj.kset = dlm_kset;
+ kobject_init(&ls->ls_kobj, &dlm_ktype);
if (ops && dlm_config.ci_recover_callbacks) {
ls->ls_ops = ops;
@@ -567,9 +580,7 @@ static int new_lockspace(const char *name, const char *cluster,
wait_event(ls->ls_recover_lock_wait,
test_bit(LSFL_RECOVER_LOCK, &ls->ls_flags));
- ls->ls_kobj.kset = dlm_kset;
- error = kobject_init_and_add(&ls->ls_kobj, &dlm_ktype, NULL,
- "%s", ls->ls_name);
+ error = kobject_add(&ls->ls_kobj, NULL, "%s", ls->ls_name);
if (error)
goto out_recoverd;
kobject_uevent(&ls->ls_kobj, KOBJ_ADD);
@@ -582,7 +593,7 @@ static int new_lockspace(const char *name, const char *cluster,
error = do_uevent(ls, 1, 0);
if (error < 0)
- goto out_recoverd;
+ goto out_kobj;
/* wait until recovery is successful or failed */
wait_for_completion(&ls->ls_recovery_done);
@@ -600,6 +611,8 @@ static int new_lockspace(const char *name, const char *cluster,
do_uevent(ls, 0, 0);
dlm_clear_members(ls);
kfree(ls->ls_node_array);
+ out_kobj:
+ kobject_del(&ls->ls_kobj);
out_recoverd:
dlm_recoverd_stop(ls);
out_callback:
@@ -615,6 +628,7 @@ static int new_lockspace(const char *name, const char *cluster,
rhashtable_destroy(&ls->ls_rsbtbl);
out_lsfree:
kobject_put(&ls->ls_kobj);
+ wait_for_completion(&ls->ls_kobj_done);
kfree(ls);
out:
module_put(THIS_MODULE);
@@ -740,6 +754,8 @@ static int release_lockspace(struct dlm_ls *ls, unsigned int release_option)
dlm_user_daemon_available())
do_uevent(ls, 0, (release_option == DLM_RELEASE_RECOVER));
+ kobject_del(&ls->ls_kobj);
+
dlm_recoverd_stop(ls);
/* clear the LSFL_RUNNING flag to fast up
@@ -759,8 +775,6 @@ static int release_lockspace(struct dlm_ls *ls, unsigned int release_option)
dlm_delete_debug_file(ls);
- kobject_put(&ls->ls_kobj);
-
xa_destroy(&ls->ls_recover_xa);
kfree(ls->ls_recover_buf);
--
2.56.0.455.g6c5a503b38-goog
^ permalink raw reply [flat|nested] 10+ messages in thread* [PATCH v3 6/9] xen/sys-hypervisor: Add release callback to hyp_sysfs_kobj_type
2026-11-08 22:39 [PATCH v3 0/9] Add __must_init and require explicit kobj_type::release Ian Rogers
` (4 preceding siblings ...)
2026-11-08 22:39 ` [PATCH v3 5/9] dlm: Free dlm_ls in kobject release callback Ian Rogers
@ 2026-11-08 22:39 ` Ian Rogers
2026-11-08 22:39 ` [PATCH v3 7/9] ubifs: sysfs: Use kset_create_and_add() for ubifs_kset Ian Rogers
` (2 subsequent siblings)
8 siblings, 0 replies; 10+ messages in thread
From: Ian Rogers @ 2026-11-08 22:39 UTC (permalink / raw)
To: Danilo Krummrich, Greg Kroah-Hartman, Kees Cook, Miguel Ojeda,
Rafael J . Wysocki
Cc: Madhavan Srinivasan, Michael Ellerman, Nicholas Piggin,
Christophe Leroy, Nayna Jain, Srish Srinivasan, Mimi Zohar,
Yoshinori Sato, Rich Felker, John Paul Adrian Glaubitz,
Juergen Gross, Stefano Stabellini, Oleksandr Tyshchenko,
Nathan Chancellor, Nick Desaulniers, Viresh Kumar, Zhongqiu Han,
Alexander Aring, Felix Kuehling, Christian König,
Zhihao Cheng, Sumanth Korikkar, Bill Wendling, Justin Stitt,
driver-core, llvm, linux-hardening, linux-fsdevel, linux-doc,
linux-acpi, linux-pm, linuxppc-dev, linux-sh, linux-s390, gfs2,
xen-devel, linux-mtd, amd-gfx, dri-devel, linux-kernel,
Ian Rogers
hypervisor_init() in drivers/base/hypervisor.c creates hypervisor_kobj
with kobject_create_and_add() (which allocates a dynamic kobject using
dynamic_kobj_ktype), and hypervisor_subsys_init() in
drivers/xen/sys-hypervisor.c then overwrites hypervisor_kobj->ktype with
&hyp_sysfs_kobj_type, which had no .release callback.
Add hyp_sysfs_release() calling kfree(kobj) to preserve the dynamic
kobject release behavior.
Fixes: cff7e81b3dd7 ("xen: add /sys/hypervisor support")
Signed-off-by: Ian Rogers <irogers@google.com>
---
drivers/xen/sys-hypervisor.c | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/drivers/xen/sys-hypervisor.c b/drivers/xen/sys-hypervisor.c
index 91923242a5ae..0e8a2cd69fd6 100644
--- a/drivers/xen/sys-hypervisor.c
+++ b/drivers/xen/sys-hypervisor.c
@@ -659,7 +659,13 @@ static const struct sysfs_ops hyp_sysfs_ops = {
.store = hyp_sysfs_store,
};
+static void hyp_sysfs_release(struct kobject *kobj)
+{
+ kfree(kobj);
+}
+
static const struct kobj_type hyp_sysfs_kobj_type = {
+ .release = hyp_sysfs_release,
.sysfs_ops = &hyp_sysfs_ops,
};
--
2.56.0.455.g6c5a503b38-goog
^ permalink raw reply [flat|nested] 10+ messages in thread* [PATCH v3 7/9] ubifs: sysfs: Use kset_create_and_add() for ubifs_kset
2026-11-08 22:39 [PATCH v3 0/9] Add __must_init and require explicit kobj_type::release Ian Rogers
` (5 preceding siblings ...)
2026-11-08 22:39 ` [PATCH v3 6/9] xen/sys-hypervisor: Add release callback to hyp_sysfs_kobj_type Ian Rogers
@ 2026-11-08 22:39 ` Ian Rogers
2026-11-08 22:39 ` [PATCH v3 8/9] drm/amdkfd: Free queue in procfs_queue_type kobject release callback Ian Rogers
2026-11-08 22:39 ` [PATCH v3 9/9] kobject: Require explicit initialization of struct kobj_type::release Ian Rogers
8 siblings, 0 replies; 10+ messages in thread
From: Ian Rogers @ 2026-11-08 22:39 UTC (permalink / raw)
To: Danilo Krummrich, Greg Kroah-Hartman, Kees Cook, Miguel Ojeda,
Rafael J . Wysocki
Cc: Madhavan Srinivasan, Michael Ellerman, Nicholas Piggin,
Christophe Leroy, Nayna Jain, Srish Srinivasan, Mimi Zohar,
Yoshinori Sato, Rich Felker, John Paul Adrian Glaubitz,
Juergen Gross, Stefano Stabellini, Oleksandr Tyshchenko,
Nathan Chancellor, Nick Desaulniers, Viresh Kumar, Zhongqiu Han,
Alexander Aring, Felix Kuehling, Christian König,
Zhihao Cheng, Sumanth Korikkar, Bill Wendling, Justin Stitt,
driver-core, llvm, linux-hardening, linux-fsdevel, linux-doc,
linux-acpi, linux-pm, linuxppc-dev, linux-sh, linux-s390, gfs2,
xen-devel, linux-mtd, amd-gfx, dri-devel, linux-kernel,
Ian Rogers
ubifs_kset was a static struct kset using a custom ubifs_ktype that
had no default_groups and no .release callback. With
CONFIG_DEBUG_KOBJECT_RELEASE=y, unloading the ubifs module while delayed
kobject release is pending causes a use-after-free on the static kset.
Replace the static ubifs_kset and empty ubifs_ktype with a dynamically
allocated kset via kset_create_and_add().
Fixes: 203a55f04f66 ("ubifs: Fix memory leak in ubifs_sysfs_init()")
Tested-by: Zhihao Cheng <chengzhihao1@huawei.com>
Reviewed-by: Zhihao Cheng <chengzhihao1@huawei.com>
Signed-off-by: Ian Rogers <irogers@google.com>
---
fs/ubifs/sysfs.c | 24 +++++++-----------------
1 file changed, 7 insertions(+), 17 deletions(-)
diff --git a/fs/ubifs/sysfs.c b/fs/ubifs/sysfs.c
index dbf967dcf26e..e20931e3a62f 100644
--- a/fs/ubifs/sysfs.c
+++ b/fs/ubifs/sysfs.c
@@ -80,13 +80,7 @@ static const struct kobj_type ubifs_sb_ktype = {
.release = ubifs_sb_release,
};
-static const struct kobj_type ubifs_ktype = {
- .sysfs_ops = &ubifs_attr_ops,
-};
-
-static struct kset ubifs_kset = {
- .kobj = {.ktype = &ubifs_ktype},
-};
+static struct kset *ubifs_kset;
int ubifs_sysfs_register(struct ubifs_info *c)
{
@@ -107,7 +101,7 @@ int ubifs_sysfs_register(struct ubifs_info *c)
goto out_free;
}
- c->kobj.kset = &ubifs_kset;
+ c->kobj.kset = ubifs_kset;
init_completion(&c->kobj_unregister);
ret = kobject_init_and_add(&c->kobj, &ubifs_sb_ktype, NULL,
@@ -139,18 +133,14 @@ void ubifs_sysfs_unregister(struct ubifs_info *c)
int __init ubifs_sysfs_init(void)
{
- int ret;
+ ubifs_kset = kset_create_and_add("ubifs", NULL, fs_kobj);
+ if (!ubifs_kset)
+ return -ENOMEM;
- kobject_set_name(&ubifs_kset.kobj, "ubifs");
- ubifs_kset.kobj.parent = fs_kobj;
- ret = kset_register(&ubifs_kset);
- if (ret)
- kset_put(&ubifs_kset);
-
- return ret;
+ return 0;
}
void ubifs_sysfs_exit(void)
{
- kset_unregister(&ubifs_kset);
+ kset_unregister(ubifs_kset);
}
--
2.56.0.455.g6c5a503b38-goog
^ permalink raw reply [flat|nested] 10+ messages in thread* [PATCH v3 8/9] drm/amdkfd: Free queue in procfs_queue_type kobject release callback
2026-11-08 22:39 [PATCH v3 0/9] Add __must_init and require explicit kobj_type::release Ian Rogers
` (6 preceding siblings ...)
2026-11-08 22:39 ` [PATCH v3 7/9] ubifs: sysfs: Use kset_create_and_add() for ubifs_kset Ian Rogers
@ 2026-11-08 22:39 ` Ian Rogers
2026-11-08 22:39 ` [PATCH v3 9/9] kobject: Require explicit initialization of struct kobj_type::release Ian Rogers
8 siblings, 0 replies; 10+ messages in thread
From: Ian Rogers @ 2026-11-08 22:39 UTC (permalink / raw)
To: Danilo Krummrich, Greg Kroah-Hartman, Kees Cook, Miguel Ojeda,
Rafael J . Wysocki
Cc: Madhavan Srinivasan, Michael Ellerman, Nicholas Piggin,
Christophe Leroy, Nayna Jain, Srish Srinivasan, Mimi Zohar,
Yoshinori Sato, Rich Felker, John Paul Adrian Glaubitz,
Juergen Gross, Stefano Stabellini, Oleksandr Tyshchenko,
Nathan Chancellor, Nick Desaulniers, Viresh Kumar, Zhongqiu Han,
Alexander Aring, Felix Kuehling, Christian König,
Zhihao Cheng, Sumanth Korikkar, Bill Wendling, Justin Stitt,
driver-core, llvm, linux-hardening, linux-fsdevel, linux-doc,
linux-acpi, linux-pm, linuxppc-dev, linux-sh, linux-s390, gfs2,
xen-devel, linux-mtd, amd-gfx, dri-devel, linux-kernel,
Ian Rogers
struct queue embeds a struct kobject (q->kobj) for procfs entries, but
procfs_queue_type had no .release callback and uninit_queue() freed q
immediately after kfd_procfs_del_queue() called kobject_put(&q->kobj).
With CONFIG_DEBUG_KOBJECT_RELEASE=y, this causes a use-after-free.
Add kfd_procfs_queue_release() to free struct queue from the kobject
release callback, change kfd_procfs_del_queue() to only remove the
kobject from sysfs via kobject_del(), and drop the final reference in
uninit_queue() via kobject_put(). Check q->kobj.state_in_sysfs before
calling kobject_del() in kfd_procfs_del_queue() to avoid warnings if
sysfs creation previously failed.
Fixes: 6d220a7e7971 ("drm/amdkfd: Add queue information to sysfs")
Reviewed-by: Felix Kuehling <felix.kuehling@amd.com>
Signed-off-by: Ian Rogers <irogers@google.com>
---
drivers/gpu/drm/amd/amdkfd/kfd_process.c | 12 +++++++++---
drivers/gpu/drm/amd/amdkfd/kfd_queue.c | 5 ++++-
2 files changed, 13 insertions(+), 4 deletions(-)
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_process.c b/drivers/gpu/drm/amd/amdkfd/kfd_process.c
index 6663718fb83c..b349e0d8d47b 100644
--- a/drivers/gpu/drm/amd/amdkfd/kfd_process.c
+++ b/drivers/gpu/drm/amd/amdkfd/kfd_process.c
@@ -512,7 +512,15 @@ static const struct sysfs_ops procfs_queue_ops = {
.show = kfd_procfs_queue_show,
};
+static void kfd_procfs_queue_release(struct kobject *kobj)
+{
+ struct queue *q = container_of(kobj, struct queue, kobj);
+
+ kfree(q);
+}
+
static const struct kobj_type procfs_queue_type = {
+ .release = kfd_procfs_queue_release,
.sysfs_ops = &procfs_queue_ops,
.default_groups = procfs_queue_groups,
};
@@ -552,7 +560,6 @@ int kfd_procfs_add_queue(struct queue *q)
if (ret < 0) {
pr_warn("Creating proc/<pid>/queues/%u failed",
q->properties.queue_id);
- kobject_put(&q->kobj);
return ret;
}
@@ -697,11 +704,10 @@ static void kfd_procfs_add_sysfs_files(struct kfd_process *p)
void kfd_procfs_del_queue(struct queue *q)
{
- if (!q || !q->process->kobj)
+ if (!q || !q->process || !q->process->kobj || !q->kobj.state_in_sysfs)
return;
kobject_del(&q->kobj);
- kobject_put(&q->kobj);
}
int kfd_process_create_wq(void)
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_queue.c b/drivers/gpu/drm/amd/amdkfd/kfd_queue.c
index 6010a5d7a7eb..f7413d651620 100644
--- a/drivers/gpu/drm/amd/amdkfd/kfd_queue.c
+++ b/drivers/gpu/drm/amd/amdkfd/kfd_queue.c
@@ -83,7 +83,10 @@ int init_queue(struct queue **q, const struct queue_properties *properties)
void uninit_queue(struct queue *q)
{
- kfree(q);
+ if (q && q->kobj.state_initialized)
+ kobject_put(&q->kobj);
+ else
+ kfree(q);
}
#if IS_ENABLED(CONFIG_HSA_AMD_SVM)
--
2.56.0.455.g6c5a503b38-goog
^ permalink raw reply [flat|nested] 10+ messages in thread* [PATCH v3 9/9] kobject: Require explicit initialization of struct kobj_type::release
2026-11-08 22:39 [PATCH v3 0/9] Add __must_init and require explicit kobj_type::release Ian Rogers
` (7 preceding siblings ...)
2026-11-08 22:39 ` [PATCH v3 8/9] drm/amdkfd: Free queue in procfs_queue_type kobject release callback Ian Rogers
@ 2026-11-08 22:39 ` Ian Rogers
8 siblings, 0 replies; 10+ messages in thread
From: Ian Rogers @ 2026-11-08 22:39 UTC (permalink / raw)
To: Danilo Krummrich, Greg Kroah-Hartman, Kees Cook, Miguel Ojeda,
Rafael J . Wysocki
Cc: Madhavan Srinivasan, Michael Ellerman, Nicholas Piggin,
Christophe Leroy, Nayna Jain, Srish Srinivasan, Mimi Zohar,
Yoshinori Sato, Rich Felker, John Paul Adrian Glaubitz,
Juergen Gross, Stefano Stabellini, Oleksandr Tyshchenko,
Nathan Chancellor, Nick Desaulniers, Viresh Kumar, Zhongqiu Han,
Alexander Aring, Felix Kuehling, Christian König,
Zhihao Cheng, Sumanth Korikkar, Bill Wendling, Justin Stitt,
driver-core, llvm, linux-hardening, linux-fsdevel, linux-doc,
linux-acpi, linux-pm, linuxppc-dev, linux-sh, linux-s390, gfs2,
xen-devel, linux-mtd, amd-gfx, dri-devel, linux-kernel,
Ian Rogers
Documentation/core-api/kobject.rst states:
"One important point cannot be overstated: every kobject must have a
release() method, and the kobject must persist (in a consistent state)
until that method is called. If these constraints are not met, the code
is flawed. Note that the kernel will warn you if you forget to provide
a release() method. Do not try to get rid of this warning by providing
an \"empty\" release function."
Annotate struct kobj_type::release with __must_init so the compiler
diagnoses any struct kobj_type initializer that omits .release.
For the remaining legacy struct kobj_type definitions where the kobject
is static, per-CPU, a permanent firmware structure, or embedded inside a
devm- or parent-managed allocation rather than freed by kobject_put(),
explicitly initialize .release = NULL with a comment documenting why no
release callback is provided.
Many of these legacy sites are not safe with CONFIG_DEBUG_KOBJECT_RELEASE
(for example when backing memory is freed, zeroed, or unmapped on module
unload while delayed kobject cleanup is still pending). Fixing those
lifetimes is left to follow-up patches; this change does not alter their
behavior.
Link: https://lpc.events/event/20/contributions/2392/
Signed-off-by: Ian Rogers <irogers@google.com>
---
arch/arm64/kernel/cpuinfo.c | 5 +++++
drivers/acpi/sysfs.c | 2 ++
drivers/dma/ioat/sysfs.c | 7 +++++++
drivers/gpu/drm/amd/amdgpu/amdgpu_ualink.c | 5 +++++
drivers/gpu/drm/amd/amdgpu/amdgpu_xcp.c | 10 +++++++++
drivers/infiniband/hw/hfi1/sysfs.c | 5 +++++
drivers/infiniband/hw/usnic/usnic_ib_sysfs.c | 5 +++++
drivers/parisc/pdc_stable.c | 5 +++++
drivers/power/supply/ab8500_fg.c | 5 +++++
drivers/s390/char/sclp_mem.c | 2 ++
drivers/soc/hisilicon/kunpeng_hccs.c | 21 +++++++++++++++++++
.../fbdev/omap2/omapfb/dss/display-sysfs.c | 7 +++++++
.../fbdev/omap2/omapfb/dss/manager-sysfs.c | 8 +++++++
.../fbdev/omap2/omapfb/dss/overlay-sysfs.c | 8 +++++++
fs/erofs/sysfs.c | 10 +++++++++
fs/f2fs/sysfs.c | 15 +++++++++++++
fs/ocfs2/cluster/masklog.c | 5 +++++
include/linux/kobject.h | 2 +-
18 files changed, 126 insertions(+), 1 deletion(-)
diff --git a/arch/arm64/kernel/cpuinfo.c b/arch/arm64/kernel/cpuinfo.c
index 94e6cd211d70..7a4ac8dd0b86 100644
--- a/arch/arm64/kernel/cpuinfo.c
+++ b/arch/arm64/kernel/cpuinfo.c
@@ -295,6 +295,11 @@ const struct seq_operations cpuinfo_op = {
static const struct kobj_type cpuregs_kobj_type = {
+ /*
+ * Pre-existing: info->kobj is embedded in per-CPU cpu_data;
+ * cpuid_cpu_offline() only calls kobject_del().
+ */
+ .release = NULL,
.sysfs_ops = &kobj_sysfs_ops,
};
diff --git a/drivers/acpi/sysfs.c b/drivers/acpi/sysfs.c
index a4534b3e3cfb..a10f14524dd9 100644
--- a/drivers/acpi/sysfs.c
+++ b/drivers/acpi/sysfs.c
@@ -975,6 +975,8 @@ static struct attribute *hotplug_profile_attrs[] = {
ATTRIBUTE_GROUPS(hotplug_profile);
static const struct kobj_type acpi_hotplug_profile_ktype = {
+ /* Pre-existing: hotplug->kobj is embedded in static struct acpi_scan_hotplug objects. */
+ .release = NULL,
.sysfs_ops = &kobj_sysfs_ops,
.default_groups = hotplug_profile_groups,
};
diff --git a/drivers/dma/ioat/sysfs.c b/drivers/dma/ioat/sysfs.c
index 976134df8108..b9af60e198ef 100644
--- a/drivers/dma/ioat/sysfs.c
+++ b/drivers/dma/ioat/sysfs.c
@@ -167,6 +167,13 @@ static const struct attribute *const ioat_attrs[] = {
ATTRIBUTE_GROUPS(ioat);
const struct kobj_type ioat_ktype = {
+ /*
+ * Pre-existing: ioatdma_chan is freed by release_ioatdma(), not
+ * by kobject_put(). With CONFIG_DEBUG_KOBJECT_RELEASE the delayed
+ * kobject cleanup queued by ioat_kobject_del() may run after
+ * that kfree(), a use-after-free.
+ */
+ .release = NULL,
.sysfs_ops = &ioat_sysfs_ops,
.default_groups = ioat_groups,
};
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ualink.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ualink.c
index 6cd3927a7e82..a2a027e4b118 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ualink.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ualink.c
@@ -892,6 +892,11 @@ static const struct attribute_group ualink_xcp_info_group = {
};
static const struct kobj_type ualink_xcp_info_ktype = {
+ /*
+ * Pre-existing: xcp->ualink.kobj is embedded in struct amdgpu_xcp_mgr
+ * rather than freed individually by kobject_put().
+ */
+ .release = NULL,
.sysfs_ops = &kobj_sysfs_ops
};
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_xcp.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_xcp.c
index ab14079d1c42..0847134a1391 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_xcp.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_xcp.c
@@ -797,6 +797,11 @@ static const struct sysfs_ops xcp_cfg_res_sysfs_ops = {
};
static const struct kobj_type xcp_cfg_res_sysfs_ktype = {
+ /*
+ * Pre-existing: xcp_res is embedded in struct amdgpu_xcp_cfg
+ * rather than freed individually by kobject_put().
+ */
+ .release = NULL,
.sysfs_ops = &xcp_cfg_res_sysfs_ops,
.default_groups = xcp_cfg_res_sysfs_groups,
};
@@ -1061,6 +1066,11 @@ static const struct attribute_group amdgpu_xcp_attrs_group = {
};
static const struct kobj_type xcp_sysfs_ktype = {
+ /*
+ * Pre-existing: xcp is embedded in struct amdgpu_xcp_mgr
+ * rather than freed individually by kobject_put().
+ */
+ .release = NULL,
.sysfs_ops = &kobj_sysfs_ops,
};
diff --git a/drivers/infiniband/hw/hfi1/sysfs.c b/drivers/infiniband/hw/hfi1/sysfs.c
index 372cfd13dc61..5a1aca06b542 100644
--- a/drivers/infiniband/hw/hfi1/sysfs.c
+++ b/drivers/infiniband/hw/hfi1/sysfs.c
@@ -608,6 +608,11 @@ static const struct sysfs_ops sde_sysfs_ops = {
};
static struct kobj_type sde_ktype = {
+ /*
+ * Pre-existing: sdma_engine is embedded in dd->per_sdma array
+ * rather than freed by kobject_put().
+ */
+ .release = NULL,
.sysfs_ops = &sde_sysfs_ops,
};
diff --git a/drivers/infiniband/hw/usnic/usnic_ib_sysfs.c b/drivers/infiniband/hw/usnic/usnic_ib_sysfs.c
index fdb63a8fb997..0c9dbf93a0e9 100644
--- a/drivers/infiniband/hw/usnic/usnic_ib_sysfs.c
+++ b/drivers/infiniband/hw/usnic/usnic_ib_sysfs.c
@@ -245,6 +245,11 @@ static struct attribute *usnic_ib_qpn_default_attrs[] = {
ATTRIBUTE_GROUPS(usnic_ib_qpn_default);
static struct kobj_type usnic_ib_qpn_type = {
+ /*
+ * Pre-existing: qp_grp->kobj is embedded in RDMA core-managed
+ * struct usnic_ib_qp_grp rather than freed by kobject_put().
+ */
+ .release = NULL,
.sysfs_ops = &usnic_ib_qpn_sysfs_ops,
.default_groups = usnic_ib_qpn_default_groups,
};
diff --git a/drivers/parisc/pdc_stable.c b/drivers/parisc/pdc_stable.c
index 6b567a74fc2c..2f530e8c6757 100644
--- a/drivers/parisc/pdc_stable.c
+++ b/drivers/parisc/pdc_stable.c
@@ -484,6 +484,11 @@ ATTRIBUTE_GROUPS(paths_subsys);
/* Specific kobject type for our PDC paths */
static const struct kobj_type ktype_pdcspath = {
+ /*
+ * Pre-existing: pdcspath_entry instances are static; lifetime
+ * is not controlled by kobject_put().
+ */
+ .release = NULL,
.sysfs_ops = &pdcspath_attr_ops,
.default_groups = paths_subsys_groups,
};
diff --git a/drivers/power/supply/ab8500_fg.c b/drivers/power/supply/ab8500_fg.c
index 069e7fee1d16..f71630d92231 100644
--- a/drivers/power/supply/ab8500_fg.c
+++ b/drivers/power/supply/ab8500_fg.c
@@ -2539,6 +2539,11 @@ static struct attribute *ab8500_fg_attrs[] = {
ATTRIBUTE_GROUPS(ab8500_fg);
static const struct kobj_type ab8500_fg_ktype = {
+ /*
+ * Pre-existing: fg_kobject is embedded in devm-allocated struct
+ * ab8500_fg; ab8500_fg_sysfs_exit() only calls kobject_del().
+ */
+ .release = NULL,
.sysfs_ops = &ab8500_fg_sysfs_ops,
.default_groups = ab8500_fg_groups,
};
diff --git a/drivers/s390/char/sclp_mem.c b/drivers/s390/char/sclp_mem.c
index 6df1926d4c62..2fb7271dce36 100644
--- a/drivers/s390/char/sclp_mem.c
+++ b/drivers/s390/char/sclp_mem.c
@@ -305,6 +305,8 @@ static ssize_t sclp_memmap_on_memory_store(struct kobject *kobj, struct kobj_att
}
static const struct kobj_type ktype = {
+ /* Pre-existing: permanent firmware kobjects, never freed */
+ .release = NULL,
.sysfs_ops = &kobj_sysfs_ops,
};
diff --git a/drivers/soc/hisilicon/kunpeng_hccs.c b/drivers/soc/hisilicon/kunpeng_hccs.c
index 0cc2953d59a5..da7a64c95058 100644
--- a/drivers/soc/hisilicon/kunpeng_hccs.c
+++ b/drivers/soc/hisilicon/kunpeng_hccs.c
@@ -1038,6 +1038,13 @@ static struct attribute *hccs_port_default_attrs[] = {
ATTRIBUTE_GROUPS(hccs_port_default);
static const struct kobj_type hccs_port_type = {
+ /*
+ * Pre-existing: hccs_port_info is allocated via devm_kzalloc()
+ * rather than freed by kobject_put(). With
+ * CONFIG_DEBUG_KOBJECT_RELEASE the delayed kobject cleanup may run
+ * after devm frees it on unbind, a use-after-free.
+ */
+ .release = NULL,
.sysfs_ops = &hccs_comm_ops,
.default_groups = hccs_port_default_groups,
};
@@ -1110,6 +1117,13 @@ static struct attribute *hccs_die_default_attrs[] = {
ATTRIBUTE_GROUPS(hccs_die_default);
static const struct kobj_type hccs_die_type = {
+ /*
+ * Pre-existing: hccs_die_info is allocated via devm_kzalloc()
+ * rather than freed by kobject_put(). With
+ * CONFIG_DEBUG_KOBJECT_RELEASE the delayed kobject cleanup may run
+ * after devm frees it on unbind, a use-after-free.
+ */
+ .release = NULL,
.sysfs_ops = &hccs_comm_ops,
.default_groups = hccs_die_default_groups,
};
@@ -1213,6 +1227,13 @@ static struct attribute *hccs_chip_default_attrs[] = {
ATTRIBUTE_GROUPS(hccs_chip_default);
static const struct kobj_type hccs_chip_type = {
+ /*
+ * Pre-existing: hccs_chip_info is allocated via devm_kzalloc()
+ * rather than freed by kobject_put(). With
+ * CONFIG_DEBUG_KOBJECT_RELEASE the delayed kobject cleanup may run
+ * after devm frees it on unbind, a use-after-free.
+ */
+ .release = NULL,
.sysfs_ops = &hccs_comm_ops,
.default_groups = hccs_chip_default_groups,
};
diff --git a/drivers/video/fbdev/omap2/omapfb/dss/display-sysfs.c b/drivers/video/fbdev/omap2/omapfb/dss/display-sysfs.c
index ae937854403b..452920a4e2a9 100644
--- a/drivers/video/fbdev/omap2/omapfb/dss/display-sysfs.c
+++ b/drivers/video/fbdev/omap2/omapfb/dss/display-sysfs.c
@@ -304,6 +304,13 @@ static const struct sysfs_ops display_sysfs_ops = {
};
static struct kobj_type display_ktype = {
+ /*
+ * Pre-existing: dssdev->kobj is embedded in struct omap_dss_device
+ * and zeroed in display_uninit_sysfs() right after kobject_put().
+ * With CONFIG_DEBUG_KOBJECT_RELEASE that memset() clobbers the
+ * pending delayed kobject cleanup.
+ */
+ .release = NULL,
.sysfs_ops = &display_sysfs_ops,
.default_groups = display_sysfs_groups,
};
diff --git a/drivers/video/fbdev/omap2/omapfb/dss/manager-sysfs.c b/drivers/video/fbdev/omap2/omapfb/dss/manager-sysfs.c
index 1b644be5fe2e..c343c33199af 100644
--- a/drivers/video/fbdev/omap2/omapfb/dss/manager-sysfs.c
+++ b/drivers/video/fbdev/omap2/omapfb/dss/manager-sysfs.c
@@ -496,6 +496,14 @@ static const struct sysfs_ops manager_sysfs_ops = {
};
static struct kobj_type manager_ktype = {
+ /*
+ * Pre-existing: mgr->kobj is embedded in dynamically allocated
+ * managers[], zeroed in dss_manager_kobj_uninit() right after
+ * kobject_put(), and freed in dss_uninit_overlay_managers(). With
+ * CONFIG_DEBUG_KOBJECT_RELEASE that clobbers and frees the pending
+ * delayed kobject cleanup.
+ */
+ .release = NULL,
.sysfs_ops = &manager_sysfs_ops,
.default_groups = manager_sysfs_groups,
};
diff --git a/drivers/video/fbdev/omap2/omapfb/dss/overlay-sysfs.c b/drivers/video/fbdev/omap2/omapfb/dss/overlay-sysfs.c
index 1da4fb1c77b4..5c14446af9b3 100644
--- a/drivers/video/fbdev/omap2/omapfb/dss/overlay-sysfs.c
+++ b/drivers/video/fbdev/omap2/omapfb/dss/overlay-sysfs.c
@@ -429,6 +429,14 @@ static const struct sysfs_ops overlay_sysfs_ops = {
};
static struct kobj_type overlay_ktype = {
+ /*
+ * Pre-existing: ovl->kobj is embedded in dynamically allocated
+ * overlays[] and freed in dss_uninit_overlays() right after
+ * dss_overlay_kobj_uninit() calls kobject_put(). With
+ * CONFIG_DEBUG_KOBJECT_RELEASE the delayed kobject cleanup may run
+ * after kfree(overlays), a use-after-free.
+ */
+ .release = NULL,
.sysfs_ops = &overlay_sysfs_ops,
.default_groups = overlay_sysfs_groups,
};
diff --git a/fs/erofs/sysfs.c b/fs/erofs/sysfs.c
index dfcec9376cd5..2ea6773cd98f 100644
--- a/fs/erofs/sysfs.c
+++ b/fs/erofs/sysfs.c
@@ -238,6 +238,11 @@ static const struct kobj_type erofs_sb_ktype = {
static const struct kobj_type erofs_ktype = {
.default_groups = erofs_groups,
.sysfs_ops = &erofs_attr_ops,
+ /*
+ * Pre-existing: erofs_root is a static struct kset; lifetime
+ * is not controlled by kobject_put().
+ */
+ .release = NULL,
};
static struct kset erofs_root = {
@@ -247,6 +252,11 @@ static struct kset erofs_root = {
static const struct kobj_type erofs_feat_ktype = {
.default_groups = erofs_feat_groups,
.sysfs_ops = &erofs_attr_ops,
+ /*
+ * Pre-existing: erofs_feat is a static struct kobject; lifetime
+ * is not controlled by kobject_put().
+ */
+ .release = NULL,
};
static struct kobject erofs_feat = {
diff --git a/fs/f2fs/sysfs.c b/fs/f2fs/sysfs.c
index 430356e500af..6e15695cb75f 100644
--- a/fs/f2fs/sysfs.c
+++ b/fs/f2fs/sysfs.c
@@ -1683,6 +1683,11 @@ static const struct kobj_type f2fs_sb_ktype = {
static const struct kobj_type f2fs_ktype = {
.sysfs_ops = &f2fs_attr_ops,
+ /*
+ * Pre-existing: f2fs_kset is a static struct kset; lifetime
+ * is not controlled by kobject_put().
+ */
+ .release = NULL,
};
static struct kset f2fs_kset = {
@@ -1697,6 +1702,11 @@ static const struct sysfs_ops f2fs_feat_attr_ops = {
static const struct kobj_type f2fs_feat_ktype = {
.default_groups = f2fs_feat_groups,
.sysfs_ops = &f2fs_feat_attr_ops,
+ /*
+ * Pre-existing: f2fs_feat is a static struct kobject; lifetime
+ * is not controlled by kobject_put().
+ */
+ .release = NULL,
};
static struct kobject f2fs_feat = {
@@ -1711,6 +1721,11 @@ static const struct sysfs_ops f2fs_tune_attr_ops = {
static const struct kobj_type f2fs_tune_ktype = {
.default_groups = f2fs_tune_groups,
.sysfs_ops = &f2fs_tune_attr_ops,
+ /*
+ * Pre-existing: f2fs_tune is a static struct kobject; lifetime
+ * is not controlled by kobject_put().
+ */
+ .release = NULL,
};
static struct kobject f2fs_tune = {
diff --git a/fs/ocfs2/cluster/masklog.c b/fs/ocfs2/cluster/masklog.c
index 563881ddbf00..ff8a1cf51e72 100644
--- a/fs/ocfs2/cluster/masklog.c
+++ b/fs/ocfs2/cluster/masklog.c
@@ -147,6 +147,11 @@ static const struct sysfs_ops mlog_attr_ops = {
static struct kobj_type mlog_ktype = {
.default_groups = mlog_default_groups,
.sysfs_ops = &mlog_attr_ops,
+ /*
+ * Pre-existing: mlog_kset is a static struct kset; lifetime
+ * is not controlled by kobject_put().
+ */
+ .release = NULL,
};
static struct kset mlog_kset = {
diff --git a/include/linux/kobject.h b/include/linux/kobject.h
index 55e37a5d405e..8a1332030884 100644
--- a/include/linux/kobject.h
+++ b/include/linux/kobject.h
@@ -114,7 +114,7 @@ void kobject_get_ownership(const struct kobject *kobj, kuid_t *uid, kgid_t *gid)
char *kobject_get_path(const struct kobject *kobj, gfp_t flag);
struct kobj_type {
- void (*release)(struct kobject *kobj);
+ void (*release)(struct kobject *kobj) __must_init;
const struct sysfs_ops *sysfs_ops;
const struct attribute_group **default_groups;
const struct kobj_ns_type_operations *(*child_ns_type)(const struct kobject *kobj);
--
2.56.0.455.g6c5a503b38-goog
^ permalink raw reply [flat|nested] 10+ messages in thread