summaryrefslogtreecommitdiff
path: root/utils/pscap.c
diff options
context:
space:
mode:
Diffstat (limited to 'utils/pscap.c')
-rw-r--r--utils/pscap.c117
1 files changed, 90 insertions, 27 deletions
diff --git a/utils/pscap.c b/utils/pscap.c
index e51b10a..9b96973 100644
--- a/utils/pscap.c
+++ b/utils/pscap.c
@@ -1,6 +1,6 @@
/*
* pscap.c - A program that lists running processes with capabilities
- * Copyright (c) 2009 Red Hat Inc., Durham, North Carolina.
+ * Copyright (c) 2009,2012,2020 Red Hat Inc.
* All Rights Reserved.
*
* This software may be freely redistributed and/or modified under the
@@ -15,7 +15,8 @@
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to the
- * Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor
+ * Boston, MA 02110-1335, USA.
*
* Authors:
* Steve Grubb <sgrubb@redhat.com>
@@ -24,28 +25,63 @@
#include "config.h"
#include <stdio.h>
#include <stdio_ext.h>
+#include <unistd.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <dirent.h>
#include <fcntl.h>
#include <pwd.h>
+#include <stdbool.h>
+#include <sys/stat.h>
#include "cap-ng.h"
+#define CMD_LEN 16
+#define USERNS_MARK_LEN 2
static void usage(void)
{
- fprintf(stderr, "usage: pscap [-a]\n");
+ fprintf(stderr, "usage: pscap [-a|-p pid]\n");
exit(1);
}
+/*
+ * Precise recursive checks for parent-child relation between namespaces
+ * using ioctl() were avoided, because there didn't seem to be any case when
+ * we may dereference the namespace symlink in /proc/PID/ns for processes in
+ * user namespaces other than the current or child ones. Thus, the check just
+ * tries to dereference the link and checks that it does not point to the
+ * current NS.
+ */
+static bool in_child_userns(int pid)
+{
+ char ns_file_path[32];
+ struct stat statbuf;
+ ino_t own_ns_inode;
+ dev_t own_ns_dev;
+
+ if (stat("/proc/self/ns/user", &statbuf) < 0)
+ return false;
+
+ own_ns_inode = statbuf.st_ino;
+ own_ns_dev = statbuf.st_dev;
+
+ snprintf(ns_file_path, 32, "/proc/%d/ns/user", pid);
+ if (stat(ns_file_path, &statbuf) < 0)
+ return false;
+
+ return statbuf.st_ino != own_ns_inode || statbuf.st_dev != own_ns_dev;
+}
+
int main(int argc, char *argv[])
{
DIR *d;
struct dirent *ent;
int header = 0, show_all = 0, caps;
+ pid_t our_pid = getpid();
+ pid_t target_pid = 0;
- if (argc > 2) {
+ if (argc > 3) {
fputs("Too many arguments\n", stderr);
usage();
}
@@ -55,23 +91,29 @@ int main(int argc, char *argv[])
else
usage();
}
-
- /* Drop capabilities so we aren't listed */
- caps = capng_have_capabilities(CAPNG_SELECT_CAPS);
- if (caps == CAPNG_FULL) {
- capng_clear(CAPNG_SELECT_BOTH);
- capng_apply(CAPNG_SELECT_BOTH);
+ else if (argc == 3) {
+ if (strcmp(argv[1], "-p") == 0) {
+ errno = 0;
+ target_pid = strtol(argv[2], NULL, 10);
+ if (errno) {
+ fprintf(stderr, "Can't read pid: %s\n", argv[2]);
+ return 1;
+ }
+ if (target_pid == 1)
+ show_all = 1;
+ } else
+ usage();
}
d = opendir("/proc");
if (d == NULL) {
- printf("Can't open /proc: %s\n", strerror(errno));
+ fprintf(stderr, "Can't open /proc: %s\n", strerror(errno));
return 1;
}
while (( ent = readdir(d) )) {
int pid, ppid, uid = -1, euid = -1;
char buf[100];
- char *tmp, cmd[16], state, *name = NULL;
+ char *tmp, cmd[CMD_LEN + USERNS_MARK_LEN], state, *name = NULL;
int fd, len;
struct passwd *p;
@@ -83,9 +125,16 @@ int main(int argc, char *argv[])
if (errno)
continue;
+ if (target_pid && (pid != target_pid))
+ continue;
+
+ /* Skip our pid so we aren't listed */
+ if (pid == our_pid)
+ continue;
+
// Parse up the stat file for the proc
snprintf(buf, 32, "/proc/%d/stat", pid);
- fd = open(buf, O_RDONLY, 0);
+ fd = open(buf, O_RDONLY|O_CLOEXEC, 0);
if (fd < 0)
continue;
len = read(fd, buf, sizeof buf - 1);
@@ -110,11 +159,11 @@ int main(int argc, char *argv[])
continue;
// now get the capabilities
- capng_clear(CAPNG_SELECT_BOTH);
+ capng_clear(CAPNG_SELECT_ALL);
capng_setpid(pid);
if (capng_get_caps_process())
continue;
-
+
// And print out anything with capabilities
caps = capng_have_capabilities(CAPNG_SELECT_CAPS);
if (caps > CAPNG_NONE) {
@@ -122,7 +171,7 @@ int main(int argc, char *argv[])
FILE *f;
int line;
snprintf(buf, 32, "/proc/%d/status", pid);
- f = fopen(buf, "rt");
+ f = fopen(buf, "rte");
if (f == NULL)
euid = 0;
else {
@@ -142,12 +191,10 @@ int main(int argc, char *argv[])
}
fclose(f);
}
-
- len = read(fd, buf, sizeof buf - 1);
- close(fd);
+
if (header == 0) {
- printf("%-5s %-5s %-10s %-16s %s\n",
- "ppid", "pid", "name", "command",
+ printf("%-5s %-5s %-10s %-18s %s\n",
+ "ppid", "pid", "uid", "command",
"capabilities");
header = 1;
}
@@ -163,24 +210,40 @@ int main(int argc, char *argv[])
name = p->pw_name;
// If not taking this branch, use last val
}
+
+ if (in_child_userns(pid))
+ strcat(cmd, " *");
+
if (name) {
- printf("%-5d %-5d %-10s %-16s ", ppid, pid,
+ printf("%-5d %-5d %-10s %-18s ", ppid, pid,
name, cmd);
} else
- printf("%-5d %-5d %-10d %-16s ", ppid, pid,
+ printf("%-5d %-5d %-10d %-18s ", ppid, pid,
uid, cmd);
if (caps == CAPNG_PARTIAL) {
capng_print_caps_text(CAPNG_PRINT_STDOUT,
CAPNG_PERMITTED);
+ if (capng_have_capabilities(
+ CAPNG_SELECT_AMBIENT) > CAPNG_NONE)
+ printf(" @");
if (capng_have_capabilities(CAPNG_SELECT_BOUNDS)
- == CAPNG_FULL)
+ > CAPNG_NONE)
printf(" +");
printf("\n");
- } else
- printf("full\n");
+ } else {
+ printf("full");
+ if (capng_have_capabilities(
+ CAPNG_SELECT_AMBIENT) > CAPNG_NONE)
+ printf(" @");
+ if (capng_have_capabilities(CAPNG_SELECT_BOUNDS)
+ > CAPNG_NONE)
+ printf(" +");
+ printf("\n");
+ }
}
}
- closedir(d);
+ closedir(d);
return 0;
}
+