Skip to content

Commit 10d04c2

Browse files
df7cbakpm00
authored andcommitted
mm/migrate: fix do_pages_stat in compat mode
For arrays with more than 16 entries, the old code would incorrectly advance the pages pointer by 16 words instead of 16 compat_uptr_t. Fix by doing the pointer arithmetic inside get_compat_pages_array where pages32 is already a correctly-typed pointer. Discovered while working on PostgreSQL 18's new NUMA introspection code. Link: https://lkml.kernel.org/r/[email protected] Fixes: 5b1b561 ("mm: simplify compat_sys_move_pages") Signed-off-by: Christoph Berg <[email protected]> Acked-by: David Hildenbrand <[email protected]> Suggested-by: David Hildenbrand <[email protected]> Reported-by: Bertrand Drouvot <[email protected]> Reported-by: Tomas Vondra <[email protected]> Closes: https://www.postgresql.org/message-id/flat/6342f601-77de-4ee0-8c2a-3deb50ceac5b%40vondra.me#86402e3d80c031788f5f55b42c459471 Cc: Alistair Popple <[email protected]> Cc: Byungchul Park <[email protected]> Cc: Gregory Price <[email protected]> Cc: "Huang, Ying" <[email protected]> Cc: Joshua Hahn <[email protected]> Cc: Mathew Brost <[email protected]> Cc: Rakie Kim <[email protected]> Cc: Zi Yan <[email protected]> Signed-off-by: Andrew Morton <[email protected]>
1 parent bb1b592 commit 10d04c2

File tree

1 file changed

+8
-6
lines changed

1 file changed

+8
-6
lines changed

mm/migrate.c

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2399,14 +2399,15 @@ static void do_pages_stat_array(struct mm_struct *mm, unsigned long nr_pages,
23992399

24002400
static int get_compat_pages_array(const void __user *chunk_pages[],
24012401
const void __user * __user *pages,
2402+
unsigned long chunk_offset,
24022403
unsigned long chunk_nr)
24032404
{
24042405
compat_uptr_t __user *pages32 = (compat_uptr_t __user *)pages;
24052406
compat_uptr_t p;
24062407
int i;
24072408

24082409
for (i = 0; i < chunk_nr; i++) {
2409-
if (get_user(p, pages32 + i))
2410+
if (get_user(p, pages32 + chunk_offset + i))
24102411
return -EFAULT;
24112412
chunk_pages[i] = compat_ptr(p);
24122413
}
@@ -2425,27 +2426,28 @@ static int do_pages_stat(struct mm_struct *mm, unsigned long nr_pages,
24252426
#define DO_PAGES_STAT_CHUNK_NR 16UL
24262427
const void __user *chunk_pages[DO_PAGES_STAT_CHUNK_NR];
24272428
int chunk_status[DO_PAGES_STAT_CHUNK_NR];
2429+
unsigned long chunk_offset = 0;
24282430

24292431
while (nr_pages) {
24302432
unsigned long chunk_nr = min(nr_pages, DO_PAGES_STAT_CHUNK_NR);
24312433

24322434
if (in_compat_syscall()) {
24332435
if (get_compat_pages_array(chunk_pages, pages,
2434-
chunk_nr))
2436+
chunk_offset, chunk_nr))
24352437
break;
24362438
} else {
2437-
if (copy_from_user(chunk_pages, pages,
2439+
if (copy_from_user(chunk_pages, pages + chunk_offset,
24382440
chunk_nr * sizeof(*chunk_pages)))
24392441
break;
24402442
}
24412443

24422444
do_pages_stat_array(mm, chunk_nr, chunk_pages, chunk_status);
24432445

2444-
if (copy_to_user(status, chunk_status, chunk_nr * sizeof(*status)))
2446+
if (copy_to_user(status + chunk_offset, chunk_status,
2447+
chunk_nr * sizeof(*status)))
24452448
break;
24462449

2447-
pages += chunk_nr;
2448-
status += chunk_nr;
2450+
chunk_offset += chunk_nr;
24492451
nr_pages -= chunk_nr;
24502452
}
24512453
return nr_pages ? -EFAULT : 0;

0 commit comments

Comments
 (0)