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 the array is not empty anymore and the potential address sharing is avoided. 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 unlikely to be encountered at this time, this seems mostly 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, avoid them if possible.
Reported-by: kernel test robot oliver.sang@intel.com Closes: https://lore.kernel.org/oe-lkp/202408051453.f638857e-lkp@intel.com 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 --- This was originally part of a feature series [0], but is resubmitted on its own to make it into v6.11To.
[0] https://lore.kernel.org/lkml/20240805-sysctl-const-api-v2-0-52c85f02ee5e@wei... --- 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);
--- base-commit: 3e9bff3bbe1355805de919f688bef4baefbfd436 change-id: 20240827-sysctl-const-shared-identity-9ab816e5fdfb
Best regards,
Hi Thomas,
Sorry for the delay in my response.
On Tue, Aug 27, 2024 at 11:54:43AM +0200, 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 the array is not empty anymore and the potential address sharing is avoided. 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 unlikely to be encountered at this time, this seems mostly 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, avoid them if possible.
Reported-by: kernel test robot oliver.sang@intel.com Closes: https://lore.kernel.org/oe-lkp/202408051453.f638857e-lkp@intel.com 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
This was originally part of a feature series [0], but is resubmitted on its own to make it into v6.11To.
It might be too late for 6.11 final since nobody seems to have picked it up at this point but maybe it could make 6.12-rc1 and be backported in one of the first couple of stable releases?
Regardless, thanks for sending the patch.
Acked-by: Nathan Chancellor nathan@kernel.org
[0] https://lore.kernel.org/lkml/20240805-sysctl-const-api-v2-0-52c85f02ee5e@wei...
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);
base-commit: 3e9bff3bbe1355805de919f688bef4baefbfd436 change-id: 20240827-sysctl-const-shared-identity-9ab816e5fdfb
Best regards,
Thomas Weißschuh linux@weissschuh.net
linux-stable-mirror@lists.linaro.org