Linux userland API discussions
 help / color / mirror / Atom feed
* [RFC PATCH 1/3] fs: Add documentation to some `struct fs_struct` fields
From: John Ericson @ 2026-06-29  6:58 UTC (permalink / raw)
  To: Andy Lutomirski, Al Viro, Christian Brauner, Jan Kara,
	David Howells, Chuck Lever, Jeff Layton, Shuah Khan, David Laight,
	H. Peter Anvin, Li Chen, Cong Wang, Arnd Bergmann,
	Thomas Gleixner, Ingo Molnar, Borislav Petkov, Dave Hansen,
	Jonathan Corbet, Kees Cook, Sergei Zimmerman, Farid Zakaria,
	linux-arch, LKML, linux-fsdevel, linux-api, netfs, linux-nfs
  Cc: John Ericson
In-Reply-To: <20260629065934.1425479-1-John.Ericson@Obsidian.Systems>

From: John Ericson <mail@JohnEricson.me>

This will be expanded upon in the next commit.

Link: https://lore.kernel.org/all/a49ce818-f38d-41b0-bbf7-80b8aad998b1@app.fastmail.com/
Signed-off-by: John Ericson <mail@JohnEricson.me>
---
 include/linux/fs_struct.h | 16 +++++++++++++++-
 1 file changed, 15 insertions(+), 1 deletion(-)

diff --git a/include/linux/fs_struct.h b/include/linux/fs_struct.h
index 0070764b790a..b5db5de9eb01 100644
--- a/include/linux/fs_struct.h
+++ b/include/linux/fs_struct.h
@@ -12,7 +12,21 @@ struct fs_struct {
 	seqlock_t seq;
 	int umask;
 	int in_exec;
-	struct path root, pwd;
+
+	/*
+	 * The root directory for the task(s) that points to this
+	 * `fs_struct`. The root directory also controls how `..`
+	 * resolve; path traversal is not allowed to resolve upwards
+	 * beyond the root directory. (It is for this latter reason that
+	 * `chroot` is a privileged operation.)
+	 */
+	struct path root;
+
+	/*
+	 * The current working directory for the task(s) that points to
+	 * this `fs_struct`.
+	 */
+	struct path pwd;
 } __randomize_layout;
 
 extern struct kmem_cache *fs_cachep;
-- 
2.51.2


^ permalink raw reply related

* [RFC PATCH 2/3] fs: support tasks with a null root or cwd
From: John Ericson @ 2026-06-29  6:58 UTC (permalink / raw)
  To: Andy Lutomirski, Al Viro, Christian Brauner, Jan Kara,
	David Howells, Chuck Lever, Jeff Layton, Shuah Khan, David Laight,
	H. Peter Anvin, Li Chen, Cong Wang, Arnd Bergmann,
	Thomas Gleixner, Ingo Molnar, Borislav Petkov, Dave Hansen,
	Jonathan Corbet, Kees Cook, Sergei Zimmerman, Farid Zakaria,
	linux-arch, LKML, linux-fsdevel, linux-api, netfs, linux-nfs
  Cc: John Ericson
In-Reply-To: <20260629065934.1425479-1-John.Ericson@Obsidian.Systems>

From: John Ericson <mail@JohnEricson.me>

A task's root directory (`fs->root`) and current working directory
(`fs->pwd`) are normally established by `chroot(2)`/`pivot_root(2)` and
`chdir(2)`/`fchdir(2)` (or inherited across `fork(2)`). Allow either to
instead be the null path, as documented in `struct fs_struct`. The two
are independent: a task may opt out of one, the other, or both.

A task with no root cannot use absolute pathnames, and its `..` is no
longer bounded by a process root: it climbs to the root of the mount the
walk is in (the security implications are discussed in `struct
fs_struct`). A task with no cwd cannot use `AT_FDCWD`-relative
pathnames. Either way it can still name files through the `*at(2)`
descriptors it holds.

Teach the readers of these fields to cope instead of dereferencing the
NULL dentry, each checking the field it uses:

- namei: `set_root()` now tolerates a NULL root (skipping the
  `nd->root.dentry->d_seq` read), so `nd_jump_root()` returns `-ENOENT`
  for absolute paths and symlinks, while `..` falls through to
  `follow_dotdot()` -- which already treats a NULL `nd->root` as "no
  boundary" and climbs. The `AT_FDCWD` legs of `path_init()` return
  `-ENOENT` with no cwd; real-dirfd lookups (`openat(2)`, `openat2(2)`)
  are unaffected.

- `getcwd(2)`, `/proc/PID/{root,cwd}`, `open_by_handle_at()` with
  `AT_FDCWD`, and the cachefiles `cull`/`inuse` commands return an error
  rather than dereferencing the NULL path.

The setters need no change: `chdir(2)`/`chroot(2)`/`pivot_root(2)`
resolve via `filename_lookup(AT_FDCWD, ...)`, which simply fails with no
root or cwd, and `fchdir(2)` installs a cwd from an fd without
consulting the old one. `d_path()` is unaffected: `__prepend_path()`
only compares against the root.

These opt-outs are not sticky; keeping a task rootless or cwd-less is an
orthogonal policy decision (e.g. seccomp filtering the setters above).

Link: https://lore.kernel.org/all/a49ce818-f38d-41b0-bbf7-80b8aad998b1@app.fastmail.com/
Signed-off-by: John Ericson <mail@JohnEricson.me>
Assisted-by: Claude:claude-opus-4-8
---
 fs/cachefiles/daemon.c    |  6 ++++--
 fs/d_path.c               |  6 +++++-
 fs/fhandle.c              |  3 +++
 fs/namei.c                | 22 ++++++++++++++++++++--
 fs/proc/base.c            |  8 ++++++--
 include/linux/fs_struct.h | 13 +++++++++++++
 6 files changed, 51 insertions(+), 7 deletions(-)

diff --git a/fs/cachefiles/daemon.c b/fs/cachefiles/daemon.c
index 4117b145ac94..344feeb89c61 100644
--- a/fs/cachefiles/daemon.c
+++ b/fs/cachefiles/daemon.c
@@ -652,7 +652,8 @@ static int cachefiles_daemon_cull(struct cachefiles_cache *cache, char *args)
 
 	get_fs_pwd(current->fs, &path);
 
-	if (!d_can_lookup(path.dentry))
+	/* A task may have no cwd. */
+	if (!path.mnt || !d_can_lookup(path.dentry))
 		goto notdir;
 
 	cachefiles_begin_secure(cache, &saved_cred);
@@ -723,7 +724,8 @@ static int cachefiles_daemon_inuse(struct cachefiles_cache *cache, char *args)
 
 	get_fs_pwd(current->fs, &path);
 
-	if (!d_can_lookup(path.dentry))
+	/* A task may have no cwd. */
+	if (!path.mnt || !d_can_lookup(path.dentry))
 		goto notdir;
 
 	cachefiles_begin_secure(cache, &saved_cred);
diff --git a/fs/d_path.c b/fs/d_path.c
index a48957c0971e..5f16d1efa37c 100644
--- a/fs/d_path.c
+++ b/fs/d_path.c
@@ -422,7 +422,11 @@ SYSCALL_DEFINE2(getcwd, char __user *, buf, unsigned long, size)
 	rcu_read_lock();
 	get_fs_root_and_pwd_rcu(current->fs, &root, &pwd);
 
-	if (unlikely(d_unlinked(pwd.dentry))) {
+	/* A task may have no cwd. */
+	if (unlikely(!pwd.mnt)) {
+		rcu_read_unlock();
+		error = -ENOENT;
+	} else if (unlikely(d_unlinked(pwd.dentry))) {
 		rcu_read_unlock();
 		error = -ENOENT;
 	} else {
diff --git a/fs/fhandle.c b/fs/fhandle.c
index 1ca7eb3a6cb5..560f88f53633 100644
--- a/fs/fhandle.c
+++ b/fs/fhandle.c
@@ -180,6 +180,9 @@ static int get_path_anchor(int fd, struct path *root)
 
 	if (fd == AT_FDCWD) {
 		get_fs_pwd(current->fs, root);
+		/* A task may have no cwd. */
+		if (!root->mnt)
+			return -ENOENT;
 		return 0;
 	}
 
diff --git a/fs/namei.c b/fs/namei.c
index 5cc9f0f466b8..06b16815e866 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -1120,11 +1120,20 @@ static int set_root(struct nameidata *nd)
 		do {
 			seq = read_seqbegin(&fs->seq);
 			nd->root = fs->root;
-			nd->root_seq = __read_seqcount_begin(&nd->root.dentry->d_seq);
+			/*
+			 * A task may have no root. Leave nd->root as the NULL
+			 * path and skip the d_seq read: absolute lookups turn
+			 * the absence into -ENOENT in nd_jump_root(), while ".."
+			 * treats a NULL root as "no boundary" and climbs to its
+			 * mount root.
+			 */
+			if (likely(nd->root.mnt))
+				nd->root_seq = __read_seqcount_begin(&nd->root.dentry->d_seq);
 		} while (read_seqretry(&fs->seq, seq));
 	} else {
 		get_fs_root(fs, &nd->root);
-		nd->state |= ND_ROOT_GRABBED;
+		if (likely(nd->root.mnt))
+			nd->state |= ND_ROOT_GRABBED;
 	}
 	return 0;
 }
@@ -1143,6 +1152,9 @@ static int nd_jump_root(struct nameidata *nd)
 		if (unlikely(error))
 			return error;
 	}
