LKML Archive mirror
 help / color / mirror / Atom feed
* [v2]serial_core:recognize invalid pointer from userspace
@ 2016-03-10  3:17 Jiang Lu
  2016-03-10  3:17 ` [v2] serial_core:recognize " Jiang Lu
  0 siblings, 1 reply; 6+ messages in thread
From: Jiang Lu @ 2016-03-10  3:17 UTC (permalink / raw
  To: gregkh, linux-kernel, linux-serial




Hi,
[v1 -> v2]

Fix a compile warning with data convert.

[v1 log]

When running setserial, application issue a TIOCGSERIAL iotcl to get serial setting, then update 
serial setting with TIOCSSERIAL ioctl. It always failed with TIOCSSERIAL ioctl, for application
pass 0xffffffff for iomem_base in serial_struct to kernel.

On 32bit rootfs & 64bit kernel, compat_ioctl use 0xffffffff as a magic number to mark invalid pointer
for iomem_base in serial_struct when truncating a 64bit pointer into 32bit.

Serial driver need recognize this invalid pointer when parsing serial_struct from userspace.

Thanks
Jiang Lu

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

* [v2] serial_core:recognize invalid pointer from userspace
  2016-03-10  3:17 [v2]serial_core:recognize invalid pointer from userspace Jiang Lu
@ 2016-03-10  3:17 ` Jiang Lu
  2016-03-10  3:34   ` Greg KH
  0 siblings, 1 reply; 6+ messages in thread
From: Jiang Lu @ 2016-03-10  3:17 UTC (permalink / raw
  To: gregkh, linux-kernel, linux-serial

compat_ioctl use 0xffffffff as a magic number to mark invalid pointer
for iomem_base in serial_struct when truncating a 64bit pointer into
32bit.

Serial driver need recognize this invalid pointer when parsing
serial_struct from userspace.

Signed-off-by: Jiang Lu <lu.jiang@windriver.com>
---
 drivers/tty/serial/serial_core.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c
index a5d545e..d293536 100644
--- a/drivers/tty/serial/serial_core.c
+++ b/drivers/tty/serial/serial_core.c
@@ -745,6 +745,9 @@ static int uart_set_info(struct tty_struct *tty, struct tty_port *port,
 	 * allocations, we should treat type changes the same as
 	 * IO port changes.
 	 */
+	if ((unsigned long)new_info->iomem_base == 0xffffffff)
+		new_info->iomem_base = (void *)(unsigned long)uport->mapbase;
+
 	change_port = !(uport->flags & UPF_FIXED_PORT)
 		&& (new_port != uport->iobase ||
 		    (unsigned long)new_info->iomem_base != uport->mapbase ||
-- 
1.9.1

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

* Re: [v2] serial_core:recognize invalid pointer from userspace
  2016-03-10  3:17 ` [v2] serial_core:recognize " Jiang Lu
@ 2016-03-10  3:34   ` Greg KH
  2016-03-10  4:56     ` Lu.Jiang
  0 siblings, 1 reply; 6+ messages in thread
