All of lore.kernel.org
 help / color / mirror / Atom feed
From: Peter Hurley <peter@hurleysoftware.com>
To: "Herton R. Krzesinski" <herton@redhat.com>
Cc: linux-kernel@vger.kernel.org, Alan Cox <alan@linux.intel.com>,
	Greg Kroah-Hartman <gregkh@linuxfoundation.org>,
	Jiri Slaby <jslaby@suse.com>,
	Andrew Morton <akpm@linux-foundation.org>,
	Josh Triplett <josh@joshtriplett.org>,
	Al Viro <viro@zeniv.linux.org.uk>,
	David Howells <dhowells@redhat.com>
Subject: Re: [PATCH 2/2] pty: make sure super_block is still valid in final /dev/tty close
Date: Wed, 13 Jan 2016 09:54:03 -0800	[thread overview]
Message-ID: <56968F3B.20502@hurleysoftware.com> (raw)
In-Reply-To: <1452521264-21766-3-git-send-email-herton@redhat.com>

Hi Herton,

On 01/11/2016 06:07 AM, Herton R. Krzesinski wrote:
> Considering current pty code and multiple devpts instances, it's possible
> to umount a devpts file system while a program still has /dev/tty opened
> pointing to a previosuly closed pty pair in that instance. In the case all
> ptmx and pts/N files are closed, umount can be done. If the program closes
> /dev/tty after umount is done, devpts_kill_index will use now an invalid
> super_block, which was already destroyed in the umount operation after
> running ->kill_sb. This is another "use after free" type of issue, but now
> related to the allocated super_block instance.
> 
> To avoid the problem (warning at ida_remove and potential crashes) for
> this specific case, I added two functions in devpts which grabs additional
> references to the super_block, which pty code now uses so it makes sure
> the super block structure is still valid until pty shutdown is done.
> I also moved the additional inode references to the same functions, which
> also covered similar case with inode being freed before /dev/tty final
> close/shutdown.

Thanks for discovering and working this problem.
Comments below.


> Signed-off-by: Herton R. Krzesinski <herton@redhat.com>
> Cc: stable@vger.kernel.org # 2.6.29+
> ---
>  drivers/tty/pty.c         |  9 ++++++---
>  fs/devpts/inode.c         | 20 ++++++++++++++++++++
>  include/linux/devpts_fs.h |  4 ++++
>  3 files changed, 30 insertions(+), 3 deletions(-)
> 
> diff --git a/drivers/tty/pty.c b/drivers/tty/pty.c
> index 96016e5..7fc1b3e 100644
> --- a/drivers/tty/pty.c
> +++ b/drivers/tty/pty.c
> @@ -688,7 +688,7 @@ static void pty_unix98_shutdown(struct tty_struct *tty)
>  	else
>  		ptmx_inode = tty->link->driver_data;
>  	devpts_kill_index(ptmx_inode, tty->index);
> -	iput(ptmx_inode); /* drop reference we acquired at ptmx_open */
> +	devpts_iput_sb_deactive(ptmx_inode);
>  }
>  
>  static const struct tty_operations ptm_unix98_ops = {
> @@ -785,9 +785,12 @@ static int ptmx_open(struct inode *inode, struct file *filp)
>  	 * still have /dev/tty opened pointing to the master/slave pair (ptmx
>  	 * is closed/released before /dev/tty), we must make sure that the inode
>  	 * is still valid when we call the final pty_unix98_shutdown, thus we
> -	 * hold an additional reference to the ptmx inode
> +	 * hold an additional reference to the ptmx inode. For the same /dev/tty
> +	 * last close case, we also need to make sure the super_block isn't
> +	 * destroyed (devpts instance unmounted), before /dev/tty is closed and
> +	 * on its release devpts_kill_index is called.
>  	 */
> -	ihold(inode);
> +	devpts_ihold_sb_active(inode);
>  
>  	tty_add_file(tty, filp);
>  
> diff --git a/fs/devpts/inode.c b/fs/devpts/inode.c
> index c35ffdc..66a5421 100644
> --- a/fs/devpts/inode.c
> +++ b/fs/devpts/inode.c
> @@ -575,6 +575,26 @@ void devpts_kill_index(struct inode *ptmx_inode, int idx)
>  	mutex_unlock(&allocated_ptys_lock);
>  }
>  
> +/*
> + * pty code needs to hold extra references in case of last /dev/tty close
> + */
> +
> +void devpts_ihold_sb_active(struct inode *ptmx_inode)
> +{
> +	struct super_block *sb = pts_sb_from_inode(ptmx_inode);
> +
> +	atomic_inc(&sb->s_active);
> +	ihold(ptmx_inode);
> +}
> +
> +void devpts_iput_sb_deactive(struct inode *ptmx_inode)
> +{
> +	struct super_block *sb = pts_sb_from_inode(ptmx_inode);
> +
> +	iput(ptmx_inode);
> +	deactivate_super(sb);
> +}

