mirror of
https://git.proxmox.com/git/mirror_zfs.git
synced 2026-01-14 17:22:05 +03:00
Fix interaction of abd_iter_map()/abd_iter_unmap() with HIGHMEM
HIGHMEM kmap interfaces operate on only a single page at a time yet ZFS hadn't accounted for this, resulting in crashes and potential memory corruption on HIGHMEM (typically 32-bit) systems. This was caught by PaX's KERNSEAL feature as it makes use of HIGHMEM functionality on x64. On typical 64-bit systems, this issue wouldn't have been observed, as the map interfaces simply fall back to returning an address in lowmem where the contiguous pages can be accessed directly. Joint work with the PaX Team, tested by Mark van Dijk Reviewed-by: RageLtMan <rageltman@sempervictus> Reviewed-by: Rob Norris <robn@despairlabs.com> Reviewed-by: Brian Behlendorf <behlendorf1@llnl.gov> Signed-off-by: bspengler-oss <94915855+bspengler-oss@users.noreply.github.com> Closes #15668 Closes #18030
This commit is contained in:
parent
a2f768f61f
commit
5e271995d1
@ -915,7 +915,14 @@ abd_iter_map(struct abd_iter *aiter)
|
||||
aiter->iter_mapsize = MIN(aiter->iter_sg->length - offset,
|
||||
aiter->iter_abd->abd_size - aiter->iter_pos);
|
||||
|
||||
paddr = zfs_kmap_local(sg_page(aiter->iter_sg));
|
||||
struct page *page = sg_page(aiter->iter_sg);
|
||||
if (PageHighMem(page)) {
|
||||
page = nth_page(page, offset / PAGE_SIZE);
|
||||
offset &= PAGE_SIZE - 1;
|
||||
aiter->iter_mapsize = MIN(aiter->iter_mapsize,
|
||||
PAGE_SIZE - offset);
|
||||
}
|
||||
paddr = zfs_kmap_local(page);
|
||||
}
|
||||
|
||||
aiter->iter_mapaddr = (char *)paddr + offset;
|
||||
@ -933,8 +940,14 @@ abd_iter_unmap(struct abd_iter *aiter)
|
||||
return;
|
||||
|
||||
if (!abd_is_linear(aiter->iter_abd)) {
|
||||
size_t offset = aiter->iter_offset;
|
||||
|
||||
struct page *page = sg_page(aiter->iter_sg);
|
||||
if (PageHighMem(page))
|
||||
offset &= PAGE_SIZE - 1;
|
||||
|
||||
/* LINTED E_FUNC_SET_NOT_USED */
|
||||
zfs_kunmap_local(aiter->iter_mapaddr - aiter->iter_offset);
|
||||
zfs_kunmap_local(aiter->iter_mapaddr - offset);
|
||||
}
|
||||
|
||||
ASSERT3P(aiter->iter_mapaddr, !=, NULL);
|
||||
|
||||
Loading…
Reference in New Issue
Block a user