Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

nstree: add listns()

Add a new listns() system call that allows userspace to iterate through
namespaces in the system. This provides a programmatic interface to
discover and inspect namespaces, enhancing existing namespace apis.

Currently, there is no direct way for userspace to enumerate namespaces
in the system. Applications must resort to scanning /proc/<pid>/ns/
across all processes, which is:

1. Inefficient - requires iterating over all processes
2. Incomplete - misses inactive namespaces that aren't attached to any
running process but are kept alive by file descriptors, bind mounts,
or parent namespace references
3. Permission-heavy - requires access to /proc for many processes
4. No ordering or ownership.
5. No filtering per namespace type: Must always iterate and check all
namespaces.

The list goes on. The listns() system call solves these problems by
providing direct kernel-level enumeration of namespaces. It is similar
to listmount() but obviously tailored to namespaces.

/*
* @req: Pointer to struct ns_id_req specifying search parameters
* @ns_ids: User buffer to receive namespace IDs
* @nr_ns_ids: Size of ns_ids buffer (maximum number of IDs to return)
* @flags: Reserved for future use (must be 0)
*/
ssize_t listns(const struct ns_id_req *req, u64 *ns_ids,
size_t nr_ns_ids, unsigned int flags);

Returns:
- On success: Number of namespace IDs written to ns_ids
- On error: Negative error code

/*
* @size: Structure size
* @ns_id: Starting point for iteration; use 0 for first call, then
* use the last returned ID for subsequent calls to paginate
* @ns_type: Bitmask of namespace types to include (from enum ns_type):
* 0: Return all namespace types
* MNT_NS: Mount namespaces
* NET_NS: Network namespaces
* USER_NS: User namespaces
* etc. Can be OR'd together
* @user_ns_id: Filter results to namespaces owned by this user namespace:
* 0: Return all namespaces (subject to permission checks)
* LISTNS_CURRENT_USER: Namespaces owned by caller's user namespace
* Other value: Namespaces owned by the specified user namespace ID
*/
struct ns_id_req {
__u32 size; /* sizeof(struct ns_id_req) */
__u32 spare; /* Reserved, must be 0 */
__u64 ns_id; /* Last seen namespace ID (for pagination) */
__u32 ns_type; /* Filter by namespace type(s) */
__u32 spare2; /* Reserved, must be 0 */
__u64 user_ns_id; /* Filter by owning user namespace */
};

Example 1: List all namespaces

void list_all_namespaces(void)
{
struct ns_id_req req = {
.size = sizeof(req),
.ns_id = 0, /* Start from beginning */
.ns_type = 0, /* All types */
.user_ns_id = 0, /* All user namespaces */
};
uint64_t ids[100];
ssize_t ret;

printf("All namespaces in the system:\n");
do {
ret = listns(&req, ids, 100, 0);
if (ret < 0) {
perror("listns");
break;
}

for (ssize_t i = 0; i < ret; i++)
printf(" Namespace ID: %llu\n", (unsigned long long)ids[i]);

/* Continue from last seen ID */
if (ret > 0)
req.ns_id = ids[ret - 1];
} while (ret == 100); /* Buffer was full, more may exist */
}

Example 2: List network namespaces only

void list_network_namespaces(void)
{
struct ns_id_req req = {
.size = sizeof(req),
.ns_id = 0,
.ns_type = NET_NS, /* Only network namespaces */
.user_ns_id = 0,
};
uint64_t ids[100];
ssize_t ret;

ret = listns(&req, ids, 100, 0);
if (ret < 0) {
perror("listns");
return;
}

printf("Network namespaces: %zd found\n", ret);
for (ssize_t i = 0; i < ret; i++)
printf(" netns ID: %llu\n", (unsigned long long)ids[i]);
}

Example 3: List namespaces owned by current user namespace

void list_owned_namespaces(void)
{
struct ns_id_req req = {
.size = sizeof(req),
.ns_id = 0,
.ns_type = 0, /* All types */
.user_ns_id = LISTNS_CURRENT_USER, /* Current userns */
};
uint64_t ids[100];
ssize_t ret;

ret = listns(&req, ids, 100, 0);
if (ret < 0) {
perror("listns");
return;
}

printf("Namespaces owned by my user namespace: %zd\n", ret);
for (ssize_t i = 0; i < ret; i++)
printf(" ns ID: %llu\n", (unsigned long long)ids[i]);
}

Example 4: List multiple namespace types

void list_network_and_mount_namespaces(void)
{
struct ns_id_req req = {
.size = sizeof(req),
.ns_id = 0,
.ns_type = NET_NS | MNT_NS, /* Network and mount */
.user_ns_id = 0,
};
uint64_t ids[100];
ssize_t ret;

ret = listns(&req, ids, 100, 0);
printf("Network and mount namespaces: %zd found\n", ret);
}

Example 5: Pagination through large namespace sets

void list_all_with_pagination(void)
{
struct ns_id_req req = {
.size = sizeof(req),
.ns_id = 0,
.ns_type = 0,
.user_ns_id = 0,
};
uint64_t ids[50];
size_t total = 0;
ssize_t ret;

printf("Enumerating all namespaces with pagination:\n");

while (1) {
ret = listns(&req, ids, 50, 0);
if (ret < 0) {
perror("listns");
break;
}
if (ret == 0)
break; /* No more namespaces */

total += ret;
printf(" Batch: %zd namespaces\n", ret);

/* Last ID in this batch becomes start of next batch */
req.ns_id = ids[ret - 1];

if (ret < 50)
break; /* Partial batch = end of results */
}

printf("Total: %zu namespaces\n", total);
}

Permission Model

listns() respects namespace isolation and capabilities:

(1) Global listing (user_ns_id = 0):
- Requires CAP_SYS_ADMIN in the namespace's owning user namespace
- OR the namespace must be in the caller's namespace context (e.g.,
a namespace the caller is currently using)
- User namespaces additionally allow listing if the caller has
CAP_SYS_ADMIN in that user namespace itself
(2) Owner-filtered listing (user_ns_id != 0):
- Requires CAP_SYS_ADMIN in the specified owner user namespace
- OR the namespace must be in the caller's namespace context
- This allows unprivileged processes to enumerate namespaces they own
(3) Visibility:
- Only "active" namespaces are listed
- A namespace is active if it has a non-zero __ns_ref_active count
- This includes namespaces used by running processes, held by open
file descriptors, or kept active by bind mounts
- Inactive namespaces (kept alive only by internal kernel
references) are not visible via listns()

Link: https://patch.msgid.link/20251029-work-namespace-nstree-listns-v4-19-2e6f823ebdc0@kernel.org
Signed-off-by: Christian Brauner <brauner@kernel.org>

