All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH] x86: __memcpy_flushcache: fix wrong alignment if size > 2^32
@ 2022-04-19 13:56 Mikulas Patocka
  2022-04-19 17:13 ` Linus Torvalds
  0 siblings, 1 reply; 4+ messages in thread
From: Mikulas Patocka @ 2022-04-19 13:56 UTC (permalink / raw)
  To: Linus Torvalds, Andrew Morton, Thomas Gleixner, Ingo Molnar,
	Borislav Petkov, Dave Hansen, H. Peter Anvin
  Cc: x86, linux-kernel

The first "if" condition in __memcpy_flushcache is supposed to align the
"dest" variable to 8 bytes and copy data up to this alignment. However,
this condition may misbehave if "size" is greater than 4GiB.

The statement min_t(unsigned, size, ALIGN(dest, 8) - dest); casts both
arguments to unsigned int and selects the smaller one. However, the cast
truncates high bits in "size" and it results in misbehavior.

For example:
	suppose that size == 0x100000001, dest == 0x200000002
	min_t(unsigned, size, ALIGN(dest, 8) - dest) == min_t(0x1, 0xe) == 0x1;
	...
	dest += 0x1;
so we copy just one byte "and" dest remains unaligned.

This patch fixes the bug by replacing unsigned with size_t.

Signed-off-by: Mikulas Patocka <mpatocka@redhat.com>

---
 arch/x86/lib/usercopy_64.c |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

Index: linux-2.6/arch/x86/lib/usercopy_64.c
===================================================================
--- linux-2.6.orig/arch/x86/lib/usercopy_64.c
+++ linux-2.6/arch/x86/lib/usercopy_64.c
@@ -119,7 +119,7 @@ void __memcpy_flushcache(void *_dst, con
 
 	/* cache copy and flush to align dest */
 	if (!IS_ALIGNED(dest, 8)) {
-		unsigned len = min_t(unsigned, size, ALIGN(dest, 8) - dest);
+		size_t len = min_t(size_t, size, ALIGN(dest, 8) - dest);
 
 		memcpy((void *) dest, (void *) source, len);
 		clean_cache_range((void *) dest, len);


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

* Re: [PATCH] x86: __memcpy_flushcache: fix wrong alignment if size > 2^32
  2022-04-19 13:56 [PATCH] x86: __memcpy_flushcache: fix wrong alignment if size > 2^32 Mikulas Patocka
@ 2022-04-19 17:13 ` Linus Torvalds
  2022-04-19 20:11   ` [PATCH v2] " Mikulas Patocka
  0 siblings, 1 reply; 4+ messages in thread
From: Linus Torvalds @ 2022-04-19 17:13 UTC (permalink / raw)
  To: Mikulas Patocka
  Cc: Andrew Morton, Thomas Gleixner, Ingo Molnar, Borislav Petkov,
	Dave Hansen, H. Peter Anvin, the arch/x86 maintainers,
	Linux Kernel Mailing List

On Tue, Apr 19, 2022 at 6:56 AM Mikulas Patocka <mpatocka@redhat.com> wrote:
>
> The first "if" condition in __memcpy_flushcache is supposed to align the
> "dest" variable to 8 bytes and copy data up to this alignment. However,
> this condition may misbehave if "size" is greater than 4GiB.

You're not wrong, but I also don't think it would be wrong to just have a

        if (WARN_ON_ONCE(size > MAX_INT))
                return;

in there instead.

It' not like "> 2**32" should ever really be a valid thing for any
kind of copy in the kernel. Even if that were to be what you actually
wanted to do (which sounds very unlikely), you'd need to split it up
with cond_resched() just for latency reasons.

             Linus

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

* [PATCH v2] x86: __memcpy_flushcache: fix wrong alignment if size > 2^32
  2022-04-19 17:13 ` Linus Torvalds
