Skip to content

Commit 16549e3

Browse files
bspengler-ossRageLtMan
authored andcommitted
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 Signed-off-by: bspengler-oss <94915855+bspengler-oss@users.noreply.github.com>
1 parent 1f3444f commit 16549e3

File tree

1 file changed

+17
-2
lines changed

1 file changed

+17
-2
lines changed

module/os/linux/zfs/abd_os.c

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -911,11 +911,19 @@ abd_iter_map(struct abd_iter *aiter)
911911
aiter->iter_mapsize = aiter->iter_abd->abd_size - offset;
912912
paddr = ABD_LINEAR_BUF(aiter->iter_abd);
913913
} else {
914+
struct page *page;
915+
914916
offset = aiter->iter_offset;
915917
aiter->iter_mapsize = MIN(aiter->iter_sg->length - offset,
916918
aiter->iter_abd->abd_size - aiter->iter_pos);
917919

918-
paddr = zfs_kmap_local(sg_page(aiter->iter_sg));
920+
page = sg_page(aiter->iter_sg);
921+
if (PageHighMem(page)) {
922+
page = nth_page(page, offset / PAGE_SIZE);
923+
offset &= ~PAGE_MASK;
924+
aiter->iter_mapsize = MIN(aiter->iter_mapsize, PAGE_SIZE - offset);
925+
}
926+
paddr = zfs_kmap_local(page);
919927
}
920928

921929
aiter->iter_mapaddr = (char *)paddr + offset;
@@ -933,8 +941,15 @@ abd_iter_unmap(struct abd_iter *aiter)
933941
return;
934942

935943
if (!abd_is_linear(aiter->iter_abd)) {
944+
struct page *page;
945+
size_t offset = aiter->iter_offset;
946+
947+
page = sg_page(aiter->iter_sg);
948+
if (PageHighMem(page))
949+
offset &= ~PAGE_MASK;
950+
936951
/* LINTED E_FUNC_SET_NOT_USED */
937-
zfs_kunmap_local(aiter->iter_mapaddr - aiter->iter_offset);
952+
zfs_kunmap_local(aiter->iter_mapaddr - offset);
938953
}
939954

940955
ASSERT3P(aiter->iter_mapaddr, !=, NULL);

0 commit comments

Comments
 (0)