We might as well roll in this functionality into
devpts_new_index() and devpts_kill_index().

I realize that's muddying the separation of concern.

Alternatively, name the functions for the logical operation
rather than specifically for what they do (eg. devpts_add_ref())

Regards,
Peter Hurley


> +
>  /**
>   * devpts_pty_new -- create a new inode in /dev/pts/
>   * @ptmx_inode: inode of the master
> diff --git a/include/linux/devpts_fs.h b/include/linux/devpts_fs.h
> index 251a209..f73ef49 100644
> --- a/include/linux/devpts_fs.h
> +++ b/include/linux/devpts_fs.h
> @@ -19,6 +19,8 @@
>  
>  int devpts_new_index(struct inode *ptmx_inode);
>  void devpts_kill_index(struct inode *ptmx_inode, int idx);
> +void devpts_ihold_sb_active(struct inode *ptmx_inode);
> +void devpts_iput_sb_deactive(struct inode *ptmx_inode);
>  /* mknod in devpts */
>  struct inode *devpts_pty_new(struct inode *ptmx_inode, dev_t device, int index,
>  		void *priv);
> @@ -32,6 +34,8 @@ void devpts_pty_kill(struct inode *inode);
>  /* Dummy stubs in the no-pty case */
>  static inline int devpts_new_index(struct inode *ptmx_inode) { return -EINVAL; }
>  static inline void devpts_kill_index(struct inode *ptmx_inode, int idx) { }
> +static inline void devpts_ihold_sb_active(struct inode *ptmx_inode) { }
> +static inline void devpts_iput_sb_deactive(struct inode *ptmx_inode) { }
>  static inline struct inode *devpts_pty_new(struct inode *ptmx_inode,
>  		dev_t device, int index, void *priv)
>  {
> 

  reply	other threads:[~2016-01-13 17:54 UTC|newest]

Thread overview: 12+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2016-01-11 14:07 pty: fix use after free issues at pty_unix98_shutdown Herton R. Krzesinski
2016-01-11 14:07 ` [PATCH 1/2 v2] pty: fix possible use after free of tty->driver_data Herton R. Krzesinski
2016-01-13 17:39   ` Peter Hurley
2016-01-13 18:28     ` Josh Triplett
2016-01-14 20:09       ` Herton R. Krzesinski
2016-01-14 21:27         ` Peter Hurley
2016-01-11 14:07 ` [PATCH 2/2] pty: make sure super_block is still valid in final /dev/tty close Herton R. Krzesinski
2016-01-13 17:54   ` Peter Hurley [this message]
2016-01-14 19:56     ` [PATCH 2/2 v2] " Herton R. Krzesinski
2016-01-16 21:09       ` Peter Hurley
2016-01-14 20:03     ` [PATCH 2/2] " Herton R. Krzesinski
2016-01-16 21:43       ` Peter Hurley

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=56968F3B.20502@hurleysoftware.com \
    --to=peter@hurleysoftware.com \
    --cc=akpm@linux-foundation.org \
    --cc=alan@linux.intel.com \
    --cc=dhowells@redhat.com \
    --cc=gregkh@linuxfoundation.org \
    --cc=herton@redhat.com \
    --cc=josh@joshtriplett.org \
    --cc=jslaby@suse.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=viro@zeniv.linux.org.uk \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
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.