linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH] Fix do_pages_stat to use compat_uptr_t
       [not found] ` <d42cc185-b774-4d5e-9a51-0581dd5f3962@arm.com>
@ 2025-06-25 15:24   ` Christoph Berg
  2025-06-25 15:42     ` David Hildenbrand
  2025-06-25 20:39     ` [PATCH] Fix do_pages_stat to use compat_uptr_t Andrew Morton
  0 siblings, 2 replies; 12+ messages in thread
From: Christoph Berg @ 2025-06-25 15:24 UTC (permalink / raw)
  To: Andrew Morton, David Hildenbrand, Zi Yan, Matthew Brost,
	Joshua Hahn, Rakie Kim, Byungchul Park, Gregory Price, Ying Huang,
	Alistair Popple,
	open list:MEMORY MANAGEMENT - MEMORY POLICY AND MIGRATION,
	open list

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.

Signed-off-by: Christoph Berg <myon@debian.org>
Suggested-by: Bertrand Drouvot <bertranddrouvot.pg@gmail.com>
---
 mm/migrate.c | 8 +++++++-
 1 file changed, 7 insertions(+), 1 deletion(-)

diff --git a/mm/migrate.c b/mm/migrate.c
index 8cf0f9c9599..542c81ec3ed 100644
--- a/mm/migrate.c
+++ b/mm/migrate.c
@@ -2444,7 +2444,13 @@ static int do_pages_stat(struct mm_struct *mm, unsigned long nr_pages,
 		if (copy_to_user(status, chunk_status, chunk_nr * sizeof(*status)))
 			break;
 
-		pages += chunk_nr;
+		if (in_compat_syscall()) {
+			compat_uptr_t __user *pages32 = (compat_uptr_t __user *)pages;
+
+			pages32 += chunk_nr;
+			pages = (const void __user * __user *) pages32;
+		} else
+			pages += chunk_nr;
 		status += chunk_nr;
 		nr_pages -= chunk_nr;
 	}
-- 
2.47.2


^ permalink raw reply related	[flat|nested] 12+ messages in thread

* Re: [PATCH] Fix do_pages_stat to use compat_uptr_t
  2025-06-25 15:24   ` [PATCH] Fix do_pages_stat to use compat_uptr_t Christoph Berg
@ 2025-06-25 15:42     ` David Hildenbrand
  2025-07-01 16:58       ` [PATCH v2] mm/migrate: Fix do_pages_stat in 32-bit mode Christoph Berg
  2025-06-25 20:39     ` [PATCH] Fix do_pages_stat to use compat_uptr_t Andrew Morton
  1 sibling, 1 reply; 12+ messages in thread
From: David Hildenbrand @ 2025-06-25 15:42 UTC (permalink / raw)
  To: Christoph Berg, Andrew Morton, Zi Yan, Matthew Brost, Joshua Hahn,
	Rakie Kim, Byungchul Park, Gregory Price, Ying Huang,
	Alistair Popple,
	open list:MEMORY MANAGEMENT - MEMORY POLICY AND MIGRATION,
	open list

On 25.06.25 17:24, Christoph Berg wrote:

Subject should start with "mm/migrate:"

> 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.
> 
> Signed-off-by: Christoph Berg <myon@debian.org>
> Suggested-by: Bertrand Drouvot <bertranddrouvot.pg@gmail.com>

Likely we want a

Fixes:

and then this is probably "Reported-by:" paired with a "Closes:" link
to any such report.

But I'm wondering how long this has already been like that. :)

> ---
>   mm/migrate.c | 8 +++++++-
>   1 file changed, 7 insertions(+), 1 deletion(-)
> 
> diff --git a/mm/migrate.c b/mm/migrate.c
> index 8cf0f9c9599..542c81ec3ed 100644
> --- a/mm/migrate.c
> +++ b/mm/migrate.c
> @@ -2444,7 +2444,13 @@ static int do_pages_stat(struct mm_struct *mm, unsigned long nr_pages,
>   		if (copy_to_user(status, chunk_status, chunk_nr * sizeof(*status)))
>   			break;
>   
> -		pages += chunk_nr;
> +		if (in_compat_syscall()) {
> +			compat_uptr_t __user *pages32 = (compat_uptr_t __user *)pages;
> +
> +			pages32 += chunk_nr;
> +			pages = (const void __user * __user *) pages32;
> +		} else
> +			pages += chunk_nr;
>   		status += chunk_nr;
>   		nr_pages -= chunk_nr;
>   	}

Something a bit more elegant might be:

