The test if a table is a permanently empty one, inspects the address of
the registered ctl_table argument.
However as sysctl_mount_point is an empty array and does not occupy and
space it can end up sharing an address with another object in memory.
If that other object itself is a "struct ctl_table" then registering
that table will fail as it's incorrectly recognized as permanently empty.
Avoid this issue by adding a dummy element to the array so that is not
empty anymore.
Explicitly register the table with zero elements as otherwise the dummy
element would be recognized as a sentinel element which would lead to a
runtime warning from the sysctl core.
While the issue seems not being encountered at this time, this seems
mostly to be due to luck.
Also a future change, constifying sysctl_mount_point and root_table, can
reliably trigger this issue on clang 18.
Given that empty arrays are non-standard in the first place it seems
prudent to avoid them if possible.
Fixes: 4a7b29f65094 ("sysctl: move sysctl type to ctl_table_header")
Fixes: a35dd3a786f5 ("sysctl: drop now unnecessary out-of-bounds check")
Cc: stable@vger.kernel.org
Signed-off-by: Thomas Weißschuh <linux@weissschuh.net>
---
fs/proc/proc_sysctl.c | 11 ++++++++---
1 file changed, 8 insertions(+), 3 deletions(-)
diff --git a/fs/proc/proc_sysctl.c b/fs/proc/proc_sysctl.c
index 9553e77c9d31..d11ebc055ce0 100644
--- a/fs/proc/proc_sysctl.c
+++ b/fs/proc/proc_sysctl.c
@@ -29,8 +29,13 @@ static const struct inode_operations proc_sys_inode_operations;
static const struct file_operations proc_sys_dir_file_operations;
static const struct inode_operations proc_sys_dir_operations;
-/* Support for permanently empty directories */
-static struct ctl_table sysctl_mount_point[] = { };
+/*
+ * Support for permanently empty directories.
+ * Must be non-empty to avoid sharing an address with other tables.
+ */
+static struct ctl_table sysctl_mount_point[] = {
+ { }
+};
/**
* register_sysctl_mount_point() - registers a sysctl mount point
@@ -42,7 +47,7 @@ static struct ctl_table sysctl_mount_point[] = { };
*/
struct ctl_table_header *register_sysctl_mount_point(const char *path)
{
- return register_sysctl(path, sysctl_mount_point);
+ return register_sysctl_sz(path, sysctl_mount_point, 0);
}
EXPORT_SYMBOL(register_sysctl_mount_point);
--
2.46.0
Hi Joel,
On 2024-08-05 11:39:35+0000, Thomas Weißschuh wrote:
> The test if a table is a permanently empty one, inspects the address of
> the registered ctl_table argument.
> However as sysctl_mount_point is an empty array and does not occupy and
> space it can end up sharing an address with another object in memory.
> If that other object itself is a "struct ctl_table" then registering
> that table will fail as it's incorrectly recognized as permanently empty.
>
> Avoid this issue by adding a dummy element to the array so that is not
> empty anymore.
> Explicitly register the table with zero elements as otherwise the dummy
> element would be recognized as a sentinel element which would lead to a
> runtime warning from the sysctl core.
>
> While the issue seems not being encountered at this time, this seems
> mostly to be due to luck.
> Also a future change, constifying sysctl_mount_point and root_table, can
> reliably trigger this issue on clang 18.
>
> Given that empty arrays are non-standard in the first place it seems
> prudent to avoid them if possible.
>
> Fixes: 4a7b29f65094 ("sysctl: move sysctl type to ctl_table_header")
> Fixes: a35dd3a786f5 ("sysctl: drop now unnecessary out-of-bounds check")
> Cc: stable@vger.kernel.org
> Signed-off-by: Thomas Weißschuh <linux@weissschuh.net>
Any updates on this?
I fear it can theoretically also happen on v6.11.
> ---
> fs/proc/proc_sysctl.c | 11 ++++++++---
> 1 file changed, 8 insertions(+), 3 deletions(-)
>
> diff --git a/fs/proc/proc_sysctl.c b/fs/proc/proc_sysctl.c
> index 9553e77c9d31..d11ebc055ce0 100644
> --- a/fs/proc/proc_sysctl.c
> +++ b/fs/proc/proc_sysctl.c
> @@ -29,8 +29,13 @@ static const struct inode_operations proc_sys_inode_operations;
> static const struct file_operations proc_sys_dir_file_operations;
> static const struct inode_operations proc_sys_dir_operations;
>
> -/* Support for permanently empty directories */
> -static struct ctl_table sysctl_mount_point[] = { };
> +/*
> + * Support for permanently empty directories.
> + * Must be non-empty to avoid sharing an address with other tables.
> + */
> +static struct ctl_table sysctl_mount_point[] = {
> + { }
> +};
>
> /**
> * register_sysctl_mount_point() - registers a sysctl mount point
> @@ -42,7 +47,7 @@ static struct ctl_table sysctl_mount_point[] = { };
> */
> struct ctl_table_header *register_sysctl_mount_point(const char *path)
> {
> - return register_sysctl(path, sysctl_mount_point);
> + return register_sysctl_sz(path, sysctl_mount_point, 0);
> }
> EXPORT_SYMBOL(register_sysctl_mount_point);
>
>
> --
> 2.46.0
>
On Sat, Aug 24, 2024 at 08:05:08PM +0200, Thomas Weißschuh wrote:
> Hi Joel,
>
> On 2024-08-05 11:39:35+0000, Thomas Weißschuh wrote:
> > The test if a table is a permanently empty one, inspects the address of
> > the registered ctl_table argument.
> > However as sysctl_mount_point is an empty array and does not occupy and
> > space it can end up sharing an address with another object in memory.
> > If that other object itself is a "struct ctl_table" then registering
> > that table will fail as it's incorrectly recognized as permanently empty.
> >
> > Avoid this issue by adding a dummy element to the array so that is not
> > empty anymore.
> > Explicitly register the table with zero elements as otherwise the dummy
> > element would be recognized as a sentinel element which would lead to a
> > runtime warning from the sysctl core.
> >
> > While the issue seems not being encountered at this time, this seems
> > mostly to be due to luck.
> > Also a future change, constifying sysctl_mount_point and root_table, can
> > reliably trigger this issue on clang 18.
> >
> > Given that empty arrays are non-standard in the first place it seems
> > prudent to avoid them if possible.
> >
> > Fixes: 4a7b29f65094 ("sysctl: move sysctl type to ctl_table_header")
> > Fixes: a35dd3a786f5 ("sysctl: drop now unnecessary out-of-bounds check")
> > Cc: stable@vger.kernel.org
> > Signed-off-by: Thomas Weißschuh <linux@weissschuh.net>
>
> Any updates on this?
> I fear it can theoretically also happen on v6.11.
>
This is already in next and will probably make it for v6.11. The "fixed"
tag will make is so it is ported to 6.10.
Best
--
Joel Granados
(trimmed recipients to only sysctl maintainers)
Hi Joel,
On 2024-08-05 11:39:35+0000, Thomas Weißschuh wrote:
> The test if a table is a permanently empty one, inspects the address of
> the registered ctl_table argument.
> However as sysctl_mount_point is an empty array and does not occupy and
> space it can end up sharing an address with another object in memory.
> If that other object itself is a "struct ctl_table" then registering
> that table will fail as it's incorrectly recognized as permanently empty.
>
> Avoid this issue by adding a dummy element to the array so that is not
> empty anymore.
> Explicitly register the table with zero elements as otherwise the dummy
> element would be recognized as a sentinel element which would lead to a
> runtime warning from the sysctl core.
>
> While the issue seems not being encountered at this time, this seems
> mostly to be due to luck.
> Also a future change, constifying sysctl_mount_point and root_table, can
> reliably trigger this issue on clang 18.
>
> Given that empty arrays are non-standard in the first place it seems
> prudent to avoid them if possible.
Unfortunately I forgot to include the following trailers in this patch:
Reported-by: kernel test robot <oliver.sang@intel.com>
Closes: https://lore.kernel.org/oe-lkp/202408051453.f638857e-lkp@intel.com
They will be part of v3 if it comes to that, but if you end up applying
v2, please do also add those trailers.
> Fixes: 4a7b29f65094 ("sysctl: move sysctl type to ctl_table_header")
> Fixes: a35dd3a786f5 ("sysctl: drop now unnecessary out-of-bounds check")
> Cc: stable@vger.kernel.org
> Signed-off-by: Thomas Weißschuh <linux@weissschuh.net>
> ---
> fs/proc/proc_sysctl.c | 11 ++++++++---
> 1 file changed, 8 insertions(+), 3 deletions(-)
>
> diff --git a/fs/proc/proc_sysctl.c b/fs/proc/proc_sysctl.c
> index 9553e77c9d31..d11ebc055ce0 100644
> --- a/fs/proc/proc_sysctl.c
> +++ b/fs/proc/proc_sysctl.c
> @@ -29,8 +29,13 @@ static const struct inode_operations proc_sys_inode_operations;
> static const struct file_operations proc_sys_dir_file_operations;
> static const struct inode_operations proc_sys_dir_operations;
>
> -/* Support for permanently empty directories */
> -static struct ctl_table sysctl_mount_point[] = { };
> +/*
> + * Support for permanently empty directories.
> + * Must be non-empty to avoid sharing an address with other tables.
> + */
> +static struct ctl_table sysctl_mount_point[] = {
> + { }
> +};
>
> /**
> * register_sysctl_mount_point() - registers a sysctl mount point
> @@ -42,7 +47,7 @@ static struct ctl_table sysctl_mount_point[] = { };
> */
> struct ctl_table_header *register_sysctl_mount_point(const char *path)
> {
> - return register_sysctl(path, sysctl_mount_point);
> + return register_sysctl_sz(path, sysctl_mount_point, 0);
> }
> EXPORT_SYMBOL(register_sysctl_mount_point);
Thanks,
Thomas
On Mon, Aug 05, 2024 at 01:51:55PM +0200, Thomas Weißschuh wrote: > (trimmed recipients to only sysctl maintainers) > > Hi Joel, > > On 2024-08-05 11:39:35+0000, Thomas Weißschuh wrote: > > The test if a table is a permanently empty one, inspects the address of > > the registered ctl_table argument. > > However as sysctl_mount_point is an empty array and does not occupy and > > space it can end up sharing an address with another object in memory. > > If that other object itself is a "struct ctl_table" then registering > > that table will fail as it's incorrectly recognized as permanently empty. > > > > Avoid this issue by adding a dummy element to the array so that is not > > empty anymore. > > Explicitly register the table with zero elements as otherwise the dummy > > element would be recognized as a sentinel element which would lead to a > > runtime warning from the sysctl core. > > > > While the issue seems not being encountered at this time, this seems > > mostly to be due to luck. > > Also a future change, constifying sysctl_mount_point and root_table, can > > reliably trigger this issue on clang 18. > > > > Given that empty arrays are non-standard in the first place it seems > > prudent to avoid them if possible. > > Unfortunately I forgot to include the following trailers in this patch: > > Reported-by: kernel test robot <oliver.sang@intel.com> > Closes: https://lore.kernel.org/oe-lkp/202408051453.f638857e-lkp@intel.com > > They will be part of v3 if it comes to that, but if you end up applying > v2, please do also add those trailers. > This is a bugfix and it should be included in the next release. Please send this commit separately with the Reported-by tag, I'll make sure that this gets pushed up for 6.11. I'll add reviewing the rest of the patchset to my "coming back from PTO" todolist. But since we are so late in the cycle, it might get bumped to the next release. Thx -- Joel Granados
© 2016 - 2025 Red Hat, Inc.