diff mbox series

USB: serial: console: Fix potential use-after-free in usb_console_setup()

Message ID 20220916073552.4093048-1-windhl@126.com (mailing list archive)
State New, archived
Headers show
Series USB: serial: console: Fix potential use-after-free in usb_console_setup() | expand

Commit Message

Liang He Sept. 16, 2022, 7:35 a.m. UTC
In usb_console_setup(), if we goto error_get_interface and the
usb_serial_put() may finally call kfree(serial). However, the next
line will call 'mutex_unlock(&serial->disc_mutex)' which can cause
a potential UAF bug.

Fixes: 7bd032dc2793 ("USB serial: update the console driver")
Signed-off-by: Liang He <windhl@126.com>
---

 I don't know if the refcount can be zero here, so if it cannot be zero,
this code is safe and please ignore my patch.

 drivers/usb/serial/console.c | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

Comments

Alan Stern Sept. 16, 2022, 3:04 p.m. UTC | #1
On Fri, Sep 16, 2022 at 03:35:52PM +0800, Liang He wrote:
> In usb_console_setup(), if we goto error_get_interface and the
> usb_serial_put() may finally call kfree(serial). However, the next
> line will call 'mutex_unlock(&serial->disc_mutex)' which can cause
> a potential UAF bug.

Why not just move the mutex_unlock() call up one line, before the 
usb_serial_put()?

> Fixes: 7bd032dc2793 ("USB serial: update the console driver")
> Signed-off-by: Liang He <windhl@126.com>
> ---
> 
>  I don't know if the refcount can be zero here, so if it cannot be zero,
> this code is safe and please ignore my patch.
> 
>  drivers/usb/serial/console.c | 5 +++--
>  1 file changed, 3 insertions(+), 2 deletions(-)
> 
> diff --git a/drivers/usb/serial/console.c b/drivers/usb/serial/console.c
> index b97aa40ca4d1..21ac2dd6baca 100644
> --- a/drivers/usb/serial/console.c
> +++ b/drivers/usb/serial/console.c
> @@ -62,6 +62,7 @@ static int usb_console_setup(struct console *co, char *options)
>  	int cflag = CREAD | HUPCL | CLOCAL;
>  	char *s;
>  	struct usb_serial *serial;
> +	struct mutex *s_mutex;
>  	struct usb_serial_port *port;
>  	int retval;
>  	struct tty_struct *tty = NULL;
> @@ -116,7 +117,7 @@ static int usb_console_setup(struct console *co, char *options)
>  		return -ENODEV;
>  	}
>  	serial = port->serial;
> -
> +	s_mutex = &serial->disc_mutex;
>  	retval = usb_autopm_get_interface(serial->interface);
>  	if (retval)
>  		goto error_get_interface;
> @@ -190,7 +191,7 @@ static int usb_console_setup(struct console *co, char *options)
>  	usb_autopm_put_interface(serial->interface);
>   error_get_interface:
>  	usb_serial_put(serial);
> -	mutex_unlock(&serial->disc_mutex);
> +	mutex_unlock(s_mutex);

If the old code was unsafe then so is this, because s_mutex points to a 
mutex that is embedded within the serial structure.  If the structure 
was deallocated by usb_serial_put() then so was the mutex.

Alan Stern

