Skip to content

Commit 82430d8

Browse files
Add ps command to list processes using deleted binaries and libraries
1 parent 336b12e commit 82430d8

File tree

7 files changed

+271
-0
lines changed

7 files changed

+271
-0
lines changed

auto.def

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,13 @@ if {[string match *-freebsd* [get-define host]]} {
106106
define-feature libmd
107107
}
108108
}
109+
cc-with { -libs { -lprocstat }} {
110+
if {![cc-check-functions procstat_open_sysctl]} {
111+
user-error "Unable to find libprocstat"
112+
} else {
113+
define-feature libprocstat
114+
}
115+
}
109116
}
110117

111118
cc-with { -libs { -larchive }} {

docs/Makefile.autosetup

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ MAN8= pkg-add.8 \
2626
pkg-key.8 \
2727
pkg-lock.8 \
2828
pkg-query.8 \
29+
pkg-ps.8 \
2930
pkg-register.8 \
3031
pkg-repo.8 \
3132
pkg-rquery.8 \

docs/pkg-ps.8

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
.\"
2+
.\" Redistribution and use in source and binary forms, with or without
3+
.\" modification, are permitted provided that the following conditions
4+
.\" are met:
5+
.\" 1. Redistributions of source code must retain the above copyright
6+
.\" notice, this list of conditions and the following disclaimer.
7+
.\" 2. Redistributions in binary form must reproduce the above copyright
8+
.\" notice, this list of conditions and the following disclaimer in the
9+
.\" documentation and/or other materials provided with the distribution.
10+
.\"
11+
.\"
12+
.\" @(#)pkg.8
13+
.\"
14+
.Dd May 30, 2024
15+
.Dt PKG-PS 8
16+
.Os
17+
.Sh NAME
18+
.Nm "pkg ps"
19+
.Nd list running processes using deleted binaries and libraries
20+
.Sh SYNOPSIS
21+
.Nm
22+
.Op Fl v
23+
.Pp
24+
.Nm
25+
.Op Cm --verbose
26+
.Sh DESCRIPTION
27+
.Nm
28+
List running processes using deleted binaries and libraries.
29+
This program must be run as root if any of these sysctl's are set to zero:
30+
.Bl -column
31+
.It "security.bsd.unprivileged_proc_debug"
32+
.It "security.bsd.see_other_gids"
33+
.It "security.bsd.see_other_uids"
34+
.El
35+
.Sh OPTIONS
36+
The following options are supported by
37+
.Nm :
38+
.Bl -tag -width xxxxxxxxxxxx
39+
.It Fl v , Cm --verbose
40+
Verbose output. List full command line arguments.
41+
.El
42+
.Sh FILES
43+
See
44+
.Xr pkg.conf 5 .
45+
.Sh SEE ALSO
46+
.Xr pkg_create 3 ,
47+
.Xr pkg_printf 3 ,
48+
.Xr pkg_repos 3 ,
49+
.Xr pkg-keywords 5 ,
50+
.Xr pkg-lua-script 5 ,
51+
.Xr pkg-repository 5 ,
52+
.Xr pkg-script 5 ,
53+
.Xr pkg.conf 5 ,
54+
.Xr pkg 8 ,
55+
.Xr pkg-add 8 ,
56+
.Xr pkg-alias 8 ,
57+
.Xr pkg-annotate 8 ,
58+
.Xr pkg-audit 8 ,
59+
.Xr pkg-autoremove 8 ,
60+
.Xr pkg-check 8 ,
61+
.Xr pkg-clean 8 ,
62+
.Xr pkg-config 8 ,
63+
.Xr pkg-create 8 ,
64+
.Xr pkg-delete 8 ,
65+
.Xr pkg-fetch 8 ,
66+
.Xr pkg-info 8 ,
67+
.Xr pkg-install 8 ,
68+
.Xr pkg-lock 8 ,
69+
.Xr pkg-query 8 ,
70+
.Xr pkg-register 8 ,
71+
.Xr pkg-repo 8 ,
72+
.Xr pkg-rquery 8 ,
73+
.Xr pkg-search 8 ,
74+
.Xr pkg-set 8 ,
75+
.Xr pkg-shell 8 ,
76+
.Xr pkg-shlib 8 ,
77+
.Xr pkg-ssh 8 ,
78+
.Xr pkg-stats 8 ,
79+
.Xr pkg-update 8 ,
80+
.Xr pkg-updating 8 ,
81+
.Xr pkg-upgrade 8 ,
82+
.Xr pkg-version 8 ,
83+
.Xr pkg-which 8

src/Makefile.autosetup

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,10 @@ OTHER_LIBS+= -lresolv
7070
@if HAVE_LIBMD
7171
OTHER_LIBS+= -lmd
7272
@endif
73+
@if HAVE_LIBPROCSTAT
74+
SRCS+= ps.c
75+
OTHER_LIBS+= -lprocstat -lkvm
76+
@endif
7377

7478
@if libmachista
7579
LOCAL_LDFLAGS= $(LIBPKGFLAT) $(LIBS) $(OTHER_LIBS) -lresolv

src/main.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,9 @@ static struct commands {
9696
{ "install", "Installs packages from remote package repositories and local archives", exec_install, usage_install},
9797
{ "lock", "Locks package against modifications or deletion", exec_lock, usage_lock},
9898
{ "plugins", "Manages plugins and displays information about plugins", exec_plugins, usage_plugins},
99+
#ifdef HAVE_LIBPROCSTAT
100+
{ "ps", "List running processes using deleted binaries and libraries", exec_ps, usage_ps},
101+
#endif
99102
{ "query", "Queries information about installed packages", exec_query, usage_query},
100103
{ "register", "Registers a package into the local database", exec_register, usage_register},
101104
{ "remove", "Deletes packages from the database and the system", exec_delete, usage_delete},

src/pkgcli.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,10 @@ int exec_lock(int, char **);
102102
int exec_unlock(int, char **);
103103
void usage_lock(void);
104104

105+
/* pkg ps */
106+
int exec_ps(int, char **);
107+
void usage_ps(void);
108+
105109
/* pkg query */
106110
int exec_query(int, char **);
107111
void usage_query(void);

src/ps.c

Lines changed: 169 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,169 @@
1+
/*-
2+
* Copyright (c) 2024 Ricardo Branco <[email protected]>
3+
* All rights reserved.
4+
*
5+
* Redistribution and use in source and binary forms, with or without
6+
* modification, are permitted provided that the following conditions
7+
* are met:
8+
* 1. Redistributions of source code must retain the above copyright
9+
* notice, this list of conditions and the following disclaimer
10+
* in this position and unchanged.
11+
* 2. Redistributions in binary form must reproduce the above copyright
12+
* notice, this list of conditions and the following disclaimer in the
13+
* documentation and/or other materials provided with the distribution.
14+
*
15+
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
16+
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17+
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18+
* IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
19+
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20+
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21+
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22+
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23+
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24+
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25+
*/
26+
27+
#include <sys/types.h>
28+
#include <sys/param.h>
29+
#include <sys/queue.h>
30+
#include <sys/socket.h>
31+
#include <sys/sysctl.h>
32+
#include <sys/user.h>
33+
34+
#include <err.h>
35+
#include <errno.h>
36+
#include <getopt.h>
37+
#include <libprocstat.h>
38+
#include <limits.h>
39+
#include <stdbool.h>
40+
#include <stdio.h>
41+
#include <vis.h>
42+
43+
#include <pkg.h>
44+
45+
#include "pkgcli.h"
46+
47+
static char *safe_string(char *);
48+
static void print_argv(struct procstat *, struct kinfo_proc *);
49+
static void print_proc(struct procstat *, struct kinfo_proc *, int);
50+
51+
void
52+
usage_ps(void)
53+
{
54+
fprintf(stderr,
55+
"Usage: pkg ps [-v]\n\n");
56+
fprintf(stderr, "For more information see 'pkg help install'.\n");
57+
}
58+
59+
int
60+
exec_ps(int argc, char **argv)
61+
{
62+
struct kinfo_proc *procs;
63+
struct procstat *ps;
64+
int ch;
65+
unsigned int count;
66+
bool verbose = false;
67+
68+
struct option longopts[] = {
69+
{ "verbose", no_argument, NULL, 'v' },
70+
{ NULL, 0, NULL, 0 },
71+
};
72+
73+
while ((ch = getopt_long(argc, argv, "v", longopts, NULL)) != -1) {
74+
switch (ch) {
75+
case 'v':
76+
verbose = true;
77+
break;
78+
default:
79+
usage_install();
80+
return (EXIT_FAILURE);
81+
}
82+
}
83+
argc -= optind;
84+
argv += optind;
85+
86+
if (argc > 0) {
87+
usage_ps();
88+
return (EXIT_FAILURE);
89+
}
90+
91+
/* Will fail if security.bsd.unprivileged_proc_debug=0 */
92+
ps = procstat_open_sysctl();
93+
if (ps == NULL)
94+
err(1, "procstat_open_sysctl");
95+
96+
procs = procstat_getprocs(ps, KERN_PROC_PROC, 0, &count);
97+
if (procs == NULL) {
98+
procstat_close(ps);
99+
err(1, "procstat_getprocs");
100+
}
101+
102+
printf("PID\tPPID\tUID\tUser\tCommand\n");
103+
for (unsigned int i = 0; i < count; i++)
104+
if (procs[i].ki_pid != 0)
105+
print_proc(ps, &procs[i], verbose);
106+
107+
procstat_freeprocs(ps, procs);
108+
procstat_close(ps);
109+
return (0);
110+
}
111+
112+
static void
113+
print_proc(struct procstat *ps, struct kinfo_proc *kp, int verbose)
114+
{
115+
unsigned int count;
116+
117+
struct kinfo_vmentry *vmmap = procstat_getvmmap(ps, kp, &count);
118+
if (vmmap == NULL) {
119+
if (errno != EPERM && errno != ENOENT)
120+
err(1, "procstat_getvmmap: %d", kp->ki_pid);
121+
return;
122+
}
123+
124+
for (unsigned int i = 0; i < count; i++)
125+
/* Print executable mappings with no path */
126+
if (vmmap[i].kve_type == KVME_TYPE_VNODE &&
127+
vmmap[i].kve_protection & KVME_PROT_EXEC &&
128+
vmmap[i].kve_path[0] == '\0') {
129+
printf("%d\t%d\t%d\t%s\t%s\n", kp->ki_pid, kp->ki_ppid,
130+
kp->ki_ruid, kp->ki_login, kp->ki_comm);
131+
if (verbose)
132+
print_argv(ps, kp);
133+
break;
134+
}
135+
136+
procstat_freevmmap(ps, vmmap);
137+
}
138+
139+
static void
140+
print_argv(struct procstat *ps, struct kinfo_proc *kp)
141+
{
142+
char **argv = procstat_getargv(ps, kp, 0);
143+
if (argv == NULL) {
144+
warn("procstat_getargv: %d", kp->ki_pid);
145+
return;
146+
}
147+
148+
printf("\t");
149+
do {
150+
printf(" %s", safe_string(*argv));
151+
} while (*++argv);
152+
printf("\n");
153+
154+
procstat_freeargv(ps);
155+
}
156+
157+
static char *
158+
safe_string(char *arg) {
159+
static char *vis = NULL;
160+
161+
if (vis == NULL) {
162+
vis = malloc(PATH_MAX * 4 + 1);
163+
if (vis == NULL)
164+
err(1, "malloc");
165+
}
166+
(void)strvis(vis, arg, VIS_TAB | VIS_NL | VIS_CSTYLE);
167+
168+
return vis;
169+
}

0 commit comments

Comments
 (0)