The vdso_u_time_data, vdso_u_rng_data, and vdso_u_arch_data arrays
are seen by GCC as single instances (due to their declarations in
include/vdso/datapage.h). When the vdso data pointers are dereferenced
with an offset, GCC thinks there is an access beyond the returned single
instance. These are actually arrays constructed at link time, so declare
them as such.
Silence the warning seen with -Warray-bounds:
In file included from ../include/linux/export.h:5,
from ../include/linux/linkage.h:7,
from ../arch/x86/include/asm/cache.h:5,
from ../include/vdso/cache.h:5,
from ../include/linux/cache.h:6,
from ../include/linux/time.h:5,
from ../arch/x86/entry/vdso/vclock_gettime.c:11:
In function 'vdso_read_begin',
inlined from 'do_coarse_timens' at
../arch/x86/entry/vdso/../../../../lib/vdso/gettimeofday.c:204:9,
inlined from 'do_coarse' at
../arch/x86/entry/vdso/../../../../lib/vdso/gettimeofday.c:233:12,
inlined from '__cvdso_clock_gettime_common' at
../arch/x86/entry/vdso/../../../../lib/vdso/gettimeofday.c:305:10,
inlined from '__cvdso_clock_gettime_data.constprop' at
../arch/x86/entry/vdso/../../../../lib/vdso/gettimeofday.c:322:7:
../include/asm-generic/rwonce.h:44:26: error: array subscript 1024 is outside
array bounds of 'struct vdso_time_data[1]' [-Werror=array-bounds=]
...
../include/vdso/helpers.h:14:32: note: in expansion of macro 'READ_ONCE'
14 | while (unlikely((seq = READ_ONCE(vc->seq)) & 1))
| ^~~~~~~~~
Reachable via:
static __always_inline const struct vdso_time_data
*__arch_get_vdso_u_time_data(void)
{
return &vdso_u_time_data;
}
...
return __cvdso_clock_gettime_data(__arch_get_vdso_u_time_data(), clock,
ts);
...
__cvdso_clock_gettime_common(const struct vdso_time_data *vd, ...)
...
const struct vdso_clock *vc = vd->clock_data;
...
if (likely(msk & VDSO_HRES))
vc = &vc[CS_HRES_COARSE];
...
while (unlikely((seq = READ_ONCE(vc->seq)) & 1))
Signed-off-by: Kees Cook <[email protected]>
---
Cc: Andy Lutomirski <[email protected]>
Cc: Thomas Gleixner <[email protected]>
Cc: Vincenzo Frascino <[email protected]>
Cc: Arnd Bergmann <[email protected]>
Cc: <[email protected]>
---
include/asm-generic/vdso/vsyscall.h | 4 ++--
include/vdso/datapage.h | 6 +++---
arch/loongarch/vdso/vgetcpu.c | 2 +-
arch/riscv/kernel/vdso/hwprobe.c | 4 ++--
4 files changed, 8 insertions(+), 8 deletions(-)
diff --git a/include/asm-generic/vdso/vsyscall.h
b/include/asm-generic/vdso/vsyscall.h
index 5c6d9799f4e7..743056f804ed 100644
--- a/include/asm-generic/vdso/vsyscall.h
+++ b/include/asm-generic/vdso/vsyscall.h
@@ -7,14 +7,14 @@
#ifndef __arch_get_vdso_u_time_data
static __always_inline const struct vdso_time_data
*__arch_get_vdso_u_time_data(void)
{
- return &vdso_u_time_data;
+ return vdso_u_time_data;
}
#endif
#ifndef __arch_get_vdso_u_rng_data
static __always_inline const struct vdso_rng_data
*__arch_get_vdso_u_rng_data(void)
{
- return &vdso_u_rng_data;
+ return vdso_u_rng_data;
}
#endif
diff --git a/include/vdso/datapage.h b/include/vdso/datapage.h
index 23c39b96190f..8c3408c8b126 100644
--- a/include/vdso/datapage.h
+++ b/include/vdso/datapage.h
@@ -164,9 +164,9 @@ struct vdso_rng_data {
* With the hidden visibility, the compiler simply generates a PC-relative
* relocation, and this is what we need.
*/
-extern struct vdso_time_data vdso_u_time_data
__attribute__((visibility("hidden")));
-extern struct vdso_rng_data vdso_u_rng_data
__attribute__((visibility("hidden")));
-extern struct vdso_arch_data vdso_u_arch_data
__attribute__((visibility("hidden")));
+extern struct vdso_time_data vdso_u_time_data[]
__attribute__((visibility("hidden")));
+extern struct vdso_rng_data vdso_u_rng_data[]
__attribute__((visibility("hidden")));
+extern struct vdso_arch_data vdso_u_arch_data[]
__attribute__((visibility("hidden")));
extern struct vdso_time_data *vdso_k_time_data;
extern struct vdso_rng_data *vdso_k_rng_data;
diff --git a/arch/loongarch/vdso/vgetcpu.c b/arch/loongarch/vdso/vgetcpu.c
index 73af49242ecd..d09f9d860bf0 100644
--- a/arch/loongarch/vdso/vgetcpu.c
+++ b/arch/loongarch/vdso/vgetcpu.c
@@ -39,7 +39,7 @@ int __vdso_getcpu(unsigned int *cpu, unsigned int *node,
struct getcpu_cache *un
*cpu = cpu_id;
if (node)
- *node = vdso_u_arch_data.pdata[cpu_id].node;
+ *node = vdso_u_arch_data->pdata[cpu_id].node;
return 0;
}
diff --git a/arch/riscv/kernel/vdso/hwprobe.c b/arch/riscv/kernel/vdso/hwprobe.c
index 8f45500d0a6e..fc2ab4e6a9ab 100644
--- a/arch/riscv/kernel/vdso/hwprobe.c
+++ b/arch/riscv/kernel/vdso/hwprobe.c
@@ -16,7 +16,7 @@ static int riscv_vdso_get_values(struct riscv_hwprobe *pairs,
size_t pair_count,
size_t cpusetsize, unsigned long *cpus,
unsigned int flags)
{
- const struct vdso_arch_data *avd = &vdso_u_arch_data;
+ const struct vdso_arch_data *avd = vdso_u_arch_data;
bool all_cpus = !cpusetsize && !cpus;
struct riscv_hwprobe *p = pairs;
struct riscv_hwprobe *end = pairs + pair_count;
@@ -50,7 +50,7 @@ static int riscv_vdso_get_cpus(struct riscv_hwprobe *pairs,
size_t pair_count,
size_t cpusetsize, unsigned long *cpus,
unsigned int flags)
{
- const struct vdso_arch_data *avd = &vdso_u_arch_data;
+ const struct vdso_arch_data *avd = vdso_u_arch_data;
struct riscv_hwprobe *p = pairs;
struct riscv_hwprobe *end = pairs + pair_count;
unsigned char *c = (unsigned char *)cpus;
--
2.34.1