Skip to content

Commit b5232c2

Browse files
Peter Zijlstragregkh
authored andcommitted
sched/topology: Fix sched_domain_span()
[ Upstream commit e379dce ] Commit 8e8e23d ("sched/topology: Compute sd_weight considering cpuset partitions") ends up relying on the fact that structure initialization should not touch the flexible array. However, the official GCC specification for "Arrays of Length Zero" [*] says: Although the size of a zero-length array is zero, an array member of this kind may increase the size of the enclosing type as a result of tail padding. Additionally, structure initialization will zero tail padding. With the end result that since offsetof(*type, member) < sizeof(*type), array initialization will clobber the flex array. Luckily, the way flexible array sizes are calculated is: sizeof(*type) + count * sizeof(*type->member) This means we have the complete size of the flex array *outside* of sizeof(*type), so use that instead of relying on the broken flex array definition. [*] https://gcc.gnu.org/onlinedocs/gcc/Zero-Length.html Fixes: 8e8e23d ("sched/topology: Compute sd_weight considering cpuset partitions") Reported-by: Nathan Chancellor <nathan@kernel.org> Debugged-by: K Prateek Nayak <kprateek.nayak@amd.com> Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org> Tested-by: Jon Hunter <jonathanh@nvidia.com> Tested-by: Chen Yu <yu.c.chen@intel.com> Tested-by: K Prateek Nayak <kprateek.nayak@amd.com> Tested-by: Nathan Chancellor <nathan@kernel.org> Link: https://patch.msgid.link/20260323093627.GY3738010@noisy.programming.kicks-ass.net Signed-off-by: Sasha Levin <sashal@kernel.org>
1 parent 87800a0 commit b5232c2

1 file changed

Lines changed: 18 additions & 6 deletions

File tree

include/linux/sched/topology.h

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -141,18 +141,30 @@ struct sched_domain {
141141

142142
unsigned int span_weight;
143143
/*
144-
* Span of all CPUs in this domain.
144+
* See sched_domain_span(), on why flex arrays are broken.
145145
*
146-
* NOTE: this field is variable length. (Allocated dynamically
147-
* by attaching extra space to the end of the structure,
148-
* depending on how many CPUs the kernel has booted up with)
149-
*/
150146
unsigned long span[];
147+
*/
151148
};
152149

153150
static inline struct cpumask *sched_domain_span(struct sched_domain *sd)
154151
{
155-
return to_cpumask(sd->span);
152+
/*
153+
* Turns out that C flexible arrays are fundamentally broken since it
154+
* is allowed for offsetof(*sd, span) < sizeof(*sd), this means that
155+
* structure initialzation *sd = { ... }; which writes every byte
156+
* inside sizeof(*type), will over-write the start of the flexible
157+
* array.
158+
*
159+
* Luckily, the way we allocate sched_domain is by:
160+
*
161+
* sizeof(*sd) + cpumask_size()
162+
*
163+
* this means that we have sufficient space for the whole flex array
164+
* *outside* of sizeof(*sd). So use that, and avoid using sd->span.
165+
*/
166+
unsigned long *bitmap = (void *)sd + sizeof(*sd);
167+
return to_cpumask(bitmap);
156168
}
157169

158170
extern void partition_sched_domains(int ndoms_new, cpumask_var_t doms_new[],

0 commit comments

Comments
 (0)