evh_bytechan: fix out of bounds accesses

Started by Stephen Rothwell on Jan 9, 2020 · 28 messages from 7 authors · Last reply Mar 17, 2020

Subsystems (3)

Maintainers (4)

STALE2424d LANDED

Status: Landed in mainline as 3670664b5da5 on 2020-03-17.

open the first message on its own page

Message details and related content
ev_byte_channel_send() assumes that its third argument is a 16 byte array.
Some places where it is called it may not be (or we can't easily tell
if it is).  Newer compilers have started producing warnings about this,
so make sure we actually pass a 16 byte array.

There may be more elegant solutions to this, but the driver is quite
old and hasn't been updated in many years.

The warnings (from a powerpc allyesconfig build) are:

In file included from include/linux/byteorder/big_endian.h:5,
                 from arch/powerpc/include/uapi/asm/byteorder.h:14,
                 from include/asm-generic/bitops/le.h:6,
                 from arch/powerpc/include/asm/bitops.h:250,
                 from include/linux/bitops.h:29,
                 from include/linux/kernel.h:12,
                 from include/asm-generic/bug.h:19,
                 from arch/powerpc/include/asm/bug.h:109,
                 from include/linux/bug.h:5,
                 from include/linux/mmdebug.h:5,
                 from include/linux/gfp.h:5,
                 from include/linux/slab.h:15,
                 from drivers/tty/ehv_bytechan.c:24:
drivers/tty/ehv_bytechan.c: In function ‘ehv_bc_udbg_putc’:
arch/powerpc/include/asm/epapr_hcalls.h:298:20: warning: array subscript 1 is outside array bounds of ‘const char[1]’ [-Warray-bounds]
  298 |  r6 = be32_to_cpu(p[1]);
include/uapi/linux/byteorder/big_endian.h:40:51: note: in definition of macro ‘__be32_to_cpu’
   40 | #define __be32_to_cpu(x) ((__force __u32)(__be32)(x))
      |                                                   ^
arch/powerpc/include/asm/epapr_hcalls.h:298:7: note: in expansion of macro ‘be32_to_cpu’
  298 |  r6 = be32_to_cpu(p[1]);
      |       ^~~~~~~~~~~
drivers/tty/ehv_bytechan.c:166:13: note: while referencing ‘data’
  166 | static void ehv_bc_udbg_putc(char c)
      |             ^~~~~~~~~~~~~~~~
In file included from include/linux/byteorder/big_endian.h:5,
                 from arch/powerpc/include/uapi/asm/byteorder.h:14,
                 from include/asm-generic/bitops/le.h:6,
                 from arch/powerpc/include/asm/bitops.h:250,
                 from include/linux/bitops.h:29,

127 more lines

diff --git a/drivers/tty/ehv_bytechan.c b/drivers/tty/ehv_bytechan.c
index 769e0a5d1dfc..546f80c49ae6 100644
--- a/drivers/tty/ehv_bytechan.c
+++ b/drivers/tty/ehv_bytechan.c
@@ -136,6 +136,20 @@ static int find_console_handle(void)
 	return 1;
 }
 
+static unsigned int local_ev_byte_channel_send(unsigned int handle,
+        unsigned int *count, const char *p)
+{
+	char buffer[EV_BYTE_CHANNEL_MAX_BYTES];
+	unsigned int c = *count;
+
+	if (c < sizeof(buffer)) {
+		memcpy(buffer, p, c);
+		memset(&buffer[c], 0, sizeof(buffer) - c);
+		p = buffer;
+	}
+	return ev_byte_channel_send(handle, count, p);
+}
+
 /*************************** EARLY CONSOLE DRIVER ***************************/
 
 #ifdef CONFIG_PPC_EARLY_DEBUG_EHV_BC
@@ -154,7 +168,7 @@ static void byte_channel_spin_send(const char data)
 
 	do {
 		count = 1;
-		ret = ev_byte_channel_send(CONFIG_PPC_EARLY_DEBUG_EHV_BC_HANDLE,
+		ret = local_ev_byte_channel_send(CONFIG_PPC_EARLY_DEBUG_EHV_BC_HANDLE,
 					   &count, &data);
 	} while (ret == EV_EAGAIN);
 }
