UBSAN: array-index-out-of-bounds

9 views
Skip to first unread message

Randy Dunlap

unread,
Dec 19, 2025, 11:20:16 PM12/19/25
to Kees Cook, kasa...@googlegroups.com, linux-h...@vger.kernel.org

from kernel bugzilla:
https://bugzilla.kernel.org/show_bug.cgi?id=220823


Dec 15 22:01:52 orpheus kernel: UBSAN: array-index-out-of-bounds in /var/tmp/portage/sys-kernel/gentoo-kernel-6.18.1/work/linux-6.18/drivers/mtd/devices/mtd_intel_dg.c:750:15


(from drivers/mtd/devices/mtd_intel_dg.c:)

nvm = kzalloc(struct_size(nvm, regions, nregions), GFP_KERNEL);
...

for (n = 0, i = 0; i < INTEL_DG_NVM_REGIONS; i++) {
if (!invm->regions[i].name)
continue;

char *name = kasprintf(GFP_KERNEL, "%s.%s",
dev_name(&aux_dev->dev), invm->regions[i].name);
if (!name)
continue;
750: nvm->regions[n].name = name;
nvm->regions[n].id = i;
n++;
}
nvm->nregions = n;


regions is a flexible array in struct intel_dg_nvm *nvm; [see below]
regions is counted_by nvm->nregions.

Question: does UBSAN use the value of the counted_by variable for array bounds
checking?
If so, that means nvm->nregions must be updated before the array entry
is used. Is that correct?

If not, how does UBSAN do array-bounds checking in cases like this?


struct intel_dg_nvm {
struct kref refcnt;
struct mtd_info mtd;
struct mutex lock; /* region access lock */
void __iomem *base;
void __iomem *base2;
bool non_posted_erase;

size_t size;
unsigned int nregions;
struct {
const char *name;
u8 id;
u64 offset;
u64 size;
unsigned int is_readable:1;
unsigned int is_writable:1;
} regions[] __counted_by(nregions);
};

thanks.
--
~Randy

Kees Cook

unread,
Dec 22, 2025, 6:28:43 PM12/22/25
to Randy Dunlap, kasa...@googlegroups.com, linux-h...@vger.kernel.org
On Fri, Dec 19, 2025 at 08:20:13PM -0800, Randy Dunlap wrote:
>
> from kernel bugzilla:
> https://bugzilla.kernel.org/show_bug.cgi?id=220823
>
>
> Dec 15 22:01:52 orpheus kernel: UBSAN: array-index-out-of-bounds in /var/tmp/portage/sys-kernel/gentoo-kernel-6.18.1/work/linux-6.18/drivers/mtd/devices/mtd_intel_dg.c:750:15
>
>
> (from drivers/mtd/devices/mtd_intel_dg.c:)
>
> nvm = kzalloc(struct_size(nvm, regions, nregions), GFP_KERNEL);

Yes, this needs to be immediately followed with:

nvm->nregions = nregions;

> ...
>
> for (n = 0, i = 0; i < INTEL_DG_NVM_REGIONS; i++) {
> if (!invm->regions[i].name)
> continue;
>
> char *name = kasprintf(GFP_KERNEL, "%s.%s",
> dev_name(&aux_dev->dev), invm->regions[i].name);
> if (!name)
> continue;
> 750: nvm->regions[n].name = name;
> nvm->regions[n].id = i;
> n++;
> }
> nvm->nregions = n;
>
>
> regions is a flexible array in struct intel_dg_nvm *nvm; [see below]
> regions is counted_by nvm->nregions.

Now, will nregions change again after this point? There is a question of
whether nvm->nregions represents the _allocation_ size or the _valid_
size. It seems like a max is allocated but then only populated up to a
certain point?

> Question: does UBSAN use the value of the counted_by variable for array bounds
> checking?

Yes.

> If so, that means nvm->nregions must be updated before the array entry
> is used. Is that correct?

Yes.

--
Kees Cook

Gustavo A. R. Silva

unread,
Dec 22, 2025, 9:16:16 PM12/22/25
to Kees Cook, Randy Dunlap, kasa...@googlegroups.com, linux-h...@vger.kernel.org


On 12/23/25 08:28, Kees Cook wrote:
> On Fri, Dec 19, 2025 at 08:20:13PM -0800, Randy Dunlap wrote:
>>
>> from kernel bugzilla:
>> https://bugzilla.kernel.org/show_bug.cgi?id=220823
>>
>>
>> Dec 15 22:01:52 orpheus kernel: UBSAN: array-index-out-of-bounds in /var/tmp/portage/sys-kernel/gentoo-kernel-6.18.1/work/linux-6.18/drivers/mtd/devices/mtd_intel_dg.c:750:15
>>
>>
>> (from drivers/mtd/devices/mtd_intel_dg.c:)
>>
>> nvm = kzalloc(struct_size(nvm, regions, nregions), GFP_KERNEL);
>
> Yes, this needs to be immediately followed with:
>
> nvm->nregions = nregions;
>

I submitted a fix for this that day:

https://lore.kernel.org/linux-hardening/aUZFLezigzZQVt55@kspp/

It seems someone had submitted a patch in Nov, but it was
never applied upstream.

-Gustavo
Reply all
Reply to author
Forward
0 new messages