From: Greg KH @ 2016-03-10  3:34 UTC (permalink / raw
  To: Jiang Lu; +Cc: linux-kernel, linux-serial

On Thu, Mar 10, 2016 at 11:17:23AM +0800, Jiang Lu wrote:
> compat_ioctl use 0xffffffff as a magic number to mark invalid pointer
> for iomem_base in serial_struct when truncating a 64bit pointer into
> 32bit.
> 
> Serial driver need recognize this invalid pointer when parsing
> serial_struct from userspace.
> 
> Signed-off-by: Jiang Lu <lu.jiang@windriver.com>
> ---
>  drivers/tty/serial/serial_core.c | 3 +++
>  1 file changed, 3 insertions(+)
> 
> diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c
> index a5d545e..d293536 100644
> --- a/drivers/tty/serial/serial_core.c
> +++ b/drivers/tty/serial/serial_core.c
> @@ -745,6 +745,9 @@ static int uart_set_info(struct tty_struct *tty, struct tty_port *port,
>  	 * allocations, we should treat type changes the same as
>  	 * IO port changes.
>  	 */
> +	if ((unsigned long)new_info->iomem_base == 0xffffffff)
> +		new_info->iomem_base = (void *)(unsigned long)uport->mapbase;

This looks really odd to me, why do we care about userspace issues here?
Shouldn't the compat ioctl code have handled this already all for us?

And why set it to mapbase?  Just to keep it from being changed?

this worries me...

greg k-h

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

* Re: [v2] serial_core:recognize invalid pointer from userspace
  2016-03-10  3:34   ` Greg KH
@ 2016-03-10  4:56     ` Lu.Jiang
  2016-03-10 13:46       ` One Thousand Gnomes
  0 siblings, 1 reply; 6+ messages in thread
From: Lu.Jiang @ 2016-03-10  4:56 UTC (permalink / raw
  To: Greg KH; +Cc: linux-kernel, linux-serial

[-- Attachment #1: Type: text/plain, Size: 2550 bytes --]

On 2016年03月10日 11:34, Greg KH wrote:
> On Thu, Mar 10, 2016 at 11:17:23AM +0800, Jiang Lu wrote:
>> compat_ioctl use 0xffffffff as a magic number to mark invalid pointer
>> for iomem_base in serial_struct when truncating a 64bit pointer into
>> 32bit.
>>
>> Serial driver need recognize this invalid pointer when parsing
>> serial_struct from userspace.
>>
>> Signed-off-by: Jiang Lu <lu.jiang@windriver.com>
>> ---
>>   drivers/tty/serial/serial_core.c | 3 +++
>>   1 file changed, 3 insertions(+)
>>
>> diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c
>> index a5d545e..d293536 100644
>> --- a/drivers/tty/serial/serial_core.c
>> +++ b/drivers/tty/serial/serial_core.c
>> @@ -745,6 +745,9 @@ static int uart_set_info(struct tty_struct *tty, struct tty_port *port,
>>   	 * allocations, we should treat type changes the same as
>>   	 * IO port changes.
>>   	 */
>> +	if ((unsigned long)new_info->iomem_base == 0xffffffff)
>> +		new_info->iomem_base = (void *)(unsigned long)uport->mapbase;
> This looks really odd to me, why do we care about userspace issues here?
> Shouldn't the compat ioctl code have handled this already all for us?
When getting serial struct, compat ioctl code just set it to 0xffffffff 
when 64bit iomem_base is beyond 32bit in kernel.

Then when setting serial_struct, compat ioctl code for TIOCSSERIAL can 
not restore original value, it need serial_core to take care of this.
>
> And why set it to mapbase?  Just to keep it from being changed?

Serial_core just restore the invalid value with original value to make 
following code in uart_set_info() happy.

>
> this worries me...


Actually, This member introduce lots of trouble with 32bit/64bit 
conversion. For example,

When userspace get setting with TIOCGSERIAL,

1.On 64bit kernel + 32bit rootfs, compat ioctl code use 0xffffffff to 
mark invalid conversion.

2.On 32bit kernel with 64bit physical address, uart_get_info() in 
serial_core will truncate a 64bit address into 32bit pointer with 
following code:
     retinfo->iomem_base      = (void *)(unsigned long)uport->mapbase;

Then when setting with TIOCSSERIAL ioctl, application can not provide 
original value for iomem_base, it leads setserial can not work on such 
boards.

I don't know why kernel should expose this value to userspace, and seems 
no need for userspace application to update an physical address for driver.
Can we consider drop this member in handle for TIOCSSERIAL ioctl. Please 
see a rough patch in attachment.

Thanks
Jiang Lu
>
> greg k-h
>


[-- Attachment #2: 0001-serial_core-stop-updating-mapbase-in-uart_set_info.patch --]
[-- Type: text/x-patch, Size: 2032 bytes --]

>From 9bad3c17ef447c5cf89a2465833bbabed2800fe7 Mon Sep 17 00:00:00 2001
From: Jiang Lu <lu.jiang@windriver.com>
Date: Thu, 10 Mar 2016 12:51:54 +0800
Subject: [PATCH] serial_core:stop updating mapbase in uart_set_info()

Stop updating mapbase with iomem_base in uart_set_info().

Signed-off-by: Jiang Lu <lu.jiang@windriver.com>
---
 drivers/tty/serial/serial_core.c | 6 +-----
 1 file changed, 1 insertion(+), 5 deletions(-)

diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c
index a5d545e..cda9f9e 100644
--- a/drivers/tty/serial/serial_core.c
+++ b/drivers/tty/serial/serial_core.c
@@ -747,7 +747,6 @@ static int uart_set_info(struct tty_struct *tty, struct tty_port *port,
 	 */
 	change_port = !(uport->flags & UPF_FIXED_PORT)
 		&& (new_port != uport->iobase ||
-		    (unsigned long)new_info->iomem_base != uport->mapbase ||
 		    new_info->hub6 != uport->hub6 ||
 		    new_info->io_type != uport->iotype ||
 		    new_info->iomem_reg_shift != uport->regshift ||
@@ -803,11 +802,10 @@ static int uart_set_info(struct tty_struct *tty, struct tty_port *port,
 	}
 
 	if (change_port) {
-		unsigned long old_iobase, old_mapbase;
+		unsigned long old_iobase;
 		unsigned int old_type, old_iotype, old_hub6, old_shift;
 
 		old_iobase = uport->iobase;
-		old_mapbase = uport->mapbase;
 		old_type = uport->type;
 		old_hub6 = uport->hub6;
 		old_iotype = uport->iotype;
@@ -824,7 +822,6 @@ static int uart_set_info(struct tty_struct *tty, struct tty_port *port,
 		uport->hub6 = new_info->hub6;
 		uport->iotype = new_info->io_type;
 		uport->regshift = new_info->iomem_reg_shift;
-		uport->mapbase = (unsigned long)new_info->iomem_base;
 
 		/*
 		 * Claim and map the new regions
@@ -846,7 +843,6 @@ static int uart_set_info(struct tty_struct *tty, struct tty_port *port,
 			uport->hub6 = old_hub6;
 			uport->iotype = old_iotype;
 			uport->regshift = old_shift;
-			uport->mapbase = old_mapbase;
 
 			if (old_type != PORT_UNKNOWN) {
 				retval = uport->ops->request_port(uport);
-- 
1.9.1


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

* Re: [v2] serial_core:recognize invalid pointer from userspace
  2016-03-10  4:56     ` Lu.Jiang
@ 2016-03-10 13:46       ` One Thousand Gnomes
  2016-03-11  2:30         ` Lu.Jiang
  0 siblings, 1 reply; 6+ messages in thread
From: One Thousand Gnomes @ 2016-03-10 13:46 UTC (permalink / raw
  To: Lu.Jiang; +Cc: Greg KH, linux-kernel, linux-serial

> When userspace get setting with TIOCGSERIAL,
> 
> 1.On 64bit kernel + 32bit rootfs, compat ioctl code use 0xffffffff to 
> mark invalid conversion.

Start at the beginning. What is being passed back and forth that causes
the problem. What memory address does your uart have ?

> 2.On 32bit kernel with 64bit physical address, uart_get_info() in 
> serial_core will truncate a 64bit address into 32bit pointer with 
> following code:
>      retinfo->iomem_base      = (void *)(unsigned long)uport->mapbase;
> 
> Then when setting with TIOCSSERIAL ioctl, application can not provide 
> original value for iomem_base, it leads setserial can not work on such 
> boards.

Yes - it's a legacy feature that isn't really needed on 64bit systems.

> I don't know why kernel should expose this value to userspace, and seems 
> no need for userspace application to update an physical address for driver.
> Can we consider drop this member in handle for TIOCSSERIAL ioctl. Please 
> see a rough patch in attachment.

There are old PC and embedded cases from the time before devicetree and
ACPI were the default. It's now an API people rely upon.

It would make sense I think to return 0 for the base address if it
exceeds 32bits, and also to ignore a TIOCSSERIAL that passes 0 as the
address back. Would that fix your use case ?

Alan

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

* Re: [v2] serial_core:recognize invalid pointer from userspace
  2016-03-10 13:46       ` One Thousand Gnomes
@ 2016-03-11  2:30         ` Lu.Jiang
  0 siblings, 0 replies; 6+ messages in thread
From: Lu.Jiang @ 2016-03-11  2:30 UTC (permalink / raw
  To: One Thousand Gnomes; +Cc: Greg KH, linux-kernel, linux-serial

On 2016年03月10日 21:46, One Thousand Gnomes wrote:
>> When userspace get setting with TIOCGSERIAL,
>>
>> 1.On 64bit kernel + 32bit rootfs, compat ioctl code use 0xffffffff to
>> mark invalid conversion.
> Start at the beginning. What is being passed back and forth that causes
> the problem. What memory address does your uart have ?

In fs/compat_ioctl.c, serial_struct_ioctl() use following code for 
convert a 64bit pointer into 32bit userspace pointer

         if (cmd == TIOCGSERIAL && err >= 0) {
                 if (copy_in_user(ss32, ss, offsetof(SS32, iomem_base)) ||
                     get_user(iomem_base, &ss->iomem_base))
                         return -EFAULT;
                 base = (unsigned long)iomem_base  >> 32 ?
                         0xffffffff : (unsigned)(unsigned long)iomem_base;

If iomem_base exceed 4G, TIOCGSERIAL didn't return right value for 
iomem_base.

it  use following code to covert 32bit to 64bit.
         if (cmd == TIOCSSERIAL) {
                 if (copy_in_user(ss, ss32, offsetof(SS32, iomem_base)) ||
                     get_user(udata, &ss32->iomem_base))
                         return -EFAULT;
                 iomem_base = compat_ptr(udata);


static inline void __user *compat_ptr(compat_uptr_t uptr)
{
         return (void __user *)(unsigned long)uptr;
}

You can see userspace application didn't get valid iomem_base via 
TIOCGSERAIL.
When issuing TIOCSSERIAL, application can not provide a workable value 
for kernel. It means TIOCSSERIAL can not work.

Typical serial setting application setserial is depend on those 2 ioctls.

>
>> 2.On 32bit kernel with 64bit physical address, uart_get_info() in
>> serial_core will truncate a 64bit address into 32bit pointer with
>> following code:
>>       retinfo->iomem_base      = (void *)(unsigned long)uport->mapbase;
>>
>> Then when setting with TIOCSSERIAL ioctl, application can not provide
>> original value for iomem_base, it leads setserial can not work on such
>> boards.
> Yes - it's a legacy feature that isn't really needed on 64bit systems.
>
>> I don't know why kernel should expose this value to userspace, and seems
>> no need for userspace application to update an physical address for driver.
>> Can we consider drop this member in handle for TIOCSSERIAL ioctl. Please
>> see a rough patch in attachment.
> There are old PC and embedded cases from the time before devicetree and
> ACPI were the default. It's now an API people rely upon.
>
> It would make sense I think to return 0 for the base address if it
> exceeds 32bits, and also to ignore a TIOCSSERIAL that passes 0 as the
> address back. Would that fix your use case ?

If boards relay on this TIOCSSERIAL only working on 32bit, this solution 
is workable.


Thanks
Jiang Lu



>
> Alan
>

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

end of thread, other threads:[~2016-03-11  2:31 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2016-03-10  3:17 [v2]serial_core:recognize invalid pointer from userspace Jiang Lu
2016-03-10  3:17 ` [v2] serial_core:recognize " Jiang Lu
2016-03-10  3:34   ` Greg KH
2016-03-10  4:56     ` Lu.Jiang
2016-03-10 13:46       ` One Thousand Gnomes
2016-03-11  2:30         ` Lu.Jiang

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 read-only IMAP folder(s) and NNTP newsgroup(s).