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/aGREU0XTB48w9CwN@msg.df7cb.de Fixes: 5b1b561 ("mm: simplify compat_sys_move_pages") Signed-off-by: Christoph Berg <myon@debian.org> Acked-by: David Hildenbrand <david@redhat.com> Suggested-by: David Hildenbrand <david@redhat.com> Reported-by: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reported-by: Tomas Vondra <tomas@vondra.me> Closes: https://www.postgresql.org/message-id/flat/6342f601-77de-4ee0-8c2a-3deb50ceac5b%40vondra.me#86402e3d80c031788f5f55b42c459471 Cc: Alistair Popple <apopple@nvidia.com> Cc: Byungchul Park <byungchul@sk.com> Cc: Gregory Price <gourry@gourry.net> Cc: "Huang, Ying" <ying.huang@linux.alibaba.com> Cc: Joshua Hahn <joshua.hahnjy@gmail.com> Cc: Mathew Brost <matthew.brost@intel.com> Cc: Rakie Kim <rakie.kim@sk.com> Cc: Zi Yan <ziy@nvidia.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
1 parent bb1b592 commit 10d04c2

1 file changed

Lines changed: 8 additions & 6 deletions

File tree

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)