diff --git a/mm/migrate.c b/mm/migrate.c
index ea8c74d996592..fc99448771041 100644
--- a/mm/migrate.c
+++ b/mm/migrate.c
@@ -2398,6 +2398,7 @@ static void do_pages_stat_array(struct mm_struct *mm, unsigned long nr_pages,
  
  static int get_compat_pages_array(const void __user *chunk_pages[],
                                   const void __user * __user *pages,
+                                 unsigned long chunk_offs,
                                   unsigned long chunk_nr)
  {
         compat_uptr_t __user *pages32 = (compat_uptr_t __user *)pages;
@@ -2405,7 +2406,7 @@ static int get_compat_pages_array(const void __user *chunk_pages[],
         int i;
  
         for (i = 0; i < chunk_nr; i++) {
-               if (get_user(p, pages32 + i))
+               if (get_user(p, pages32 + i + chunk_offs))
                         return -EFAULT;
                 chunk_pages[i] = compat_ptr(p);
         }
@@ -2424,13 +2425,14 @@ static int do_pages_stat(struct mm_struct *mm, unsigned long nr_pages,
  #define DO_PAGES_STAT_CHUNK_NR 16UL
         const void __user *chunk_pages[DO_PAGES_STAT_CHUNK_NR];
         int chunk_status[DO_PAGES_STAT_CHUNK_NR];
+       unsigned long chunk_offs = 0;
  
         while (nr_pages) {
                 unsigned long chunk_nr = min(nr_pages, DO_PAGES_STAT_CHUNK_NR);
  
                 if (in_compat_syscall()) {
                         if (get_compat_pages_array(chunk_pages, pages,
-                                                  chunk_nr))
+                                                  chunk_offs, chunk_nr))
                                 break;
                 } else {
                         if (copy_from_user(chunk_pages, pages,
@@ -2440,11 +2442,11 @@ static int do_pages_stat(struct mm_struct *mm, unsigned long nr_pages,
  
                 do_pages_stat_array(mm, chunk_nr, chunk_pages, chunk_status);
  
-               if (copy_to_user(status, chunk_status, chunk_nr * sizeof(*status)))
+               if (copy_to_user(status + chunk_offs, chunk_status,
+                                chunk_nr * sizeof(*status)))
                         break;
  
-               pages += chunk_nr;
-               status += chunk_nr;
+               chunk_offs += chunk_nr;
                 nr_pages -= chunk_nr;
         }
         return nr_pages ? -EFAULT : 0;

(untested, of course)


-- 
Cheers,

David / dhildenb


^ permalink raw reply related	[flat|nested] 12+ messages in thread

* Re: [PATCH] Fix do_pages_stat to use compat_uptr_t
  2025-06-25 15:24   ` [PATCH] Fix do_pages_stat to use compat_uptr_t Christoph Berg
  2025-06-25 15:42     ` David Hildenbrand
@ 2025-06-25 20:39     ` Andrew Morton
  2025-06-25 21:10       ` Christoph Berg
  1 sibling, 1 reply; 12+ messages in thread
From: Andrew Morton @ 2025-06-25 20:39 UTC (permalink / raw)
  To: Christoph Berg
  Cc: David Hildenbrand, Zi Yan, Matthew Brost, Joshua Hahn, Rakie Kim,
	Byungchul Park, Gregory Price, Ying Huang, Alistair Popple,
	open list:MEMORY MANAGEMENT - MEMORY POLICY AND MIGRATION,
	open list

On Wed, 25 Jun 2025 17:24:14 +0200 Christoph Berg <myon@debian.org> wrote:

> 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.
> 
> ...
>
> --- a/mm/migrate.c
> +++ b/mm/migrate.c
> @@ -2444,7 +2444,13 @@ static int do_pages_stat(struct mm_struct *mm, unsigned long nr_pages,
>  		if (copy_to_user(status, chunk_status, chunk_nr * sizeof(*status)))
>  			break;
>  
> -		pages += chunk_nr;
> +		if (in_compat_syscall()) {
> +			compat_uptr_t __user *pages32 = (compat_uptr_t __user *)pages;
> +
> +			pages32 += chunk_nr;
> +			pages = (const void __user * __user *) pages32;
> +		} else
> +			pages += chunk_nr;
>  		status += chunk_nr;
>  		nr_pages -= chunk_nr;
>  	}

Seems this has been present since 2010.

I'll update the Subject: as David suggests and I'll add a cc:stable,
thanks.  I'll also add a note that David suggested an alternative, so
please let's advance that option.

Also, a coding-style tweak:

--- a/mm/migrate.c~fix-do_pages_stat-to-use-compat_uptr_t-fix
+++ a/mm/migrate.c
@@ -2449,8 +2449,9 @@ static int do_pages_stat(struct mm_struc
 
 			pages32 += chunk_nr;
 			pages = (const void __user * __user *) pages32;
-		} else
+		} else {
 			pages += chunk_nr;
+		}
 		status += chunk_nr;
 		nr_pages -= chunk_nr;
 	}
_


^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH] Fix do_pages_stat to use compat_uptr_t
  2025-06-25 20:39     ` [PATCH] Fix do_pages_stat to use compat_uptr_t Andrew Morton
@ 2025-06-25 21:10       ` Christoph Berg
  2025-06-25 21:15         ` Andrew Morton
  0 siblings, 1 reply; 12+ messages in thread
From: Christoph Berg @ 2025-06-25 21:10 UTC (permalink / raw)
  To: Andrew Morton
  Cc: David Hildenbrand, Zi Yan, Matthew Brost, Joshua Hahn, Rakie Kim,
	Byungchul Park, Gregory Price, Ying Huang, Alistair Popple,
	open list:MEMORY MANAGEMENT - MEMORY POLICY AND MIGRATION,
	open list

Re: Andrew Morton
> I'll update the Subject: as David suggests and I'll add a cc:stable,
> thanks.  I'll also add a note that David suggested an alternative, so
> please let's advance that option.

Sorry, I'm new here. Do I have to do anything now? The above sounds
like the alternative coding by David would be preferred, but the other
mails say the patches have already been pushed to a hotfix branch? Or
are we doing both, i.e. stable gets the simple fix and next the pretty
one?

Christoph

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH] Fix do_pages_stat to use compat_uptr_t
  2025-06-25 21:10       ` Christoph Berg
@ 2025-06-25 21:15         ` Andrew Morton
  2025-06-26  8:16           ` David Hildenbrand
  0 siblings, 1 reply; 12+ messages in thread
From: Andrew Morton @ 2025-06-25 21:15 UTC (permalink / raw)
  To: Christoph Berg
  Cc: David Hildenbrand, Zi Yan, Matthew Brost, Joshua Hahn, Rakie Kim,
	Byungchul Park, Gregory Price, Ying Huang, Alistair Popple,
	open list:MEMORY MANAGEMENT - MEMORY POLICY AND MIGRATION,
	open list

On Wed, 25 Jun 2025 23:10:13 +0200 Christoph Berg <myon@debian.org> wrote:

> Re: Andrew Morton
> > I'll update the Subject: as David suggests and I'll add a cc:stable,
> > thanks.  I'll also add a note that David suggested an alternative, so
> > please let's advance that option.
> 
> Sorry, I'm new here. Do I have to do anything now? The above sounds
> like the alternative coding by David would be preferred, but the other
> mails say the patches have already been pushed to a hotfix branch? Or
> are we doing both, i.e. stable gets the simple fix and next the pretty
> one?

Well I added the v1 patch for testing and so it doesn't get lost -
fixing the bug is the most important thing.

But if a nicer v2 patch is sent in the next few days, I can switch to
that version.


^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH] Fix do_pages_stat to use compat_uptr_t
  2025-06-25 21:15         ` Andrew Morton
@ 2025-06-26  8:16           ` David Hildenbrand
  2025-06-26 19:21             ` Christoph Berg
  0 siblings, 1 reply; 12+ messages in thread
From: David Hildenbrand @ 2025-06-26  8:16 UTC (permalink / raw)
  To: Andrew Morton, Christoph Berg
  Cc: Zi Yan, Matthew Brost, Joshua Hahn, Rakie Kim, Byungchul Park,
	Gregory Price, Ying Huang, Alistair Popple,
	open list:MEMORY MANAGEMENT - MEMORY POLICY AND MIGRATION,
	open list

On 25.06.25 23:15, Andrew Morton wrote:
> On Wed, 25 Jun 2025 23:10:13 +0200 Christoph Berg <myon@debian.org> wrote:
> 
>> Re: Andrew Morton
>>> I'll update the Subject: as David suggests and I'll add a cc:stable,
>>> thanks.  I'll also add a note that David suggested an alternative, so
>>> please let's advance that option.
>>
>> Sorry, I'm new here. Do I have to do anything now? The above sounds
>> like the alternative coding by David would be preferred

See if my proposal makes sense, and then incorporate+test it.

You can feel free to add my

Suggested-by: David Hildenbrand <david@redhat.com>

-- 
Cheers,

David / dhildenb


^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH] Fix do_pages_stat to use compat_uptr_t
  2025-06-26  8:16           ` David Hildenbrand
@ 2025-06-26 19:21             ` Christoph Berg
  0 siblings, 0 replies; 12+ messages in thread
From: Christoph Berg @ 2025-06-26 19:21 UTC (permalink / raw)
  To: David Hildenbrand
  Cc: Andrew Morton, Zi Yan, Matthew Brost, Joshua Hahn, Rakie Kim,
	Byungchul Park, Gregory Price, Ying Huang, Alistair Popple,
	open list:MEMORY MANAGEMENT - MEMORY POLICY AND MIGRATION,
	open list

Re: David Hildenbrand
> See if my proposal makes sense, and then incorporate+test it.
> 
> You can feel free to add my
> 
> Suggested-by: David Hildenbrand <david@redhat.com>

Thanks, will do. But it will be next week, currently busy with the ham
radio fair in Friedrichshafen.

Christoph

^ permalink raw reply	[flat|nested] 12+ messages in thread

* [PATCH v2] mm/migrate: Fix do_pages_stat in 32-bit mode
  2025-06-25 15:42     ` David Hildenbrand
@ 2025-07-01 16:58       ` Christoph Berg
  2025-07-01 17:09         ` Zi Yan
  0 siblings, 1 reply; 12+ messages in thread
From: Christoph Berg @ 2025-07-01 16:58 UTC (permalink / raw)
  To: David Hildenbrand, Andrew Morton
  Cc: Zi Yan, Matthew Brost, Joshua Hahn, Rakie Kim, Byungchul Park,
	Gregory Price, Ying Huang, Alistair Popple,
	open list:MEMORY MANAGEMENT - MEMORY POLICY AND MIGRATION,
	open list

Re: David Hildenbrand
> Subject should start with "mm/migrate:"
> Likely we want a
> Fixes:
> and then this is probably "Reported-by:" paired with a "Closes:" link
> to any such report.

I included these now, except for "Closes:" which I have to idea what
to put in.

> But I'm wondering how long this has already been like that. :)

The now-offending "pages += chunk_nr" line is from 2010, but I think
the bug is rather from 5b1b561ba73c8ab9c98e5dfd14dc7ee47efb6530 (2021)
which reshuffled the array-vs-32-bit handling.

> Something a bit more elegant might be:

Thanks, I used your patch draft with some minor changes.

>  static int get_compat_pages_array(const void __user *chunk_pages[],
>                                   const void __user * __user *pages,
> +                                 unsigned long chunk_offs,

I replaced chunk_offs with "chunk_offset" since "offs" looked too much
like plural (list of offsets) to me.

>                 if (in_compat_syscall()) {
>                         if (get_compat_pages_array(chunk_pages, pages,
> -                                                  chunk_nr))
> +                                                  chunk_offs, chunk_nr))
>                                 break;
>                 } else {
>                         if (copy_from_user(chunk_pages, pages,

The else branch here needs tweaking as well:

                } else {
-                       if (copy_from_user(chunk_pages, pages,
+                       if (copy_from_user(chunk_pages, pages + chunk_offset,
                                      chunk_nr * sizeof(*chunk_pages)))


> @@ -2440,11 +2442,11 @@ static int do_pages_stat(struct mm_struct *mm, unsigned long nr_pages,
>                 do_pages_stat_array(mm, chunk_nr, chunk_pages, chunk_status);
> -               if (copy_to_user(status, chunk_status, chunk_nr * sizeof(*status)))
> +               if (copy_to_user(status + chunk_offs, chunk_status,
> +                                chunk_nr * sizeof(*status)))

This seems to work, but honestly I am wondering, if copy_from_user
needs a special 32-bit case, doesn't copy_to_user need special casing
as well?

> (untested, of course)

The attached patch makes PG18's new numa test pass on amd64 kernels
both in amd64 and i386 userlands.

(In the meantime, PG git head got a workaround that limits the chunk
size to the same 16 as used in do_pages_stat; I tested with the
version before that.)

Christoph


From fdbcbc88825bc2e857dfeeebc91d62864e0774dd Mon Sep 17 00:00:00 2001
From: Christoph Berg <myon@debian.org>
Date: Tue, 24 Jun 2025 16:44:27 +0200
Subject: [PATCH v2] mm/migrate: Fix do_pages_stat in 32-bit 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.

Signed-off-by: Christoph Berg <myon@debian.org>
Reported-by: Bertrand Drouvot <bertranddrouvot.pg@gmail.com>
Reported-by: Tomas Vondra <tomas@vondra.me>
Suggested-by: David Hildenbrand <david@redhat.com>
Fixes: 5b1b561ba73c8ab9c98e5dfd14dc7ee47efb6530
---
 mm/migrate.c | 14 ++++++++------
 1 file changed, 8 insertions(+), 6 deletions(-)

diff --git a/mm/migrate.c b/mm/migrate.c
index 8cf0f9c9599d..2c88f3b33833 100644
--- a/mm/migrate.c
+++ b/mm/migrate.c
@@ -2399,6 +2399,7 @@ static void do_pages_stat_array(struct mm_struct *mm, unsigned long nr_pages,
 
 static int get_compat_pages_array(const void __user *chunk_pages[],
 				  const void __user * __user *pages,
+				  unsigned long chunk_offset,
 				  unsigned long chunk_nr)
 {
 	compat_uptr_t __user *pages32 = (compat_uptr_t __user *)pages;
@@ -2406,7 +2407,7 @@ static int get_compat_pages_array(const void __user *chunk_pages[],
 	int i;
 
 	for (i = 0; i < chunk_nr; i++) {
-		if (get_user(p, pages32 + i))
+		if (get_user(p, pages32 + chunk_offset + i))
 			return -EFAULT;
 		chunk_pages[i] = compat_ptr(p);
 	}
@@ -2425,27 +2426,28 @@ static int do_pages_stat(struct mm_struct *mm, unsigned long nr_pages,
 #define DO_PAGES_STAT_CHUNK_NR 16UL
 	const void __user *chunk_pages[DO_PAGES_STAT_CHUNK_NR];
 	int chunk_status[DO_PAGES_STAT_CHUNK_NR];
+	unsigned long chunk_offset = 0;
 
 	while (nr_pages) {
 		unsigned long chunk_nr = min(nr_pages, DO_PAGES_STAT_CHUNK_NR);
 
 		if (in_compat_syscall()) {
 			if (get_compat_pages_array(chunk_pages, pages,
-						   chunk_nr))
+						   chunk_offset, chunk_nr))
 				break;
 		} else {
-			if (copy_from_user(chunk_pages, pages,
+			if (copy_from_user(chunk_pages, pages + chunk_offset,
 				      chunk_nr * sizeof(*chunk_pages)))
 				break;
 		}
 
 		do_pages_stat_array(mm, chunk_nr, chunk_pages, chunk_status);
 
-		if (copy_to_user(status, chunk_status, chunk_nr * sizeof(*status)))
+		if (copy_to_user(status + chunk_offset, chunk_status,
+				 chunk_nr * sizeof(*status)))
 			break;
 
-		pages += chunk_nr;
-		status += chunk_nr;
+		chunk_offset += chunk_nr;
 		nr_pages -= chunk_nr;
 	}
 	return nr_pages ? -EFAULT : 0;
-- 
2.47.2


^ permalink raw reply related	[flat|nested] 12+ messages in thread

* Re: [PATCH v2] mm/migrate: Fix do_pages_stat in 32-bit mode
  2025-07-01 16:58       ` [PATCH v2] mm/migrate: Fix do_pages_stat in 32-bit mode Christoph Berg
@ 2025-07-01 17:09         ` Zi Yan
  2025-07-01 17:55           ` [PATCH v3] " Christoph Berg
  0 siblings, 1 reply; 12+ messages in thread
From: Zi Yan @ 2025-07-01 17:09 UTC (permalink / raw)
  To: Christoph Berg
  Cc: David Hildenbrand, Andrew Morton, Matthew Brost, Joshua Hahn,
	Rakie Kim, Byungchul Park, Gregory Price, Ying Huang,
	Alistair Popple,
	open list:MEMORY MANAGEMENT - MEMORY POLICY AND MIGRATION,
	open list

On 1 Jul 2025, at 12:58, Christoph Berg wrote:

> Re: David Hildenbrand
>> Subject should start with "mm/migrate:"
>> Likely we want a
>> Fixes:
>> and then this is probably "Reported-by:" paired with a "Closes:" link
>> to any such report.
>
> I included these now, except for "Closes:" which I have to idea what
> to put in.

Fixes should be:

Fixes: 5b1b561ba73c ("mm: simplify compat_sys_move_pages")

Closes could be a link to the bug report.

>
>> But I'm wondering how long this has already been like that. :)
>
> The now-offending "pages += chunk_nr" line is from 2010, but I think
> the bug is rather from 5b1b561ba73c8ab9c98e5dfd14dc7ee47efb6530 (2021)
> which reshuffled the array-vs-32-bit handling.
>
>> Something a bit more elegant might be:
>
> Thanks, I used your patch draft with some minor changes.
>
>>  static int get_compat_pages_array(const void __user *chunk_pages[],
>>                                   const void __user * __user *pages,
>> +                                 unsigned long chunk_offs,
>
> I replaced chunk_offs with "chunk_offset" since "offs" looked too much
> like plural (list of offsets) to me.
>
>>                 if (in_compat_syscall()) {
>>                         if (get_compat_pages_array(chunk_pages, pages,
>> -                                                  chunk_nr))
>> +                                                  chunk_offs, chunk_nr))
>>                                 break;
>>                 } else {
>>                         if (copy_from_user(chunk_pages, pages,
>
> The else branch here needs tweaking as well:
>
>                 } else {
> -                       if (copy_from_user(chunk_pages, pages,
> +                       if (copy_from_user(chunk_pages, pages + chunk_offset,
>                                       chunk_nr * sizeof(*chunk_pages)))
>
>
>> @@ -2440,11 +2442,11 @@ static int do_pages_stat(struct mm_struct *mm, unsigned long nr_pages,
>>                 do_pages_stat_array(mm, chunk_nr, chunk_pages, chunk_status);
>> -               if (copy_to_user(status, chunk_status, chunk_nr * sizeof(*status)))
>> +               if (copy_to_user(status + chunk_offs, chunk_status,
>> +                                chunk_nr * sizeof(*status)))
>
> This seems to work, but honestly I am wondering, if copy_from_user
> needs a special 32-bit case, doesn't copy_to_user need special casing
> as well?
>
>> (untested, of course)
>
> The attached patch makes PG18's new numa test pass on amd64 kernels
> both in amd64 and i386 userlands.
>
> (In the meantime, PG git head got a workaround that limits the chunk
> size to the same 16 as used in do_pages_stat; I tested with the
> version before that.)
>
> Christoph
>
>
> From fdbcbc88825bc2e857dfeeebc91d62864e0774dd Mon Sep 17 00:00:00 2001
> From: Christoph Berg <myon@debian.org>
> Date: Tue, 24 Jun 2025 16:44:27 +0200
> Subject: [PATCH v2] mm/migrate: Fix do_pages_stat in 32-bit 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.
>
> Signed-off-by: Christoph Berg <myon@debian.org>
> Reported-by: Bertrand Drouvot <bertranddrouvot.pg@gmail.com>
> Reported-by: Tomas Vondra <tomas@vondra.me>
> Suggested-by: David Hildenbrand <david@redhat.com>
> Fixes: 5b1b561ba73c8ab9c98e5dfd14dc7ee47efb6530
> ---
>  mm/migrate.c | 14 ++++++++------
>  1 file changed, 8 insertions(+), 6 deletions(-)
>
> diff --git a/mm/migrate.c b/mm/migrate.c
> index 8cf0f9c9599d..2c88f3b33833 100644
> --- a/mm/migrate.c
> +++ b/mm/migrate.c
> @@ -2399,6 +2399,7 @@ static void do_pages_stat_array(struct mm_struct *mm, unsigned long nr_pages,
>
>  static int get_compat_pages_array(const void __user *chunk_pages[],
>  				  const void __user * __user *pages,
> +				  unsigned long chunk_offset,
>  				  unsigned long chunk_nr)
>  {
>  	compat_uptr_t __user *pages32 = (compat_uptr_t __user *)pages;
> @@ -2406,7 +2407,7 @@ static int get_compat_pages_array(const void __user *chunk_pages[],
>  	int i;
>
>  	for (i = 0; i < chunk_nr; i++) {
> -		if (get_user(p, pages32 + i))
> +		if (get_user(p, pages32 + chunk_offset + i))
>  			return -EFAULT;
>  		chunk_pages[i] = compat_ptr(p);
>  	}
> @@ -2425,27 +2426,28 @@ static int do_pages_stat(struct mm_struct *mm, unsigned long nr_pages,
>  #define DO_PAGES_STAT_CHUNK_NR 16UL
>  	const void __user *chunk_pages[DO_PAGES_STAT_CHUNK_NR];
>  	int chunk_status[DO_PAGES_STAT_CHUNK_NR];
> +	unsigned long chunk_offset = 0;
>
>  	while (nr_pages) {
>  		unsigned long chunk_nr = min(nr_pages, DO_PAGES_STAT_CHUNK_NR);
>
>  		if (in_compat_syscall()) {
>  			if (get_compat_pages_array(chunk_pages, pages,
> -						   chunk_nr))
> +						   chunk_offset, chunk_nr))
>  				break;
>  		} else {
> -			if (copy_from_user(chunk_pages, pages,
> +			if (copy_from_user(chunk_pages, pages + chunk_offset,
>  				      chunk_nr * sizeof(*chunk_pages)))
>  				break;
>  		}
>
>  		do_pages_stat_array(mm, chunk_nr, chunk_pages, chunk_status);
>
> -		if (copy_to_user(status, chunk_status, chunk_nr * sizeof(*status)))
> +		if (copy_to_user(status + chunk_offset, chunk_status,
> +				 chunk_nr * sizeof(*status)))
>  			break;
>
> -		pages += chunk_nr;
> -		status += chunk_nr;
> +		chunk_offset += chunk_nr;
>  		nr_pages -= chunk_nr;
>  	}
>  	return nr_pages ? -EFAULT : 0;
> -- 
> 2.47.2


Best Regards,
Yan, Zi

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH v3] mm/migrate: Fix do_pages_stat in 32-bit mode
  2025-07-01 17:09         ` Zi Yan
@ 2025-07-01 17:55           ` Christoph Berg
  2025-07-01 18:17             ` David Hildenbrand
  0 siblings, 1 reply; 12+ messages in thread
From: Christoph Berg @ 2025-07-01 17:55 UTC (permalink / raw)
  To: Zi Yan
  Cc: David Hildenbrand, Andrew Morton, Matthew Brost, Joshua Hahn,
	Rakie Kim, Byungchul Park, Gregory Price, Ying Huang,
	Alistair Popple,
	open list:MEMORY MANAGEMENT - MEMORY POLICY AND MIGRATION,
	open list

Re: Zi Yan
> Fixes should be:
> 
> Fixes: 5b1b561ba73c ("mm: simplify compat_sys_move_pages")
> 
> Closes could be a link to the bug report.

Updated, thanks.

> > This seems to work, but honestly I am wondering, if copy_from_user
> > needs a special 32-bit case, doesn't copy_to_user need special casing
> > as well?

Scratch that, it works because an int[] is copied back, and that's
always the same size.

So I think the patch is good to go.

Christoph


From 426c93d558572248273cf386ca784626ae431413 Mon Sep 17 00:00:00 2001
From: Christoph Berg <myon@debian.org>
Date: Tue, 24 Jun 2025 16:44:27 +0200
Subject: [PATCH v3] mm/migrate: Fix do_pages_stat in 32-bit 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.

Signed-off-by: Christoph Berg <myon@debian.org>
Suggested-by: David Hildenbrand <david@redhat.com>
Fixes: 5b1b561ba73c ("mm: simplify compat_sys_move_pages")
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
---
 mm/migrate.c | 14 ++++++++------
 1 file changed, 8 insertions(+), 6 deletions(-)

diff --git a/mm/migrate.c b/mm/migrate.c
index 8cf0f9c9599d..2c88f3b33833 100644
--- a/mm/migrate.c
+++ b/mm/migrate.c
@@ -2399,6 +2399,7 @@ static void do_pages_stat_array(struct mm_struct *mm, unsigned long nr_pages,
 
 static int get_compat_pages_array(const void __user *chunk_pages[],
 				  const void __user * __user *pages,
+				  unsigned long chunk_offset,
 				  unsigned long chunk_nr)
 {
 	compat_uptr_t __user *pages32 = (compat_uptr_t __user *)pages;
@@ -2406,7 +2407,7 @@ static int get_compat_pages_array(const void __user *chunk_pages[],
 	int i;
 
 	for (i = 0; i < chunk_nr; i++) {
-		if (get_user(p, pages32 + i))
+		if (get_user(p, pages32 + chunk_offset + i))
 			return -EFAULT;
 		chunk_pages[i] = compat_ptr(p);
 	}
@@ -2425,27 +2426,28 @@ static int do_pages_stat(struct mm_struct *mm, unsigned long nr_pages,
 #define DO_PAGES_STAT_CHUNK_NR 16UL
 	const void __user *chunk_pages[DO_PAGES_STAT_CHUNK_NR];
 	int chunk_status[DO_PAGES_STAT_CHUNK_NR];
+	unsigned long chunk_offset = 0;
 
 	while (nr_pages) {
 		unsigned long chunk_nr = min(nr_pages, DO_PAGES_STAT_CHUNK_NR);
 
 		if (in_compat_syscall()) {
 			if (get_compat_pages_array(chunk_pages, pages,
-						   chunk_nr))
+						   chunk_offset, chunk_nr))
 				break;
 		} else {
-			if (copy_from_user(chunk_pages, pages,
+			if (copy_from_user(chunk_pages, pages + chunk_offset,
 				      chunk_nr * sizeof(*chunk_pages)))
 				break;
 		}
 
 		do_pages_stat_array(mm, chunk_nr, chunk_pages, chunk_status);
 
-		if (copy_to_user(status, chunk_status, chunk_nr * sizeof(*status)))
+		if (copy_to_user(status + chunk_offset, chunk_status,
+				 chunk_nr * sizeof(*status)))
 			break;
 
-		pages += chunk_nr;
-		status += chunk_nr;
+		chunk_offset += chunk_nr;
 		nr_pages -= chunk_nr;
 	}
 	return nr_pages ? -EFAULT : 0;
-- 
2.47.2


^ permalink raw reply related	[flat|nested] 12+ messages in thread

* Re: [PATCH v3] mm/migrate: Fix do_pages_stat in 32-bit mode
  2025-07-01 17:55           ` [PATCH v3] " Christoph Berg
@ 2025-07-01 18:17             ` David Hildenbrand
  2025-07-03 17:39               ` Christoph Berg
  0 siblings, 1 reply; 12+ messages in thread
From: David Hildenbrand @ 2025-07-01 18:17 UTC (permalink / raw)
  To: Christoph Berg, Zi Yan
  Cc: Andrew Morton, Matthew Brost, Joshua Hahn, Rakie Kim,
	Byungchul Park, Gregory Price, Ying Huang, Alistair Popple,
	open list:MEMORY MANAGEMENT - MEMORY POLICY AND MIGRATION,
	open list

On 01.07.25 19:55, Christoph Berg wrote:
> Re: Zi Yan
>> Fixes should be:
>>
>> Fixes: 5b1b561ba73c ("mm: simplify compat_sys_move_pages")
>>
>> Closes could be a link to the bug report.
> 
> Updated, thanks.
> 
>>> This seems to work, but honestly I am wondering, if copy_from_user
>>> needs a special 32-bit case, doesn't copy_to_user need special casing
>>> as well?
> 
> Scratch that, it works because an int[] is copied back, and that's
> always the same size.
> 
> So I think the patch is good to go.
> 
> Christoph
> 
> 

If you have to resend, next time resend the full patch separately, not 
as reply to the previous version.

>  From 426c93d558572248273cf386ca784626ae431413 Mon Sep 17 00:00:00 2001
> From: Christoph Berg <myon@debian.org>
> Date: Tue, 24 Jun 2025 16:44:27 +0200
> Subject: [PATCH v3] mm/migrate: Fix do_pages_stat in 32-bit mode

s/32-bit mode/compat mode/ ?

Because on native 32bit it should be working fine.

> 
> 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.
> 
> Signed-off-by: Christoph Berg <myon@debian.org>
> Suggested-by: David Hildenbrand <david@redhat.com>
> Fixes: 5b1b561ba73c ("mm: simplify compat_sys_move_pages")

Hmm, still not sure if 5b1b561ba73c really introduced the issue. I think 
it only messed with the "pages" pointer, not with the "status" pointer?

Hmmmm


I assume we want to Cc stable. @Andrew can do that.

> 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
> ---

Acked-by: David Hildenbrand <david@redhat.com>

-- 
Cheers,

David / dhildenb


^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH v3] mm/migrate: Fix do_pages_stat in 32-bit mode
  2025-07-01 18:17             ` David Hildenbrand
@ 2025-07-03 17:39               ` Christoph Berg
  0 siblings, 0 replies; 12+ messages in thread
From: Christoph Berg @ 2025-07-03 17:39 UTC (permalink / raw)
  To: David Hildenbrand
  Cc: Zi Yan, Andrew Morton, Matthew Brost, Joshua Hahn, Rakie Kim,
	Byungchul Park, Gregory Price, Ying Huang, Alistair Popple,
	open list:MEMORY MANAGEMENT - MEMORY POLICY AND MIGRATION,
	open list

Re: David Hildenbrand
> > 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.
> > 
> > Signed-off-by: Christoph Berg <myon@debian.org>
> > Suggested-by: David Hildenbrand <david@redhat.com>
> > Fixes: 5b1b561ba73c ("mm: simplify compat_sys_move_pages")
> 
> Hmm, still not sure if 5b1b561ba73c really introduced the issue. I think it
> only messed with the "pages" pointer, not with the "status" pointer?

"pages" was the broken one. "status" isn't affected by compat mode.

> Acked-by: David Hildenbrand <david@redhat.com>

Thanks!

Christoph

^ permalink raw reply	[flat|nested] 12+ messages in thread

end of thread, other threads:[~2025-07-03 17:39 UTC | newest]

Thread overview: 12+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
     [not found] <aFrBhyHQFffJ4xgX@msg.df7cb.de>
     [not found] ` <d42cc185-b774-4d5e-9a51-0581dd5f3962@arm.com>
2025-06-25 15:24   ` [PATCH] Fix do_pages_stat to use compat_uptr_t Christoph Berg
2025-06-25 15:42     ` David Hildenbrand
2025-07-01 16:58       ` [PATCH v2] mm/migrate: Fix do_pages_stat in 32-bit mode Christoph Berg
2025-07-01 17:09         ` Zi Yan
2025-07-01 17:55           ` [PATCH v3] " Christoph Berg
2025-07-01 18:17             ` David Hildenbrand
2025-07-03 17:39               ` Christoph Berg
2025-06-25 20:39     ` [PATCH] Fix do_pages_stat to use compat_uptr_t Andrew Morton
2025-06-25 21:10       ` Christoph Berg
2025-06-25 21:15         ` Andrew Morton
2025-06-26  8:16           ` David Hildenbrand
2025-06-26 19:21             ` Christoph Berg

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).