@@ -221,7 +235,7 @@ static int ehv_bc_console_byte_channel_send(unsigned int handle, const char *s,
 	while (count) {
 		len = min_t(unsigned int, count, EV_BYTE_CHANNEL_MAX_BYTES);
 		do {
-			ret = ev_byte_channel_send(handle, &len, s);
+			ret = local_ev_byte_channel_send(handle, &len, s);
 		} while (ret == EV_EAGAIN);
 		count -= len;
 		s += len;
@@ -401,7 +415,7 @@ static void ehv_bc_tx_dequeue(struct ehv_bc_data *bc)
 			    CIRC_CNT_TO_END(bc->head, bc->tail, BUF_SIZE),
 			    EV_BYTE_CHANNEL_MAX_BYTES);
 
-		ret = ev_byte_channel_send(bc->handle, &len, bc->buf + bc->tail);
+		ret = local_ev_byte_channel_send(bc->handle, &len, bc->buf + bc->tail);
 
 		/* 'len' is valid only if the return code is 0 or EV_EAGAIN */
 		if (!ret || (ret == EV_EAGAIN))
-- 
2.25.0.rc1

-- 
Cheers,
Stephen Rothwell
Message details and related content
Stephen Rothwell [off-list ref] writes:
ev_byte_channel_send() assumes that its third argument is a 16 byte array.
Some places where it is called it may not be (or we can't easily tell
if it is).  Newer compilers have started producing warnings about this,
so make sure we actually pass a 16 byte array.

There may be more elegant solutions to this, but the driver is quite
old and hasn't been updated in many years.
...
Fixes: dcd83aaff1c8 ("tty/powerpc: introduce the ePAPR embedded hypervisor byte channel driver")
Cc: Michael Ellerman <mpe@ellerman.id.au>
Cc: PowerPC Mailing List <redacted>
Signed-off-by: Stephen Rothwell <redacted>
---
 drivers/tty/ehv_bytechan.c | 20 +++++++++++++++++---
 1 file changed, 17 insertions(+), 3 deletions(-)

I have only build tested this change so it would be good to get some
response from the PowerPC maintainers/developers.
I've never heard of it, and I have no idea how to test it.

It's not used by qemu, I guess there is/was a Freescale hypervisor that
used it.

But maybe it's time to remove it if it's not being maintained/used by
anyone?

cheers

quoted hunk
diff --git a/drivers/tty/ehv_bytechan.c b/drivers/tty/ehv_bytechan.c
index 769e0a5d1dfc..546f80c49ae6 100644
--- a/drivers/tty/ehv_bytechan.c
+++ b/drivers/tty/ehv_bytechan.c
@@ -136,6 +136,20 @@ static int find_console_handle(void)
 	return 1;
 }
 
+static unsigned int local_ev_byte_channel_send(unsigned int handle,
+        unsigned int *count, const char *p)
+{
+	char buffer[EV_BYTE_CHANNEL_MAX_BYTES];
+	unsigned int c = *count;
+
+	if (c < sizeof(buffer)) {
+		memcpy(buffer, p, c);
+		memset(&buffer[c], 0, sizeof(buffer) - c);
+		p = buffer;
+	}
+	return ev_byte_channel_send(handle, count, p);
+}
+
 /*************************** EARLY CONSOLE DRIVER ***************************/
 
 #ifdef CONFIG_PPC_EARLY_DEBUG_EHV_BC
@@ -154,7 +168,7 @@ static void byte_channel_spin_send(const char data)
 
 	do {
 		count = 1;
-		ret = ev_byte_channel_send(CONFIG_PPC_EARLY_DEBUG_EHV_BC_HANDLE,
+		ret = local_ev_byte_channel_send(CONFIG_PPC_EARLY_DEBUG_EHV_BC_HANDLE,
 					   &count, &data);
 	} while (ret == EV_EAGAIN);
 }