+	/* Absolute paths need a root to jump to; a task may have none. */
+	if (unlikely(!nd->root.mnt))
+		return -ENOENT;
 	if (nd->flags & LOOKUP_RCU) {
 		struct dentry *d;
 		nd->path = nd->root;
@@ -2732,11 +2744,17 @@ static const char *path_init(struct nameidata *nd, unsigned flags)
 			do {
 				seq = read_seqbegin(&fs->seq);
 				nd->path = fs->pwd;
+				/* A task may have no cwd. */
+				if (unlikely(!nd->path.mnt))
+					return ERR_PTR(-ENOENT);
 				nd->inode = nd->path.dentry->d_inode;
 				nd->seq = __read_seqcount_begin(&nd->path.dentry->d_seq);
 			} while (read_seqretry(&fs->seq, seq));
 		} else {
 			get_fs_pwd(current->fs, &nd->path);
+			/* A task may have no cwd. */
+			if (unlikely(!nd->path.mnt))
+				return ERR_PTR(-ENOENT);
 			nd->inode = nd->path.dentry->d_inode;
 		}
 	} else {
diff --git a/fs/proc/base.c b/fs/proc/base.c
index 780f81259052..7f7cc86ce262 100644
--- a/fs/proc/base.c
+++ b/fs/proc/base.c
@@ -213,7 +213,9 @@ static int get_task_root(struct task_struct *task, struct path *root)
 	task_lock(task);
 	if (task->fs) {
 		get_fs_root(task->fs, root);
-		result = 0;
+		/* A task may have no root. */
+		if (root->mnt)
+			result = 0;
 	}
 	task_unlock(task);
 	return result;
@@ -227,7 +229,9 @@ static int proc_cwd_link(struct dentry *dentry, struct path *path,
 	task_lock(task);
 	if (task->fs) {
 		get_fs_pwd(task->fs, path);
-		result = 0;
+		/* A task may have no cwd. */
+		if (path->mnt)
+			result = 0;
 	}
 	task_unlock(task);
 	return result;
diff --git a/include/linux/fs_struct.h b/include/linux/fs_struct.h
index b5db5de9eb01..84423b4bd21a 100644
--- a/include/linux/fs_struct.h
+++ b/include/linux/fs_struct.h
@@ -13,18 +13,31 @@ struct fs_struct {
 	int umask;
 	int in_exec;
 
+	/*
+	 * Note that these paths are explicitly intended to be nullable.
+	 * Since they are inline structs and not pointers, we use `.mnt
+	 * == NULL` to indicate nullability of the path as a whole.
+	 */
+
 	/*
 	 * The root directory for the task(s) that points to this
 	 * `fs_struct`. The root directory also controls how `..`
 	 * resolve; path traversal is not allowed to resolve upwards
 	 * beyond the root directory. (It is for this latter reason that
 	 * `chroot` is a privileged operation.)
+	 *
+	 * If null (as described above), absolute paths will not
+	 * resolve. In addition `..` will be unbounded, until one
+	 * reaches the top of the mount tree.
 	 */
 	struct path root;
 
 	/*
 	 * The current working directory for the task(s) that points to
 	 * this `fs_struct`.
+	 *
+	 * If null (as described above), relative paths with `AT_FDCWD`
+	 * will not resolve.
 	 */
 	struct path pwd;
 } __randomize_layout;
-- 
2.51.2


^ permalink raw reply related

* [RFC PATCH 3/3] fs: add KUnit tests for tasks with a null root or cwd
From: John Ericson @ 2026-06-29  6:58 UTC (permalink / raw)
  To: Andy Lutomirski, Al Viro, Christian Brauner, Jan Kara,
	David Howells, Chuck Lever, Jeff Layton, Shuah Khan, David Laight,
	H. Peter Anvin, Li Chen, Cong Wang, Arnd Bergmann,
	Thomas Gleixner, Ingo Molnar, Borislav Petkov, Dave Hansen,
	Jonathan Corbet, Kees Cook, Sergei Zimmerman, Farid Zakaria,
	linux-arch, LKML, linux-fsdevel, linux-api, netfs, linux-nfs
  Cc: John Ericson
In-Reply-To: <20260629065934.1425479-1-John.Ericson@Obsidian.Systems>

From: John Ericson <mail@JohnEricson.me>

A KUnit suite (`CONFIG_NULL_ROOT_CWD_KUNIT_TEST`) exercises the previous
patch against a task whose own root and/or cwd it nulls: absolute and
`AT_FDCWD`-relative lookups fail, `..` climbs, and descriptor-anchored
lookups keep working. Each test unshares its `fs_struct` so it only ever
touches a private copy, and restores the original root/cwd afterwards.

It is gated by `CONFIG_NULL_ROOT_CWD_KUNIT_TEST` and `#include`d into
`fs/fs_struct.c`, following the `fs/tests/*_kunit.c` pattern.

Link: https://lore.kernel.org/all/a49ce818-f38d-41b0-bbf7-80b8aad998b1@app.fastmail.com/
Signed-off-by: John Ericson <mail@JohnEricson.me>
Assisted-by: Claude:claude-opus-4-8
---
 fs/Kconfig                     |  11 +++
 fs/fs_struct.c                 |   4 +
 fs/tests/null_root_cwd_kunit.c | 147 +++++++++++++++++++++++++++++++++
 3 files changed, 162 insertions(+)
 create mode 100644 fs/tests/null_root_cwd_kunit.c

diff --git a/fs/Kconfig b/fs/Kconfig
index cf6ae64776e6..9023597b6e2b 100644
--- a/fs/Kconfig
+++ b/fs/Kconfig
@@ -18,6 +18,17 @@ config VALIDATE_FS_PARSER
 config FS_IOMAP
 	bool
 
+config NULL_ROOT_CWD_KUNIT_TEST
+	bool "KUnit tests for tasks with a null root or cwd" if !KUNIT_ALL_TESTS
+	depends on KUNIT=y
+	default KUNIT_ALL_TESTS
+	help
+	  Build KUnit tests that exercise path resolution for tasks whose
+	  fs->root and/or fs->pwd is the NULL path (no root directory and/or
+	  no current working directory).
+
+	  If unsure, say N.
+
 # Stackable filesystems
 config FS_STACK
 	bool
diff --git a/fs/fs_struct.c b/fs/fs_struct.c
index 394875d06fd6..bf620bba7f35 100644
--- a/fs/fs_struct.c
+++ b/fs/fs_struct.c
@@ -153,3 +153,7 @@ struct fs_struct init_fs = {
 	.seq		= __SEQLOCK_UNLOCKED(init_fs.seq),
 	.umask		= 0022,
 };
+
+#ifdef CONFIG_NULL_ROOT_CWD_KUNIT_TEST
+#include "tests/null_root_cwd_kunit.c"
+#endif
diff --git a/fs/tests/null_root_cwd_kunit.c b/fs/tests/null_root_cwd_kunit.c
new file mode 100644
index 000000000000..3fb7e63545f8
--- /dev/null
+++ b/fs/tests/null_root_cwd_kunit.c
@@ -0,0 +1,147 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * KUnit tests for tasks whose fs->root and/or fs->pwd is the NULL path.
+ * See "fs: support tasks with a null root or cwd".
+ *
+ * Each test runs against this task's own fs_struct. We unshare it first
+ * so we only ever touch a private copy, never the shared one, and we
+ * restore the original root/cwd afterwards.
+ */
+#include <kunit/test.h>
+#include <linux/fs_struct.h>
+#include <linux/namei.h>
+#include <linux/path.h>
+
+/* The NULL path: { .mnt = NULL, .dentry = NULL }. */
+static const struct path null_path;
+
+struct null_fs_ctx {
+	struct path saved_root;
+	struct path saved_pwd;
+	struct path anchor;	/* a real directory, standing in for a dirfd */
+};
+
+static int null_fs_setup(struct null_fs_ctx *ctx)
+{
+	int err;
+
+	err = unshare_fs_struct();
+	if (err)
+		return err;
+	err = kern_path("/", LOOKUP_DIRECTORY, &ctx->anchor);
+	if (err)
+		return err;
+	get_fs_root(current->fs, &ctx->saved_root);
+	get_fs_pwd(current->fs, &ctx->saved_pwd);
+	return 0;
+}
+
+static void null_fs_teardown(struct null_fs_ctx *ctx)
+{
+	set_fs_root(current->fs, &ctx->saved_root);
+	set_fs_pwd(current->fs, &ctx->saved_pwd);
+	path_put(&ctx->saved_root);
+	path_put(&ctx->saved_pwd);
+	path_put(&ctx->anchor);
+}
+
+/* Resolve @name, drop any reference it returns, and yield the errno. */
+static int try_kern_path(const char *name)
+{
+	struct path out;
+	int err = kern_path(name, 0, &out);
+
+	if (!err)
+		path_put(&out);
+	return err;
+}
+
+static int try_fd_relative(struct null_fs_ctx *ctx, const char *name)
+{
+	struct path out;
+	int err = vfs_path_lookup(ctx->anchor.dentry, ctx->anchor.mnt,
+				  name, 0, &out);
+
+	if (!err)
+		path_put(&out);
+	return err;
+}
+
+/* No root: absolute paths fail, but ".." climbs and the cwd still works. */
+static void null_root_test(struct kunit *test)
+{
+	struct null_fs_ctx ctx;
+
+	KUNIT_ASSERT_EQ(test, null_fs_setup(&ctx), 0);
+	set_fs_root(current->fs, &null_path);
+
+	/* A leading '/' has nothing to anchor to. */
+	KUNIT_EXPECT_EQ(test, try_kern_path("/"), -ENOENT);
+
+	/* ".." is unbounded rather than refused (it would have been
+	 * -ENOENT before this feature). It starts from the still-present
+	 * cwd and runs out of parents at the mount root.
+	 */
+	KUNIT_EXPECT_EQ(test, try_kern_path(".."), 0);
+
+	/* The cwd is untouched: AT_FDCWD-relative lookups still resolve. */
+	KUNIT_EXPECT_EQ(test, try_kern_path("."), 0);
+
+	/* A dirfd-anchored lookup never consults fs->root. */
+	KUNIT_EXPECT_EQ(test, try_fd_relative(&ctx, "."), 0);
+
+	null_fs_teardown(&ctx);
+}
+
+/* No cwd: AT_FDCWD-relative paths fail, but absolute and dirfds work. */
+static void null_cwd_test(struct kunit *test)
+{
+	struct null_fs_ctx ctx;
+
+	KUNIT_ASSERT_EQ(test, null_fs_setup(&ctx), 0);
+	set_fs_pwd(current->fs, &null_path);
+
+	/* Relative-to-cwd lookups have no starting point. */
+	KUNIT_EXPECT_EQ(test, try_kern_path("."), -ENOENT);
+	KUNIT_EXPECT_EQ(test, try_kern_path("foo"), -ENOENT);
+
+	/* The root is untouched: absolute lookups still resolve. */
+	KUNIT_EXPECT_EQ(test, try_kern_path("/"), 0);
+
+	/* A dirfd-anchored lookup never consults fs->pwd. */
+	KUNIT_EXPECT_EQ(test, try_fd_relative(&ctx, "."), 0);
+
+	null_fs_teardown(&ctx);
+}
+
+/* Neither root nor cwd: only descriptor-relative lookups remain. */
+static void null_root_and_cwd_test(struct kunit *test)
+{
+	struct null_fs_ctx ctx;
+
+	KUNIT_ASSERT_EQ(test, null_fs_setup(&ctx), 0);
+	set_fs_root(current->fs, &null_path);
+	set_fs_pwd(current->fs, &null_path);
+
+	KUNIT_EXPECT_EQ(test, try_kern_path("/"), -ENOENT);
+	KUNIT_EXPECT_EQ(test, try_kern_path("."), -ENOENT);
+
+	/* The held descriptor still names files. */
+	KUNIT_EXPECT_EQ(test, try_fd_relative(&ctx, "."), 0);
+
+	null_fs_teardown(&ctx);
+}
+
+static struct kunit_case null_root_cwd_test_cases[] = {
+	KUNIT_CASE(null_root_test),
+	KUNIT_CASE(null_cwd_test),
+	KUNIT_CASE(null_root_and_cwd_test),
+	{},
+};
+
+static struct kunit_suite null_root_cwd_test_suite = {
+	.name = "null_root_cwd",
+	.test_cases = null_root_cwd_test_cases,
+};
+
+kunit_test_suite(null_root_cwd_test_suite);
-- 
2.51.2


^ permalink raw reply related

* Re: [PATCH v2 0/7] vmsplice: fix some problems in my previous vmsplice patchset
From: Christian Brauner @ 2026-06-29  8:56 UTC (permalink / raw)
  To: David Hildenbrand (Arm)
  Cc: Askar Safin, akpm, avagin, axboe, brauner, collin.funk1,
	david.laight.linux, dhowells, fuse-devel, hch, jack, joannelkoong,
	kernel, linux-api, linux-fsdevel, linux-kernel, linux-mm, luto,
	metze, miklos, netdev, patches, pfalcato, torvalds, val, viro, w,
	willy
In-Reply-To: <63f7860c-4f5c-4682-8914-27978b9fbfe1@kernel.org>

On 2026-06-25 12:35 +0200, David Hildenbrand (Arm) wrote:
> On 6/25/26 12:11, Askar Safin wrote:
> > "David Hildenbrand (Arm)" <david@kernel.org>:
> >> I think we concluded that we cannot rip out vmsplice that way at this point, and
> >> I suspect that Christian will drop that topic branch from -next after -rc1.
> > 
> > I think my patches still have a chance.
> 
> I talked to Christian and it doesn't sound like it.

The amount of regression reports that we got in short succession doesn't
make it likely that we can merge a plain degradation.


^ permalink raw reply

* Re: [RFC PATCH 2/3] fs: support tasks with a null root or cwd
From: Christian Brauner @ 2026-06-29  9:19 UTC (permalink / raw)
  To: John Ericson
  Cc: Andy Lutomirski, Al Viro, Christian Brauner, Jan Kara,
	David Howells, Chuck Lever, Jeff Layton, Shuah Khan, David Laight,
	H. Peter Anvin, Li Chen, Cong Wang, Arnd Bergmann,
	Thomas Gleixner, Ingo Molnar, Borislav Petkov, Dave Hansen,
	Jonathan Corbet, Kees Cook, Sergei Zimmerman, Farid Zakaria,
	linux-arch, LKML, linux-fsdevel, linux-api, netfs, linux-nfs,
	John Ericson
In-Reply-To: <20260629065934.1425479-3-John.Ericson@Obsidian.Systems>

> A task's root directory (`fs->root`) and current working directory
> (`fs->pwd`) are normally established by `chroot(2)`/`pivot_root(2)` and
> `chdir(2)`/`fchdir(2)` (or inherited across `fork(2)`). Allow either to
> instead be the null path, as documented in `struct fs_struct`. The two
> are independent: a task may opt out of one, the other, or both.

No, absolutely we're not going to have tasks with struct path's in their
struct fs_struct that have NULL members in them. struct path is used
insanely widely in the kernel this is just an an open invitation for a
slew of security bugs. Not going to happen.

-- 
Christian Brauner <brauner@kernel.org>

^ permalink raw reply

* Re: [RFC] Null Namespaces
From: Christian Brauner @ 2026-06-29 10:31 UTC (permalink / raw)
  To: Al Viro
  Cc: John Ericson, Andy Lutomirski, Li Chen, Cong Wang, linux-arch,
	LKML, linux-fsdevel, linux-api, Arnd Bergmann, Thomas Gleixner,
	Ingo Molnar, Borislav Petkov, Dave Hansen, H. Peter Anvin,
	Jan Kara, Jonathan Corbet, Shuah Khan, Kees Cook,
	Sergei Zimmerman, Farid Zakaria
In-Reply-To: <20260626001538.GO2636677@ZenIV>

> So supply a library of your own and try to convince people to use it
> instead of libc.  You'll have to anyway, seeing that a large and

I agree. And in fact that is what we've been doing:

https://github.com/cyphar/libpathrs

I also plan on splitting the chase*() machinery in systemd out as
a separate C library as well:

https://github.com/systemd/systemd/blob/104750fd60da4c563650785e272a7ce0a6694d01/src/basic/chase.c#L238

> hard-to-predict part of libc will be non-functional.  Which syscalls
> are used by your library is entirely up to you.
> 
> Would that kind of thing added kernel-side assist the development of such
> library?  Maybe, but I wouldn't bet too much on that - if you start from

It wouldn't really and we haven't needed it for that.

^ permalink raw reply

* Re: [RFC] Null Namespaces
From: Christian Brauner @ 2026-06-29 10:39 UTC (permalink / raw)
  To: John Ericson
  Cc: H. Peter Anvin, Al Viro, Li Chen, Cong Wang, linux-arch, LKML,
	linux-fsdevel, linux-api, Arnd Bergmann, Andy Lutomirski,
	Thomas Gleixner, Ingo Molnar, Borislav Petkov, Dave Hansen,
	Jan Kara, Jonathan Corbet, Shuah Khan, Kees Cook,
	Sergei Zimmerman, Farid Zakaria
In-Reply-To: <614b290f-e274-4eb2-b687-008b004de526@app.fastmail.com>

> The kernel rightfully has consolidated path resolution in a few key
> places as much as possible -- the internal `struct path` does not suffer
> from these issues. I barely modify those places to support null root and
> CWD, and because of that consolidation, we shouldn't expect new places
> to crop up in the future. (Duplicative path resolution logic is a bad
> idea whether or not we have a nascent, little-used NULL-cwd/root code
> path.) Therefore, I think existing code review, even among people
> totally ignorant of this feature, will protect us --- the vast majority
> of code will just be working with `struct path`, and be totally
> unaffected by this change.

I actually did laugh out loud reading this. I'm sorry, I can't really
take this argument seriously. May I introduce you to drivers/ for a
start and the history of path lookup exploits of the last - say 10
years.

You have to excuse me but it's a mixture of amusement and slight anger.
Amusement because this is really naive and thus also a bit endearing.
Anger because it single-handedly dismisses how big of an attack surface
and problem space path lookup is. The equivalent of every math
professor's "trivial. excercise left to the reader".

^ permalink raw reply

* Re: [RFC] Null Namespaces
From: Christian Brauner @ 2026-06-29 11:45 UTC (permalink / raw)
  To: John Ericson
  Cc: Li Chen, Cong Wang, linux-arch, linux-kernel, linux-fsdevel,
	linux-api, Arnd Bergmann, Andy Lutomirski, Thomas Gleixner,
	Ingo Molnar, Borislav Petkov, Dave Hansen, H. Peter Anvin,
	Jan Kara, Jonathan Corbet, Shuah Khan, Alexander Viro, Kees Cook,
	Sergei Zimmerman, Farid Zakaria
In-Reply-To: <a49ce818-f38d-41b0-bbf7-80b8aad998b1@app.fastmail.com>

On Wed, Jun 24, 2026 at 06:51:47PM -0400, John Ericson wrote:
> Hello, I am hoping to discuss an idea I've had for a while, that I am
> calling "null namespaces" that has become more relevant with some recent
> other discussions. First I'll discuss null namespaces in general terms,
> and then I'll link those recent discussions and relate null namespaces
> to them.
> 
> ### Null namespaces
> 
> The essence of null namespaces is trying to give processes as little
> ambient authority as possible, so they are lighter weight and allowed to
> do even less than fully unshared processes today.
> 
> Namespaces as they exist today are frequently described as an isolation
> mechanism, but I think this is the conflation of two different things.
> *Removing* a new process from its parent's namespaces unquestionably is
> increasing isolation --- no disagreement there. But putting the process
> in new namespaces is something else; I would call it supporting
> "delusions of grandeur" of that process. For example, namespaces allow a
> process to do mounts, have `CAP_SYS_ADMIN`, create network interfaces,
> look up other processes by PID, etc.
> 
> Conceptually, to remove a process from one ambient authority scope (the
> very name "namespaces" indicates they are about ambient authority)
> should not require putting it in some ambient authority scope. Just
> because, for example, the process cannot see one mount tree, doesn't
> mean it needs to see another.
> 
> Here's what I am thinking would happen concretely:
> 
> First, the simpler cases:
> 
> #### Null mount namespace
> 
> - requires:
> 
>   - null root file system: absolute paths don't work.
> 
>   - null current working directory: relative paths with traditional,
>     non-`*at` system calls (and `*at` ones using `AT_FDCWD`) don't work.
> 
> - All operations relating to the "ambient" mount tree don't work.
> 
> - `*at` operations with a file descriptor do work.
> 
> - The new fd-based mount APIs with detached mounts do work, modulo
>   the calling process having enough permissions (as usual).

Nothing here requires you to NULL anything and I oppose this on code
sanity reasons alone. We shoud absolutely not start to stash any NULL
pointers in core kernel objects such as struct path that are used
everywhere.

So I've added nullfs a few releases back. It's currently not mountable
from userspace but I've already mentioned in the commit message that
this is going to change. But I also added:

unshare(UNSHARE_EMPTY_MNTNS)
clone3(CLONE_EMPTY_MNTNS)

In both cases the process is placed into a completely empty mount
namespace with nullfs as it's root and cwd. If you're in a new mount
namespace with CAP_SYS_ADMIN thrown away it means you're going to be in
nullfs forever.

It's possible we can come up with:

unshare(UNSHARE_FS_EMPTY)
clone3(CLONE_FS_EMPTY)

which just moves the task into an isolated nullfs instance (it would
need some thinking about interactions with chroot()).

But I guess the even simpler model would be to copy what I've been doing
for pidfs:

+static struct path nullfs_root_path = {};
+
+void nullfs_get_root(struct path *path)
+{
+       *path = nullfs_root_path;
+       path_get(path);
+}
+
 static void __init init_mount_tree(void)
 {
        struct vfsmount *mnt, *nullfs_mnt;
@@ -6209,6 +6217,8 @@ static void __init init_mount_tree(void)
        /* Mount mutable rootfs on top of nullfs. */
        root.mnt                = nullfs_mnt;
        root.dentry             = nullfs_mnt->mnt_root;
+       nullfs_root_path.mnt    = nullfs_mnt;
+       pidfs_root_path.dentry  = nullfs_mnt->mnt_root;

        LOCK_MOUNT_EXACT(mp, &root);
        if (unlikely(IS_ERR(mp.parent)))
diff --git a/include/uapi/linux/fcntl.h b/include/uapi/linux/fcntl.h
index aadfbf6e0cb3..f55c87c70b78 100644
--- a/include/uapi/linux/fcntl.h
+++ b/include/uapi/linux/fcntl.h
@@ -124,6 +124,7 @@ struct delegation {

 #define FD_PIDFS_ROOT                  -10002 /* Root of the pidfs filesystem */
 #define FD_NSFS_ROOT                   -10003 /* Root of the nsfs filesystem */
+#define FD_NULLFS_ROOT                 -10004 /* Root of the nullfs filesystem */
 #define FD_INVALID                     -10009 /* Invalid file descriptor: -10000 - EBADF = -10009 */

 /* Generic flags for the *at(2) family of syscalls. */

we then add fchroot() (overdue anyway) and then teach both fchdir() and
fchroot() to honor FD_NULLFS_ROOT. Then a process may shed its fs state
and move itself into nullfs. Restrict *chdir() and *chroot() for said
process via seccomp and it's locked in forever as well.

^ permalink raw reply related

* Re: [PATCH v2 1/2] man/man3/errno.3: Document EFTYPE error code
From: Dorjoy Chowdhury @ 2026-06-29 16:15 UTC (permalink / raw)
  To: Alejandro Colomar
  Cc: Florian Weimer, linux-man, brauner, jlayton, libc-alpha,
	linux-api
In-Reply-To: <ae9lMz0SRR-sn1Uz@devuan>

Hi,

The OPENAT2_REGULAR and EFTYPE changes are in the 7.2-rc1 now I
believe. I am not sure if it's the right time to merge the man-page
changes now. I also don't know the whole flow so I'm asking. Do both
of these need to be added to glibc manually or do these get pulled in
from the uapi headers of linux into glibc automatically?

Regards,
Dorjoy

On Mon, Apr 27, 2026 at 7:33 PM Alejandro Colomar <alx@kernel.org> wrote:
>
> Hi Florian,
>
> On 2026-04-27T15:29:30+0200, Florian Weimer wrote:
> > * Alejandro Colomar:
> >
> > > Hi Florian,
> > >
> > > On 2026-04-27T12:34:30+0200, Florian Weimer wrote:
> > >> * Alejandro Colomar:
> > >>
> > >> > [CC += libc-alpha]
> > >> >
> > >> > Hi Dorjoy,
> > >> >
> > >> > On 2026-04-26T17:14:25+0600, Dorjoy Chowdhury wrote:
> > >> >> Signed-off-by: Dorjoy Chowdhury <dorjoychy111@gmail.com>
> > >> >
> > >> > Thanks!
> > >> >
> > >> >  Reviewed-by: Alejandro Colomar <alx@kernel.org>
> > >> >
> > >> > I will wait until glibc adds this error code to their <errno.h> before
> > >> > applying the patch.  This means either you should write and send a patch
> > >> > to glibc (if so, please CC me), or you should ask them to add it
> > >> > themselves (if you're not comfortable writing glibc code).
> > >>
> > >> I'm not sure where this is coming from.
> > >
> > > Here's a link to the thread:
> > > <https://lore.kernel.org/linux-man/20260426111707.36541-1-dorjoychy111@gmail.com/T/>
> > >
> > >> POSIX says EFTYPE was rejected
> > >> in favor of ENOTTY.
> > >
> > > Could you please share a link to that?
> > >
> > > Anyway, I guess ENOTTY would be inappropriate in this case.  Although
> > > maybe a better error code could be devised; I don't know.  This is why
> > > I wanted glibc involved in this discussion before this arrives to a
> > > Linux release.  Thanks for the quick feedback!
> >
> > It's in the Rationale for System Interfaces:
> >
> > “
> > [EFTYPE]
> >     This error code was proposed in earlier proposals as "Inappropriate
> >     operation for file type", meaning that the operation requested is
> >     not appropriate for the file specified in the function call. This
> >     code was proposed, although the same idea was covered by [ENOTTY],
> >     because the connotations of the name would be misleading. It was
> >     pointed out that the fcntl() function uses the error code [EINVAL]
> >     for this notion, and hence all instances of [EFTYPE] were changed to
> >     this code.
> > ”
> >
> > I replied on linux-fsdevel, too.
>
> Thanks!
>
> >
> > (It would be nice to submit patches introducing new error codes to
> > linux-api with a subject mentioning the error code.)
>
> Thanks!  I'll remember this advice for when receiving patches that add
> error codes.
>
> >
> > Thanks,
> > Florian
>
> Cheers,
> Alex
>
> --
> <https://www.alejandro-colomar.es>

^ permalink raw reply

* Re: [PATCH v2 1/2] man/man3/errno.3: Document EFTYPE error code
From: Alejandro Colomar @ 2026-06-29 21:02 UTC (permalink / raw)
  To: Dorjoy Chowdhury
  Cc: Florian Weimer, linux-man, brauner, jlayton, libc-alpha,
	linux-api
In-Reply-To: <CAFfO_h7V4gX6NbQvPtTF=XeH44j4O1oxWcArE+fzKM9FTmDKRg@mail.gmail.com>

[-- Attachment #1: Type: text/plain, Size: 3804 bytes --]

Hi Dorjoy,

On 2026-06-29T22:15:45+0600, Dorjoy Chowdhury wrote:
> Hi,
> 
> The OPENAT2_REGULAR and EFTYPE changes are in the 7.2-rc1 now I
> believe. I am not sure if it's the right time to merge the man-page
> changes now.

Yes, it is.

> I also don't know the whole flow so I'm asking.

If it's in an -rc, and you believe there won't be significant changes
before release, we can merge the documentation already.  If there's any
last-minute change before the actual 7.2 release, just send some patch
fixing the documentation.

Please keep all the CCs when sending the patches, and send in reply to
the first message in this thread, so that it's easier to correlate them.
Please also include CC tags in the trailer of the commit message.

> Do both
> of these need to be added to glibc manually or do these get pulled in
> from the uapi headers of linux into glibc automatically?

I don't know about this; someone from glibc will have to comment.


Have a lovely night!
Alex

> 
> Regards,
> Dorjoy
> 
> On Mon, Apr 27, 2026 at 7:33 PM Alejandro Colomar <alx@kernel.org> wrote:
> >
> > Hi Florian,
> >
> > On 2026-04-27T15:29:30+0200, Florian Weimer wrote:
> > > * Alejandro Colomar:
> > >
> > > > Hi Florian,
> > > >
> > > > On 2026-04-27T12:34:30+0200, Florian Weimer wrote:
> > > >> * Alejandro Colomar:
> > > >>
> > > >> > [CC += libc-alpha]
> > > >> >
> > > >> > Hi Dorjoy,
> > > >> >
> > > >> > On 2026-04-26T17:14:25+0600, Dorjoy Chowdhury wrote:
> > > >> >> Signed-off-by: Dorjoy Chowdhury <dorjoychy111@gmail.com>
> > > >> >
> > > >> > Thanks!
> > > >> >
> > > >> >  Reviewed-by: Alejandro Colomar <alx@kernel.org>
> > > >> >
> > > >> > I will wait until glibc adds this error code to their <errno.h> before
> > > >> > applying the patch.  This means either you should write and send a patch
> > > >> > to glibc (if so, please CC me), or you should ask them to add it
> > > >> > themselves (if you're not comfortable writing glibc code).
> > > >>
> > > >> I'm not sure where this is coming from.
> > > >
> > > > Here's a link to the thread:
> > > > <https://lore.kernel.org/linux-man/20260426111707.36541-1-dorjoychy111@gmail.com/T/>
> > > >
> > > >> POSIX says EFTYPE was rejected
> > > >> in favor of ENOTTY.
> > > >
> > > > Could you please share a link to that?
> > > >
> > > > Anyway, I guess ENOTTY would be inappropriate in this case.  Although
> > > > maybe a better error code could be devised; I don't know.  This is why
> > > > I wanted glibc involved in this discussion before this arrives to a
> > > > Linux release.  Thanks for the quick feedback!
> > >
> > > It's in the Rationale for System Interfaces:
> > >
> > > “
> > > [EFTYPE]
> > >     This error code was proposed in earlier proposals as "Inappropriate
> > >     operation for file type", meaning that the operation requested is
> > >     not appropriate for the file specified in the function call. This
> > >     code was proposed, although the same idea was covered by [ENOTTY],
> > >     because the connotations of the name would be misleading. It was
> > >     pointed out that the fcntl() function uses the error code [EINVAL]
> > >     for this notion, and hence all instances of [EFTYPE] were changed to
> > >     this code.
> > > ”
> > >
> > > I replied on linux-fsdevel, too.
> >
> > Thanks!
> >
> > >
> > > (It would be nice to submit patches introducing new error codes to
> > > linux-api with a subject mentioning the error code.)
> >
> > Thanks!  I'll remember this advice for when receiving patches that add
> > error codes.
> >
> > >
> > > Thanks,
> > > Florian
> >
> > Cheers,
> > Alex
> >
> > --
> > <https://www.alejandro-colomar.es>
> 

-- 
<https://www.alejandro-colomar.es>

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply

* Re: [RFC] Null Namespaces
From: Andy Lutomirski @ 2026-06-29 21:06 UTC (permalink / raw)
  To: Christian Brauner
  Cc: John Ericson, Li Chen, Cong Wang, linux-arch, linux-kernel,
	linux-fsdevel, linux-api, Arnd Bergmann, Andy Lutomirski,
	Thomas Gleixner, Ingo Molnar, Borislav Petkov, Dave Hansen,
	H. Peter Anvin, Jan Kara, Jonathan Corbet, Shuah Khan,
	Alexander Viro, Kees Cook, Sergei Zimmerman, Farid Zakaria
In-Reply-To: <20260629-hauer-erhitzen-sobald-96d3dff68707@brauner>

On Mon, Jun 29, 2026 at 4:45 AM Christian Brauner <brauner@kernel.org> wrote:
>

> But I guess the even simpler model would be to copy what I've been doing
> for pidfs:
>
> +static struct path nullfs_root_path = {};
> +
> +void nullfs_get_root(struct path *path)
> +{
> +       *path = nullfs_root_path;
> +       path_get(path);
> +}
> +
>  static void __init init_mount_tree(void)
>  {
>         struct vfsmount *mnt, *nullfs_mnt;
> @@ -6209,6 +6217,8 @@ static void __init init_mount_tree(void)
>         /* Mount mutable rootfs on top of nullfs. */
>         root.mnt                = nullfs_mnt;
>         root.dentry             = nullfs_mnt->mnt_root;
> +       nullfs_root_path.mnt    = nullfs_mnt;
> +       pidfs_root_path.dentry  = nullfs_mnt->mnt_root;
>
>         LOCK_MOUNT_EXACT(mp, &root);
>         if (unlikely(IS_ERR(mp.parent)))
> diff --git a/include/uapi/linux/fcntl.h b/include/uapi/linux/fcntl.h
> index aadfbf6e0cb3..f55c87c70b78 100644
> --- a/include/uapi/linux/fcntl.h
> +++ b/include/uapi/linux/fcntl.h
> @@ -124,6 +124,7 @@ struct delegation {
>
>  #define FD_PIDFS_ROOT                  -10002 /* Root of the pidfs filesystem */
>  #define FD_NSFS_ROOT                   -10003 /* Root of the nsfs filesystem */
> +#define FD_NULLFS_ROOT                 -10004 /* Root of the nullfs filesystem */
>  #define FD_INVALID                     -10009 /* Invalid file descriptor: -10000 - EBADF = -10009 */
>
>  /* Generic flags for the *at(2) family of syscalls. */
>
> we then add fchroot() (overdue anyway) and then teach both fchdir() and
> fchroot() to honor FD_NULLFS_ROOT. Then a process may shed its fs state
> and move itself into nullfs. Restrict *chdir() and *chroot() for said
> process via seccomp and it's locked in forever as well.
>

One thing comes to mind that might need a bit of care: this would give
an API for any task to get an fd to a directory that lives in the init
mount namespace.  It's not at all obvious to me that this is dangerous
or even observable (you're not about to find a setuid program in
nullfs), but I think it's at least worth a tiny bit of consideration.

But if this happens, maybe we could finally land one of the patches to
enable unprivileged chroot?  It's been tried a few times.

https://lore.kernel.org/lkml/0e2f0f54e19bff53a3739ecfddb4ffa9a6dbde4d.1327858005.git.luto@amacapital.net/

https://lore.kernel.org/all/20210316203633.424794-2-mic@digikod.net/

I think the need for it has reduced a tiny bit with user namespaces,
as you can sort of emulate it by unsharing your user namespace and
thus getting enough privilege, but this is rather heavyweight and
limiting.


If all of the above landed, then the old chroot /var/empty kludge that
security-minded programs have done for decades could finally be
modernized and not require any privilege :)

Hmm, thinking aloud: every now and then someone brings up the idea of
having an fd (really an OFD) that points to a file or a directory but
carries less in the way of permissions/capabilities than the usual
OFDs.  If we had a way to make an OFD to a directory that forced
RESOLVE_BENEATH (or RESOLVE_IN_ROOT) and that propagated that
restriction to anything you open using it, and if an unprivileged
process could chroot itself to nullfs, then we would be getting quite
close to what Capsicum can do.

--Andy

^ permalink raw reply

* Re: [RFC] Null Namespaces
From: John Ericson @ 2026-06-30  2:50 UTC (permalink / raw)
  To: Christian Brauner
  Cc: Li Chen, Cong Wang, linux-arch, LKML, linux-fsdevel, linux-api,
	Arnd Bergmann, Andy Lutomirski, Thomas Gleixner, Ingo Molnar,
	Borislav Petkov, Dave Hansen, H. Peter Anvin, Jan Kara,
	Jonathan Corbet, Shuah Khan, Al Viro, Kees Cook, Sergei Zimmerman,
	Farid Zakaria
In-Reply-To: <20260629-hauer-erhitzen-sobald-96d3dff68707@brauner>

On Mon, Jun 29, 2026, at 7:45 AM, Christian Brauner wrote:
> But I guess the even simpler model would be to copy what I've been doing
> for pidfs:
>
> [...]
>
> we then add fchroot() (overdue anyway) and then teach both fchdir() and
> fchroot() to honor FD_NULLFS_ROOT. Then a process may shed its fs state
> and move itself into nullfs. Restrict *chdir() and *chroot() for said
> process via seccomp and it's locked in forever as well.

This looks good! It delivers most of what I want, and I do want to be
very clear that while I am responding to your comments on my patch
below, I would still be very pleased if we just did this, much more than
I am pleased with the status quo.

(And also, yes, good to create the long-overdue fchroot regardless of
what we do here.)

> Nothing here requires you to NULL anything and I oppose this on code
> sanity reasons alone. We shoud absolutely not start to stash any NULL
> pointers in core kernel objects such as struct path that are used
> everywhere.

Before we do the "pidfd style" nullfs route, I want to make one thing
clear about my patch: I was *not* trying to relax the invariant across
the board that (live) `struct path` should only contain non-null
pointers. Rather, I just want `struct fs_struct` to contain ("morally")
`Option<struct path>`. My use of the null pointer was merely me doing
the sort of ragged union packing that, for example, Rust does. I think
as a matter of A_B_I (emphasis on "binary"), this is fine, and not
going to cause Armageddon --- `struct path` is widely used, but `struct
fs_struct` is (as far as I can tell) not.

All that said, as a matter of A_P_I (emphasis on "program"), I do see
your point that it's too easy for someone to not read my comment, and
then `struct path` with null pointers starts leaking all over the place,
making a big mess. I think a simple enough fix is to just use another C
encoding, such as a union, for `Option<struct path>`.

For example:

    union optional_path {
        struct {
            void *p0, *p1; /* must be null */
        } __randomize_layout null_path;
        struct path path; /* both fields must be non-null */
    };

To continue saving space, or --- if relying on the overlap of
`null_path` and `path.mnt` is too sketchy --- making a bona fide tagged
union:

    struct optional_path {
        enum {
            OPTIONAL_PATH_ABSENT,
            OPTIONAL_PATH_PRESENT,
        } tag;
        union {
            struct {} null_path;
            struct path path;
        };
    };

And either way, there can be an inline function:

    const struct path * /* nullable */
    get_optional_path(const struct optional_path * /* non-nullable */);

taking a non-null pointer and returning a nullable pointer to help
consumers of `struct fs_struct` not screw up accessing `root` and `pwd`.

A third option is simply copying the definition of `struct path`, doing:

    /* Just like `struct path`, but instead of both fields always being
     * non-null, both fields can also both be null to indicate an absent
     * path. One field null, the other field non-null is still not
     * permitted, however.
     */
    struct optional_path {
            struct vfsmount *optional_mnt;
            struct dentry *optional_dentry;
    } __randomize_layout;

in which case `get_optional_path` works by value instead of by
reference, because in the `CONFIG_RANDSTRUCT`-case the field order may
not be the same.

Any of these 3 variations would make absolutely clear that the
invariants around `struct path` have not changed, and only `struct
fs_struct` is changed. Furthermore, the API breakage on `fs->pwd` and
`fs->root` will mechanically ensure that all consumers get caught and
fixed (with the fix being to use `get_optional_path` and check for the
null case).

I do like these versions better than my original, because I do agree
making a safer C API is worthwhile. And because of the API breakage
forcing a complete patch as discussed above, I think that if I make a v2
along these lines, the diff will either prove or refute my basic premise
that `pwd` and `root` in `struct fs_struct`, unlike `struct path`, are
not widely used, and so changing their definitions like this (from
`struct path` to `... optional_path`) is lightweight.

Thanks,

John

^ permalink raw reply

* Re: [RFC] Null Namespaces
From: John Ericson @ 2026-06-30  4:25 UTC (permalink / raw)
  To: Andy Lutomirski, Christian Brauner
  Cc: Li Chen, Cong Wang, linux-arch, LKML, linux-fsdevel, linux-api,
	Arnd Bergmann, Thomas Gleixner, Ingo Molnar, Borislav Petkov,
	Dave Hansen, H. Peter Anvin, Jan Kara, Jonathan Corbet,
	Shuah Khan, Al Viro, Kees Cook, Sergei Zimmerman, Farid Zakaria
In-Reply-To: <CALCETrVuh0-biOw=TgYN9ERTFAoiki57XeZ3S2T3dO2+hL54gA@mail.gmail.com>

On Mon, Jun 29, 2026, at 5:06 PM, Andy Lutomirski wrote:
> But if this happens, maybe we could finally land one of the patches to
> enable unprivileged chroot?  It's been tried a few times.

> If we had a way to make an OFD to a directory that forced
> RESOLVE_BENEATH (or RESOLVE_IN_ROOT) and that propagated that
> restriction to anything you open using it, and if an unprivileged
> process could chroot itself to nullfs, then we would be getting quite
> close to what Capsicum can do.

I just want to briefly say that I agree that these are both things worth
pursuing.

Once the root and working directories are sorted out (whether by nullfs
or by making those optional in `fs_struct`, see my other email), I am
fine putting my yet-unsubmitted patches for the null namespaces
themselves on hold and addressing these things instead. I can indeed see
it may be useful to wrap up such loose ends in VFS-land while we are
here, before switching gears to other namespaces and other subsystems.

John

^ permalink raw reply

* Re: [RFC] Null Namespaces
From: Christian Brauner @ 2026-06-30  7:14 UTC (permalink / raw)
  To: John Ericson
  Cc: Li Chen, Cong Wang, linux-arch, LKML, linux-fsdevel, linux-api,
	Arnd Bergmann, Andy Lutomirski, Thomas Gleixner, Ingo Molnar,
	Borislav Petkov, Dave Hansen, H. Peter Anvin, Jan Kara,
	Jonathan Corbet, Shuah Khan, Al Viro, Kees Cook, Sergei Zimmerman,
	Farid Zakaria
In-Reply-To: <eb390c52-eeb3-44b3-88e9-e65c52a26c05@app.fastmail.com>

On Mon, Jun 29, 2026 at 10:50:38PM -0400, John Ericson wrote:
> On Mon, Jun 29, 2026, at 7:45 AM, Christian Brauner wrote:
> > But I guess the even simpler model would be to copy what I've been doing
> > for pidfs:
> >
> > [...]
> >
> > we then add fchroot() (overdue anyway) and then teach both fchdir() and
> > fchroot() to honor FD_NULLFS_ROOT. Then a process may shed its fs state
> > and move itself into nullfs. Restrict *chdir() and *chroot() for said
> > process via seccomp and it's locked in forever as well.
> 
> This looks good! It delivers most of what I want, and I do want to be
> very clear that while I am responding to your comments on my patch
> below, I would still be very pleased if we just did this, much more than
> I am pleased with the status quo.
> 
> (And also, yes, good to create the long-overdue fchroot regardless of
> what we do here.)
> 
> > Nothing here requires you to NULL anything and I oppose this on code
> > sanity reasons alone. We shoud absolutely not start to stash any NULL
> > pointers in core kernel objects such as struct path that are used
> > everywhere.
> 
> Before we do the "pidfd style" nullfs route, I want to make one thing
> clear about my patch: I was *not* trying to relax the invariant across
> the board that (live) `struct path` should only contain non-null
> pointers. Rather, I just want `struct fs_struct` to contain ("morally")
> `Option<struct path>`. My use of the null pointer was merely me doing
> the sort of ragged union packing that, for example, Rust does. I think
> as a matter of A_B_I (emphasis on "binary"), this is fine, and not
> going to cause Armageddon --- `struct path` is widely used, but `struct
> fs_struct` is (as far as I can tell) not.
> 
> All that said, as a matter of A_P_I (emphasis on "program"), I do see
> your point that it's too easy for someone to not read my comment, and
> then `struct path` with null pointers starts leaking all over the place,
> making a big mess. I think a simple enough fix is to just use another C
> encoding, such as a union, for `Option<struct path>`.
> 
> For example:
> 
>     union optional_path {
>         struct {
>             void *p0, *p1; /* must be null */
>         } __randomize_layout null_path;
>         struct path path; /* both fields must be non-null */
>     };
> 
> To continue saving space, or --- if relying on the overlap of
> `null_path` and `path.mnt` is too sketchy --- making a bona fide tagged
> union:
> 
>     struct optional_path {
>         enum {
>             OPTIONAL_PATH_ABSENT,
>             OPTIONAL_PATH_PRESENT,
>         } tag;
>         union {
>             struct {} null_path;
>             struct path path;
>         };
>     };

I think Al is about to have a stroke reading this... and I might too.
I agree with the sentiment I disagree with the details of this and
touching the whole kernel for this. You know what the easy solution is:
don't allow a struct path to be empty...

^ permalink raw reply

* [PATCH v2 0/9] vDSO: Respect COMPAT_32BIT_TIME
From: Thomas Weißschuh @ 2026-06-30  7:38 UTC (permalink / raw)
  To: Andy Lutomirski, Thomas Gleixner, Ingo Molnar, Borislav Petkov,
	Dave Hansen, x86, H. Peter Anvin, Russell King, Catalin Marinas,
	Will Deacon, Madhavan Srinivasan, Michael Ellerman,
	Nicholas Piggin, Christophe Leroy (CS GROUP), Thomas Bogendoerfer,
	Vincenzo Frascino, John Stultz, Stephen Boyd, David S. Miller,
	Andreas Larsson
  Cc: Thomas Weißschuh, linux-kernel, linux-arm-kernel,
	linuxppc-dev, linux-mips, Arnd Bergmann, linux-api, sparclinux

If CONFIG_COMPAT_32BIT_TIME is disabled then the vDSO should not
provide any 32-bit time related functionality. This is the intended
effect of the kconfig option and also the fallback system calls would
also not be implemented.

Currently the kconfig option does not affect the gettimeofday() syscall,
so also keep that in the vDSO.

I also tried to introduce some helpers to avoid much of the ifdeffery,
but due to the high variance in the architecture-specific glue code
these would need to handle they ended up being worse than the current
proposal.

As a side-effect this will make the self-tests more reliable,
as there is now always a matching syscall available for each vDSO function.

clock_gettime_time64() was only introduced in v6.19, so libc implementations
are likely not using it yet.

Signed-off-by: Thomas Weißschuh <thomas.weissschuh@linutronix.de>
---
Changes in v2:
- Also handle SPARC.
- Drop MIPS cleanup patches.
- Also handle gettimeofday().
- Add more static validations.
- Rebase on v7.2-rc1.
- Link to v1: https://lore.kernel.org/r/20260227-vdso-compat_32bit_time-v1-0-3f0286a7bac3@linutronix.de

To: Andy Lutomirski <luto@kernel.org>
To: Thomas Gleixner <tglx@kernel.org>
To: Ingo Molnar <mingo@redhat.com>
To: Borislav Petkov <bp@alien8.de>
To: Dave Hansen <dave.hansen@linux.intel.com>
To: x86@kernel.org
To: H. Peter Anvin <hpa@zytor.com>
To: Russell King <linux@armlinux.org.uk>
To: Catalin Marinas <catalin.marinas@arm.com>
To: Will Deacon <will@kernel.org>
To: Madhavan Srinivasan <maddy@linux.ibm.com>
To: Michael Ellerman <mpe@ellerman.id.au>
To: Nicholas Piggin <npiggin@gmail.com>
To: Christophe Leroy (CS GROUP) <chleroy@kernel.org>
To: Thomas Bogendoerfer <tsbogend@alpha.franken.de>
To: Vincenzo Frascino <vincenzo.frascino@arm.com>
To: John Stultz <jstultz@google.com>
To: Stephen Boyd <sboyd@kernel.org>
To: "David S. Miller" <davem@davemloft.net>
To: Andreas Larsson <andreas@gaisler.com>
Cc: linux-kernel@vger.kernel.org
Cc: linux-arm-kernel@lists.infradead.org
Cc: linuxppc-dev@lists.ozlabs.org
Cc: linux-mips@vger.kernel.org
Cc: Arnd Bergmann <arnd@arndb.de>
Cc: linux-api@vger.kernel.org
Cc: sparclinux@vger.kernel.org

---
Thomas Weißschuh (9):
      time: Respect COMPAT_32BIT_TIME for old time type functions
      vdso/gettimeofday: Validate system call existence for time() and gettimeofday()
      x86/vdso: Respect COMPAT_32BIT_TIME
      arm64: vdso32: Respect COMPAT_32BIT_TIME
      ARM: VDSO: Respect COMPAT_32BIT_TIME
      powerpc/vdso: Respect COMPAT_32BIT_TIME
      MIPS: VDSO: Respect COMPAT_32BIT_TIME
      sparc: vdso: Respect COMPAT_32BIT_TIME
      vdso/gettimeofday: Verify COMPAT_32BIT_TIME interactions

 arch/arm/vdso/vdso.lds.S                    |  2 ++
 arch/arm/vdso/vgettimeofday.c               | 14 ++++++++------
 arch/arm64/kernel/vdso32/vdso.lds.S         |  2 ++
 arch/arm64/kernel/vdso32/vgettimeofday.c    | 14 ++++++++------
 arch/mips/vdso/vdso.lds.S                   |  2 ++
 arch/mips/vdso/vgettimeofday.c              |  3 +++
 arch/powerpc/kernel/vdso/gettimeofday.S     |  8 ++++++++
 arch/powerpc/kernel/vdso/vdso32.lds.S       | 10 ++++++----
 arch/powerpc/kernel/vdso/vgettimeofday.c    | 16 ++++++++++------
 arch/sparc/vdso/vclock_gettime.c            |  4 ++++
 arch/sparc/vdso/vdso32/vdso32.lds.S         |  6 ++++--
 arch/x86/entry/vdso/common/vclock_gettime.c | 20 ++++++++++++--------
 arch/x86/entry/vdso/vdso32/vdso32.lds.S     |  2 ++
 kernel/sys_ni.c                             |  4 ++++
 kernel/time/time.c                          | 24 ++++++++++++++++++++----
 lib/vdso/gettimeofday.c                     | 20 ++++++++++++++++++++
 16 files changed, 115 insertions(+), 36 deletions(-)
---
base-commit: e6da2429169af9b33f3629b69905d89bb5ee9e64
change-id: 20260113-vdso-compat_32bit_time-e808763e976a

Best regards,
--  
Thomas Weißschuh (Schneider Electric) <thomas.weissschuh@linutronix.de>


^ permalink raw reply

* [PATCH v2 1/9] time: Respect COMPAT_32BIT_TIME for old time type functions
From: Thomas Weißschuh @ 2026-06-30  7:38 UTC (permalink / raw)
  To: Andy Lutomirski, Thomas Gleixner, Ingo Molnar, Borislav Petkov,
	Dave Hansen, x86, H. Peter Anvin, Russell King, Catalin Marinas,
	Will Deacon, Madhavan Srinivasan, Michael Ellerman,
	Nicholas Piggin, Christophe Leroy (CS GROUP), Thomas Bogendoerfer,
	Vincenzo Frascino, John Stultz, Stephen Boyd, David S. Miller,
	Andreas Larsson
  Cc: Thomas Weißschuh, linux-kernel, linux-arm-kernel,
	linuxppc-dev, linux-mips, Arnd Bergmann, linux-api, sparclinux
In-Reply-To: <20260630-vdso-compat_32bit_time-v2-0-520d194640dd@linutronix.de>

The "old" time types use 32-bit seconds which are not y2038-safe.
Respect COMPAT_32BIT_TIME for functions using those types.
time(), stime() and gettimeofday() are disabled completely.

settimeofday() is kept as it is required to do the initial timewarping
after boot. However the 'tv' argument will be rejected.

Link: https://lore.kernel.org/lkml/e9487ebe-3730-438a-9c23-e45f75986ecc@app.fastmail.com/
Signed-off-by: Thomas Weißschuh <thomas.weissschuh@linutronix.de>
---
 kernel/sys_ni.c    |  4 ++++
 kernel/time/time.c | 24 ++++++++++++++++++++----
 2 files changed, 24 insertions(+), 4 deletions(-)

diff --git a/kernel/sys_ni.c b/kernel/sys_ni.c
index add3032da16f..c8be0abaa407 100644
--- a/kernel/sys_ni.c
+++ b/kernel/sys_ni.c
@@ -351,6 +351,10 @@ COND_SYSCALL(ppoll_time32);
 COND_SYSCALL_COMPAT(ppoll_time32);
 COND_SYSCALL(utimensat_time32);
 COND_SYSCALL(clock_adjtime32);
+COND_SYSCALL(gettimeofday);
+COND_SYSCALL_COMPAT(gettimeofday);
+COND_SYSCALL(time);
+COND_SYSCALL(stime);
 
 /*
  * The syscalls below are not found in include/uapi/asm-generic/unistd.h
diff --git a/kernel/time/time.c b/kernel/time/time.c
index 0dd63a91e7c5..0b7aa432bc76 100644
--- a/kernel/time/time.c
+++ b/kernel/time/time.c
@@ -43,6 +43,12 @@
 #include <generated/timeconst.h>
 #include "timekeeping.h"
 
+#if defined(CONFIG_64BIT) || defined(CONFIG_COMPAT_32BIT_TIME)
+#define __WANT_OLD_TIME_TYPE_SYSCALL 1
+#endif
+
+static_assert(sizeof(__kernel_old_time_t) == 8 ? IS_ENABLED(__WANT_OLD_TIME_TYPE_SYSCALL) : true);
+
 /*
  * The timezone where the local system is located.  Used as a default by some
  * programs who obtain this value by using gettimeofday.
@@ -51,7 +57,7 @@ struct timezone sys_tz;
 
 EXPORT_SYMBOL(sys_tz);
 
-#ifdef __ARCH_WANT_SYS_TIME
+#if defined(__ARCH_WANT_SYS_TIME) && defined(__WANT_OLD_TIME_TYPE_SYSCALL)
 
 /*
  * sys_time() can be implemented in user-level using
@@ -96,7 +102,7 @@ SYSCALL_DEFINE1(stime, __kernel_old_time_t __user *, tptr)
 	return 0;
 }
 
-#endif /* __ARCH_WANT_SYS_TIME */
+#endif /* __ARCH_WANT_SYS_TIME && __WANT_OLD_TIME_TYPE_SYSCALL */
 
 #ifdef CONFIG_COMPAT_32BIT_TIME
 #ifdef __ARCH_WANT_SYS_TIME32
@@ -137,6 +143,7 @@ SYSCALL_DEFINE1(stime32, old_time32_t __user *, tptr)
 #endif /* __ARCH_WANT_SYS_TIME32 */
 #endif
 
+#ifdef __WANT_OLD_TIME_TYPE_SYSCALL
 SYSCALL_DEFINE2(gettimeofday, struct __kernel_old_timeval __user *, tv,
 		struct timezone __user *, tz)
 {
@@ -154,6 +161,7 @@ SYSCALL_DEFINE2(gettimeofday, struct __kernel_old_timeval __user *, tv,
 	}
 	return 0;
 }
+#endif /* __WANT_OLD_TIME_TYPE_SYSCALL */
 
 /*
  * In case for some reason the CMOS clock has not already been running
@@ -203,6 +211,9 @@ SYSCALL_DEFINE2(settimeofday, struct __kernel_old_timeval __user *, tv,
 	struct timezone new_tz;
 
 	if (tv) {
+		if (!IS_ENABLED(__WANT_OLD_TIME_TYPE_SYSCALL))
+			return -EINVAL;
+
 		if (get_user(new_ts.tv_sec, &tv->tv_sec) ||
 		    get_user(new_ts.tv_nsec, &tv->tv_usec))
 			return -EFAULT;
@@ -220,7 +231,7 @@ SYSCALL_DEFINE2(settimeofday, struct __kernel_old_timeval __user *, tv,
 	return do_sys_settimeofday64(tv ? &new_ts : NULL, tz ? &new_tz : NULL);
 }
 
-#ifdef CONFIG_COMPAT
+#ifdef CONFIG_COMPAT_32BIT_TIME
 COMPAT_SYSCALL_DEFINE2(gettimeofday, struct old_timeval32 __user *, tv,
 		       struct timezone __user *, tz)
 {
@@ -239,7 +250,9 @@ COMPAT_SYSCALL_DEFINE2(gettimeofday, struct old_timeval32 __user *, tv,
 
 	return 0;
 }
+#endif /* CONFIG_COMPAT_32BIT_TIME */
 
+#ifdef CONFIG_COMPAT
 COMPAT_SYSCALL_DEFINE2(settimeofday, struct old_timeval32 __user *, tv,
 		       struct timezone __user *, tz)
 {
@@ -247,6 +260,9 @@ COMPAT_SYSCALL_DEFINE2(settimeofday, struct old_timeval32 __user *, tv,
 	struct timezone new_tz;
 
 	if (tv) {
+		if (!IS_ENABLED(__WANT_OLD_TIME_TYPE_SYSCALL))
+			return -EINVAL;
+
 		if (get_user(new_ts.tv_sec, &tv->tv_sec) ||
 		    get_user(new_ts.tv_nsec, &tv->tv_usec))
 			return -EFAULT;
@@ -263,7 +279,7 @@ COMPAT_SYSCALL_DEFINE2(settimeofday, struct old_timeval32 __user *, tv,
 
 	return do_sys_settimeofday64(tv ? &new_ts : NULL, tz ? &new_tz : NULL);
 }
-#endif
+#endif /* CONFIG_COMPAT */
 
 #ifdef CONFIG_64BIT
 SYSCALL_DEFINE1(adjtimex, struct __kernel_timex __user *, txc_p)

-- 
2.55.0


^ permalink raw reply related

* [PATCH v2 2/9] vdso/gettimeofday: Validate system call existence for time() and gettimeofday()
From: Thomas Weißschuh @ 2026-06-30  7:38 UTC (permalink / raw)
  To: Andy Lutomirski, Thomas Gleixner, Ingo Molnar, Borislav Petkov,
	Dave Hansen, x86, H. Peter Anvin, Russell King, Catalin Marinas,
	Will Deacon, Madhavan Srinivasan, Michael Ellerman,
	Nicholas Piggin, Christophe Leroy (CS GROUP), Thomas Bogendoerfer,
	Vincenzo Frascino, John Stultz, Stephen Boyd, David S. Miller,
	Andreas Larsson
  Cc: Thomas Weißschuh, linux-kernel, linux-arm-kernel,
	linuxppc-dev, linux-mips, Arnd Bergmann, linux-api, sparclinux
In-Reply-To: <20260630-vdso-compat_32bit_time-v2-0-520d194640dd@linutronix.de>

Not all architectures have the system calls for time() and
gettimeofday(). When the system call is missing, the vDSO function
should also not be present.

Validate that.

Signed-off-by: Thomas Weißschuh <thomas.weissschuh@linutronix.de>
---
 lib/vdso/gettimeofday.c | 10 ++++++++++
 1 file changed, 10 insertions(+)

diff --git a/lib/vdso/gettimeofday.c b/lib/vdso/gettimeofday.c
index e0f289d3d110..b8c1fc85eb74 100644
--- a/lib/vdso/gettimeofday.c
+++ b/lib/vdso/gettimeofday.c
@@ -12,6 +12,8 @@
 #include <vdso/time32.h>
 #include <vdso/time64.h>
 
+#include <uapi/linux/unistd.h>
+
 /*
  * The generic vDSO implementation requires that gettimeofday.h
  * provides:
@@ -348,6 +350,10 @@ __cvdso_gettimeofday_data(const struct vdso_time_data *vd,
 {
 	const struct vdso_clock *vc = vd->clock_data;
 
+#ifndef __NR_gettimeofday
+	BUILD_BUG();
+#endif
+
 	if (likely(tv != NULL)) {
 		struct __kernel_timespec ts;
 
@@ -382,6 +388,10 @@ __cvdso_time_data(const struct vdso_time_data *vd, __kernel_old_time_t *time)
 	const struct vdso_clock *vc = vd->clock_data;
 	__kernel_old_time_t t;
 
+#ifndef __NR_time
+	BUILD_BUG();
+#endif
+
 	if (vdso_is_timens_clock(vc)) {
 		vd = vdso_timens_data(vd);
 		vc = vd->clock_data;

-- 
2.55.0


^ permalink raw reply related

* [PATCH v2 3/9] x86/vdso: Respect COMPAT_32BIT_TIME
From: Thomas Weißschuh @ 2026-06-30  7:38 UTC (permalink / raw)
  To: Andy Lutomirski, Thomas Gleixner, Ingo Molnar, Borislav Petkov,
	Dave Hansen, x86, H. Peter Anvin, Russell King, Catalin Marinas,
	Will Deacon, Madhavan Srinivasan, Michael Ellerman,
	Nicholas Piggin, Christophe Leroy (CS GROUP), Thomas Bogendoerfer,
	Vincenzo Frascino, John Stultz, Stephen Boyd, David S. Miller,
	Andreas Larsson
  Cc: Thomas Weißschuh, linux-kernel, linux-arm-kernel,
	linuxppc-dev, linux-mips, Arnd Bergmann, linux-api, sparclinux
In-Reply-To: <20260630-vdso-compat_32bit_time-v2-0-520d194640dd@linutronix.de>

If CONFIG_COMPAT_32BIT_TIME is disabled then the vDSO should not
provide any 32-bit time related functionality. This is the intended
effect of the kconfig option and also the fallback system calls would
also not be implemented.

Currently the kconfig option does not affect the gettimeofday() syscall,
so also keep that in the vDSO.

Signed-off-by: Thomas Weißschuh <thomas.weissschuh@linutronix.de>
---
 arch/x86/entry/vdso/common/vclock_gettime.c | 20 ++++++++++++--------
 arch/x86/entry/vdso/vdso32/vdso32.lds.S     |  2 ++
 2 files changed, 14 insertions(+), 8 deletions(-)

diff --git a/arch/x86/entry/vdso/common/vclock_gettime.c b/arch/x86/entry/vdso/common/vclock_gettime.c
index 57066f346b3f..304dbd1f9db4 100644
--- a/arch/x86/entry/vdso/common/vclock_gettime.c
+++ b/arch/x86/entry/vdso/common/vclock_gettime.c
@@ -15,6 +15,7 @@
 
 #include "lib/vdso/gettimeofday.c"
 
+#if defined(__x86_64__) || defined(CONFIG_COMPAT_32BIT_TIME)
 int __vdso_gettimeofday(struct __kernel_old_timeval *tv, struct timezone *tz)
 {
 	return __cvdso_gettimeofday(tv, tz);
@@ -29,6 +30,7 @@ __kernel_old_time_t __vdso_time(__kernel_old_time_t *t)
 }
 
 __kernel_old_time_t time(__kernel_old_time_t *t)	__attribute__((weak, alias("__vdso_time")));
+#endif /* CONFIG_COMPAT_32BIT_TIME */
 
 
 #if defined(CONFIG_X86_64) && !defined(BUILD_VDSO32_64)
@@ -51,6 +53,7 @@ int clock_getres(clockid_t, struct __kernel_timespec *)
 
 #else
 /* i386 only */
+#ifdef CONFIG_COMPAT_32BIT_TIME
 int __vdso_clock_gettime(clockid_t clock, struct old_timespec32 *ts)
 {
 	return __cvdso_clock_gettime32(clock, ts);
@@ -59,14 +62,6 @@ int __vdso_clock_gettime(clockid_t clock, struct old_timespec32 *ts)
 int clock_gettime(clockid_t, struct old_timespec32 *)
 	__attribute__((weak, alias("__vdso_clock_gettime")));
 
-int __vdso_clock_gettime64(clockid_t clock, struct __kernel_timespec *ts)
-{
-	return __cvdso_clock_gettime(clock, ts);
-}
-
-int clock_gettime64(clockid_t, struct __kernel_timespec *)
-	__attribute__((weak, alias("__vdso_clock_gettime64")));
-
 int __vdso_clock_getres(clockid_t clock, struct old_timespec32 *res)
 {
 	return __cvdso_clock_getres_time32(clock, res);
@@ -74,6 +69,15 @@ int __vdso_clock_getres(clockid_t clock, struct old_timespec32 *res)
 
 int clock_getres(clockid_t, struct old_timespec32 *)
 	__attribute__((weak, alias("__vdso_clock_getres")));
+#endif /* CONFIG_COMPAT_32BIT_TIME */
+
+int __vdso_clock_gettime64(clockid_t clock, struct __kernel_timespec *ts)
+{
+	return __cvdso_clock_gettime(clock, ts);
+}
+
+int clock_gettime64(clockid_t, struct __kernel_timespec *)
+	__attribute__((weak, alias("__vdso_clock_gettime64")));
 
 int __vdso_clock_getres_time64(clockid_t clock, struct __kernel_timespec *ts)
 {
diff --git a/arch/x86/entry/vdso/vdso32/vdso32.lds.S b/arch/x86/entry/vdso/vdso32/vdso32.lds.S
index cee8f7f9fe80..00629192db56 100644
--- a/arch/x86/entry/vdso/vdso32/vdso32.lds.S
+++ b/arch/x86/entry/vdso/vdso32/vdso32.lds.S
@@ -23,10 +23,12 @@ VERSION
 {
 	LINUX_2.6 {
 	global:
+#ifdef CONFIG_COMPAT_32BIT_TIME
 		__vdso_clock_gettime;
 		__vdso_gettimeofday;
 		__vdso_time;
 		__vdso_clock_getres;
+#endif /* CONFIG_COMPAT_32BIT_TIME */
 		__vdso_clock_gettime64;
 		__vdso_clock_getres_time64;
 		__vdso_getcpu;

-- 
2.55.0


^ permalink raw reply related

* [PATCH v2 4/9] arm64: vdso32: Respect COMPAT_32BIT_TIME
From: Thomas Weißschuh @ 2026-06-30  7:38 UTC (permalink / raw)
  To: Andy Lutomirski, Thomas Gleixner, Ingo Molnar, Borislav Petkov,
	Dave Hansen, x86, H. Peter Anvin, Russell King, Catalin Marinas,
	Will Deacon, Madhavan Srinivasan, Michael Ellerman,
	Nicholas Piggin, Christophe Leroy (CS GROUP), Thomas Bogendoerfer,
	Vincenzo Frascino, John Stultz, Stephen Boyd, David S. Miller,
	Andreas Larsson
  Cc: Thomas Weißschuh, linux-kernel, linux-arm-kernel,
	linuxppc-dev, linux-mips, Arnd Bergmann, linux-api, sparclinux
In-Reply-To: <20260630-vdso-compat_32bit_time-v2-0-520d194640dd@linutronix.de>

If CONFIG_COMPAT_32BIT_TIME is disabled then the vDSO should not
provide any 32-bit time related functionality. This is the intended
effect of the kconfig option and also the fallback system calls would
also not be implemented.

Currently the kconfig option does not affect the gettimeofday() syscall,
so also keep that in the vDSO.

Signed-off-by: Thomas Weißschuh <thomas.weissschuh@linutronix.de>
---
 arch/arm64/kernel/vdso32/vdso.lds.S      |  2 ++
 arch/arm64/kernel/vdso32/vgettimeofday.c | 14 ++++++++------
 2 files changed, 10 insertions(+), 6 deletions(-)

diff --git a/arch/arm64/kernel/vdso32/vdso.lds.S b/arch/arm64/kernel/vdso32/vdso.lds.S
index c374fb0146f3..12bfc39e8aab 100644
--- a/arch/arm64/kernel/vdso32/vdso.lds.S
+++ b/arch/arm64/kernel/vdso32/vdso.lds.S
@@ -82,9 +82,11 @@ VERSION
 {
 	LINUX_2.6 {
 	global:
+#ifdef CONFIG_COMPAT_32BIT_TIME
 		__vdso_clock_gettime;
 		__vdso_gettimeofday;
 		__vdso_clock_getres;
+#endif /* CONFIG_COMPAT_32BIT_TIME */
 		__vdso_clock_gettime64;
 		__vdso_clock_getres_time64;
 	local: *;
diff --git a/arch/arm64/kernel/vdso32/vgettimeofday.c b/arch/arm64/kernel/vdso32/vgettimeofday.c
index 0c6998ebe491..12d0255cc2cf 100644
--- a/arch/arm64/kernel/vdso32/vgettimeofday.c
+++ b/arch/arm64/kernel/vdso32/vgettimeofday.c
@@ -8,16 +8,17 @@
 #define BUILD_VDSO32_64
 #include <vdso/gettime.h>
 
+#ifdef CONFIG_COMPAT_32BIT_TIME
 int __vdso_clock_gettime(clockid_t clock,
 			 struct old_timespec32 *ts)
 {
 	return __cvdso_clock_gettime32(clock, ts);
 }
 
-int __vdso_clock_gettime64(clockid_t clock,
-			   struct __kernel_timespec *ts)
+int __vdso_clock_getres(clockid_t clock_id,
+			struct old_timespec32 *res)
 {
-	return __cvdso_clock_gettime(clock, ts);
+	return __cvdso_clock_getres_time32(clock_id, res);
 }
 
 int __vdso_gettimeofday(struct __kernel_old_timeval *tv,
@@ -25,11 +26,12 @@ int __vdso_gettimeofday(struct __kernel_old_timeval *tv,
 {
 	return __cvdso_gettimeofday(tv, tz);
 }
+#endif /* CONFIG_COMPAT_32BIT_TIME */
 
-int __vdso_clock_getres(clockid_t clock_id,
-			struct old_timespec32 *res)
+int __vdso_clock_gettime64(clockid_t clock,
+			   struct __kernel_timespec *ts)
 {
-	return __cvdso_clock_getres_time32(clock_id, res);
+	return __cvdso_clock_gettime(clock, ts);
 }
 
 int __vdso_clock_getres_time64(clockid_t clock_id, struct __kernel_timespec *res)

-- 
2.55.0


^ permalink raw reply related

* [PATCH v2 5/9] ARM: VDSO: Respect COMPAT_32BIT_TIME
From: Thomas Weißschuh @ 2026-06-30  7:38 UTC (permalink / raw)
  To: Andy Lutomirski, Thomas Gleixner, Ingo Molnar, Borislav Petkov,
	Dave Hansen, x86, H. Peter Anvin, Russell King, Catalin Marinas,
	Will Deacon, Madhavan Srinivasan, Michael Ellerman,
	Nicholas Piggin, Christophe Leroy (CS GROUP), Thomas Bogendoerfer,
	Vincenzo Frascino, John Stultz, Stephen Boyd, David S. Miller,
	Andreas Larsson
  Cc: Thomas Weißschuh, linux-kernel, linux-arm-kernel,
	linuxppc-dev, linux-mips, Arnd Bergmann, linux-api, sparclinux
In-Reply-To: <20260630-vdso-compat_32bit_time-v2-0-520d194640dd@linutronix.de>

If CONFIG_COMPAT_32BIT_TIME is disabled then the vDSO should not
provide any 32-bit time related functionality. This is the intended
effect of the kconfig option and also the fallback system calls would
also not be implemented.

Currently the kconfig option does not affect the gettimeofday() syscall,
so also keep that in the vDSO.

Signed-off-by: Thomas Weißschuh <thomas.weissschuh@linutronix.de>
---
 arch/arm/vdso/vdso.lds.S      |  2 ++
 arch/arm/vdso/vgettimeofday.c | 14 ++++++++------
 2 files changed, 10 insertions(+), 6 deletions(-)

diff --git a/arch/arm/vdso/vdso.lds.S b/arch/arm/vdso/vdso.lds.S
index 74d8d8bc8a40..e61038c0195a 100644
--- a/arch/arm/vdso/vdso.lds.S
+++ b/arch/arm/vdso/vdso.lds.S
@@ -70,9 +70,11 @@ VERSION
 {
 	LINUX_2.6 {
 	global:
+#ifdef CONFIG_COMPAT_32BIT_TIME
 		__vdso_clock_gettime;
 		__vdso_gettimeofday;
 		__vdso_clock_getres;
+#endif /* CONFIG_COMPAT_32BIT_TIME */
 		__vdso_clock_gettime64;
 		__vdso_clock_getres_time64;
 	local: *;
diff --git a/arch/arm/vdso/vgettimeofday.c b/arch/arm/vdso/vgettimeofday.c
index f7a2f5dc2fdc..3eebeddbfd18 100644
--- a/arch/arm/vdso/vgettimeofday.c
+++ b/arch/arm/vdso/vgettimeofday.c
@@ -10,16 +10,17 @@
 #include <asm/unwind.h>
 #include <vdso/gettime.h>
 
+#ifdef CONFIG_COMPAT_32BIT_TIME
 int __vdso_clock_gettime(clockid_t clock,
 			 struct old_timespec32 *ts)
 {
 	return __cvdso_clock_gettime32(clock, ts);
 }
 
-int __vdso_clock_gettime64(clockid_t clock,
-			   struct __kernel_timespec *ts)
+int __vdso_clock_getres(clockid_t clock_id,
+			struct old_timespec32 *res)
 {
-	return __cvdso_clock_gettime(clock, ts);
+	return __cvdso_clock_getres_time32(clock_id, res);
 }
 
 int __vdso_gettimeofday(struct __kernel_old_timeval *tv,
@@ -27,11 +28,12 @@ int __vdso_gettimeofday(struct __kernel_old_timeval *tv,
 {
 	return __cvdso_gettimeofday(tv, tz);
 }
+#endif /* CONFIG_COMPAT_32BIT_TIME */
 
-int __vdso_clock_getres(clockid_t clock_id,
-			struct old_timespec32 *res)
+int __vdso_clock_gettime64(clockid_t clock,
+			   struct __kernel_timespec *ts)
 {
-	return __cvdso_clock_getres_time32(clock_id, res);
+	return __cvdso_clock_gettime(clock, ts);
 }
 
 int __vdso_clock_getres_time64(clockid_t clock_id, struct __kernel_timespec *res)

-- 
2.55.0


^ permalink raw reply related

* [PATCH v2 6/9] powerpc/vdso: Respect COMPAT_32BIT_TIME
From: Thomas Weißschuh @ 2026-06-30  7:38 UTC (permalink / raw)
  To: Andy Lutomirski, Thomas Gleixner, Ingo Molnar, Borislav Petkov,
	Dave Hansen, x86, H. Peter Anvin, Russell King, Catalin Marinas,
	Will Deacon, Madhavan Srinivasan, Michael Ellerman,
	Nicholas Piggin, Christophe Leroy (CS GROUP), Thomas Bogendoerfer,
	Vincenzo Frascino, John Stultz, Stephen Boyd, David S. Miller,
	Andreas Larsson
  Cc: Thomas Weißschuh, linux-kernel, linux-arm-kernel,
	linuxppc-dev, linux-mips, Arnd Bergmann, linux-api, sparclinux
In-Reply-To: <20260630-vdso-compat_32bit_time-v2-0-520d194640dd@linutronix.de>

If CONFIG_COMPAT_32BIT_TIME is disabled then the vDSO should not
provide any 32-bit time related functionality. This is the intended
effect of the kconfig option and also the fallback system calls would
also not be implemented.

Currently the kconfig option does not affect the gettimeofday() syscall,
so also keep that in the vDSO.

Signed-off-by: Thomas Weißschuh <thomas.weissschuh@linutronix.de>
---
 arch/powerpc/kernel/vdso/gettimeofday.S  |  8 ++++++++
 arch/powerpc/kernel/vdso/vdso32.lds.S    | 10 ++++++----
 arch/powerpc/kernel/vdso/vgettimeofday.c | 16 ++++++++++------
 3 files changed, 24 insertions(+), 10 deletions(-)

diff --git a/arch/powerpc/kernel/vdso/gettimeofday.S b/arch/powerpc/kernel/vdso/gettimeofday.S
index 1c8e51691bf8..c635cd1e77be 100644
--- a/arch/powerpc/kernel/vdso/gettimeofday.S
+++ b/arch/powerpc/kernel/vdso/gettimeofday.S
@@ -67,9 +67,11 @@
  * int __kernel_gettimeofday(struct timeval *tv, struct timezone *tz);
  *
  */
+#if defined(__powerpc64__) || defined(CONFIG_COMPAT_32BIT_TIME)
 V_FUNCTION_BEGIN(__kernel_gettimeofday)
 	cvdso_call __c_kernel_gettimeofday
 V_FUNCTION_END(__kernel_gettimeofday)
+#endif
 
 /*
  * Exact prototype of clock_gettime()
@@ -77,9 +79,11 @@ V_FUNCTION_END(__kernel_gettimeofday)
  * int __kernel_clock_gettime(clockid_t clock_id, struct timespec *tp);
  *
  */
+#if defined(__powerpc64__) || defined(CONFIG_COMPAT_32BIT_TIME)
 V_FUNCTION_BEGIN(__kernel_clock_gettime)
 	cvdso_call __c_kernel_clock_gettime
 V_FUNCTION_END(__kernel_clock_gettime)
+#endif
 
 /*
  * Exact prototype of clock_gettime64()
@@ -99,9 +103,11 @@ V_FUNCTION_END(__kernel_clock_gettime64)
  * int __kernel_clock_getres(clockid_t clock_id, struct timespec *res);
  *
  */
+#if defined(__powerpc64__) || defined(CONFIG_COMPAT_32BIT_TIME)
 V_FUNCTION_BEGIN(__kernel_clock_getres)
 	cvdso_call __c_kernel_clock_getres
 V_FUNCTION_END(__kernel_clock_getres)
+#endif
 
 /*
  * Exact prototype of clock_getres_time64()
@@ -122,6 +128,8 @@ V_FUNCTION_END(__kernel_clock_getres_time64)
  * time_t time(time *t);
  *
  */
+#if defined(__powerpc64__) || defined(CONFIG_COMPAT_32BIT_TIME)
 V_FUNCTION_BEGIN(__kernel_time)
 	cvdso_call __c_kernel_time call_time=1
 V_FUNCTION_END(__kernel_time)
+#endif
diff --git a/arch/powerpc/kernel/vdso/vdso32.lds.S b/arch/powerpc/kernel/vdso/vdso32.lds.S
index 3f384a2526ae..876c965b827d 100644
--- a/arch/powerpc/kernel/vdso/vdso32.lds.S
+++ b/arch/powerpc/kernel/vdso/vdso32.lds.S
@@ -119,13 +119,15 @@ VERSION
 {
 	VDSO_VERSION_STRING {
 	global:
-		__kernel_get_syscall_map;
-		__kernel_gettimeofday;
+#ifdef CONFIG_COMPAT_32BIT_TIME
 		__kernel_clock_gettime;
-		__kernel_clock_gettime64;
 		__kernel_clock_getres;
-		__kernel_clock_getres_time64;
+		__kernel_gettimeofday;
 		__kernel_time;
+#endif /* CONFIG_COMPAT_32BIT_TIME */
+		__kernel_get_syscall_map;
+		__kernel_clock_gettime64;
+		__kernel_clock_getres_time64;
 		__kernel_get_tbfreq;
 		__kernel_sync_dicache;
 		__kernel_sigtramp32;
diff --git a/arch/powerpc/kernel/vdso/vgettimeofday.c b/arch/powerpc/kernel/vdso/vgettimeofday.c
index 3c194e1ab562..4b712fb01a3f 100644
--- a/arch/powerpc/kernel/vdso/vgettimeofday.c
+++ b/arch/powerpc/kernel/vdso/vgettimeofday.c
@@ -18,23 +18,25 @@ int __c_kernel_clock_getres(clockid_t clock_id, struct __kernel_timespec *res,
 	return __cvdso_clock_getres_data(vd, clock_id, res);
 }
 #else
+#ifdef CONFIG_COMPAT_32BIT_TIME
 int __c_kernel_clock_gettime(clockid_t clock, struct old_timespec32 *ts,
 			     const struct vdso_time_data *vd)
 {
 	return __cvdso_clock_gettime32_data(vd, clock, ts);
 }
 
-int __c_kernel_clock_gettime64(clockid_t clock, struct __kernel_timespec *ts,
-			       const struct vdso_time_data *vd)
-{
-	return __cvdso_clock_gettime_data(vd, clock, ts);
-}
-
 int __c_kernel_clock_getres(clockid_t clock_id, struct old_timespec32 *res,
 			    const struct vdso_time_data *vd)
 {
 	return __cvdso_clock_getres_time32_data(vd, clock_id, res);
 }
+#endif /* CONFIG_COMPAT_32BIT_TIME */
+
+int __c_kernel_clock_gettime64(clockid_t clock, struct __kernel_timespec *ts,
+			       const struct vdso_time_data *vd)
+{
+	return __cvdso_clock_gettime_data(vd, clock, ts);
+}
 
 int __c_kernel_clock_getres_time64(clockid_t clock_id, struct __kernel_timespec *res,
 				   const struct vdso_time_data *vd)
@@ -43,6 +45,7 @@ int __c_kernel_clock_getres_time64(clockid_t clock_id, struct __kernel_timespec
 }
 #endif
 
+#if defined(__powerpc64__) || defined(CONFIG_COMPAT_32BIT_TIME)
 int __c_kernel_gettimeofday(struct __kernel_old_timeval *tv, struct timezone *tz,
 			    const struct vdso_time_data *vd)
 {
@@ -53,3 +56,4 @@ __kernel_old_time_t __c_kernel_time(__kernel_old_time_t *time, const struct vdso
 {
 	return __cvdso_time_data(vd, time);
 }
+#endif

-- 
2.55.0


^ permalink raw reply related

* [PATCH v2 7/9] MIPS: VDSO: Respect COMPAT_32BIT_TIME
From: Thomas Weißschuh @ 2026-06-30  7:38 UTC (permalink / raw)
  To: Andy Lutomirski, Thomas Gleixner, Ingo Molnar, Borislav Petkov,
	Dave Hansen, x86, H. Peter Anvin, Russell King, Catalin Marinas,
	Will Deacon, Madhavan Srinivasan, Michael Ellerman,
	Nicholas Piggin, Christophe Leroy (CS GROUP), Thomas Bogendoerfer,
	Vincenzo Frascino, John Stultz, Stephen Boyd, David S. Miller,
	Andreas Larsson
  Cc: Thomas Weißschuh, linux-kernel, linux-arm-kernel,
	linuxppc-dev, linux-mips, Arnd Bergmann, linux-api, sparclinux
In-Reply-To: <20260630-vdso-compat_32bit_time-v2-0-520d194640dd@linutronix.de>

If CONFIG_COMPAT_32BIT_TIME is disabled then the vDSO should not
provide any 32-bit time related functionality. This is the intended
effect of the kconfig option and also the fallback system calls would
also not be implemented.

Currently the kconfig option does not affect the gettimeofday() syscall,
so also keep that in the vDSO.

Signed-off-by: Thomas Weißschuh <thomas.weissschuh@linutronix.de>
---
 arch/mips/vdso/vdso.lds.S      | 2 ++
 arch/mips/vdso/vgettimeofday.c | 3 +++
 2 files changed, 5 insertions(+)

diff --git a/arch/mips/vdso/vdso.lds.S b/arch/mips/vdso/vdso.lds.S
index 278ab6444e98..b11ee493c67f 100644
--- a/arch/mips/vdso/vdso.lds.S
+++ b/arch/mips/vdso/vdso.lds.S
@@ -97,9 +97,11 @@ VERSION
 	LINUX_2.6 {
 #ifdef CONFIG_GENERIC_GETTIMEOFDAY
 	global:
+#if _MIPS_SIM == _MIPS_SIM_ABI64 || defined(CONFIG_COMPAT_32BIT_TIME)
 		__vdso_clock_gettime;
 		__vdso_gettimeofday;
 		__vdso_clock_getres;
+#endif
 #if _MIPS_SIM != _MIPS_SIM_ABI64
 		__vdso_clock_gettime64;
 		__vdso_clock_getres_time64;
diff --git a/arch/mips/vdso/vgettimeofday.c b/arch/mips/vdso/vgettimeofday.c
index 00f9fcfc327e..a1fb06b8973e 100644
--- a/arch/mips/vdso/vgettimeofday.c
+++ b/arch/mips/vdso/vgettimeofday.c
@@ -12,6 +12,8 @@
 #include <vdso/gettime.h>
 
 #if _MIPS_SIM != _MIPS_SIM_ABI64
+
+#ifdef CONFIG_COMPAT_32BIT_TIME
 int __vdso_clock_gettime(clockid_t clock,
 			 struct old_timespec32 *ts)
 {
@@ -29,6 +31,7 @@ int __vdso_clock_getres(clockid_t clock_id,
 {
 	return __cvdso_clock_getres_time32(clock_id, res);
 }
+#endif /* CONFIG_COMPAT_32BIT_TIME */
 
 int __vdso_clock_gettime64(clockid_t clock,
 			   struct __kernel_timespec *ts)

-- 
2.55.0


^ permalink raw reply related

* [PATCH v2 8/9] sparc: vdso: Respect COMPAT_32BIT_TIME
From: Thomas Weißschuh @ 2026-06-30  7:38 UTC (permalink / raw)
  To: Andy Lutomirski, Thomas Gleixner, Ingo Molnar, Borislav Petkov,
	Dave Hansen, x86, H. Peter Anvin, Russell King, Catalin Marinas,
	Will Deacon, Madhavan Srinivasan, Michael Ellerman,
	Nicholas Piggin, Christophe Leroy (CS GROUP), Thomas Bogendoerfer,
	Vincenzo Frascino, John Stultz, Stephen Boyd, David S. Miller,
	Andreas Larsson
  Cc: Thomas Weißschuh, linux-kernel, linux-arm-kernel,
	linuxppc-dev, linux-mips, Arnd Bergmann, linux-api, sparclinux
In-Reply-To: <20260630-vdso-compat_32bit_time-v2-0-520d194640dd@linutronix.de>

If CONFIG_COMPAT_32BIT_TIME is disabled then the vDSO should not
provide any 32-bit time related functionality. This is the intended
effect of the kconfig option and also the fallback system calls would
also not be implemented.

Currently the kconfig option does not affect the gettimeofday() syscall,
so also keep that in the vDSO.

Signed-off-by: Thomas Weißschuh <thomas.weissschuh@linutronix.de>
---
 arch/sparc/vdso/vclock_gettime.c    | 4 ++++
 arch/sparc/vdso/vdso32/vdso32.lds.S | 6 ++++--
 2 files changed, 8 insertions(+), 2 deletions(-)

diff --git a/arch/sparc/vdso/vclock_gettime.c b/arch/sparc/vdso/vclock_gettime.c
index 1d9859392e4c..221bd4ed19f5 100644
--- a/arch/sparc/vdso/vclock_gettime.c
+++ b/arch/sparc/vdso/vclock_gettime.c
@@ -21,6 +21,7 @@
 
 #include "../../../../lib/vdso/gettimeofday.c"
 
+#if defined(CONFIG_SPARC64) || defined(CONFIG_COMPAT_32BIT_TIME)
 int __vdso_gettimeofday(struct __kernel_old_timeval *tv, struct timezone *tz)
 {
 	return __cvdso_gettimeofday(tv, tz);
@@ -28,6 +29,7 @@ int __vdso_gettimeofday(struct __kernel_old_timeval *tv, struct timezone *tz)
 
 int gettimeofday(struct __kernel_old_timeval *, struct timezone *)
 	__weak __alias(__vdso_gettimeofday);
+#endif
 
 #if defined(CONFIG_SPARC64)
 int __vdso_clock_gettime(clockid_t clock, struct __kernel_timespec *ts)
@@ -40,6 +42,7 @@ int clock_gettime(clockid_t, struct __kernel_timespec *)
 
 #else
 
+#if defined(CONFIG_COMPAT_32BIT_TIME)
 int __vdso_clock_gettime(clockid_t clock, struct old_timespec32 *ts)
 {
 	return __cvdso_clock_gettime32(clock, ts);
@@ -47,6 +50,7 @@ int __vdso_clock_gettime(clockid_t clock, struct old_timespec32 *ts)
 
 int clock_gettime(clockid_t, struct old_timespec32 *)
 	__weak __alias(__vdso_clock_gettime);
+#endif
 
 int __vdso_clock_gettime64(clockid_t clock, struct __kernel_timespec *ts)
 {
diff --git a/arch/sparc/vdso/vdso32/vdso32.lds.S b/arch/sparc/vdso/vdso32/vdso32.lds.S
index a14e4f77e6f2..28052168b875 100644
--- a/arch/sparc/vdso/vdso32/vdso32.lds.S
+++ b/arch/sparc/vdso/vdso32/vdso32.lds.S
@@ -15,12 +15,14 @@
 VERSION {
 	LINUX_2.6 {
 	global:
+#ifdef CONFIG_COMPAT_32BIT_TIME
 		clock_gettime;
 		__vdso_clock_gettime;
-		clock_gettime64;
-		__vdso_clock_gettime64;
 		gettimeofday;
 		__vdso_gettimeofday;
+#endif
+		clock_gettime64;
+		__vdso_clock_gettime64;
 	local: *;
 	};
 }

-- 
2.55.0


^ permalink raw reply related

* [PATCH v2 9/9] vdso/gettimeofday: Verify COMPAT_32BIT_TIME interactions
From: Thomas Weißschuh @ 2026-06-30  7:38 UTC (permalink / raw)
  To: Andy Lutomirski, Thomas Gleixner, Ingo Molnar, Borislav Petkov,
	Dave Hansen, x86, H. Peter Anvin, Russell King, Catalin Marinas,
	Will Deacon, Madhavan Srinivasan, Michael Ellerman,
	Nicholas Piggin, Christophe Leroy (CS GROUP), Thomas Bogendoerfer,
	Vincenzo Frascino, John Stultz, Stephen Boyd, David S. Miller,
	Andreas Larsson
  Cc: Thomas Weißschuh, linux-kernel, linux-arm-kernel,
	linuxppc-dev, linux-mips, Arnd Bergmann, linux-api, sparclinux
In-Reply-To: <20260630-vdso-compat_32bit_time-v2-0-520d194640dd@linutronix.de>

If CONFIG_COMPAT_32BIT_TIME is disabled then the vDSO should not
provide any 32-bit time related functionality.

Add some build-time validations to make sure the architecture-specific
glue satisfies this requirement.

Signed-off-by: Thomas Weißschuh <thomas.weissschuh@linutronix.de>
---
 lib/vdso/gettimeofday.c | 10 ++++++++++
 1 file changed, 10 insertions(+)

diff --git a/lib/vdso/gettimeofday.c b/lib/vdso/gettimeofday.c
index b8c1fc85eb74..f7a591aba59f 100644
--- a/lib/vdso/gettimeofday.c
+++ b/lib/vdso/gettimeofday.c
@@ -25,6 +25,8 @@
  */
 #include <asm/vdso/gettimeofday.h>
 
+#include <linux/build_bug.h>
+
 /* Bring in default accessors */
 #include <vdso/vsyscall.h>
 
@@ -325,6 +327,8 @@ __cvdso_clock_gettime32_data(const struct vdso_time_data *vd, clockid_t clock,
 	struct __kernel_timespec ts;
 	bool ok;
 
+	BUILD_BUG_ON(!IS_ENABLED(CONFIG_COMPAT_32BIT_TIME));
+
 	ok = __cvdso_clock_gettime_common(vd, clock, &ts);
 
 	if (unlikely(!ok))
@@ -354,6 +358,8 @@ __cvdso_gettimeofday_data(const struct vdso_time_data *vd,
 	BUILD_BUG();
 #endif
 
+	BUILD_BUG_ON(sizeof(tv->tv_sec) != 8 && !IS_ENABLED(CONFIG_COMPAT_32BIT_TIME));
+
 	if (likely(tv != NULL)) {
 		struct __kernel_timespec ts;
 
@@ -392,6 +398,8 @@ __cvdso_time_data(const struct vdso_time_data *vd, __kernel_old_time_t *time)
 	BUILD_BUG();
 #endif
 
+	BUILD_BUG_ON(sizeof(*time) != 8 && !IS_ENABLED(CONFIG_COMPAT_32BIT_TIME));
+
 	if (vdso_is_timens_clock(vc)) {
 		vd = vdso_timens_data(vd);
 		vc = vd->clock_data;
@@ -481,6 +489,8 @@ __cvdso_clock_getres_time32_data(const struct vdso_time_data *vd, clockid_t cloc
 	struct __kernel_timespec ts;
 	bool ok;
 
+	BUILD_BUG_ON(!IS_ENABLED(CONFIG_COMPAT_32BIT_TIME));
+
 	ok = __cvdso_clock_getres_common(vd, clock, &ts);
 
 	if (unlikely(!ok))

-- 
2.55.0


^ permalink raw reply related

* Re: [PATCH v2 1/9] time: Respect COMPAT_32BIT_TIME for old time type functions
From: Arnd Bergmann @ 2026-06-30 13:00 UTC (permalink / raw)
  To: Thomas Weißschuh, Andy Lutomirski, Thomas Gleixner,
	Ingo Molnar, Borislav Petkov, Dave Hansen, x86, H. Peter Anvin,
	Russell King, Catalin Marinas, Will Deacon, Madhavan Srinivasan,
	Michael Ellerman, Nicholas Piggin, Christophe Leroy,
	Thomas Bogendoerfer, Vincenzo Frascino, John Stultz, Stephen Boyd,
	David S . Miller, Andreas Larsson
  Cc: linux-kernel, linux-arm-kernel, linuxppc-dev, linux-mips,
	linux-api, sparclinux
In-Reply-To: <20260630-vdso-compat_32bit_time-v2-1-520d194640dd@linutronix.de>

On Tue, Jun 30, 2026, at 09:38, Thomas Weißschuh wrote:
> The "old" time types use 32-bit seconds which are not y2038-safe.
> Respect COMPAT_32BIT_TIME for functions using those types.
> time(), stime() and gettimeofday() are disabled completely.

Looks good, yes

> settimeofday() is kept as it is required to do the initial timewarping
> after boot. However the 'tv' argument will be rejected.

Not sure about this part, did we already discuss this last time?

I can see how keeping the timewarping functionality is the easy way
out, but completely disabling the settimeofday syscall the same
way we do on new architectures seems so much more consistent.

Note how scripts/syscall.tbl blocks sys_settimeofday on
architectures that don't set the time32 flag, which ideally
should match the COMPAT_32BIT_TIME option here.

     Arnd

^ permalink raw reply


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox