]> git.ipfire.org Git - thirdparty/util-linux.git/commitdiff
lsns: show NETNSID for namespaces with no process running
authorMasatake YAMATO <yamato@redhat.com>
Thu, 6 Mar 2025 23:44:30 +0000 (08:44 +0900)
committerMasatake YAMATO <yamato@redhat.com>
Fri, 7 Mar 2025 23:02:29 +0000 (08:02 +0900)
Fixes #3445

The original code doesn't collect NETNSID for netns namespaces with no
process running.

A way to reproduce this issue:

    # ip netns delete X
    # ip netns add X
    # ip netns set X 117
    # ip netns show
    X (id: 117)
    netns-813c699f-4651-e5e9-6af4-cca568bf2c3a (id: 0)
    # stat /var/run/netns/X
      File: /var/run/netns/X
      Size: 0          Blocks: 0          IO Block: 4096   regular empty file
    Device: 0,4 Inode: 4026533679  Links: 1
    Access: (0444/-r--r--r--)  Uid: (    0/    root)   Gid: (    0/    root)
    Context: system_u:object_r:nsfs_t:s0
    Access: 2025-03-06 00:29:58.598605182 +0900
    Modify: 2025-03-06 00:29:58.598605182 +0900
    Change: 2025-03-06 00:29:58.598605182 +0900
     Birth: -

    # ./lsns -P -o+NETNSID
    NS TYPE  NPROCS PID USER   COMMAND NETNSID
    4026533679 net        0     root
    4026534230 user       0     yamato

NS 4026533679 should have "117" as the value of NETNSID.

Though the original code defined netnsid member in struct
lsns_namespace, the member wasn't used at all. struct lsns_process had
a member having the same name.  The original code used only the one in
struct lsns_process.

This change utilizes the netnsid member in struct lsns_namespace.

I found another bug, so I will provide a test case for this fix in a
subsequent commit.

Signed-off-by: Masatake YAMATO <yamato@redhat.com>
sys-utils/lsns.c

index e4e714c6b4369a1c9cf3f97eef7367a5f91068b1..1cf9640b3d7083d189deb899556aca44df3cfd83 100644 (file)
@@ -541,6 +541,18 @@ static int get_netnsid_via_netlink(int target_fd)
        return netnsid;
 }
 
+static int get_netnsid_for_fd(int target_fd, ino_t netino)
+{
+       int netnsid;
+
+       if (!netnsid_cache_find(netino, &netnsid)) {
+               netnsid = get_netnsid_via_netlink(target_fd);
+               netnsid_cache_add(netino, netnsid);
+       }
+
+       return netnsid;
+}
+
 static int get_netnsid_for_pc_via_netlink(struct path_cxt *pc, const char *path)
 {
        int netnsid;
@@ -772,7 +784,7 @@ static int namespace_has_process(struct lsns_namespace *ns, pid_t pid)
 }
 
 static struct lsns_namespace *add_namespace(struct lsns *ls, enum lsns_type type, ino_t ino,
-                                           ino_t parent_ino, ino_t owner_ino)
+                                           ino_t parent_ino, ino_t owner_ino, int netnsid)
 {
        struct lsns_namespace *ns = xcalloc(1, sizeof(*ns));
 
@@ -788,6 +800,7 @@ static struct lsns_namespace *add_namespace(struct lsns *ls, enum lsns_type type
        ns->id = ino;
        ns->related_id[RELA_PARENT] = parent_ino;
        ns->related_id[RELA_OWNER] = owner_ino;
+       ns->netnsid = netnsid;
 
        list_add_tail(&ns->namespaces, &ls->namespaces);
        return ns;
@@ -872,6 +885,7 @@ static struct lsns_namespace *add_namespace_for_nsfd(struct lsns *ls, int fd, in
        struct lsns_namespace *ns;
        int clone_type;
        enum lsns_type lsns_type;
+       int netnsid;
 
        clone_type = lsns_ioctl(fd, NS_GET_NSTYPE);
        if (clone_type < 0)
@@ -883,7 +897,11 @@ static struct lsns_namespace *add_namespace_for_nsfd(struct lsns *ls, int fd, in
        get_parent_ns_ino(fd, lsns_type, &ino_parent, &fd_parent);
        get_owner_ns_ino(fd, &ino_owner, &fd_owner);
 
-       ns = add_namespace(ls, lsns_type, ino, ino_parent, ino_owner);
+       netnsid = (lsns_type == LSNS_TYPE_NET)
+               ? get_netnsid_for_fd(fd, ino)
+               : LSNS_NETNS_UNUSABLE;
+
+       ns = add_namespace(ls, lsns_type, ino, ino_parent, ino_owner, netnsid);
        lsns_ioctl(fd, NS_GET_OWNER_UID, &ns->uid_fallback);
        add_uid(uid_cache, ns->uid_fallback);
 
@@ -1057,8 +1075,12 @@ static int read_assigned_namespaces(struct lsns *ls)
                        if (proc->ns_ids[i] == 0)
                                continue;
                        if (!(ns = get_namespace(ls, proc->ns_ids[i]))) {
+                               int netnsid = (i == LSNS_TYPE_NET)
+                                       ? proc->netnsid
+                                       : LSNS_NETNS_UNUSABLE;
                                ns = add_namespace(ls, i, proc->ns_ids[i],
-                                                  proc->ns_pids[i], proc->ns_oids[i]);
+                                                  proc->ns_pids[i], proc->ns_oids[i],
+                                                  netnsid);
                                if (!ns)
                                        return -ENOMEM;
                        }
@@ -1210,10 +1232,8 @@ static void fill_column(struct lsns *ls,
                xasprintf(&str, "%s", get_id(uid_cache, proc? proc->uid: ns->uid_fallback)->name);
                break;
        case COL_NETNSID:
-               if (!proc)
-                       break;
                if (ns->type == LSNS_TYPE_NET)
-                       netnsid_xasputs(&str, proc->netnsid);
+                       netnsid_xasputs(&str, ns->netnsid);
                break;
        case COL_NSFS:
                nsfs_xasputs(&str, ns, ls->tab, ls->no_wrap ? ',' : '\n');