@@ -221,7 +235,7 @@ static int ehv_bc_console_byte_channel_send(unsigned int handle, const char *s,
 	while (count) {
 		len = min_t(unsigned int, count, EV_BYTE_CHANNEL_MAX_BYTES);
 		do {
-			ret = ev_byte_channel_send(handle, &len, s);
+			ret = local_ev_byte_channel_send(handle, &len, s);

18 more quoted lines

Message details and related content
On 1/13/20 6:26 AM, Michael Ellerman wrote:
I've never heard of it, and I have no idea how to test it.

It's not used by qemu, I guess there is/was a Freescale hypervisor that
used it.
Yes, there is/was a Freescale hypervisor that I and a few others worked on.  I've added a couple people on CC that might be able to tell the current disposition of it.
But maybe it's time to remove it if it's not being maintained/used by
anyone?
I wouldn't be completely opposed to that if there really are no more users.  There really weren't any users even when I wrote the driver.

I haven't had a chance to study the patch, but my first instinct is that there's got to be a better way to fix this than introducing a memcpy.
Message details and related content
Hello,

On 13.01.2020 15:48, Timur Tabi wrote:
On 1/13/20 6:26 AM, Michael Ellerman wrote:
quoted
I've never heard of it, and I have no idea how to test it.

It's not used by qemu, I guess there is/was a Freescale hypervisor that
used it.
Yes, there is/was a Freescale hypervisor that I and a few others worked 
on.  I've added a couple people on CC that might be able to tell the 
current disposition of it.
More info on this: it's opensource and it's published here [1]. We still 
claim to maintain it but there wasn't much activity past years, as one 
might notice.
quoted
But maybe it's time to remove it if it's not being maintained/used by
anyone?
I wouldn't be completely opposed to that if there really are no more 
users.  There really weren't any users even when I wrote the driver.
There are a few users that I know of, but I can't tell if that's enough 
to justify keeping the driver.

[1] https://source.codeaurora.org/external/qoriq/qoriq-yocto-sdk/hypervisor/

---
Best Regards, Laurentiu
Message details and related content
On 1/13/20 8:34 AM, Laurentiu Tudor wrote:
There are a few users that I know of, but I can't tell if that's enough
to justify keeping the driver.

[1]https://source.codeaurora.org/external/qoriq/qoriq-yocto-sdk/hypervisor/
IIRC, the driver is the only reasonable way to get a serial console from a guest.  So if there are users of the hypervisor, then I think there's a good chance at least one is using the byte channel driver.
Message details and related content
On Thu, Jan 9, 2020 at 1:41 AM Stephen Rothwell [off-list ref] wrote:
ev_byte_channel_send() assumes that its third argument is a 16 byte array.
Some places where it is called it may not be (or we can't easily tell
if it is).  Newer compilers have started producing warnings about this,
so make sure we actually pass a 16 byte array.
...
quoted hunk
+static unsigned int local_ev_byte_channel_send(unsigned int handle,
+        unsigned int *count, const char *p)
+{
+       char buffer[EV_BYTE_CHANNEL_MAX_BYTES];
+       unsigned int c = *count;
+
+       if (c < sizeof(buffer)) {
+               memcpy(buffer, p, c);
+               memset(&buffer[c], 0, sizeof(buffer) - c);
+               p = buffer;
+       }
+       return ev_byte_channel_send(handle, count, p);
+}
Why not simply correct the parameters of ev_byte_channel_send?

static inline unsigned int ev_byte_channel_send(unsigned int handle,
-unsigned int *count, const char buffer[EV_BYTE_CHANNEL_MAX_BYTES])
+unsigned int *count, const char *buffer)

Back then, I probably thought I was just being clever with this code,
but I realize now that it doesn't make sense to do the way I did.
Message details and related content
Hi Timur,

On Mon, 13 Jan 2020 10:03:18 -0600 Timur Tabi [off-list ref] wrote:
Why not simply correct the parameters of ev_byte_channel_send?

static inline unsigned int ev_byte_channel_send(unsigned int handle,
-unsigned int *count, const char buffer[EV_BYTE_CHANNEL_MAX_BYTES])
+unsigned int *count, const char *buffer)

Back then, I probably thought I was just being clever with this code,
but I realize now that it doesn't make sense to do the way I did.
The problem is not really the declaration, the problem is that
ev_byte_channel_send always accesses 16 bytes from the buffer and it is
not always passed a buffer that long (in one case it is passed a
pointer to a single byte).  So the alternative to the memcpy approach I
have take is to complicate ev_byte_channel_send so that only accesses
count bytes from the buffer.

-- 
Cheers,
Stephen Rothwell
Message details and related content
On 1/13/20 2:25 PM, Stephen Rothwell wrote:
The problem is not really the declaration, the problem is that
ev_byte_channel_send always accesses 16 bytes from the buffer and it is
not always passed a buffer that long (in one case it is passed a
pointer to a single byte).  So the alternative to the memcpy approach I
have take is to complicate ev_byte_channel_send so that only accesses
count bytes from the buffer.
Ah, I see now.  This is all coming back to me.

I would prefer that ev_byte_channel_send() is updated to access only 'count' bytes.  If that means adding a memcpy to the ev_byte_channel_send() itself, then so be it.  Trying to figure out how to stuff n bytes into 4 32-bit registers is probably not worth the effort.
Message details and related content
Laurentiu Tudor [off-list ref] writes:
Hello,

On 13.01.2020 15:48, Timur Tabi wrote:
quoted
On 1/13/20 6:26 AM, Michael Ellerman wrote:
quoted
I've never heard of it, and I have no idea how to test it.

It's not used by qemu, I guess there is/was a Freescale hypervisor that
used it.
Yes, there is/was a Freescale hypervisor that I and a few others worked 
on.  I've added a couple people on CC that might be able to tell the 
current disposition of it.
More info on this: it's opensource and it's published here [1]. We still 
claim to maintain it but there wasn't much activity past years, as one 
might notice.
quoted
quoted
But maybe it's time to remove it if it's not being maintained/used by
anyone?
I wouldn't be completely opposed to that if there really are no more 
users.  There really weren't any users even when I wrote the driver.
There are a few users that I know of, but I can't tell if that's enough 
to justify keeping the driver.
It is, I don't want to remove code that people are actually using,
unless it's causing unsustainable maintenance burden.

But this should be easy enough to get fixed.

Could you or someone else at NXP volunteer to maintain this driver? That
shouldn't involve much work, other than fixing small things like this
warning.

cheers
Message details and related content
On 1/13/20 7:10 PM, Timur Tabi wrote:
I would prefer that ev_byte_channel_send() is updated to access only 'count' bytes.  If that means adding a memcpy to the ev_byte_channel_send() itself, then so be it.  Trying to figure out how to stuff n bytes into 4 32-bit registers is probably not worth the effort.
Looks like ev_byte_channel_receive() has the same bug, but in reverse.
Message details and related content
On Mon, 2020-01-13 at 19:13 -0600, Timur Tabi wrote:
On 1/13/20 7:10 PM, Timur Tabi wrote:
quoted
I would prefer that ev_byte_channel_send() is updated to access only 
'count' bytes.  If that means adding a memcpy to the 
ev_byte_channel_send() itself, then so be it.  Trying to figure out how 
to stuff n bytes into 4 32-
bit registers is probably not worth the effort.
Looks like ev_byte_channel_receive() has the same bug, but in reverse.
It only has one user, which always passes in a 16-byte buffer.

-Scott

Message details and related content
Hi Timur,

On Mon, 13 Jan 2020 19:10:11 -0600 Timur Tabi [off-list ref] wrote:
On 1/13/20 2:25 PM, Stephen Rothwell wrote:
quoted
The problem is not really the declaration, the problem is that
ev_byte_channel_send always accesses 16 bytes from the buffer and it is
not always passed a buffer that long (in one case it is passed a
pointer to a single byte).  So the alternative to the memcpy approach I
have take is to complicate ev_byte_channel_send so that only accesses
count bytes from the buffer.  
Ah, I see now.  This is all coming back to me.

I would prefer that ev_byte_channel_send() is updated to access only 
'count' bytes.  If that means adding a memcpy to the 
ev_byte_channel_send() itself, then so be it.  Trying to figure out how 
to stuff n bytes into 4 32-bit registers is probably not worth the effort.
Like this (I have compile tested this):

From: Stephen Rothwell <redacted>
Date: Thu, 9 Jan 2020 18:23:48 +1100
Subject: [PATCH v2] evh_bytechan: fix out of bounds accesses

ev_byte_channel_send() assumes that its third argument is a 16 byte array.
Some places where it is called it may not be (or we can't easily tell
if it is).  Newer compilers have started producing warnings about this,
so copy the bytes to send into a local array if the passed length is
to short.

Since all the calls of ev_byte_channel_send() are in one file, lets move
it there from the header file and let the compiler decide if it wants
to inline it.

The warnings are:

In file included from include/linux/byteorder/big_endian.h:5,
                 from arch/powerpc/include/uapi/asm/byteorder.h:14,
                 from include/asm-generic/bitops/le.h:6,
                 from arch/powerpc/include/asm/bitops.h:250,
                 from include/linux/bitops.h:29,
                 from include/linux/kernel.h:12,
                 from include/asm-generic/bug.h:19,
                 from arch/powerpc/include/asm/bug.h:109,
                 from include/linux/bug.h:5,
                 from include/linux/mmdebug.h:5,
                 from include/linux/gfp.h:5,
                 from include/linux/slab.h:15,
                 from drivers/tty/ehv_bytechan.c:24:
drivers/tty/ehv_bytechan.c: In function ‘ehv_bc_udbg_putc’:
arch/powerpc/include/asm/epapr_hcalls.h:298:20: warning: array subscript 1 is outside array bounds of ‘const char[1]’ [-Warray-bounds]
  298 |  r6 = be32_to_cpu(p[1]);
include/uapi/linux/byteorder/big_endian.h:40:51: note: in definition of macro ‘__be32_to_cpu’
   40 | #define __be32_to_cpu(x) ((__force __u32)(__be32)(x))
      |                                                   ^
arch/powerpc/include/asm/epapr_hcalls.h:298:7: note: in expansion of macro ‘be32_to_cpu’
  298 |  r6 = be32_to_cpu(p[1]);

131 more lines

diff --git a/arch/powerpc/include/asm/epapr_hcalls.h b/arch/powerpc/include/asm/epapr_hcalls.h
index d3a7e36f1402..75c5943c9f85 100644
--- a/arch/powerpc/include/asm/epapr_hcalls.h
+++ b/arch/powerpc/include/asm/epapr_hcalls.h
@@ -268,48 +268,6 @@ static inline unsigned int ev_int_eoi(unsigned int interrupt)
 	return r3;
 }
 