>  	return retval;
>  }
>  
> -- 
> 2.25.1
>
Liang He Sept. 16, 2022, 3:20 p.m. UTC | #2
At 2022-09-16 23:04:02, "Alan Stern" <stern@rowland.harvard.edu> wrote:
>On Fri, Sep 16, 2022 at 03:35:52PM +0800, Liang He wrote:
>> In usb_console_setup(), if we goto error_get_interface and the
>> usb_serial_put() may finally call kfree(serial). However, the next
>> line will call 'mutex_unlock(&serial->disc_mutex)' which can cause
>> a potential UAF bug.
>
>Why not just move the mutex_unlock() call up one line, before the 
>usb_serial_put()?
>
>> Fixes: 7bd032dc2793 ("USB serial: update the console driver")
>> Signed-off-by: Liang He <windhl@126.com>
>> ---
>> 
>>  I don't know if the refcount can be zero here, so if it cannot be zero,
>> this code is safe and please ignore my patch.
>> 
>>  drivers/usb/serial/console.c | 5 +++--
>>  1 file changed, 3 insertions(+), 2 deletions(-)
>> 
>> diff --git a/drivers/usb/serial/console.c b/drivers/usb/serial/console.c
>> index b97aa40ca4d1..21ac2dd6baca 100644
>> --- a/drivers/usb/serial/console.c
>> +++ b/drivers/usb/serial/console.c
>> @@ -62,6 +62,7 @@ static int usb_console_setup(struct console *co, char *options)
>>  	int cflag = CREAD | HUPCL | CLOCAL;
>>  	char *s;
>>  	struct usb_serial *serial;
>> +	struct mutex *s_mutex;
>>  	struct usb_serial_port *port;
>>  	int retval;
>>  	struct tty_struct *tty = NULL;
>> @@ -116,7 +117,7 @@ static int usb_console_setup(struct console *co, char *options)
>>  		return -ENODEV;
>>  	}
>>  	serial = port->serial;
>> -
>> +	s_mutex = &serial->disc_mutex;
>>  	retval = usb_autopm_get_interface(serial->interface);
>>  	if (retval)
>>  		goto error_get_interface;
>> @@ -190,7 +191,7 @@ static int usb_console_setup(struct console *co, char *options)
>>  	usb_autopm_put_interface(serial->interface);
>>   error_get_interface:
>>  	usb_serial_put(serial);
>> -	mutex_unlock(&serial->disc_mutex);
>> +	mutex_unlock(s_mutex);
>
>If the old code was unsafe then so is this, because s_mutex points to a 
>mutex that is embedded within the serial structure.  If the structure 
>was deallocated by usb_serial_put() then so was the mutex.
>
>Alan Stern
>
>>  	return retval;
>>  }
>>  
>> -- 
>> 2.25.1
>> 

Hi, Alan Stern,

Thanks for your review and this patch is indeed wrong!

But I am not sure if we can safely move the usb_serial_put()
out of mutex_unlock().

If it is safe, I can give a new version of patch very soon.

Can you help me confirm if it is safe?

Thanks again,

Liang
Alan Stern Sept. 16, 2022, 3:36 p.m. UTC | #3
On Fri, Sep 16, 2022 at 11:20:23PM +0800, Liang He wrote:
> 
> 
> At 2022-09-16 23:04:02, "Alan Stern" <stern@rowland.harvard.edu> wrote:
> >On Fri, Sep 16, 2022 at 03:35:52PM +0800, Liang He wrote:
> >> In usb_console_setup(), if we goto error_get_interface and the
> >> usb_serial_put() may finally call kfree(serial). However, the next
> >> line will call 'mutex_unlock(&serial->disc_mutex)' which can cause
> >> a potential UAF bug.
> >
> >Why not just move the mutex_unlock() call up one line, before the 
> >usb_serial_put()?
> >
> >> Fixes: 7bd032dc2793 ("USB serial: update the console driver")
> >> Signed-off-by: Liang He <windhl@126.com>
> >> ---
> >> 
> >>  I don't know if the refcount can be zero here, so if it cannot be zero,
> >> this code is safe and please ignore my patch.
> >> 
> >>  drivers/usb/serial/console.c | 5 +++--
> >>  1 file changed, 3 insertions(+), 2 deletions(-)
> >> 
> >> diff --git a/drivers/usb/serial/console.c b/drivers/usb/serial/console.c
> >> index b97aa40ca4d1..21ac2dd6baca 100644
> >> --- a/drivers/usb/serial/console.c
> >> +++ b/drivers/usb/serial/console.c
> >> @@ -62,6 +62,7 @@ static int usb_console_setup(struct console *co, char *options)
> >>  	int cflag = CREAD | HUPCL | CLOCAL;
> >>  	char *s;
> >>  	struct usb_serial *serial;
> >> +	struct mutex *s_mutex;
> >>  	struct usb_serial_port *port;
> >>  	int retval;
> >>  	struct tty_struct *tty = NULL;
> >> @@ -116,7 +117,7 @@ static int usb_console_setup(struct console *co, char *options)
> >>  		return -ENODEV;
> >>  	}
> >>  	serial = port->serial;
> >> -
> >> +	s_mutex = &serial->disc_mutex;
> >>  	retval = usb_autopm_get_interface(serial->interface);
> >>  	if (retval)
> >>  		goto error_get_interface;
> >> @@ -190,7 +191,7 @@ static int usb_console_setup(struct console *co, char *options)
> >>  	usb_autopm_put_interface(serial->interface);
> >>   error_get_interface:
> >>  	usb_serial_put(serial);
> >> -	mutex_unlock(&serial->disc_mutex);
> >> +	mutex_unlock(s_mutex);
> >
> >If the old code was unsafe then so is this, because s_mutex points to a 
> >mutex that is embedded within the serial structure.  If the structure 
> >was deallocated by usb_serial_put() then so was the mutex.
> >
> >Alan Stern
> >
> >>  	return retval;
> >>  }
> >>  
> >> -- 
> >> 2.25.1
> >> 
> 
> Hi, Alan Stern,
> 
> Thanks for your review and this patch is indeed wrong!
> 
> But I am not sure if we can safely move the usb_serial_put()
> out of mutex_unlock().
> 
> If it is safe, I can give a new version of patch very soon.
> 
> Can you help me confirm if it is safe?