@ 2022-04-19 20:11   ` Mikulas Patocka
  0 siblings, 0 replies; 4+ messages in thread
From: Mikulas Patocka @ 2022-04-19 20:11 UTC (permalink / raw)
  To: Linus Torvalds
  Cc: Andrew Morton, Thomas Gleixner, Ingo Molnar, Borislav Petkov,
	Dave Hansen, H. Peter Anvin, the arch/x86 maintainers,
	Linux Kernel Mailing List



On Tue, 19 Apr 2022, Linus Torvalds wrote:

> On Tue, Apr 19, 2022 at 6:56 AM Mikulas Patocka <mpatocka@redhat.com> wrote:
> >
> > The first "if" condition in __memcpy_flushcache is supposed to align the
> > "dest" variable to 8 bytes and copy data up to this alignment. However,
> > this condition may misbehave if "size" is greater than 4GiB.
> 
> You're not wrong, but I also don't think it would be wrong to just have a
> 
>         if (WARN_ON_ONCE(size > MAX_INT))
>                 return;
> 
> in there instead.

If you skip copying, it could in theory have security or reliability 
implications (the user may be reading stale data that he is not supposed 
to read). So, I think it's better to just add WARN_ON_ONCE and proceed 
with the copying.

> It' not like "> 2**32" should ever really be a valid thing for any
> kind of copy in the kernel. Even if that were to be what you actually

For example, the dm-stats subsystem (drivers/md/dm-stats.c) can allocate 
extremely large blocks of memory using vmalloc (it is only limited to 1/4 
of total system memory) - though, it doesn't use memcpy on it.

> wanted to do (which sounds very unlikely), you'd need to split it up
> with cond_resched() just for latency reasons.
> 
>              Linus



From: Mikulas Patocka <mpatocka@redhat.com>

The first "if" condition in __memcpy_flushcache is supposed to align the
"dest" variable to 8 bytes and copy data up to this alignment. However,
this condition may misbehave if "size" is greater than 4GiB.

The statement min_t(unsigned, size, ALIGN(dest, 8) - dest); casts both
arguments to unsigned int and selects the smaller one. However, the cast
truncates high bits in "size" and it results in misbehavior.

For example:
	suppose that size == 0x100000001, dest == 0x200000002
	min_t(unsigned, size, ALIGN(dest, 8) - dest) == min_t(0x1, 0xe) == 0x1;
	...
	dest += 0x1;
so we copy just one byte "and" dest remains unaligned.

This patch fixes the bug by replacing unsigned with size_t.

As the function is not supposed to be used with large size, the patch also
adds a WARN_ON_ONCE there.

Signed-off-by: Mikulas Patocka <mpatocka@redhat.com>

---
 arch/x86/lib/usercopy_64.c |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

Index: linux-2.6/arch/x86/lib/usercopy_64.c
===================================================================
--- linux-2.6.orig/arch/x86/lib/usercopy_64.c
+++ linux-2.6/arch/x86/lib/usercopy_64.c
@@ -117,9 +117,11 @@ void __memcpy_flushcache(void *_dst, con
 	unsigned long dest = (unsigned long) _dst;
 	unsigned long source = (unsigned long) _src;
 
+	WARN_ON_ONCE(size > INT_MAX);
+
 	/* cache copy and flush to align dest */
 	if (!IS_ALIGNED(dest, 8)) {
-		unsigned len = min_t(unsigned, size, ALIGN(dest, 8) - dest);
+		size_t len = min_t(size_t, size, ALIGN(dest, 8) - dest);
 
 		memcpy((void *) dest, (void *) source, len);
 		clean_cache_range((void *) dest, len);


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

* [PATCH] x86: __memcpy_flushcache: fix wrong alignment if size > 2^32
@ 2020-04-17 12:21 Mikulas Patocka
  0 siblings, 0 replies; 4+ messages in thread
From: Mikulas Patocka @ 2020-04-17 12:21 UTC (permalink / raw)
  To: Dan Williams, Thomas Gleixner, Ingo Molnar, Borislav Petkov
  Cc: H. Peter Anvin, x86, linux-kernel

The statement "min_t(unsigned, size, ALIGN(dest, 8) - dest);" casts both 
arguments to unsigned int and selects the smaller one. However, if the 
size is larger than 2^32, the truncation returns incorrect result.

For example:
	size == 0x100000001, dest == 0x200000002
	min_t(unsigned, size, ALIGN(dest, 8) - dest) == min_t(0x1, 0xe) == 0x1;
	...
	dest += 0x1;
so we copy just one byte and dest remains unaligned.

This patch fixes the bug by replacing unsigned with size_t.

Signed-off-by: Mikulas Patocka <mpatocka@redhat.com>

---
 arch/x86/lib/usercopy_64.c |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

Index: linux-2.6/arch/x86/lib/usercopy_64.c
===================================================================
--- linux-2.6.orig/arch/x86/lib/usercopy_64.c	2020-04-17 14:06:32.039999000 +0200
+++ linux-2.6/arch/x86/lib/usercopy_64.c	2020-04-17 14:06:32.039999000 +0200
@@ -141,7 +141,7 @@ void __memcpy_flushcache(void *_dst, con
 
 	/* cache copy and flush to align dest */
 	if (!IS_ALIGNED(dest, 8)) {
-		unsigned len = min_t(unsigned, size, ALIGN(dest, 8) - dest);
+		size_t len = min_t(size_t, size, ALIGN(dest, 8) - dest);
 
 		memcpy((void *) dest, (void *) source, len);
 		clean_cache_range((void *) dest, len);


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

end of thread, other threads:[~2022-04-19 20:11 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-04-19 13:56 [PATCH] x86: __memcpy_flushcache: fix wrong alignment if size > 2^32 Mikulas Patocka
2022-04-19 17:13 ` Linus Torvalds
2022-04-19 20:11   ` [PATCH v2] " Mikulas Patocka
  -- strict thread matches above, loose matches on Subject: below --
2020-04-17 12:21 [PATCH] " Mikulas Patocka

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.