-/**
- * ev_byte_channel_send - send characters to a byte stream
- * @handle: byte stream handle
- * @count: (input) num of chars to send, (output) num chars sent
- * @buffer: pointer to a 16-byte buffer
- *
- * @buffer must be at least 16 bytes long, because all 16 bytes will be
- * read from memory into registers, even if count < 16.
- *
- * Returns 0 for success, or an error code.
- */
-static inline unsigned int ev_byte_channel_send(unsigned int handle,
-	unsigned int *count, const char buffer[EV_BYTE_CHANNEL_MAX_BYTES])
-{
-	register uintptr_t r11 __asm__("r11");
-	register uintptr_t r3 __asm__("r3");
-	register uintptr_t r4 __asm__("r4");
-	register uintptr_t r5 __asm__("r5");
-	register uintptr_t r6 __asm__("r6");
-	register uintptr_t r7 __asm__("r7");
-	register uintptr_t r8 __asm__("r8");
-	const uint32_t *p = (const uint32_t *) buffer;
-
-	r11 = EV_HCALL_TOKEN(EV_BYTE_CHANNEL_SEND);
-	r3 = handle;
-	r4 = *count;
-	r5 = be32_to_cpu(p[0]);
-	r6 = be32_to_cpu(p[1]);
-	r7 = be32_to_cpu(p[2]);
-	r8 = be32_to_cpu(p[3]);
-
-	asm volatile("bl	epapr_hypercall_start"
-		: "+r" (r11), "+r" (r3),
-		  "+r" (r4), "+r" (r5), "+r" (r6), "+r" (r7), "+r" (r8)
-		: : EV_HCALL_CLOBBERS6
-	);
-
-	*count = r4;
-
-	return r3;
-}
-
 /**
  * ev_byte_channel_receive - fetch characters from a byte channel
  * @handle: byte channel handle
diff --git a/drivers/tty/ehv_bytechan.c b/drivers/tty/ehv_bytechan.c
index 769e0a5d1dfc..a5512745d0f9 100644
--- a/drivers/tty/ehv_bytechan.c
+++ b/drivers/tty/ehv_bytechan.c
@@ -136,6 +136,54 @@ static int find_console_handle(void)
 	return 1;
 }
 
+/**
+ * ev_byte_channel_send - send characters to a byte stream
+ * @handle: byte stream handle
+ * @count: (input) num of chars to send, (output) num chars sent
+ * @bp: pointer to chars to send
+ *
+ * Returns 0 for success, or an error code.
+ */
+static unsigned int ev_byte_channel_send(unsigned int handle,
+	unsigned int *count, const char *bp)
+{
+	register uintptr_t r11 __asm__("r11");
+	register uintptr_t r3 __asm__("r3");
+	register uintptr_t r4 __asm__("r4");
+	register uintptr_t r5 __asm__("r5");
+	register uintptr_t r6 __asm__("r6");
+	register uintptr_t r7 __asm__("r7");
+	register uintptr_t r8 __asm__("r8");
+	const uint32_t *p;
+	char buffer[EV_BYTE_CHANNEL_MAX_BYTES];
+	unsigned int c = *count;
+
+	if (c < sizeof(buffer)) {
+		memcpy(buffer, bp, c);
+		memset(&buffer[c], 0, sizeof(buffer) - c);
+		p = (const uint32_t *)buffer;
+	} else {
+		p = (const uint32_t *)bp;
+	}
+	r11 = EV_HCALL_TOKEN(EV_BYTE_CHANNEL_SEND);
+	r3 = handle;
+	r4 = *count;
+	r5 = be32_to_cpu(p[0]);
+	r6 = be32_to_cpu(p[1]);
+	r7 = be32_to_cpu(p[2]);
+	r8 = be32_to_cpu(p[3]);
+
+	asm volatile("bl	epapr_hypercall_start"
+		: "+r" (r11), "+r" (r3),
+		  "+r" (r4), "+r" (r5), "+r" (r6), "+r" (r7), "+r" (r8)
+		: : EV_HCALL_CLOBBERS6
+	);
+
+	*count = r4;
+
+	return r3;
+}
+
 /*************************** EARLY CONSOLE DRIVER ***************************/
 
 #ifdef CONFIG_PPC_EARLY_DEBUG_EHV_BC
