Received: by 10.213.65.68 with SMTP id h4csp467276imn; Tue, 13 Mar 2018 09:59:23 -0700 (PDT) X-Google-Smtp-Source: AG47ELsnaK0kBeKHTAoBj8GfSNgyvdIIi9aDqsRF/5jy0spVauAyQAhJFhYMbgUmHmx2bnH0TBiN X-Received: by 10.99.96.130 with SMTP id u124mr1062957pgb.252.1520960363071; Tue, 13 Mar 2018 09:59:23 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1520960363; cv=none; d=google.com; s=arc-20160816; b=KKISzSTTEFldsIillAWQqtHmHUcrp5BS9GMdT0lzROU98a47Qz9vrNEEg6r8K4AL9V E8EH/vIDC30u/tOEmBm46GO8fJmf1s/d9zNFZQbo5yTxFWLsL5z3hBA8VKPfAG/Ez7E0 1ZG9lKF7XSGU+adIDZN0d12amnHRskZRQOHp4KBBJy0ohVsUWurYrZdHDUfA1gnsCNkO wgmiWR6fmj6D4tCOjZBdT1GJj1fGGeCy4usGc2BNBxtTzFRH+l5lE1+n6mZjor5R20zH fJ0S2qpCfiTRiFSdwC1O2TW/DnTBpplIB4k1ghb/6jM2zLQYQiOLGFwQVqaFTc1Z8eMV Wg6Q== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:references:in-reply-to:message-id:date :subject:cc:to:from:arc-authentication-results; bh=uF6SA9VSCjfWVJ5Baoud+d5RUAlxPO4/3slQdGAgdpo=; b=rLR5fb2aB4GhQ0seogNET8eCQ8/juQPv+2Uz0pLSsxoHcN3gIbtoMoHCr7gOMF7UWR uRL9EbhK7NrWKx317GQVrBWqTXytfOhSROUwNG82aF06A76QCwqxK50VBgAqLiW4vTYH PJoa4IlnE60PRn9+FT9EKCPO/LudlW8aPM6Sx//vJkJZ2p4Yrg3bwJWcK4yAeP2KCgcv s5xkWicNI0s7yIzvezwnF/8IpmSMx5d1FyG8pteGVsB5bBB1EPeie/keGSS3+fTwaFef lH8u5Q/sfKI/wafP6Sh4ZFIs2Ep6ch/PvN8oSxtY6M2Cd045Wu3pVjmS7WIQFaGOSI84 vyJA== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id i11si360921pgq.332.2018.03.13.09.59.08; Tue, 13 Mar 2018 09:59:23 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S933318AbeCMQzk (ORCPT + 99 others); Tue, 13 Mar 2018 12:55:40 -0400 Received: from mail-wr0-f195.google.com ([209.85.128.195]:37072 "EHLO mail-wr0-f195.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752163AbeCMQzi (ORCPT ); Tue, 13 Mar 2018 12:55:38 -0400 Received: by mail-wr0-f195.google.com with SMTP id z12so850109wrg.4 for ; Tue, 13 Mar 2018 09:55:38 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=uF6SA9VSCjfWVJ5Baoud+d5RUAlxPO4/3slQdGAgdpo=; b=Ha6e93vn4CTaGmTrgRrme/vG19LVNcXiMTOUGQ9Dmk3ReXI0mbqsTBBVTUqFM+9+Bq 8EKnD2CwBmCfo6bcAg5lpvF+Bxl9qE+J+3SfXMG9/ryo2Ee38r26OQNk28hCGp85UDoz EgXDP+jGUn2l4LKou6ZOJxn3cnuY+pTWzcNrfIk5x79wvLBMUt/aylpD2BgUH77OshUA nN3f7Tp2548EohBQM1RVClrhFaVKoPO7xj8e4rv9x5iGauYuYL7wUx6/nfoMxY5Yhb++ h6AU8ZPhC8NyBwW4zE4y2PObzREBZlPPQcyIWxmLg7dKCwSHtdmBDR3wdRZD7IvygoBy n4hQ== X-Gm-Message-State: AElRT7GTqhfF59fPSJBwTI9pEF9boNlbCtkwPk1KXdynrJVpFzy+8HXU 5oDLM5E3MLfTGCOy+GcurnPQlCeU X-Received: by 10.223.161.195 with SMTP id v3mr1208588wrv.184.1520960137293; Tue, 13 Mar 2018 09:55:37 -0700 (PDT) Received: from localhost.localdomain (u-087-c077.eap.uni-tuebingen.de. [134.2.87.77]) by smtp.gmail.com with ESMTPSA id r128sm378881wmf.37.2018.03.13.09.55.36 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Tue, 13 Mar 2018 09:55:36 -0700 (PDT) From: Christian Brauner To: viro@zeniv.linux.org.uk, linux-kernel@vger.kernel.org, ebiederm@xmission.com, torvalds@linux-foundation.org, gregkh@linuxfoundation.org Cc: containers@lists.linux-foundation.org, Christian Brauner Subject: [PATCH 2/4 v5 RESEND] devpts: resolve devpts bind-mounts Date: Tue, 13 Mar 2018 17:55:25 +0100 Message-Id: <20180313165527.24038-3-christian.brauner@ubuntu.com> X-Mailer: git-send-email 2.15.1 In-Reply-To: <20180313165527.24038-1-christian.brauner@ubuntu.com> References: <20180313165527.24038-1-christian.brauner@ubuntu.com> Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Most libcs will still look at /dev/ptmx when opening the master fd of a pty device. When /dev/ptmx is a bind-mount of /dev/pts/ptmx and the TIOCGPTPEER ioctl() is used to safely retrieve a file descriptor for the slave side of the pty based on the master fd, the /proc/self/fd/{0,1,2} symlinks will point to /. A very simply reproducer for this issue presupposing a libc that uses TIOCGPTPEER in its openpty() implementation is: unshare --mount mount --bind /dev/pts/ptmx /dev/ptmx chmod 666 /dev/ptmx script ls -al /proc/self/fd/0 Having bind-mounts of /dev/pts/ptmx to /dev/ptmx not working correctly is a regression. In addition, it is also a fairly common scenario in containers employing user namespaces. The reason for the current failure is that the kernel tries to verify the useability of the devpts filesystem without resolving the /dev/ptmx bind-mount first. This will lead it to detect that the dentry is escaping its bind-mount. The reason is that while the devpts filesystem mounted at /dev/pts has the devtmpfs mounted at /dev as its parent mount: 21 -- -- / /dev -- 21 -- / /dev/pts devtmpfs and devpts are on different devices -- -- 0:6 / /dev -- -- 0:20 / /dev/pts This has the consequence that the pathname of the parent directory of the devpts filesystem mount at /dev/pts is /. So if /dev/ptmx is a bind-mount of /dev/pts/ptmx then the /dev/ptmx bind-mount and the devpts mount at /dev/pts will end up being located on the same device which is recorded in the superblock of their vfsmount. This means the parent directory of the /dev/ptmx bind-mount will be /ptmx: -- -- ---- /ptmx /dev/ptmx Without the bind-mount resolution patch the kernel will now perform the bind-mount escape check directly on /dev/ptmx. The function responsible for this is devpts_ptmx_path() which calls pts_path() which in turn calls path_parent_directory(). Based on the above explanation, path_parent_directory() will yield / as the parent directory for the /dev/ptmx bind-mount and not the expected /dev. Thus, the kernel detects that /dev/ptmx is escaping its bind-mount and will set /proc//fd/ to /. This patch changes the logic to first resolve any bind-mounts. After the bind-mounts have been resolved (i.e. we have traced it back to the associated devpts mount) devpts_ptmx_path() can be called. In order to guarantee correct path generation for the slave file descriptor the kernel now requires that a pts directory is found in the parent directory of the ptmx bind-mount. This implies that when doing bind-mounts the ptmx bind-mount and the devpts mount should have a common parent directory. A valid example is: mount -t devpts devpts /dev/pts mount --bind /dev/pts/ptmx /dev/ptmx an invalid example is: mount -t devpts devpts /dev/pts mount --bind /dev/pts/ptmx /ptmx This allows us to support: - calling open on ptmx devices located inside non-standard devpts mounts: mount -t devpts devpts /mnt master = open("/mnt/ptmx", ...); slave = ioctl(master, TIOCGPTPEER, ...); - calling open on ptmx devices located outside the devpts mount with a common ancestor directory: mount -t devpts devpts /dev/pts mount --bind /dev/pts/ptmx /dev/ptmx master = open("/dev/ptmx", ...); slave = ioctl(master, TIOCGPTPEER, ...); while failing on ptmx devices located outside the devpts mount without a common ancestor directory: mount -t devpts devpts /dev/pts mount --bind /dev/pts/ptmx /ptmx master = open("/ptmx", ...); slave = ioctl(master, TIOCGPTPEER, ...); in which case save path generation cannot be guaranteed. Signed-off-by: Christian Brauner Suggested-by: Eric Biederman Suggested-by: Linus Torvalds --- ChangeLog v4->v5: * reverse error handling logic to further simplify (Linus) ChangeLog v3->v4: * simplify if condition (Eric) ChangeLog v2->v3: * rework logic to account for non-standard devpts mounts such as mount -t devpts devpts /mnt (Christian) ChangeLog v1->v2: * move removal of if (path->mnt->mnt_sb->s_magic == DEVPTS_SUPER_MAGIC) condition to separate patch with non-functional changes (Linus) ChangeLog v0->v1: * remove /* Has the devpts filesystem already been found? */ if (path->mnt->mnt_sb->s_magic == DEVPTS_SUPER_MAGIC) return 0 from devpts_ptmx_path() (Eric) * check superblock after devpts_ptmx_path() returned (Christian) --- fs/devpts/inode.c | 26 ++++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/fs/devpts/inode.c b/fs/devpts/inode.c index 71b901936113..542364bf923e 100644 --- a/fs/devpts/inode.c +++ b/fs/devpts/inode.c @@ -160,21 +160,27 @@ struct vfsmount *devpts_mntget(struct file *filp, struct pts_fs_info *fsi) path = filp->f_path; path_get(&path); - /* Has the devpts filesystem already been found? */ - if (path.mnt->mnt_sb->s_magic != DEVPTS_SUPER_MAGIC) + /* Walk upward while the start point is a bind mount of + * a single file. + */ + while (path.mnt->mnt_root == path.dentry) + if (follow_up(&path) == 0) + break; + + /* devpts_ptmx_path() finds a devpts fs or returns an error. */ + if ((path.mnt->mnt_sb->s_magic != DEVPTS_SUPER_MAGIC) || + (DEVPTS_SB(path.mnt->mnt_sb) != fsi)) err = devpts_ptmx_path(&path); dput(path.dentry); - if (err) { - mntput(path.mnt); - return ERR_PTR(err); - } + if (!err) { + if (DEVPTS_SB(path.mnt->mnt_sb) == fsi) + return path.mnt; - if (DEVPTS_SB(path.mnt->mnt_sb) != fsi) { - mntput(path.mnt); - return ERR_PTR(-ENODEV); + err = -ENODEV; } - return path.mnt; + mntput(path.mnt); + return ERR_PTR(err); } struct pts_fs_info *devpts_acquire(struct file *filp) -- 2.15.1