I cannot.  You need to ask Johan (the USB-serial maintainer).

Alan Stern
Liang He Sept. 19, 2022, 1:59 a.m. UTC | #4
At 2022-09-16 23:36:47, "Alan Stern" <stern@rowland.harvard.edu> wrote:
>On Fri, Sep 16, 2022 at 11:20:23PM +0800, Liang He wrote:
>> 
>> 
>> At 2022-09-16 23:04:02, "Alan Stern" <stern@rowland.harvard.edu> wrote:
>> >On Fri, Sep 16, 2022 at 03:35:52PM +0800, Liang He wrote:
>> >> In usb_console_setup(), if we goto error_get_interface and the
>> >> usb_serial_put() may finally call kfree(serial). However, the next
>> >> line will call 'mutex_unlock(&serial->disc_mutex)' which can cause
>> >> a potential UAF bug.
>> >
>> >Why not just move the mutex_unlock() call up one line, before the 
>> >usb_serial_put()?
>> >
>> >> Fixes: 7bd032dc2793 ("USB serial: update the console driver")
>> >> Signed-off-by: Liang He <windhl@126.com>
>> >> ---
>> >> 
>> >>  I don't know if the refcount can be zero here, so if it cannot be zero,
>> >> this code is safe and please ignore my patch.
>> >> 
>> >>  drivers/usb/serial/console.c | 5 +++--
>> >>  1 file changed, 3 insertions(+), 2 deletions(-)
>> >> 
>> >> diff --git a/drivers/usb/serial/console.c b/drivers/usb/serial/console.c
>> >> index b97aa40ca4d1..21ac2dd6baca 100644
>> >> --- a/drivers/usb/serial/console.c
>> >> +++ b/drivers/usb/serial/console.c
>> >> @@ -62,6 +62,7 @@ static int usb_console_setup(struct console *co, char *options)
>> >>  	int cflag = CREAD | HUPCL | CLOCAL;
>> >>  	char *s;
>> >>  	struct usb_serial *serial;
>> >> +	struct mutex *s_mutex;
>> >>  	struct usb_serial_port *port;
>> >>  	int retval;
>> >>  	struct tty_struct *tty = NULL;
>> >> @@ -116,7 +117,7 @@ static int usb_console_setup(struct console *co, char *options)
>> >>  		return -ENODEV;
>> >>  	}
>> >>  	serial = port->serial;
>> >> -
>> >> +	s_mutex = &serial->disc_mutex;
>> >>  	retval = usb_autopm_get_interface(serial->interface);
>> >>  	if (retval)
>> >>  		goto error_get_interface;
>> >> @@ -190,7 +191,7 @@ static int usb_console_setup(struct console *co, char *options)
>> >>  	usb_autopm_put_interface(serial->interface);
>> >>   error_get_interface:
>> >>  	usb_serial_put(serial);
>> >> -	mutex_unlock(&serial->disc_mutex);
>> >> +	mutex_unlock(s_mutex);
>> >
>> >If the old code was unsafe then so is this, because s_mutex points to a 
>> >mutex that is embedded within the serial structure.  If the structure 
>> >was deallocated by usb_serial_put() then so was the mutex.
>> >
>> >Alan Stern
>> >
>> >>  	return retval;
>> >>  }
>> >>  
>> >> -- 
>> >> 2.25.1
>> >> 
>> 
>> Hi, Alan Stern,
>> 
>> Thanks for your review and this patch is indeed wrong!
>> 
>> But I am not sure if we can safely move the usb_serial_put()
>> out of mutex_unlock().
>> 
>> If it is safe, I can give a new version of patch very soon.
>> 
>> Can you help me confirm if it is safe?
>
>I cannot.  You need to ask Johan (the USB-serial maintainer).
>
>Alan Stern

Still thanks!

And from a recent similar commit, I think we can move mutex_unlock above the usb_serial_put():

https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?h=v6.0-rc5&id=6c53b45c71b4920b5e62f0ea8079a1da382b9434

Johan, please confirm if this can be accepted.

Thanks,

Liang
Johan Hovold Sept. 19, 2022, 6:51 a.m. UTC | #5
On Mon, Sep 19, 2022 at 09:59:17AM +0800, Liang He wrote:
> At 2022-09-16 23:36:47, "Alan Stern" <stern@rowland.harvard.edu> wrote:
> >On Fri, Sep 16, 2022 at 11:20:23PM +0800, Liang He wrote:
> >> At 2022-09-16 23:04:02, "Alan Stern" <stern@rowland.harvard.edu> wrote:
> >> >On Fri, Sep 16, 2022 at 03:35:52PM +0800, Liang He wrote:
> >> >> In usb_console_setup(), if we goto error_get_interface and the
> >> >> usb_serial_put() may finally call kfree(serial). However, the next
> >> >> line will call 'mutex_unlock(&serial->disc_mutex)' which can cause
> >> >> a potential UAF bug.
> >> >
> >> >Why not just move the mutex_unlock() call up one line, before the 
> >> >usb_serial_put()?

> >> >If the old code was unsafe then so is this, because s_mutex points to a 
> >> >mutex that is embedded within the serial structure.  If the structure 
> >> >was deallocated by usb_serial_put() then so was the mutex.

> >> Thanks for your review and this patch is indeed wrong!
> >> 
> >> But I am not sure if we can safely move the usb_serial_put()
> >> out of mutex_unlock().
> >> 
> >> If it is safe, I can give a new version of patch very soon.
> >> 
> >> Can you help me confirm if it is safe?
> >
> >I cannot.  You need to ask Johan (the USB-serial maintainer).

> Johan, please confirm if this can be accepted.

Yes, we should unlock before dropping the reference as Alan suggested.

Note however that there is no use-after-free here as USB serial core
holds another reference when the console is registered.

Johan
diff mbox series

Patch

diff --git a/drivers/usb/serial/console.c b/drivers/usb/serial/console.c
index b97aa40ca4d1..21ac2dd6baca 100644
--- a/drivers/usb/serial/console.c
+++ b/drivers/usb/serial/console.c
@@ -62,6 +62,7 @@  static int usb_console_setup(struct console *co, char *options)
 	int cflag = CREAD | HUPCL | CLOCAL;
 	char *s;
 	struct usb_serial *serial;
+	struct mutex *s_mutex;
 	struct usb_serial_port *port;
 	int retval;
 	struct tty_struct *tty = NULL;
@@ -116,7 +117,7 @@  static int usb_console_setup(struct console *co, char *options)
 		return -ENODEV;
 	}
 	serial = port->serial;
-
+	s_mutex = &serial->disc_mutex;
 	retval = usb_autopm_get_interface(serial->interface);
 	if (retval)
 		goto error_get_interface;
@@ -190,7 +191,7 @@  static int usb_console_setup(struct console *co, char *options)
 	usb_autopm_put_interface(serial->interface);
  error_get_interface:
 	usb_serial_put(serial);
-	mutex_unlock(&serial->disc_mutex);
+	mutex_unlock(s_mutex);
 	return retval;
 }