-- 
2.25.0.rc2

-- 
Cheers,
Stephen Rothwell
Message details and related content
On Mon, Jan 13, 2020 at 07:10:11PM -0600, Timur Tabi wrote:
Ah, I see now.  This is all coming back to me.

I would prefer that ev_byte_channel_send() is updated to access only 
'count' bytes.  If that means adding a memcpy to the 
ev_byte_channel_send() itself, then so be it.  Trying to figure out how 
to stuff n bytes into 4 32-bit registers is probably not worth the effort.
You have no working lswx I suppose?  :-)

/me slowly backs away


Segher
Message details and related content
On 14.01.2020 03:10, Michael Ellerman wrote:
Laurentiu Tudor [off-list ref] writes:
quoted
Hello,

On 13.01.2020 15:48, Timur Tabi wrote:
quoted
On 1/13/20 6:26 AM, Michael Ellerman wrote:
quoted
I've never heard of it, and I have no idea how to test it.

It's not used by qemu, I guess there is/was a Freescale hypervisor that
used it.
Yes, there is/was a Freescale hypervisor that I and a few others worked
on.  I've added a couple people on CC that might be able to tell the
current disposition of it.
More info on this: it's opensource and it's published here [1]. We still
claim to maintain it but there wasn't much activity past years, as one
might notice.
quoted
quoted
But maybe it's time to remove it if it's not being maintained/used by
anyone?
I wouldn't be completely opposed to that if there really are no more
users.  There really weren't any users even when I wrote the driver.
There are a few users that I know of, but I can't tell if that's enough
to justify keeping the driver.
It is, I don't want to remove code that people are actually using,
unless it's causing unsustainable maintenance burden.

But this should be easy enough to get fixed.
Right. I see that Stephen already came up with a proposal for a fix.
Could you or someone else at NXP volunteer to maintain this driver? That
shouldn't involve much work, other than fixing small things like this
warning.
I can offer myself. I'll send a MAINTAINERS patch if nobody is against it.

---
Best Regards, Laurentiu
Message details and related content
On Tue, Jan 14, 2020 at 05:53:41AM -0600, Timur Tabi wrote:
On 1/14/20 2:29 AM, Segher Boessenkool wrote:
quoted
You have no working lswx I suppose?:-)
I don't know if the P4080 supports lswx, but it does, than that would be 
an elegant way to fix this bug.
No e500 version supports it.  Many other CPUs do not allow it in little-
endian mode, or not in real mode, etc.


Segher
Message details and related content
-----Original Message-----
From: Linuxppc-dev <linuxppc-dev-
bounces+laurentiu.tudor=nxp.com@lists.ozlabs.org> On Behalf Of Stephen
Rothwell
Sent: Tuesday, January 14, 2020 8:32 AM
To: Timur Tabi <timur@kernel.org>
Cc: <redacted>; Greg Kroah-Hartman <gregkh@linuxfoundation.org>;
Jiri Slaby [off-list ref]; York Sun [off-list ref]; PowerPC Mailing
List [off-list ref]; swood@redhat.com
Subject: Re: [PATCH] evh_bytechan: fix out of bounds accesses

Hi Timur,

On Mon, 13 Jan 2020 19:10:11 -0600 Timur Tabi [off-list ref] wrote:
quoted
On 1/13/20 2:25 PM, Stephen Rothwell wrote:
quoted
The problem is not really the declaration, the problem is that
ev_byte_channel_send always accesses 16 bytes from the buffer and it
is
quoted
quoted
not always passed a buffer that long (in one case it is passed a
pointer to a single byte).  So the alternative to the memcpy approach
I
quoted
quoted
have take is to complicate ev_byte_channel_send so that only accesses
count bytes from the buffer.
Ah, I see now.  This is all coming back to me.

I would prefer that ev_byte_channel_send() is updated to access only
'count' bytes.  If that means adding a memcpy to the
ev_byte_channel_send() itself, then so be it.  Trying to figure out how
to stuff n bytes into 4 32-bit registers is probably not worth the
effort.

Like this (I have compile tested this):

From: Stephen Rothwell <redacted>
Date: Thu, 9 Jan 2020 18:23:48 +1100
Subject: [PATCH v2] evh_bytechan: fix out of bounds accesses

ev_byte_channel_send() assumes that its third argument is a 16 byte array.

177 more quoted lines

Tested-by: Laurentiu Tudor <laurentiu.tudor@nxp.com>

---
Best Regards, Laurentiu
Message details and related content
On 1/14/20 12:31 AM, Stephen Rothwell wrote:
quoted hunk
+/**
+ * ev_byte_channel_send - send characters to a byte stream
+ * @handle: byte stream handle
+ * @count: (input) num of chars to send, (output) num chars sent
+ * @bp: pointer to chars to send
+ *
+ * Returns 0 for success, or an error code.
+ */
+static unsigned int ev_byte_channel_send(unsigned int handle,
+	unsigned int *count, const char *bp)
Well, now you've moved this into the .c file and it is no longer available to other callers.  Anything wrong with keeping it in the .h file?
Message details and related content
Hi Timur,

On Wed, 15 Jan 2020 07:25:45 -0600 Timur Tabi [off-list ref] wrote:
On 1/14/20 12:31 AM, Stephen Rothwell wrote:
quoted
+/**
+ * ev_byte_channel_send - send characters to a byte stream
+ * @handle: byte stream handle
+ * @count: (input) num of chars to send, (output) num chars sent
+ * @bp: pointer to chars to send
+ *
+ * Returns 0 for success, or an error code.
+ */
+static unsigned int ev_byte_channel_send(unsigned int handle,
+	unsigned int *count, const char *bp)  
Well, now you've moved this into the .c file and it is no longer 
available to other callers.  Anything wrong with keeping it in the .h file?
There are currently no other callers - are there likely to be in the
future?  Even if there are, is it time critical enough that it needs to
be inlined everywhere?

-- 
Cheers,
Stephen Rothwell
Message details and related content
On Thu, 2020-01-16 at 06:42 +1100, Stephen Rothwell wrote:
Hi Timur,

On Wed, 15 Jan 2020 07:25:45 -0600 Timur Tabi [off-list ref] wrote:
quoted
On 1/14/20 12:31 AM, Stephen Rothwell wrote:
quoted
+/**
+ * ev_byte_channel_send - send characters to a byte stream
+ * @handle: byte stream handle
+ * @count: (input) num of chars to send, (output) num chars sent
+ * @bp: pointer to chars to send
+ *
+ * Returns 0 for success, or an error code.
+ */
+static unsigned int ev_byte_channel_send(unsigned int handle,
+	unsigned int *count, const char *bp)  
Well, now you've moved this into the .c file and it is no longer 
available to other callers.  Anything wrong with keeping it in the .h
file?
There are currently no other callers - are there likely to be in the
future?  Even if there are, is it time critical enough that it needs to
be inlined everywhere?
It's not performance critical and there aren't likely to be other users --
just a matter of what's cleaner.  FWIW I'd rather see the original patch,
that keeps the raw asm hcall stuff as simple wrappers in one place.

-Scott

Message details and related content
Hi Scott,

On Wed, 15 Jan 2020 14:01:35 -0600 Scott Wood [off-list ref] wrote:
On Thu, 2020-01-16 at 06:42 +1100, Stephen Rothwell wrote:
quoted
Hi Timur,

On Wed, 15 Jan 2020 07:25:45 -0600 Timur Tabi [off-list ref] wrote:  
quoted
On 1/14/20 12:31 AM, Stephen Rothwell wrote:  
quoted
+/**
+ * ev_byte_channel_send - send characters to a byte stream
+ * @handle: byte stream handle
+ * @count: (input) num of chars to send, (output) num chars sent
+ * @bp: pointer to chars to send
+ *
+ * Returns 0 for success, or an error code.
+ */
+static unsigned int ev_byte_channel_send(unsigned int handle,
+	unsigned int *count, const char *bp)    
Well, now you've moved this into the .c file and it is no longer 
available to other callers.  Anything wrong with keeping it in the .h
file?  
There are currently no other callers - are there likely to be in the
future?  Even if there are, is it time critical enough that it needs to
be inlined everywhere?  
It's not performance critical and there aren't likely to be other users --
just a matter of what's cleaner.  FWIW I'd rather see the original patch,
that keeps the raw asm hcall stuff as simple wrappers in one place.
And I don't mind either way :-)

I just want to get rid of the warnings.

-- 
Cheers,
Stephen Rothwell
Message details and related content
Hi all,

On Thu, 16 Jan 2020 11:37:14 +1100 Stephen Rothwell [off-list ref] wrote:
On Wed, 15 Jan 2020 14:01:35 -0600 Scott Wood [off-list ref] wrote:
quoted
On Thu, 2020-01-16 at 06:42 +1100, Stephen Rothwell wrote:  
quoted
Hi Timur,

On Wed, 15 Jan 2020 07:25:45 -0600 Timur Tabi [off-list ref] wrote:    
quoted
On 1/14/20 12:31 AM, Stephen Rothwell wrote:    
quoted
+/**
+ * ev_byte_channel_send - send characters to a byte stream
+ * @handle: byte stream handle
+ * @count: (input) num of chars to send, (output) num chars sent
+ * @bp: pointer to chars to send
+ *
+ * Returns 0 for success, or an error code.
+ */
+static unsigned int ev_byte_channel_send(unsigned int handle,
+	unsigned int *count, const char *bp)      
Well, now you've moved this into the .c file and it is no longer 
available to other callers.  Anything wrong with keeping it in the .h
file?    
There are currently no other callers - are there likely to be in the
future?  Even if there are, is it time critical enough that it needs to
be inlined everywhere?    
It's not performance critical and there aren't likely to be other users --
just a matter of what's cleaner.  FWIW I'd rather see the original patch,
that keeps the raw asm hcall stuff as simple wrappers in one place.  
And I don't mind either way :-)

I just want to get rid of the warnings.
Any progress with this?
-- 
Cheers,
Stephen Rothwell
Message details and related content

On 21.02.2020 01:57, Stephen Rothwell wrote:
Hi all,

On Thu, 16 Jan 2020 11:37:14 +1100 Stephen Rothwell [off-list ref] wrote:
quoted
On Wed, 15 Jan 2020 14:01:35 -0600 Scott Wood [off-list ref] wrote:
quoted
On Thu, 2020-01-16 at 06:42 +1100, Stephen Rothwell wrote:
quoted
Hi Timur,

On Wed, 15 Jan 2020 07:25:45 -0600 Timur Tabi [off-list ref] wrote:
quoted
On 1/14/20 12:31 AM, Stephen Rothwell wrote:
quoted
+/**
+ * ev_byte_channel_send - send characters to a byte stream
+ * @handle: byte stream handle
+ * @count: (input) num of chars to send, (output) num chars sent
+ * @bp: pointer to chars to send
+ *
+ * Returns 0 for success, or an error code.
+ */
+static unsigned int ev_byte_channel_send(unsigned int handle,
+	unsigned int *count, const char *bp)
Well, now you've moved this into the .c file and it is no longer
available to other callers.  Anything wrong with keeping it in the .h
file?
There are currently no other callers - are there likely to be in the
future?  Even if there are, is it time critical enough that it needs to
be inlined everywhere?
It's not performance critical and there aren't likely to be other users --
just a matter of what's cleaner.  FWIW I'd rather see the original patch,
that keeps the raw asm hcall stuff as simple wrappers in one place.
And I don't mind either way :-)

I just want to get rid of the warnings.
Any progress with this?
I think that the consensus was to pick up the original patch that is, this one: https://patchwork.ozlabs.org/patch/1220186/

I've tested it too, so please feel free to add a:

Tested-by: Laurentiu Tudor <laurentiu.tudor@nxp.com>

---
Best Regards, Laurentiu
Message details and related content
Hi Laurentiu,

On Tue, 25 Feb 2020 11:54:17 +0200 Laurentiu Tudor [off-list ref] wrote:
On 21.02.2020 01:57, Stephen Rothwell wrote:
quoted
On Thu, 16 Jan 2020 11:37:14 +1100 Stephen Rothwell [off-list ref] wrote:  
quoted
On Wed, 15 Jan 2020 14:01:35 -0600 Scott Wood [off-list ref] wrote:  
quoted
On Thu, 2020-01-16 at 06:42 +1100, Stephen Rothwell wrote:  
quoted
On Wed, 15 Jan 2020 07:25:45 -0600 Timur Tabi [off-list ref] wrote:  
quoted
On 1/14/20 12:31 AM, Stephen Rothwell wrote:  
quoted
+/**
+ * ev_byte_channel_send - send characters to a byte stream
+ * @handle: byte stream handle
+ * @count: (input) num of chars to send, (output) num chars sent
+ * @bp: pointer to chars to send
+ *
+ * Returns 0 for success, or an error code.
+ */
+static unsigned int ev_byte_channel_send(unsigned int handle,
+	unsigned int *count, const char *bp)  
Well, now you've moved this into the .c file and it is no longer
available to other callers.  Anything wrong with keeping it in the .h
file?  
There are currently no other callers - are there likely to be in the
future?  Even if there are, is it time critical enough that it needs to
be inlined everywhere?  
It's not performance critical and there aren't likely to be other users --
just a matter of what's cleaner.  FWIW I'd rather see the original patch,
that keeps the raw asm hcall stuff as simple wrappers in one place.  
And I don't mind either way :-)

