lsns: add columns for parent namespaces and owner namespaces
See ioctl_ns(2) about parent and owner namespaces. Signed-off-by: Masatake YAMATO <yamato@redhat.com>
This commit is contained in:
parent
a96932103e
commit
d652d4c666
|
@ -308,6 +308,7 @@ AC_CHECK_HEADERS([ \
|
|||
linux/fd.h \
|
||||
linux/fiemap.h \
|
||||
linux/net_namespace.h \
|
||||
linux/nsfs.h \
|
||||
linux/raw.h \
|
||||
linux/securebits.h \
|
||||
linux/tiocl.h \
|
||||
|
|
|
@ -38,6 +38,10 @@
|
|||
#include <linux/net_namespace.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_LINUX_NSFS_H
|
||||
#include <linux/nsfs.h>
|
||||
#endif
|
||||
|
||||
#include "pathnames.h"
|
||||
#include "nls.h"
|
||||
#include "xalloc.h"
|
||||
|
@ -83,6 +87,8 @@ enum {
|
|||
COL_USER,
|
||||
COL_NETNSID,
|
||||
COL_NSFS,
|
||||
COL_PNS, /* parent namespace */
|
||||
COL_ONS, /* owner namespace */
|
||||
};
|
||||
|
||||
/* column names */
|
||||
|
@ -106,7 +112,9 @@ static const struct colinfo infos[] = {
|
|||
[COL_UID] = { "UID", 0, SCOLS_FL_RIGHT, N_("UID of the PID"), SCOLS_JSON_NUMBER},
|
||||
[COL_USER] = { "USER", 0, 0, N_("username of the PID")},
|
||||
[COL_NETNSID] = { "NETNSID", 0, SCOLS_FL_RIGHT, N_("namespace ID as used by network subsystem")},
|
||||
[COL_NSFS] = { "NSFS", 0, SCOLS_FL_WRAP, N_("nsfs mountpoint (usually used network subsystem)")}
|
||||
[COL_NSFS] = { "NSFS", 0, SCOLS_FL_WRAP, N_("nsfs mountpoint (usually used network subsystem)")},
|
||||
[COL_PNS] = { "PNS", 10, SCOLS_FL_RIGHT, N_("parent namespace identifier (inode number)"), SCOLS_JSON_NUMBER },
|
||||
[COL_ONS] = { "ONS", 10, SCOLS_FL_RIGHT, N_("owner namespace identifier (inode number)"), SCOLS_JSON_NUMBER },
|
||||
};
|
||||
|
||||
static int columns[ARRAY_SIZE(infos) * 2];
|
||||
|
@ -139,6 +147,8 @@ struct lsns_namespace {
|
|||
int type; /* LSNS_* */
|
||||
int nprocs;
|
||||
int netnsid;
|
||||
ino_t parentid;
|
||||
ino_t ownerid;
|
||||
|
||||
struct lsns_process *proc;
|
||||
|
||||
|
@ -154,6 +164,9 @@ struct lsns_process {
|
|||
uid_t uid;
|
||||
|
||||
ino_t ns_ids[ARRAY_SIZE(ns_names)];
|
||||
ino_t ns_pids[ARRAY_SIZE(ns_names)];
|
||||
ino_t ns_oids[ARRAY_SIZE(ns_names)];
|
||||
|
||||
struct list_head ns_siblings[ARRAY_SIZE(ns_names)];
|
||||
|
||||
struct list_head processes; /* list of processes */
|
||||
|
@ -251,7 +264,7 @@ static inline const struct colinfo *get_column_info(unsigned num)
|
|||
return &infos[ get_column_id(num) ];
|
||||
}
|
||||
|
||||
static int get_ns_ino(int dir, const char *nsname, ino_t *ino)
|
||||
static int get_ns_ino(int dir, const char *nsname, ino_t *ino, ino_t *pino, ino_t *oino)
|
||||
{
|
||||
struct stat st;
|
||||
char path[16];
|
||||
|
@ -261,6 +274,47 @@ static int get_ns_ino(int dir, const char *nsname, ino_t *ino)
|
|||
if (fstatat(dir, path, &st, 0) != 0)
|
||||
return -errno;
|
||||
*ino = st.st_ino;
|
||||
|
||||
*pino = 0;
|
||||
*oino = 0;
|
||||
|
||||
#ifdef HAVE_LINUX_NSFS_H
|
||||
int fd, pfd, ofd;
|
||||
fd = openat(dir, path, 0);
|
||||
if (fd < 0)
|
||||
return -errno;
|
||||
if (strcmp(nsname, "pid") == 0 || strcmp(nsname, "user") == 0) {
|
||||
if ((pfd = ioctl(fd, NS_GET_PARENT)) < 0) {
|
||||
if (errno == EPERM)
|
||||
goto user;
|
||||
close(fd);
|
||||
return -errno;
|
||||
}
|
||||
if (fstat(pfd, &st) < 0) {
|
||||
close(pfd);
|
||||
close(fd);
|
||||
return -errno;
|
||||
}
|
||||
*pino = st.st_ino;
|
||||
close(pfd);
|
||||
}
|
||||
user:
|
||||
if ((ofd = ioctl(fd, NS_GET_USERNS)) < 0) {
|
||||
if (errno == EPERM)
|
||||
goto out;
|
||||
close(fd);
|
||||
return -errno;
|
||||
}
|
||||
if (fstat(ofd, &st) < 0) {
|
||||
close(ofd);
|
||||
close(fd);
|
||||
return -errno;
|
||||
}
|
||||
*oino = st.st_ino;
|
||||
close(ofd);
|
||||
out:
|
||||
close(fd);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -466,7 +520,8 @@ static int read_process(struct lsns *ls, pid_t pid)
|
|||
if (!ls->fltr_types[i])
|
||||
continue;
|
||||
|
||||
rc = get_ns_ino(dirfd(dir), ns_names[i], &p->ns_ids[i]);
|
||||
rc = get_ns_ino(dirfd(dir), ns_names[i], &p->ns_ids[i],
|
||||
&p->ns_pids[i], &p->ns_oids[i]);
|
||||
if (rc && rc != -EACCES && rc != -ENOENT)
|
||||
goto done;
|
||||
if (i == LSNS_ID_NET)
|
||||
|
@ -538,7 +593,8 @@ static int namespace_has_process(struct lsns_namespace *ns, pid_t pid)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static struct lsns_namespace *add_namespace(struct lsns *ls, int type, ino_t ino)
|
||||
static struct lsns_namespace *add_namespace(struct lsns *ls, int type, ino_t ino,
|
||||
ino_t parent_ino, ino_t owner_ino)
|
||||
{
|
||||
struct lsns_namespace *ns = xcalloc(1, sizeof(*ns));
|
||||
|
||||
|
@ -552,6 +608,8 @@ static struct lsns_namespace *add_namespace(struct lsns *ls, int type, ino_t ino
|
|||
|
||||
ns->type = type;
|
||||
ns->id = ino;
|
||||
ns->parentid = parent_ino;
|
||||
ns->ownerid = owner_ino;
|
||||
|
||||
list_add_tail(&ns->namespaces, &ls->namespaces);
|
||||
return ns;
|
||||
|
@ -617,7 +675,8 @@ static int read_namespaces(struct lsns *ls)
|
|||
if (proc->ns_ids[i] == 0)
|
||||
continue;
|
||||
if (!(ns = get_namespace(ls, proc->ns_ids[i]))) {
|
||||
ns = add_namespace(ls, i, proc->ns_ids[i]);
|
||||
ns = add_namespace(ls, i, proc->ns_ids[i],
|
||||
proc->ns_pids[i], proc->ns_oids[i]);
|
||||
if (!ns)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
@ -761,6 +820,12 @@ static void add_scols_line(struct lsns *ls, struct libscols_table *table,
|
|||
case COL_NSFS:
|
||||
nsfs_xasputs(&str, ns, ls->tab, ls->no_wrap ? ',' : '\n');
|
||||
break;
|
||||
case COL_PNS:
|
||||
xasprintf(&str, "%ju", (uintmax_t)ns->parentid);
|
||||
break;
|
||||
case COL_ONS:
|
||||
xasprintf(&str, "%ju", (uintmax_t)ns->ownerid);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -103,6 +103,7 @@ TS_CMD_SWAPOFF=${TS_CMD_SWAPOFF:-"${ts_commandsdir}swapoff"}
|
|||
TS_CMD_SWAPON=${TS_CMD_SWAPON:-"${ts_commandsdir}swapon"}
|
||||
TS_CMD_UL=${TS_CMD_UL-"${ts_commandsdir}ul"}
|
||||
TS_CMD_UMOUNT=${TS_CMD_UMOUNT:-"${ts_commandsdir}umount"}
|
||||
TS_CMD_UNSHARE=${TS_CMD_UNSHARE:-"${ts_commandsdir}unshare"}
|
||||
TS_CMD_UTMPDUMP=${TS_CMD_UTMPDUMP-"${ts_commandsdir}utmpdump"}
|
||||
TS_CMD_UUIDD=${TS_CMD_UUIDD-"${ts_commandsdir}uuidd"}
|
||||
TS_CMD_UUIDGEN=${TS_CMD_UUIDGEN-"${ts_commandsdir}uuidgen"}
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
0
|
|
@ -0,0 +1,108 @@
|
|||
#!/bin/bash
|
||||
#
|
||||
# Copyright (C) 2021 Masatake YAMATO <yamato@redhat.com>
|
||||
#
|
||||
# This file is part of util-linux.
|
||||
#
|
||||
# This file is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 2 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This file is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
|
||||
TS_TOPDIR="${0%/*}/../.."
|
||||
TS_DESC="namespace ownership and hierarchy"
|
||||
|
||||
. $TS_TOPDIR/functions.sh
|
||||
ts_init "$*"
|
||||
|
||||
# ts_skip_nonroot
|
||||
grep -q '#define HAVE_LINUX_NSFS_H' ${top_builddir}/config.h || ts_skip "no ioctl_ns support"
|
||||
|
||||
ts_check_test_command "$TS_CMD_LSNS"
|
||||
ts_check_test_command "$TS_CMD_UNSHARE"
|
||||
ts_check_prog "stat"
|
||||
ts_check_prog "mkfifo"
|
||||
ts_check_prog "touch"
|
||||
ts_check_prog "uniq"
|
||||
|
||||
ts_cd "$TS_OUTDIR"
|
||||
|
||||
# The parent process receives namespaces ids via FIFO_DATA from bash
|
||||
# run by unshare. The parent can wait till the bash process provides
|
||||
# data.
|
||||
FIFO_DATA=$TS_OUTDIR/FIFO_DATA-HIERARCHY
|
||||
|
||||
# The bash process run by unshare waits with this fifo till the parent
|
||||
# process exits. As a result, namespaecs referred by the bash
|
||||
# process can be alive till the parent process exits.
|
||||
FIFO_WAIT=$TS_OUTDIR/FIFO_WAIT-HIERARCHY
|
||||
|
||||
function cleanup {
|
||||
rm -f $FIFO_DATA
|
||||
rm -f $FIFO_WAIT
|
||||
}
|
||||
|
||||
function init {
|
||||
cleanup
|
||||
mkfifo $FIFO_DATA
|
||||
mkfifo $FIFO_WAIT
|
||||
}
|
||||
|
||||
init
|
||||
(
|
||||
exec 4> $FIFO_WAIT
|
||||
my_userns=$(stat -c %i -L /proc/self/ns/user)
|
||||
my_pidns=$(stat -c %i -L /proc/self/ns/pid)
|
||||
read child_userns < $FIFO_DATA
|
||||
read child_pidns < $FIFO_DATA
|
||||
|
||||
expected="$child_userns $my_userns $my_userns"
|
||||
actual=$("$TS_CMD_LSNS" -t user -n -o NS,PNS,ONS "$child_userns" | uniq)
|
||||
test "$expected" = "$actual"
|
||||
RESULT=$?
|
||||
if [ $RESULT -ne 0 ]; then
|
||||
echo
|
||||
echo userns expected: "$expected"
|
||||
echo userns actual: "$actual"
|
||||
cleanup
|
||||
exit $RESULT
|
||||
fi
|
||||
|
||||
expected="$child_pidns $my_pidns $child_userns"
|
||||
actual=$("$TS_CMD_LSNS" -t pid -n -o NS,PNS,ONS "$child_pidns" | uniq)
|
||||
test "$expected" = "$actual"
|
||||
RESULT=$?
|
||||
if [ $RESULT -ne 0 ]; then
|
||||
echo
|
||||
echo pidns expected: "$expected"
|
||||
echo pidns actual: "$actual"
|
||||
cleanup
|
||||
fi
|
||||
exit $RESULT
|
||||
) &
|
||||
mainpid=$!
|
||||
(
|
||||
exec 4< $FIFO_WAIT
|
||||
$TS_CMD_UNSHARE --user --pid --mount-proc --fork bash -s > $FIFO_DATA <<'EOF'
|
||||
stat -c %i -L /proc/self/ns/user
|
||||
stat -c %i -L /proc/self/ns/pid
|
||||
# Wait till FIFO_WAIT is clsoed.
|
||||
read -u 4
|
||||
EOF
|
||||
) &
|
||||
subpid=$!
|
||||
|
||||
wait $subpid
|
||||
wait $mainpid
|
||||
|
||||
RESULT=$?
|
||||
echo $RESULT >> $TS_OUTPUT
|
||||
|
||||
cleanup
|
||||
ts_finalize
|
Loading…
Reference in New Issue