+489 -3
+39
fs/nsfs.c
··· 471 471 return FILEID_NSFS; 472 472 } 473 473 474 + bool is_current_namespace(struct ns_common *ns) 475 + { 476 + switch (ns->ns_type) { 477 + #ifdef CONFIG_CGROUPS 478 + case CLONE_NEWCGROUP: 479 + return current_in_namespace(to_cg_ns(ns)); 480 + #endif 481 + #ifdef CONFIG_IPC_NS 482 + case CLONE_NEWIPC: 483 + return current_in_namespace(to_ipc_ns(ns)); 484 + #endif 485 + case CLONE_NEWNS: 486 + return current_in_namespace(to_mnt_ns(ns)); 487 + #ifdef CONFIG_NET_NS 488 + case CLONE_NEWNET: 489 + return current_in_namespace(to_net_ns(ns)); 490 + #endif 491 + #ifdef CONFIG_PID_NS 492 + case CLONE_NEWPID: 493 + return current_in_namespace(to_pid_ns(ns)); 494 + #endif 495 + #ifdef CONFIG_TIME_NS 496 + case CLONE_NEWTIME: 497 + return current_in_namespace(to_time_ns(ns)); 498 + #endif 499 + #ifdef CONFIG_USER_NS 500 + case CLONE_NEWUSER: 501 + return current_in_namespace(to_user_ns(ns)); 502 + #endif 503 + #ifdef CONFIG_UTS_NS 504 + case CLONE_NEWUTS: 505 + return current_in_namespace(to_uts_ns(ns)); 506 + #endif 507 + default: 508 + VFS_WARN_ON_ONCE(true); 509 + return false; 510 + } 511 + } 512 + 474 513 static struct dentry *nsfs_fh_to_dentry(struct super_block *sb, struct fid *fh, 475 514 int fh_len, int fh_type) 476 515 {
+2
include/linux/ns_common.h
··· 129 129 }; 130 130 }; 131 131 132 + bool is_current_namespace(struct ns_common *ns); 132 133 int __ns_common_init(struct ns_common *ns, u32 ns_type, const struct proc_ns_operations *ops, int inum); 133 134 void __ns_common_free(struct ns_common *ns); 135 + struct ns_common *__must_check ns_owner(struct ns_common *ns); 134 136 135 137 static __always_inline bool is_initial_namespace(struct ns_common *ns) 136 138 {
+4
include/linux/syscalls.h
··· 77 77 struct cachestat; 78 78 struct statmount; 79 79 struct mnt_id_req; 80 + struct ns_id_req; 80 81 struct xattr_args; 81 82 struct file_attr; 82 83 ··· 438 437 asmlinkage long sys_listmount(const struct mnt_id_req __user *req, 439 438 u64 __user *mnt_ids, size_t nr_mnt_ids, 440 439 unsigned int flags); 440 + asmlinkage long sys_listns(const struct ns_id_req __user *req, 441 + u64 __user *ns_ids, size_t nr_ns_ids, 442 + unsigned int flags); 441 443 asmlinkage long sys_truncate(const char __user *path, long length); 442 444 asmlinkage long sys_ftruncate(unsigned int fd, off_t length); 443 445 #if BITS_PER_LONG == 32
+2 -2
include/linux/user_namespace.h
··· 166 166 ns->rlimit_max[type] = max <= LONG_MAX ? max : LONG_MAX; 167 167 } 168 168 169 - #ifdef CONFIG_USER_NS 170 - 171 169 static inline struct user_namespace *to_user_ns(struct ns_common *ns) 172 170 { 173 171 return container_of(ns, struct user_namespace, ns); 174 172 } 173 + 174 + #ifdef CONFIG_USER_NS 175 175 176 176 static inline struct user_namespace *get_user_ns(struct user_namespace *ns) 177 177 {
+44
include/uapi/linux/nsfs.h
··· 81 81 #endif 82 82 }; 83 83 84 + enum ns_type { 85 + TIME_NS = (1ULL << 7), /* CLONE_NEWTIME */ 86 + MNT_NS = (1ULL << 17), /* CLONE_NEWNS */ 87 + CGROUP_NS = (1ULL << 25), /* CLONE_NEWCGROUP */ 88 + UTS_NS = (1ULL << 26), /* CLONE_NEWUTS */ 89 + IPC_NS = (1ULL << 27), /* CLONE_NEWIPC */ 90 + USER_NS = (1ULL << 28), /* CLONE_NEWUSER */ 91 + PID_NS = (1ULL << 29), /* CLONE_NEWPID */ 92 + NET_NS = (1ULL << 30), /* CLONE_NEWNET */ 93 + }; 94 + 95 + /** 96 + * struct ns_id_req - namespace ID request structure 97 + * @size: size of this structure 98 + * @spare: reserved for future use 99 + * @filter: filter mask 100 + * @ns_id: last namespace id 101 + * @user_ns_id: owning user namespace ID 102 + * 103 + * Structure for passing namespace ID and miscellaneous parameters to 104 + * statns(2) and listns(2). 105 + * 106 + * For statns(2) @param represents the request mask. 107 + * For listns(2) @param represents the last listed mount id (or zero). 108 + */ 109 + struct ns_id_req { 110 + __u32 size; 111 + __u32 spare; 112 + __u64 ns_id; 113 + struct /* listns */ { 114 + __u32 ns_type; 115 + __u32 spare2; 116 + __u64 user_ns_id; 117 + }; 118 + }; 119 + 120 + /* 121 + * Special @user_ns_id value that can be passed to listns() 122 + */ 123 + #define LISTNS_CURRENT_USER 0xffffffffffffffff /* Caller's userns */ 124 + 125 + /* List of all ns_id_req versions. */ 126 + #define NS_ID_REQ_SIZE_VER0 32 /* sizeof first published struct */ 127 + 84 128 #endif /* __LINUX_NSFS_H */
+1 -1
kernel/nscommon.c
··· 98 98 proc_free_inum(ns->inum); 99 99 } 100 100 101 - static struct ns_common *ns_owner(struct ns_common *ns) 101 + struct ns_common *__must_check ns_owner(struct ns_common *ns) 102 102 { 103 103 struct user_namespace *owner; 104 104
+397
kernel/nstree.c
··· 5 5 #include <linux/proc_ns.h> 6 6 #include <linux/rculist.h> 7 7 #include <linux/vfsdebug.h> 8 + #include <linux/syscalls.h> 8 9 #include <linux/user_namespace.h> 9 10 10 11 static __cacheline_aligned_in_smp DEFINE_SEQLOCK(ns_tree_lock); ··· 359 358 else 360 359 ns->ns_id = atomic64_inc_return(&namespace_cookie); 361 360 return ns->ns_id; 361 + } 362 + 363 + struct klistns { 364 + u64 __user *uns_ids; 365 + u32 nr_ns_ids; 366 + u64 last_ns_id; 367 + u64 user_ns_id; 368 + u32 ns_type; 369 + struct user_namespace *user_ns; 370 + bool userns_capable; 371 + struct ns_common *first_ns; 372 + }; 373 + 374 + static void __free_klistns_free(const struct klistns *kls) 375 + { 376 + if (kls->user_ns_id != LISTNS_CURRENT_USER) 377 + put_user_ns(kls->user_ns); 378 + if (kls->first_ns && kls->first_ns->ops) 379 + kls->first_ns->ops->put(kls->first_ns); 380 + } 381 + 382 + #define NS_ALL (PID_NS | USER_NS | MNT_NS | UTS_NS | IPC_NS | NET_NS | CGROUP_NS | TIME_NS) 383 + 384 + static int copy_ns_id_req(const struct ns_id_req __user *req, 385 + struct ns_id_req *kreq) 386 + { 387 + int ret; 388 + size_t usize; 389 + 390 + BUILD_BUG_ON(sizeof(struct ns_id_req) != NS_ID_REQ_SIZE_VER0); 391 + 392 + ret = get_user(usize, &req->size); 393 + if (ret) 394 + return -EFAULT; 395 + if (unlikely(usize > PAGE_SIZE)) 396 + return -E2BIG; 397 + if (unlikely(usize < NS_ID_REQ_SIZE_VER0)) 398 + return -EINVAL; 399 + memset(kreq, 0, sizeof(*kreq)); 400 + ret = copy_struct_from_user(kreq, sizeof(*kreq), req, usize); 401 + if (ret) 402 + return ret; 403 + if (kreq->spare != 0) 404 + return -EINVAL; 405 + if (kreq->ns_type & ~NS_ALL) 406 + return -EOPNOTSUPP; 407 + return 0; 408 + } 409 + 410 + static inline int prepare_klistns(struct klistns *kls, struct ns_id_req *kreq, 411 + u64 __user *ns_ids, size_t nr_ns_ids) 412 + { 413 + kls->last_ns_id = kreq->ns_id; 414 + kls->user_ns_id = kreq->user_ns_id; 415 + kls->nr_ns_ids = nr_ns_ids; 416 + kls->ns_type = kreq->ns_type; 417 + kls->uns_ids = ns_ids; 418 + return 0; 419 + } 420 + 421 + /* 422 + * Lookup a namespace owned by owner with id >= ns_id. 423 + * Returns the namespace with the smallest id that is >= ns_id. 424 + */ 425 + static struct ns_common *lookup_ns_owner_at(u64 ns_id, struct ns_common *owner) 426 + { 427 + struct ns_common *ret = NULL; 428 + struct rb_node *node; 429 + 430 + VFS_WARN_ON_ONCE(owner->ns_type != CLONE_NEWUSER); 431 + 432 + read_seqlock_excl(&ns_tree_lock); 433 + node = owner->ns_owner_tree.rb_node; 434 + 435 + while (node) { 436 + struct ns_common *ns; 437 + 438 + ns = node_to_ns_owner(node); 439 + if (ns_id <= ns->ns_id) { 440 + ret = ns; 441 + if (ns_id == ns->ns_id) 442 + break; 443 + node = node->rb_left; 444 + } else { 445 + node = node->rb_right; 446 + } 447 + } 448 + 449 + if (ret) 450 + ret = ns_get_unless_inactive(ret); 451 + read_sequnlock_excl(&ns_tree_lock); 452 + return ret; 453 + } 454 + 455 + static struct ns_common *lookup_ns_id(u64 mnt_ns_id, int ns_type) 456 + { 457 + struct ns_common *ns; 458 + 459 + guard(rcu)(); 460 + ns = ns_tree_lookup_rcu(mnt_ns_id, ns_type); 461 + if (!ns) 462 + return NULL; 463 + 464 + if (!ns_get_unless_inactive(ns)) 465 + return NULL; 466 + 467 + return ns; 468 + } 469 + 470 + static inline bool __must_check ns_requested(const struct klistns *kls, 471 + const struct ns_common *ns) 472 + { 473 + return !kls->ns_type || (kls->ns_type & ns->ns_type); 474 + } 475 + 476 + static inline bool __must_check may_list_ns(const struct klistns *kls, 477 + struct ns_common *ns) 478 + { 479 + if (kls->user_ns) { 480 + if (kls->userns_capable) 481 + return true; 482 + } else { 483 + struct ns_common *owner; 484 + struct user_namespace *user_ns; 485 + 486 + owner = ns_owner(ns); 487 + if (owner) 488 + user_ns = to_user_ns(owner); 489 + else 490 + user_ns = &init_user_ns; 491 + if (ns_capable_noaudit(user_ns, CAP_SYS_ADMIN)) 492 + return true; 493 + } 494 + 495 + if (is_current_namespace(ns)) 496 + return true; 497 + 498 + if (ns->ns_type != CLONE_NEWUSER) 499 + return false; 500 + 501 + if (ns_capable_noaudit(to_user_ns(ns), CAP_SYS_ADMIN)) 502 + return true; 503 + 504 + return false; 505 + } 506 + 507 + static void __ns_put(struct ns_common *ns) 508 + { 509 + if (ns->ops) 510 + ns->ops->put(ns); 511 + } 512 + 513 + DEFINE_FREE(ns_put, struct ns_common *, if (!IS_ERR_OR_NULL(_T)) __ns_put(_T)) 514 + 515 + static inline struct ns_common *__must_check legitimize_ns(const struct klistns *kls, 516 + struct ns_common *candidate) 517 + { 518 + struct ns_common *ns __free(ns_put) = NULL; 519 + 520 + if (!ns_requested(kls, candidate)) 521 + return NULL; 522 + 523 + ns = ns_get_unless_inactive(candidate); 524 + if (!ns) 525 + return NULL; 526 + 527 + if (!may_list_ns(kls, ns)) 528 + return NULL; 529 + 530 + return no_free_ptr(ns); 531 + } 532 + 533 + static ssize_t do_listns_userns(struct klistns *kls) 534 + { 535 + u64 __user *ns_ids = kls->uns_ids; 536 + size_t nr_ns_ids = kls->nr_ns_ids; 537 + struct ns_common *ns = NULL, *first_ns = NULL; 538 + const struct list_head *head; 539 + ssize_t ret; 540 + 541 + VFS_WARN_ON_ONCE(!kls->user_ns_id); 542 + 543 + if (kls->user_ns_id == LISTNS_CURRENT_USER) 544 + ns = to_ns_common(current_user_ns()); 545 + else if (kls->user_ns_id) 546 + ns = lookup_ns_id(kls->user_ns_id, CLONE_NEWUSER); 547 + if (!ns) 548 + return -EINVAL; 549 + kls->user_ns = to_user_ns(ns); 550 + 551 + /* 552 + * Use the rbtree to find the first namespace we care about and 553 + * then use it's list entry to iterate from there. 554 + */ 555 + if (kls->last_ns_id) { 556 + kls->first_ns = lookup_ns_owner_at(kls->last_ns_id + 1, ns); 557 + if (!kls->first_ns) 558 + return -ENOENT; 559 + first_ns = kls->first_ns; 560 + } 561 + 562 + ret = 0; 563 + head = &to_ns_common(kls->user_ns)->ns_owner; 564 + kls->userns_capable = ns_capable_noaudit(kls->user_ns, CAP_SYS_ADMIN); 565 + 566 + rcu_read_lock(); 567 + 568 + if (!first_ns) 569 + first_ns = list_entry_rcu(head->next, typeof(*ns), ns_owner_entry); 570 + for (ns = first_ns; &ns->ns_owner_entry != head && nr_ns_ids; 571 + ns = list_entry_rcu(ns->ns_owner_entry.next, typeof(*ns), ns_owner_entry)) { 572 + struct ns_common *valid __free(ns_put); 573 + 574 + valid = legitimize_ns(kls, ns); 575 + if (!valid) 576 + continue; 577 + 578 + rcu_read_unlock(); 579 + 580 + if (put_user(valid->ns_id, ns_ids + ret)) 581 + return -EINVAL; 582 + nr_ns_ids--; 583 + ret++; 584 + 585 + rcu_read_lock(); 586 + } 587 + 588 + rcu_read_unlock(); 589 + return ret; 590 + } 591 + 592 + /* 593 + * Lookup a namespace with id >= ns_id in either the unified tree or a type-specific tree. 594 + * Returns the namespace with the smallest id that is >= ns_id. 595 + */ 596 + static struct ns_common *lookup_ns_id_at(u64 ns_id, int ns_type) 597 + { 598 + struct ns_common *ret = NULL; 599 + struct ns_tree *ns_tree = NULL; 600 + struct rb_node *node; 601 + 602 + if (ns_type) { 603 + ns_tree = ns_tree_from_type(ns_type); 604 + if (!ns_tree) 605 + return NULL; 606 + } 607 + 608 + read_seqlock_excl(&ns_tree_lock); 609 + if (ns_tree) 610 + node = ns_tree->ns_tree.rb_node; 611 + else 612 + node = ns_unified_tree.rb_node; 613 + 614 + while (node) { 615 + struct ns_common *ns; 616 + 617 + if (ns_type) 618 + ns = node_to_ns(node); 619 + else 620 + ns = node_to_ns_unified(node); 621 + 622 + if (ns_id <= ns->ns_id) { 623 + if (ns_type) 624 + ret = node_to_ns(node); 625 + else 626 + ret = node_to_ns_unified(node); 627 + if (ns_id == ns->ns_id) 628 + break; 629 + node = node->rb_left; 630 + } else { 631 + node = node->rb_right; 632 + } 633 + } 634 + 635 + if (ret) 636 + ret = ns_get_unless_inactive(ret); 637 + read_sequnlock_excl(&ns_tree_lock); 638 + return ret; 639 + } 640 + 641 + static inline struct ns_common *first_ns_common(const struct list_head *head, 642 + struct ns_tree *ns_tree) 643 + { 644 + if (ns_tree) 645 + return list_entry_rcu(head->next, struct ns_common, ns_list_node); 646 + return list_entry_rcu(head->next, struct ns_common, ns_unified_list_node); 647 + } 648 + 649 + static inline struct ns_common *next_ns_common(struct ns_common *ns, 650 + struct ns_tree *ns_tree) 651 + { 652 + if (ns_tree) 653 + return list_entry_rcu(ns->ns_list_node.next, struct ns_common, ns_list_node); 654 + return list_entry_rcu(ns->ns_unified_list_node.next, struct ns_common, ns_unified_list_node); 655 + } 656 + 657 + static inline bool ns_common_is_head(struct ns_common *ns, 658 + const struct list_head *head, 659 + struct ns_tree *ns_tree) 660 + { 661 + if (ns_tree) 662 + return &ns->ns_list_node == head; 663 + return &ns->ns_unified_list_node == head; 664 + } 665 + 666 + static ssize_t do_listns(struct klistns *kls) 667 + { 668 + u64 __user *ns_ids = kls->uns_ids; 669 + size_t nr_ns_ids = kls->nr_ns_ids; 670 + struct ns_common *ns, *first_ns = NULL; 671 + struct ns_tree *ns_tree = NULL; 672 + const struct list_head *head; 673 + u32 ns_type; 674 + ssize_t ret; 675 + 676 + if (hweight32(kls->ns_type) == 1) 677 + ns_type = kls->ns_type; 678 + else 679 + ns_type = 0; 680 + 681 + if (ns_type) { 682 + ns_tree = ns_tree_from_type(ns_type); 683 + if (!ns_tree) 684 + return -EINVAL; 685 + } 686 + 687 + if (kls->last_ns_id) { 688 + kls->first_ns = lookup_ns_id_at(kls->last_ns_id + 1, ns_type); 689 + if (!kls->first_ns) 690 + return -ENOENT; 691 + first_ns = kls->first_ns; 692 + } 693 + 694 + ret = 0; 695 + if (ns_tree) 696 + head = &ns_tree->ns_list; 697 + else 698 + head = &ns_unified_list; 699 + 700 + rcu_read_lock(); 701 + 702 + if (!first_ns) 703 + first_ns = first_ns_common(head, ns_tree); 704 + 705 + for (ns = first_ns; !ns_common_is_head(ns, head, ns_tree) && nr_ns_ids; 706 + ns = next_ns_common(ns, ns_tree)) { 707 + struct ns_common *valid __free(ns_put); 708 + 709 + valid = legitimize_ns(kls, ns); 710 + if (!valid) 711 + continue; 712 + 713 + rcu_read_unlock(); 714 + 715 + if (put_user(valid->ns_id, ns_ids + ret)) 716 + return -EINVAL; 717 + 718 + nr_ns_ids--; 719 + ret++; 720 + 721 + rcu_read_lock(); 722 + } 723 + 724 + rcu_read_unlock(); 725 + return ret; 726 + } 727 + 728 + SYSCALL_DEFINE4(listns, const struct ns_id_req __user *, req, 729 + u64 __user *, ns_ids, size_t, nr_ns_ids, unsigned int, flags) 730 + { 731 + struct klistns klns __free(klistns_free) = {}; 732 + const size_t maxcount = 1000000; 733 + struct ns_id_req kreq; 734 + ssize_t ret; 735 + 736 + if (flags) 737 + return -EINVAL; 738 + 739 + if (unlikely(nr_ns_ids > maxcount)) 740 + return -EOVERFLOW; 741 + 742 + if (!access_ok(ns_ids, nr_ns_ids * sizeof(*ns_ids))) 743 + return -EFAULT; 744 + 745 + ret = copy_ns_id_req(req, &kreq); 746 + if (ret) 747 + return ret; 748 + 749 + ret = prepare_klistns(&klns, &kreq, ns_ids, nr_ns_ids); 750 + if (ret) 751 + return ret; 752 + 753 + if (kreq.user_ns_id) 754 + return do_listns_userns(&klns); 755 + 756 + return do_listns(&klns); 362 757 }