Skip to content

Commit d494deb

Browse files
Wang Haorankawasaki
authored andcommitted
iov_iter: use kmemdup_array for dup_iter to harden against overflow
While auditing the Linux 7.0-rc2 kernel, I identified a potential security vulnerability in the iov_iter framework's memory allocation logic. The dup_iter() function, which is exported via EXPORT_SYMBOL, currently uses kmemdup() with a raw multiplication to allocate the duplicate iovec array: new->iov = kmemdup(from->iov, nr_segs * sizeof(struct iovec), gfp); The hazard here is that dup_iter() relies on a primitive multiplication without any integrated overflow check. Since nr_segs is often derived from user-space input, this line is vulnerable to integer overflow (on 32-bit systems or via type narrowing), potentially leading to a small allocation followed by a large out-of-bounds memory copy. Furthermore, it allows for unbounded memory allocations, as the function lacks intrinsic knowledge of safe limits. On the 7.0-rc2 branch, several high-impact callchains still rely on this exported function: drivers/usb/gadget/function/f_fs.c: The ffs_epfile_read_iter() path demonstrates why relying on dup_iter() is dangerous: it performs allocation based on user input before verifying driver state. This confirms that dup_iter() must be hardened internally as it cannot assume pre-validated input. drivers/usb/gadget/legacy/inode.c: The ep_read_iter() path illustrates how dup_iter()’s lack of boundary awareness compounds resource risks. When combined with other allocations, it creates a multiplier effect for kernel memory pressure. This patch replaces kmemdup() with kmemdup_array(), which utilizes check_mul_overflow() to ensure the allocation size is calculated safely, hardening dup_iter() against malicious or malformed inputs from its callers Signed-off-by: Wang Haoran <[email protected]> Reviewed-by: Christoph Hellwig <[email protected]>
1 parent 482ce5b commit d494deb

1 file changed

Lines changed: 4 additions & 4 deletions

File tree

lib/iov_iter.c

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1224,13 +1224,13 @@ const void *dup_iter(struct iov_iter *new, struct iov_iter *old, gfp_t flags)
12241224
{
12251225
*new = *old;
12261226
if (iov_iter_is_bvec(new))
1227-
return new->bvec = kmemdup(new->bvec,
1228-
new->nr_segs * sizeof(struct bio_vec),
1227+
return new->bvec = kmemdup_array(new->bvec,
1228+
new->nr_segs, sizeof(struct bio_vec),
12291229
flags);
12301230
else if (iov_iter_is_kvec(new) || iter_is_iovec(new))
12311231
/* iovec and kvec have identical layout */
1232-
return new->__iov = kmemdup(new->__iov,
1233-
new->nr_segs * sizeof(struct iovec),
1232+
return new->__iov = kmemdup_array(new->__iov,
1233+
new->nr_segs, sizeof(struct iovec),
12341234
flags);
12351235
return NULL;
12361236
}

0 commit comments

Comments
 (0)