From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mail.openvz.org (unknown [69.168.225.77]) by lore.virtuozzo.com (Postfix) with ESMTPS id 1765D8006A for ; Wed, 26 Aug 2026 11:05:51 +0000 (UTC) Received: from mail.openvz.org (localhost [127.0.0.1]) by mail.openvz.org (8.14.4/8.14.4) with ESMTP id 67QB4NaY007025; Wed, 26 Aug 2026 14:04:25 +0300 DKIM-Filter: OpenDKIM Filter v2.11.0 mail.openvz.org 67QB4NaY007025 Authentication-Results: mail.openvz.org; dkim=fail reason="signature verification failed" (2048-bit key) header.d=virtuozzo.com header.i=@virtuozzo.com header.b="vlzz3LI6" Received: from mail-wr1-f69.google.com (mail-wr1-f69.google.com [209.85.221.69]) by mail.openvz.org (8.14.4/8.14.4) with ESMTP id 67QB4Ljg007013 (version=TLSv1/SSLv3 cipher=AES128-GCM-SHA256 bits=128 verify=FAIL) for ; Wed, 26 Aug 2026 14:04:22 +0300 DKIM-Filter: OpenDKIM Filter v2.11.0 mail.openvz.org 67QB4Ljg007013 Received: by mail-wr1-f69.google.com with SMTP id ffacd0b85a97d-482e05af072so406597f8f.3 for ; Wed, 26 Aug 2026 04:04:21 -0700 (PDT) X-Gm-Message-State: AFuF++m36qSOfbUHaE4IuHK5ZezZI5dmx/rngSPbOdIqx4NZV/zde6go fd1E248e7gTB26MFSaNab5R5XutqJL+x8I2PxOj6gj0ONtPdmoNIcEMDXpNjgjMuq4Sh8AFFcpT +4ORWQWvJvYuWX8/RKF3MQCL5cr/EF71RP3AoGga8Pm/0Bo++RHvt0A== X-Gm-Gg: AR+sD117feL+xgTaPEX9dFsJYscmN/+2XDd8NP1LyhmcN7W7g6JfGaNJ1uJbDHxL0rN MHBJ75kE9CrV8aCB6Ys2mxVgGOjxN9UHjlyXww4Rw9OPrrbwwOUYFYWM56mvf8N4+fOSBwr0dIY vytZlxo+YrEHfWT0Pzn/AD1tgakJ1heKpzum3t0MYT+yWlK3Ug427TM7DlIFUEF7yCTWQXogt11 1XNEjeId3PQ2ut7X03YtBYzQp72NLTGHOCNA/IMBSTbn/7/m0vhSBskASowSiMSIMc+68OAAMrA 8EGtIh9et+6cwtU32oWM58/YHyfYkLlqOjUuScMNLMIsao7RDtBcOYAlLIJ6K5wfC+ZETO3PZjN KhqJ9o5fjCkQCfc3LGIhc0dgJJPTNqA== X-Received: by 2002:a05:6000:2905:b0:482:e4bc:51b2 with SMTP id ffacd0b85a97d-482e4bc5354mr3635163f8f.20.1787742261302; Wed, 26 Aug 2026 04:04:21 -0700 (PDT) X-Received: by 2002:a05:6000:2905:b0:482:e4bc:51b2 with SMTP id ffacd0b85a97d-482e4bc5354mr3635052f8f.20.1787742260655; Wed, 26 Aug 2026 04:04:20 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1787742260; cv=none; d=google.com; s=arc-20260327; b=pPUZArWB2TqibbCHclTqGn+3wrGbK5oMF5ijDRCyDNbgkotHKSd3LY0MczxthTyb9P AYOayu2MP3tE7ns7+F96vXFkxntHsA8Mfj5oL0mmobgKjwFHMmP89RkadY92X1nzPvbm QlRJ9NZaWcj3fAGq1c0TqmwFwuFM16R5JGAmv9gXMhXNrj1sPEd2gZDUWObj6GMmu2nI ofgBVcd6qdIo8oG3hXMQXdU+zIbEI83NuIOG0F1uVaQ2Yhj0qfZ6DfI/4i5vxCU/B/jN RE7T7G3+CwufHOTzr8Bhqy6bY/Iq62bDjMAEmxdN3xQLyhacc14MLUuPrRa7jH8/yMm7 gZLg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20260327; h=content-transfer-encoding:mime-version:message-id:date:subject:cc :to:from:dkim-signature; bh=qkSX1LJugjREdBfZafvxEjoscjHZhlR8E+Hk8QzBvhI=; fh=HgZU6gWxVSDFWCEWiGWrMzzoxLctZeZ+0Da/uTKKnNs=; b=caCZH3j+ZrL9r4laxTuoLlIjI7oGHL2nNOHkXE0DD6VSTQkMK9pzDh7jy4DtnU3OaI cxYmA+v4534y24+mNzoTBCwTuJfU612bXkhiYlEs1cbKlIK0f3E4XMLqAoiRIYHLPE41 nRy2Dyd1thT1XCRJ1biu0p6bJY/NAYJwACZt1AAzcEBHcZA+8i1ybKrette3vwMPu9cN qgTo8bHXFR2mCMzQjU1zd+V799ArlGUFUlm0CnSh8DBmRBJ9YK1rY3xBL3BAu7bIKuvu M3qg9/TtNroRG5D1QVTuOz1mcdydP/yGJ0Iao7Y+tU6dNnBFTujyqsAmfC/Qsb+WmqA9 nsiw==; dara=google.com ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@virtuozzo.com header.s=relay header.b=vlzz3LI6; spf=pass (google.com: domain of mirian.shilakadze@virtuozzo.com designates 130.117.225.111 as permitted sender) smtp.mailfrom=mirian.shilakadze@virtuozzo.com; dmarc=pass (p=QUARANTINE sp=QUARANTINE dis=NONE) header.from=virtuozzo.com Received: from relay.virtuozzo.com (relay.virtuozzo.com. [130.117.225.111]) by mx.google.com with ESMTPS id ffacd0b85a97d-482e28e9eb7si2263211f8f.294.2026.08.26.04.04.20 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 26 Aug 2026 04:04:20 -0700 (PDT) Received-SPF: pass (google.com: domain of mirian.shilakadze@virtuozzo.com designates 130.117.225.111 as permitted sender) client-ip=130.117.225.111; Authentication-Results: mx.google.com; dkim=pass header.i=@virtuozzo.com header.s=relay header.b=vlzz3LI6; spf=pass (google.com: domain of mirian.shilakadze@virtuozzo.com designates 130.117.225.111 as permitted sender) smtp.mailfrom=mirian.shilakadze@virtuozzo.com; dmarc=pass (p=QUARANTINE sp=QUARANTINE dis=NONE) header.from=virtuozzo.com DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=virtuozzo.com; s=relay; h=MIME-Version:Message-ID:Date:Subject:From: Content-Type; bh=qkSX1LJugjREdBfZafvxEjoscjHZhlR8E+Hk8QzBvhI=; b=vlzz3LI6Qg24 6DpT7aKpImIQUYyYLJrASmp2BmP/Awdr+r80Lp8AJ5dBalDjpkF8f9EY0AKPeulyUZME+0Ek85XNe GTG3t6fVuMX5rtmGWjUg/pgNQRDNePsMws4zZ8Bo4l11bIaurJGuOs0avyEQdTwU3zlGZBN0Ib4n6 lAzvlh7a/H1KJlcgdFhMSeXqkmbiUHiwUywCaenB+RQD2o9RFsOgDwfzBrYSIyfFTOUJCckUK2Xbl VNBpP90gRX1els9hiCP2rXtF5NZ0op+GDA9qBDcmVntmByBfEGe8hv0/LOr67UzzMkdd44QsHoi4T TtmRAavnTDlKU3gpL/724A==; Received: from ch-demo-asa.virtuozzo.com ([130.117.225.8] helo=localhost.localdomain) by relay.virtuozzo.com with esmtp (Exim 4.96) (envelope-from ) id 1wzBOL-00H4OO-18; Wed, 26 Aug 2026 13:04:19 +0200 From: Mirian Shilakadze To: khorenko@virtuozzo.com, ptikhomirov@virtuozzo.com Date: Wed, 26 Aug 2026 15:04:09 +0400 Message-ID: <20260826110415.41119-1-mirian.shilakadze@virtuozzo.com> X-Mailer: git-send-email 2.47.3 MIME-Version: 1.0 X-OZ-Fwd: true Cc: devel@openvz.org Subject: [Devel] [PATCH vz10 v2 0/2] fs/kernfs, ve: stop a container lookup unmounting host filesystems X-BeenThere: devel@openvz.org X-Mailman-Version: 2.1.12 Precedence: list List-Id: OpenVZ development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit Sender: devel-bounces@openvz.org Errors-To: devel-bounces@openvz.org Starting a container whose configuration carries a bindmount whose source is a mount with its own superblock unmounts the host's bpffs and tracefs. libvzctl needs bpffs for the cgroup v2 device controller, so once it is gone no container on the node can be managed. Every later vzctl command on any container, including ones that were already running and were never involved, prints "Unable to find mount point for bpf" twice and then reports a stale status. Recovery is a manual mount or a reboot. This is VSTOR-142552. The container start is not what does it. Any task whose VE is a container's, resolving a host path under /sys, unmounts what it finds there. setns() on a container's ve namespace, staying in the host mount namespace, is enough, and one stat() of /sys/fs/bpf both hides the entry from the caller and destroys the host's mount. kernfs_dop_revalidate() ends with a per VE visibility check and answers it with the same "return 0" that the staleness checks above it use. Those checks are properties of the kernfs node and hold for every observer: the node was deactivated, moved, renamed, or retagged. Visibility is a property of the calling task's VE, so one host dentry answers "valid" to a ve0 task and "stale" to a task inside a container. The VFS reads 0 as a global fact and calls d_invalidate(), which hands every mountpoint under that dentry to __detach_mounts(), whose mountpoint hash is not scoped to a mount namespace and whose m_list holds every mount attached at that dentry in any of them. A per VE answer therefore destroys a global object. Patch 1 reports the name as missing from that check, except on a kernfs instance the VE created, where the dentry is dropped as before. Everywhere else, the host's sysfs above all, the caller that cannot see the entry is told the name is missing, which is what the check is for, and the dentry stays valid for everyone else. What a container is told does not change either way: the errno for a hidden entry is ENOENT, because today it arrives after d_invalidate() and a fresh lookup that ends in a negative dentry. kernfs_iop_lookup() has always answered this same condition with a plain "not found". The one exception is a create attempt on a hidden name, and only on an instance the VE did not mount, where it now fails with ENOENT rather than the EACCES it fails with today. On the VE's own instance nothing changes, a create on a hidden name still fails with EACCES. Both fail either way. Patch 2 adds the regression test to the existing ve_perms selftest. It mounts a tmpfs on the entry the fixture already keeps host only, in its own mount namespace so the machine running it cannot lose a mount it needs, and requires that mount to still be there after a VE has looked the entry up. Introduced by 3dd8c2499df6 ("ve/kernfs: hide forbidden entries in container") in 2021 and reachable ever since. It went unreported because nothing in the management stack held a mount under /sys that anyone would miss, until libvzctl commit f946fae ("cgroup: switch from cgrou-v1 device controller to eBPF program") made it depend on bpffs. Testing ======= Tested on a VHI 8.0.0 node with the same script, the same container and the same bindmount on both kernels. On stock 6.12.0-211.30.1.14.4.vz10 the start fails with rc=255 and "Cancel init execution", bpffs and tracefs are both gone afterwards, vzctl status on that container and on an unrelated one prints "Unable to find mount point for bpf" twice each, and vzctl exec stops working. Losing tracefs also took the kprobes the test itself was using. With patch 1 on 6.12.0-211.39.1.16.9.vz10 the same start returns rc=0, bpffs and tracefs are untouched, both status calls are clean, and the bindmount is present inside the container and read only as requested. The same holds on a debug build with KASAN and lockdep and on the shipping configuration. Under load, 48 processes inside a container's VE entered with setns(), alongside 48 in ve0, resolved /sys/fs/bpf and a tmpfs mounted on a hidden sysfs directory, 384000 hidden lookups in total. Every VE process saw ENOENT on every lookup and every ve0 process saw the entry on every lookup, with no mixed results. A kprobe on d_invalidate() named only the test's own cgroup dentries and the /proc pid directories of reaped children, never the hidden entries, and __detach_mounts() was never called. gcov on fs/kernfs/dir.c, fs/namei.c, fs/dcache.c and fs/namespace.c agrees: the new return ran 384000 times, the staleness paths in kernfs_dop_revalidate() never ran, and __detach_mounts() was never entered. Granting a path to a VE through ve.sysfs_permissions still makes it visible and revoking it hides it again, and the host mount now survives the revoke, which it did not before. ve_perms_test passes 16 of 16 and ve_ns_owner_test 2 of 2, together with the filesystems, mount, mount_setattr, move_mount_set_group, nsfs and proc selftests. Patch 2 fails on the unpatched kernel with "the VE lookup unmounted /sys/power" and passes with patch 1 applied. The condition added in v2 was checked on both sides. During a container start it never fires: of the 13 lookups that answered 0, every one returned before reaching the visibility check, from the negative dentry branch or from !kernfs_active(), which are the device mapper and uevent nodes churning as the disk is set up. The lookups that do reach the check answer ENOENT, 8 of them, and __detach_mounts() is not called at all. It fires where it is meant to: a container looking up a hidden entry in its own sysfs instance gets the dentry dropped and the mount on it detached, while the same lookup against the host's sysfs answers ENOENT and leaves the mount alone. Two of the six ->d_revalidate call sites, __lookup_slow() and lookup_open(), were not reached at runtime. This tree carries lookup_fast_for_open(), so even an O_CREAT open resolves the last component through lookup_fast(), which leaves those two reachable only through a dcache race. Both gate d_invalidate() on exactly 0, as do the sites that were exercised, ovl_revalidate_real() and ecryptfs_d_revalidate(). v2: - patch 1: keep the old invalidate on a kernfs instance the VE created, and only report the name as missing on any other instance (Pavel) - patch 2: detect the mount with openat2(RESOLVE_NO_XDEV) rather than reading /proc/self/mountinfo (Pavel) - dropped Pavel's Reviewed-by from v1, both patches changed Mirian Shilakadze (2): fs/kernfs, ve: hide entries from a VE without invalidating the dentry selftests/ve: check that hiding an entry does not unmount it fs/kernfs/dir.c | 17 ++++++- tools/testing/selftests/ve/ve_perms_test.c | 52 ++++++++++++++++++++++ tools/testing/selftests/ve/ve_selftest.h | 40 ++++++++++++++++- 3 files changed, 105 insertions(+), 4 deletions(-) -- 2.43.0 _______________________________________________ Devel mailing list Devel@openvz.org https://lists.openvz.org/mailman/listinfo/devel