diff options
| author | Christian Brauner <brauner@kernel.org> | 2026-10-21 13:46:58 +0200 |
|---|---|---|
| committer | Christian Brauner <brauner@kernel.org> | 2026-10-22 18:50:20 +0200 |
| commit | 2a1887000e2d4adc8cb3933b53431dea6d5e310b (patch) | |
| tree | 968d19c0930211a3cdf55f5a3ddbe153a6560481 /tools/lib/python/kdoc/python_version.py | |
| parent | 8c407f829ac7b344ba0a8f43eb7b0c0e40b67afa (diff) | |
listns: don't wrap around with a U64_MAX cursor
do_listns() and do_listns_userns() take the last namespace id the caller
saw and look up the first namespace after it by searching the rbtree for
last_ns_id + 1. With U64_MAX that wraps around to zero and the search
returns the namespace with the smallest id. So a cursor at the largest
possible id restarts the listing from the beginning instead of failing
with ENOENT like a cursor of U64_MAX - 1 does. That's the case for the
unified tree, the type-specific trees and the owner tree alike.
No namespace will ever have that id. They come from a counter and a
caller that only feeds back ids it got from us can't hit this. It's
still wrong.
Instead of adding one to the cursor and searching for the smallest id
that's greater or equal make the lookup helpers search for the smallest
id that's strictly greater than the cursor. That's what both callers
want anyway and there's nothing left to overflow.
Reproducer, unprivileged:
#define _GNU_SOURCE
#include <errno.h>
#include <stdint.h>
#include <stdio.h>
#include <sys/syscall.h>
#include <unistd.h>
#ifndef __NR_listns
#define __NR_listns 470
#endif
#define CLONE_NEWUSER 0x10000000U
#define LISTNS_CURRENT_USER 0xffffffffffffffffULL
struct ns_id_req {
uint32_t size, spare;
uint64_t ns_id;
uint32_t ns_type, spare2;
uint64_t user_ns_id;
};
static void list(const char *tree, uint32_t type, uint64_t owner,
uint64_t cursor)
{
struct ns_id_req req = {
.size = sizeof(req), .ns_id = cursor, .ns_type = type,
.user_ns_id = owner,
};
uint64_t ids[8];
long ret;
errno = 0;
ret = syscall(__NR_listns, &req, ids, 8, 0);
printf("%s cursor %llu: ret %ld errno %d", tree,
(unsigned long long)cursor, ret, errno);
for (long i = 0; i < ret && i < 3; i++)
printf("%s%llu", i ? "," : " ids ", (unsigned long long)ids[i]);
printf("%s\n", ret > 3 ? ",..." : "");
}
int main(void)
{
static const uint64_t cursors[] = { 0, UINT64_MAX - 1, UINT64_MAX };
for (int i = 0; i < 3; i++)
list("unified", 0, 0, cursors[i]);
for (int i = 0; i < 3; i++)
list("userns", CLONE_NEWUSER, 0, cursors[i]);
for (int i = 0; i < 3; i++)
list("owner", 0, LISTNS_CURRENT_USER, cursors[i]);
return 0;
}
Before, on 7.3.0-rc7-00252-g4e3259b08c54 (vfs.fixes) in a VM:
unified cursor 0: ret 8 errno 0 ids 1,2,3,...
unified cursor 18446744073709551614: ret -1 errno 2
unified cursor 18446744073709551615: ret 8 errno 0 ids 1,2,3,...
userns cursor 0: ret 1 errno 0 ids 3
userns cursor 18446744073709551614: ret -1 errno 2
userns cursor 18446744073709551615: ret 1 errno 0 ids 3
owner cursor 0: ret 8 errno 0 ids 1,2,4,...
owner cursor 18446744073709551614: ret -1 errno 2
owner cursor 18446744073709551615: ret 8 errno 0 ids 1,2,4,...
After:
unified cursor 0: ret 8 errno 0 ids 1,2,3,...
unified cursor 18446744073709551614: ret -1 errno 2
unified cursor 18446744073709551615: ret -1 errno 2
userns cursor 0: ret 1 errno 0 ids 3
userns cursor 18446744073709551614: ret -1 errno 2
userns cursor 18446744073709551615: ret -1 errno 2
owner cursor 0: ret 8 errno 0 ids 1,2,4,...
owner cursor 18446744073709551614: ret -1 errno 2
owner cursor 18446744073709551615: ret -1 errno 2
Reported-by: shaos <shawnq1@163.com>
Link: https://lore.kernel.org/r/20261020110732.959552-1-shawnq1@163.com
Fixes: 76b6f5dfb3fd ("nstree: add listns()")
Cc: stable@vger.kernel.org
Link: https://patch.msgid.link/20261021-work-mount-statmount_listns_fixes-v1-5-8917a4c1bd14@kernel.org
Reviewed-by: Jeff Layton <jlayton@kernel.org>
Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
Diffstat (limited to 'tools/lib/python/kdoc/python_version.py')
0 files changed, 0 insertions, 0 deletions
