linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH] serial: core: fix suspicious security_locked_down() call
@ 2021-05-07 11:57 Ondrej Mosnacek
  2021-05-07 12:27 ` Greg Kroah-Hartman
  2021-05-10 19:36 ` Kees Cook
  0 siblings, 2 replies; 4+ messages in thread
From: Ondrej Mosnacek @ 2021-05-07 11:57 UTC (permalink / raw)
  To: Greg Kroah-Hartman, linux-serial
  Cc: David Howells, Matthew Garrett, Kees Cook, Jiri Slaby, selinux,
	linux-security-module, James Morris, linux-fsdevel, linux-kernel

The commit that added this check did so in a very strange way - first
security_locked_down() is called, its value stored into retval, and if
it's nonzero, then an additional check is made for (change_irq ||
change_port), and if this is true, the function returns. However, if
the goto exit branch is not taken, the code keeps the retval value and
continues executing the function. Then, depending on whether
uport->ops->verify_port is set, the retval value may or may not be reset
to zero and eventually the error value from security_locked_down() may
abort the function a few lines below.

I will go out on a limb and assume that this isn't the intended behavior
and that an error value from security_locked_down() was supposed to
abort the function only in case (change_irq || change_port) is true.

Note that security_locked_down() should be called last in any series of
checks, since the SELinux implementation of this hook will do a check
against the policy and generate an audit record in case of denial. If
the operation was to carry on after calling security_locked_down(), then
the SELinux denial record would be bogus.

See commit 59438b46471a ("security,lockdown,selinux: implement SELinux
lockdown") for how SELinux implements this hook.

Fixes: 794edf30ee6c ("lockdown: Lock down TIOCSSERIAL")
Signed-off-by: Ondrej Mosnacek <omosnace@redhat.com>
---
 drivers/tty/serial/serial_core.c | 8 +++++---
 1 file changed, 5 insertions(+), 3 deletions(-)

diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c
index ba31e97d3d96..d7d8e7dbda60 100644
--- a/drivers/tty/serial/serial_core.c
+++ b/drivers/tty/serial/serial_core.c
@@ -865,9 +865,11 @@ static int uart_set_info(struct tty_struct *tty, struct tty_port *port,
 		goto check_and_exit;
 	}
 
-	retval = security_locked_down(LOCKDOWN_TIOCSSERIAL);
-	if (retval && (change_irq || change_port))
-		goto exit;
+	if (change_irq || change_port) {
+		retval = security_locked_down(LOCKDOWN_TIOCSSERIAL);
+		if (retval)
+			goto exit;
+	}
 
 	/*
 	 * Ask the low level driver to verify the settings.
-- 
2.31.1


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

* Re: [PATCH] serial: core: fix suspicious security_locked_down() call
  2021-05-07 11:57 [PATCH] serial: core: fix suspicious security_locked_down() call Ondrej Mosnacek
@ 2021-05-07 12:27 ` Greg Kroah-Hartman
  2021-05-07 12:58   ` Ondrej Mosnacek
  2021-05-10 19:36 ` Kees Cook
  1 sibling, 1 reply; 4+ messages in thread
From: Greg Kroah-Hartman @ 2021-05-07 12:27 UTC (permalink / raw)
  To: Ondrej Mosnacek
  Cc: linux-serial, David Howells, Matthew Garrett, Kees Cook,
	Jiri Slaby, selinux, linux-security-module, James Morris,
	linux-fsdevel, linux-kernel

On Fri, May 07, 2021 at 01:57:19PM +0200, Ondrej Mosnacek wrote:
> The commit that added this check did so in a very strange way - first
> security_locked_down() is called, its value stored into retval, and if
> it's nonzero, then an additional check is made for (change_irq ||
> change_port), and if this is true, the function returns. However, if
> the goto exit branch is not taken, the code keeps the retval value and
> continues executing the function. Then, depending on whether
> uport->ops->verify_port is set, the retval value may or may not be reset
> to zero and eventually the error value from security_locked_down() may
> abort the function a few lines below.
> 
> I will go out on a limb and assume that this isn't the intended behavior
> and that an error value from security_locked_down() was supposed to
> abort the function only in case (change_irq || change_port) is true.

Are you _sure_ about this?

Verification from the authors and users of this odd feature might be
good to have, as I am loath to change how this works without them
weighing in here.

thanks,

greg k-h

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

* Re: [PATCH] serial: core: fix suspicious security_locked_down() call
  2021-05-07 12:27 ` Greg Kroah-Hartman
@ 2021-05-07 12:58   ` Ondrej Mosnacek
  0 siblings, 0 replies; 4+ messages in thread
From: Ondrej Mosnacek @ 2021-05-07 12:58 UTC (permalink / raw)
  To: Greg Kroah-Hartman
  Cc: linux-serial, David Howells, Matthew Garrett, Kees Cook,
	Jiri Slaby, SElinux list, Linux Security Module list,
	James Morris, Linux FS Devel, Linux kernel mailing list

On Fri, May 7, 2021 at 2:27 PM Greg Kroah-Hartman
<gregkh@linuxfoundation.org> wrote:
> On Fri, May 07, 2021 at 01:57:19PM +0200, Ondrej Mosnacek wrote:
> > The commit that added this check did so in a very strange way - first
> > security_locked_down() is called, its value stored into retval, and if
> > it's nonzero, then an additional check is made for (change_irq ||
> > change_port), and if this is true, the function returns. However, if
> > the goto exit branch is not taken, the code keeps the retval value and
> > continues executing the function. Then, depending on whether
> > uport->ops->verify_port is set, the retval value may or may not be reset
> > to zero and eventually the error value from security_locked_down() may
> > abort the function a few lines below.
> >
> > I will go out on a limb and assume that this isn't the intended behavior
> > and that an error value from security_locked_down() was supposed to
> > abort the function only in case (change_irq || change_port) is true.
>
> Are you _sure_ about this?
>
> Verification from the authors and users of this odd feature might be
> good to have, as I am loath to change how this works without them
> weighing in here.

I'm not completely sure and I'm with you on not merging this without
feedback from people involved in the original patch and/or whoever
understands the logic in said function.

-- 
Ondrej Mosnacek
Software Engineer, Linux Security - SELinux kernel
Red Hat, Inc.


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

* Re: [PATCH] serial: core: fix suspicious security_locked_down() call
  2021-05-07 11:57 [PATCH] serial: core: fix suspicious security_locked_down() call Ondrej Mosnacek
  2021-05-07 12:27 ` Greg Kroah-Hartman
@ 2021-05-10 19:36 ` Kees Cook
  1 sibling, 0 replies; 4+ messages in thread
From: Kees Cook @ 2021-05-10 19:36 UTC (permalink / raw)
  To: Ondrej Mosnacek
  Cc: Greg Kroah-Hartman, linux-serial, David Howells, Matthew Garrett,
	Jiri Slaby, selinux, linux-security-module, James Morris,
	linux-fsdevel, linux-kernel

On Fri, May 07, 2021 at 01:57:19PM +0200, Ondrej Mosnacek wrote:
> The commit that added this check did so in a very strange way - first
> security_locked_down() is called, its value stored into retval, and if
> it's nonzero, then an additional check is made for (change_irq ||
> change_port), and if this is true, the function returns. However, if
> the goto exit branch is not taken, the code keeps the retval value and
> continues executing the function. Then, depending on whether
> uport->ops->verify_port is set, the retval value may or may not be reset
> to zero and eventually the error value from security_locked_down() may
> abort the function a few lines below.
> 
> I will go out on a limb and assume that this isn't the intended behavior
> and that an error value from security_locked_down() was supposed to
> abort the function only in case (change_irq || change_port) is true.
> 
> Note that security_locked_down() should be called last in any series of
> checks, since the SELinux implementation of this hook will do a check
> against the policy and generate an audit record in case of denial. If
> the operation was to carry on after calling security_locked_down(), then
> the SELinux denial record would be bogus.
> 
> See commit 59438b46471a ("security,lockdown,selinux: implement SELinux
> lockdown") for how SELinux implements this hook.
> 
> Fixes: 794edf30ee6c ("lockdown: Lock down TIOCSSERIAL")
> Signed-off-by: Ondrej Mosnacek <omosnace@redhat.com>
> ---
>  drivers/tty/serial/serial_core.c | 8 +++++---
>  1 file changed, 5 insertions(+), 3 deletions(-)
> 
> diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c
> index ba31e97d3d96..d7d8e7dbda60 100644
> --- a/drivers/tty/serial/serial_core.c
> +++ b/drivers/tty/serial/serial_core.c
> @@ -865,9 +865,11 @@ static int uart_set_info(struct tty_struct *tty, struct tty_port *port,
>  		goto check_and_exit;
>  	}
>  
> -	retval = security_locked_down(LOCKDOWN_TIOCSSERIAL);
> -	if (retval && (change_irq || change_port))
> -		goto exit;
> +	if (change_irq || change_port) {
> +		retval = security_locked_down(LOCKDOWN_TIOCSSERIAL);
> +		if (retval)
> +			goto exit;
> +	}
>  
>  	/*
>  	 * Ask the low level driver to verify the settings.

Oops. Yeah, good catch -- I missed the kind of weird handling of retval
in this function when I originally reviewed it.

I think the goals of just covering IRQ/IO port changes originate from here:
https://lore.kernel.org/lkml/26173.1479769852@warthog.procyon.org.uk/

And I think the "Reported-by: Greg KH" originates from here:
https://lore.kernel.org/lkml/20161206071104.GA10292@kroah.com/

So, yes, I think your fix is correct.

Acked-by: Kees Cook <keescook@chromium.org>

-- 
Kees Cook

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

end of thread, other threads:[~2021-05-10 19:37 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-05-07 11:57 [PATCH] serial: core: fix suspicious security_locked_down() call Ondrej Mosnacek
2021-05-07 12:27 ` Greg Kroah-Hartman
2021-05-07 12:58   ` Ondrej Mosnacek
2021-05-10 19:36 ` Kees Cook

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