I just want to get rid of the warnings.  
Any progress with this?

6 more quoted lines

So, whose tree should his go via?

-- 
Cheers,
Stephen Rothwell
Message details and related content

On 25.02.2020 22:56, Stephen Rothwell wrote:
Hi Laurentiu,

On Tue, 25 Feb 2020 11:54:17 +0200 Laurentiu Tudor [off-list ref] wrote:
quoted
On 21.02.2020 01:57, Stephen Rothwell wrote:
quoted
On Thu, 16 Jan 2020 11:37:14 +1100 Stephen Rothwell [off-list ref] wrote:
quoted
On Wed, 15 Jan 2020 14:01:35 -0600 Scott Wood [off-list ref] wrote:
quoted
On Thu, 2020-01-16 at 06:42 +1100, Stephen Rothwell wrote:
quoted
On Wed, 15 Jan 2020 07:25:45 -0600 Timur Tabi [off-list ref] wrote:
quoted
On 1/14/20 12:31 AM, Stephen Rothwell wrote:
quoted
+/**
+ * ev_byte_channel_send - send characters to a byte stream
+ * @handle: byte stream handle
+ * @count: (input) num of chars to send, (output) num chars sent
+ * @bp: pointer to chars to send
+ *
+ * Returns 0 for success, or an error code.
+ */
+static unsigned int ev_byte_channel_send(unsigned int handle,
+	unsigned int *count, const char *bp)
Well, now you've moved this into the .c file and it is no longer
available to other callers.  Anything wrong with keeping it in the .h
file?
There are currently no other callers - are there likely to be in the
future?  Even if there are, is it time critical enough that it needs to
be inlined everywhere?
It's not performance critical and there aren't likely to be other users --
just a matter of what's cleaner.  FWIW I'd rather see the original patch,
that keeps the raw asm hcall stuff as simple wrappers in one place.
And I don't mind either way :-)

I just want to get rid of the warnings.

12 more quoted lines

Maybe Scott or Michael can help us here. And while at it maybe, take a look at this patch [1] too.

[1] https://patchwork.ozlabs.org/patch/1227780/

---
Best Regards, Laurentiu
Message details and related content
On Thu, 2020-01-09 at 07:39:12 UTC, Stephen Rothwell wrote:
ev_byte_channel_send() assumes that its third argument is a 16 byte array.
Some places where it is called it may not be (or we can't easily tell
if it is).  Newer compilers have started producing warnings about this,
so make sure we actually pass a 16 byte array.

There may be more elegant solutions to this, but the driver is quite
old and hasn't been updated in many years.

The warnings (from a powerpc allyesconfig build) are:

In file included from include/linux/byteorder/big_endian.h:5,
                 from arch/powerpc/include/uapi/asm/byteorder.h:14,
                 from include/asm-generic/bitops/le.h:6,
                 from arch/powerpc/include/asm/bitops.h:250,
                 from include/linux/bitops.h:29,
                 from include/linux/kernel.h:12,
                 from include/asm-generic/bug.h:19,
                 from arch/powerpc/include/asm/bug.h:109,
                 from include/linux/bug.h:5,
                 from include/linux/mmdebug.h:5,
                 from include/linux/gfp.h:5,
                 from include/linux/slab.h:15,
                 from drivers/tty/ehv_bytechan.c:24:
drivers/tty/ehv_bytechan.c: In function =E2=80=98ehv_bc_udbg_putc=E2=80=99:
arch/powerpc/include/asm/epapr_hcalls.h:298:20: warning: array subscript 1 =
is outside array bounds of =E2=80=98const char[1]=E2=80=99 [-Warray-bounds]
  298 |  r6 =3D be32_to_cpu(p[1]);
include/uapi/linux/byteorder/big_endian.h:40:51: note: in definition of mac=
ro =E2=80=98__be32_to_cpu=E2=80=99
   40 | #define __be32_to_cpu(x) ((__force __u32)(__be32)(x))
      |                                                   ^
arch/powerpc/include/asm/epapr_hcalls.h:298:7: note: in expansion of macro =
=E2=80=98be32_to_cpu=E2=80=99
  298 |  r6 =3D be32_to_cpu(p[1]);
      |       ^~~~~~~~~~~
drivers/tty/ehv_bytechan.c:166:13: note: while referencing =E2=80=98data=E2=
=80=99
  166 | static void ehv_bc_udbg_putc(char c)
      |             ^~~~~~~~~~~~~~~~
In file included from include/linux/byteorder/big_endian.h:5,

145 more quoted lines

Applied to powerpc next, thanks.

https://git.kernel.org/powerpc/c/3670664b5da555a2a481449b3baafff113b0ac35

cheers
Keyboard shortcuts
hback out one level
jnext message in thread / next series-diff position
kprevious message in thread / previous series-diff position
ldrill in
Escclose help / fold thread tree
?toggle this help