15f9f795stas/*-
29da7bddpfg * SPDX-License-Identifier: BSD-4-Clause
39da7bddpfg *
42a8ac69tychon * Copyright (c) 2017 Dell EMC
55f9f795stas * Copyright (c) 2009 Stanislav Sedov <stas@FreeBSD.org>
65f9f795stas * Copyright (c) 1988, 1993
75f9f795stas *      The Regents of the University of California.  All rights reserved.
85f9f795stas *
95f9f795stas * Redistribution and use in source and binary forms, with or without
105f9f795stas * modification, are permitted provided that the following conditions
115f9f795stas * are met:
125f9f795stas * 1. Redistributions of source code must retain the above copyright
135f9f795stas *    notice, this list of conditions and the following disclaimer.
145f9f795stas * 2. Redistributions in binary form must reproduce the above copyright
155f9f795stas *    notice, this list of conditions and the following disclaimer in the
165f9f795stas *    documentation and/or other materials provided with the distribution.
175f9f795stas * 3. All advertising materials mentioning features or use of this software
185f9f795stas *    must display the following acknowledgement:
195f9f795stas *      This product includes software developed by the University of
205f9f795stas *      California, Berkeley and its contributors.
215f9f795stas * 4. Neither the name of the University nor the names of its contributors
225f9f795stas *    may be used to endorse or promote products derived from this software
235f9f795stas *    without specific prior written permission.
245f9f795stas *
255f9f795stas * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
265f9f795stas * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
275f9f795stas * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
285f9f795stas * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
295f9f795stas * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
305f9f795stas * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
315f9f795stas * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
325f9f795stas * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
335f9f795stas * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
345f9f795stas * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
355f9f795stas * SUCH DAMAGE.
365f9f795stas */
375f9f795stas
385f9f795stas#include <sys/cdefs.h>
395f9f795stas__FBSDID("$FreeBSD$");
405f9f795stas
415f9f795stas#include <sys/param.h>
425c12ddatrociny#include <sys/elf.h>
435f9f795stas#include <sys/time.h>
44398b483trociny#include <sys/resourcevar.h>
4549b0478trociny#define	_WANT_UCRED
4649b0478trociny#include <sys/ucred.h>
4749b0478trociny#undef _WANT_UCRED
485f9f795stas#include <sys/proc.h>
495f9f795stas#include <sys/user.h>
505f9f795stas#include <sys/stat.h>
515f9f795stas#include <sys/vnode.h>
525f9f795stas#include <sys/socket.h>
537168facglebius#define	_WANT_SOCKET
545f9f795stas#include <sys/socketvar.h>
555f9f795stas#include <sys/domain.h>
565f9f795stas#include <sys/protosw.h>
575f9f795stas#include <sys/un.h>
587168facglebius#define	_WANT_UNPCB
595f9f795stas#include <sys/unpcb.h>
605f9f795stas#include <sys/sysctl.h>
615f9f795stas#include <sys/tty.h>
625f9f795stas#include <sys/filedesc.h>
635f9f795stas#include <sys/queue.h>
645f9f795stas#define	_WANT_FILE
655f9f795stas#include <sys/file.h>
665f9f795stas#include <sys/conf.h>
67679fa5ejhb#include <sys/ksem.h>
68506e2f1jhb#include <sys/mman.h>
69a400e9crwatson#include <sys/capsicum.h>
7030a91actychon#include <sys/ptrace.h>
715f9f795stas#define	_KERNEL
725f9f795stas#include <sys/mount.h>
735f9f795stas#include <sys/pipe.h>
745f9f795stas#include <ufs/ufs/quota.h>
755f9f795stas#include <ufs/ufs/inode.h>
765f9f795stas#include <fs/devfs/devfs.h>
775f9f795stas#include <fs/devfs/devfs_int.h>
785f9f795stas#undef _KERNEL
795f9f795stas#include <nfs/nfsproto.h>
805f9f795stas#include <nfsclient/nfs.h>
815f9f795stas#include <nfsclient/nfsnode.h>
825f9f795stas
835f9f795stas#include <vm/vm.h>
845f9f795stas#include <vm/vm_map.h>
855f9f795stas#include <vm/vm_object.h>
865f9f795stas
875f9f795stas#include <net/route.h>
885f9f795stas#include <netinet/in.h>
895f9f795stas#include <netinet/in_systm.h>
905f9f795stas#include <netinet/ip.h>
913a5c9aaglebius#define	_WANT_INPCB
925f9f795stas#include <netinet/in_pcb.h>
935f9f795stas
945f9f795stas#include <assert.h>
955f9f795stas#include <ctype.h>
965f9f795stas#include <err.h>
975f9f795stas#include <fcntl.h>
985f9f795stas#include <kvm.h>
995f9f795stas#include <libutil.h>
1005f9f795stas#include <limits.h>
1015f9f795stas#include <paths.h>
1025f9f795stas#include <pwd.h>
1035f9f795stas#include <stdio.h>
1045f9f795stas#include <stdlib.h>
1055f9f795stas#include <stddef.h>
1065f9f795stas#include <string.h>
1075f9f795stas#include <unistd.h>
1085f9f795stas#include <netdb.h>
1095f9f795stas
1105f9f795stas#include <libprocstat.h>
1115f9f795stas#include "libprocstat_internal.h"
1125f9f795stas#include "common_kvm.h"
11316ea628trociny#include "core.h"
1145f9f795stas
1155f9f795stasint     statfs(const char *, struct statfs *);	/* XXX */
1165f9f795stas
1175f9f795stas#define	PROCSTAT_KVM	1
1185f9f795stas#define	PROCSTAT_SYSCTL	2
11916ea628trociny#define	PROCSTAT_CORE	3
1205f9f795stas
121890cfdctrocinystatic char	**getargv(struct procstat *procstat, struct kinfo_proc *kp,
122890cfdctrociny    size_t nchr, int env);
1235f9f795stasstatic char	*getmnton(kvm_t *kd, struct mount *m);
12408b1137trocinystatic struct kinfo_vmentry *	kinfo_getvmmap_core(struct procstat_core *core,
12508b1137trociny    int *cntp);
1265c12ddatrocinystatic Elf_Auxinfo	*procstat_getauxv_core(struct procstat_core *core,
1275c12ddatrociny    unsigned int *cntp);
1285c12ddatrocinystatic Elf_Auxinfo	*procstat_getauxv_sysctl(pid_t pid, unsigned int *cntp);
1295f9f795stasstatic struct filestat_list	*procstat_getfiles_kvm(
1305f9f795stas    struct procstat *procstat, struct kinfo_proc *kp, int mmapped);
1315f9f795stasstatic struct filestat_list	*procstat_getfiles_sysctl(
1325f9f795stas    struct procstat *procstat, struct kinfo_proc *kp, int mmapped);
1335f9f795stasstatic int	procstat_get_pipe_info_sysctl(struct filestat *fst,
1345f9f795stas    struct pipestat *pipe, char *errbuf);
1355f9f795stasstatic int	procstat_get_pipe_info_kvm(kvm_t *kd, struct filestat *fst,
1365f9f795stas    struct pipestat *pipe, char *errbuf);
1375f9f795stasstatic int	procstat_get_pts_info_sysctl(struct filestat *fst,
1385f9f795stas    struct ptsstat *pts, char *errbuf);
1395f9f795stasstatic int	procstat_get_pts_info_kvm(kvm_t *kd, struct filestat *fst,
1405f9f795stas    struct ptsstat *pts, char *errbuf);
141679fa5ejhbstatic int	procstat_get_sem_info_sysctl(struct filestat *fst,
142679fa5ejhb    struct semstat *sem, char *errbuf);
143679fa5ejhbstatic int	procstat_get_sem_info_kvm(kvm_t *kd, struct filestat *fst,
144679fa5ejhb    struct semstat *sem, char *errbuf);
145506e2f1jhbstatic int	procstat_get_shm_info_sysctl(struct filestat *fst,
146506e2f1jhb    struct shmstat *shm, char *errbuf);
147506e2f1jhbstatic int	procstat_get_shm_info_kvm(kvm_t *kd, struct filestat *fst,
148506e2f1jhb    struct shmstat *shm, char *errbuf);
1495f9f795stasstatic int	procstat_get_socket_info_sysctl(struct filestat *fst,
1505f9f795stas    struct sockstat *sock, char *errbuf);
1515f9f795stasstatic int	procstat_get_socket_info_kvm(kvm_t *kd, struct filestat *fst,
1525f9f795stas    struct sockstat *sock, char *errbuf);
1535f9f795stasstatic int	to_filestat_flags(int flags);
1545f9f795stasstatic int	procstat_get_vnode_info_kvm(kvm_t *kd, struct filestat *fst,
1555f9f795stas    struct vnstat *vn, char *errbuf);
1565f9f795stasstatic int	procstat_get_vnode_info_sysctl(struct filestat *fst,
1575f9f795stas    struct vnstat *vn, char *errbuf);
1581597072trocinystatic gid_t	*procstat_getgroups_core(struct procstat_core *core,
1591597072trociny    unsigned int *count);
16049b0478trocinystatic gid_t *	procstat_getgroups_kvm(kvm_t *kd, struct kinfo_proc *kp,
16149b0478trociny    unsigned int *count);
1621597072trocinystatic gid_t	*procstat_getgroups_sysctl(pid_t pid, unsigned int *count);
163457eff3trocinystatic struct kinfo_kstack	*procstat_getkstack_sysctl(pid_t pid,
164457eff3trociny    int *cntp);
16549b0478trocinystatic int	procstat_getosrel_core(struct procstat_core *core,
16649b0478trociny    int *osrelp);
16749b0478trocinystatic int	procstat_getosrel_kvm(kvm_t *kd, struct kinfo_proc *kp,
16849b0478trociny    int *osrelp);
16949b0478trocinystatic int	procstat_getosrel_sysctl(pid_t pid, int *osrelp);
17093aa05atrocinystatic int	procstat_getpathname_core(struct procstat_core *core,
17193aa05atrociny    char *pathname, size_t maxlen);
17293aa05atrocinystatic int	procstat_getpathname_sysctl(pid_t pid, char *pathname,
17393aa05atrociny    size_t maxlen);
174398b483trocinystatic int	procstat_getrlimit_core(struct procstat_core *core, int which,
175398b483trociny    struct rlimit* rlimit);
17649b0478trocinystatic int	procstat_getrlimit_kvm(kvm_t *kd, struct kinfo_proc *kp,
17749b0478trociny    int which, struct rlimit* rlimit);
178398b483trocinystatic int	procstat_getrlimit_sysctl(pid_t pid, int which,
179398b483trociny    struct rlimit* rlimit);
1804ca5694trocinystatic int	procstat_getumask_core(struct procstat_core *core,
1814ca5694trociny    unsigned short *maskp);
18249b0478trocinystatic int	procstat_getumask_kvm(kvm_t *kd, struct kinfo_proc *kp,
18349b0478trociny    unsigned short *maskp);
1844ca5694trocinystatic int	procstat_getumask_sysctl(pid_t pid, unsigned short *maskp);
1855f9f795stasstatic int	vntype2psfsttype(int type);
1865f9f795stas
1875f9f795stasvoid
1885f9f795stasprocstat_close(struct procstat *procstat)
1895f9f795stas{
1905f9f795stas
1915f9f795stas	assert(procstat);
1925f9f795stas	if (procstat->type == PROCSTAT_KVM)
1935f9f795stas		kvm_close(procstat->kd);
19416ea628trociny	else if (procstat->type == PROCSTAT_CORE)
19516ea628trociny		procstat_core_close(procstat->core);
196890cfdctrociny	procstat_freeargv(procstat);
197890cfdctrociny	procstat_freeenvv(procstat);
1981fb58e6pluknet	free(procstat);
1995f9f795stas}
2005f9f795stas
2015f9f795stasstruct procstat *
2025f9f795stasprocstat_open_sysctl(void)
2035f9f795stas{
2045f9f795stas	struct procstat *procstat;
2055f9f795stas
2065f9f795stas	procstat = calloc(1, sizeof(*procstat));
2075f9f795stas	if (procstat == NULL) {
2085f9f795stas		warn("malloc()");
2095f9f795stas		return (NULL);
2105f9f795stas	}
2115f9f795stas	procstat->type = PROCSTAT_SYSCTL;
2125f9f795stas	return (procstat);
2135f9f795stas}
2145f9f795stas
2155f9f795stasstruct procstat *
2165f9f795stasprocstat_open_kvm(const char *nlistf, const char *memf)
2175f9f795stas{
2185f9f795stas	struct procstat *procstat;
2195f9f795stas	kvm_t *kd;
2205f9f795stas	char buf[_POSIX2_LINE_MAX];
2215f9f795stas
2225f9f795stas	procstat = calloc(1, sizeof(*procstat));
2235f9f795stas	if (procstat == NULL) {
2245f9f795stas		warn("malloc()");
2255f9f795stas		return (NULL);
2265f9f795stas	}
2275f9f795stas	kd = kvm_openfiles(nlistf, memf, NULL, O_RDONLY, buf);
2285f9f795stas	if (kd == NULL) {
2295f9f795stas		warnx("kvm_openfiles(): %s", buf);
2305f9f795stas		free(procstat);
2315f9f795stas		return (NULL);
2325f9f795stas	}
2335f9f795stas	procstat->type = PROCSTAT_KVM;
2345f9f795stas	procstat->kd = kd;
2355f9f795stas	return (procstat);
2365f9f795stas}
2375f9f795stas
23816ea628trocinystruct procstat *
23916ea628trocinyprocstat_open_core(const char *filename)
24016ea628trociny{
24116ea628trociny	struct procstat *procstat;
24216ea628trociny	struct procstat_core *core;
24316ea628trociny
24416ea628trociny	procstat = calloc(1, sizeof(*procstat));
24516ea628trociny	if (procstat == NULL) {
24616ea628trociny		warn("malloc()");
24716ea628trociny		return (NULL);
24816ea628trociny	}
24916ea628trociny	core = procstat_core_open(filename);
25016ea628trociny	if (core == NULL) {
25116ea628trociny		free(procstat);
25216ea628trociny		return (NULL);
25316ea628trociny	}
25416ea628trociny	procstat->type = PROCSTAT_CORE;
25516ea628trociny	procstat->core = core;
25616ea628trociny	return (procstat);
25716ea628trociny}
25816ea628trociny
2595f9f795stasstruct kinfo_proc *
2605f9f795stasprocstat_getprocs(struct procstat *procstat, int what, int arg,
2615f9f795stas    unsigned int *count)
2625f9f795stas{
2635f9f795stas	struct kinfo_proc *p0, *p;
264a2ac4bajhb	size_t len, olen;
2655f9f795stas	int name[4];
266c04046davg	int cnt;
2675f9f795stas	int error;
2685f9f795stas
2695f9f795stas	assert(procstat);
2705f9f795stas	assert(count);
2715f9f795stas	p = NULL;
2725f9f795stas	if (procstat->type == PROCSTAT_KVM) {
273c04046davg		*count = 0;
274c04046davg		p0 = kvm_getprocs(procstat->kd, what, arg, &cnt);
275c04046davg		if (p0 == NULL || cnt <= 0)
2765f9f795stas			return (NULL);
277c04046davg		*count = cnt;
2785f9f795stas		len = *count * sizeof(*p);
2795f9f795stas		p = malloc(len);
2805f9f795stas		if (p == NULL) {
2817319104jilles			warnx("malloc(%zu)", len);
2825f9f795stas			goto fail;
2835f9f795stas		}
2845f9f795stas		bcopy(p0, p, len);
2855f9f795stas		return (p);
2865f9f795stas	} else if (procstat->type == PROCSTAT_SYSCTL) {
2875f9f795stas		len = 0;
2885f9f795stas		name[0] = CTL_KERN;
2895f9f795stas		name[1] = KERN_PROC;
2905f9f795stas		name[2] = what;
2915f9f795stas		name[3] = arg;
2929e0a154ngie		error = sysctl(name, nitems(name), NULL, &len, NULL, 0);
2935f9f795stas		if (error < 0 && errno != EPERM) {
2945f9f795stas			warn("sysctl(kern.proc)");
2955f9f795stas			goto fail;
2965f9f795stas		}
2975f9f795stas		if (len == 0) {
2985f9f795stas			warnx("no processes?");
2995f9f795stas			goto fail;
3005f9f795stas		}
301a2ac4bajhb		do {
302a2ac4bajhb			len += len / 10;
303a2ac4bajhb			p = reallocf(p, len);
304a2ac4bajhb			if (p == NULL) {
305a2ac4bajhb				warnx("reallocf(%zu)", len);
306a2ac4bajhb				goto fail;
307a2ac4bajhb			}
308a2ac4bajhb			olen = len;
3099e0a154ngie			error = sysctl(name, nitems(name), p, &len, NULL, 0);
310a2ac4bajhb		} while (error < 0 && errno == ENOMEM && olen == len);
3115f9f795stas		if (error < 0 && errno != EPERM) {
3125f9f795stas			warn("sysctl(kern.proc)");
3135f9f795stas			goto fail;
3145f9f795stas		}
3155f9f795stas		/* Perform simple consistency checks. */
3165f9f795stas		if ((len % sizeof(*p)) != 0 || p->ki_structsize != sizeof(*p)) {
31716ea628trociny			warnx("kinfo_proc structure size mismatch (len = %zu)", len);
31816ea628trociny			goto fail;
31916ea628trociny		}
32016ea628trociny		*count = len / sizeof(*p);
32116ea628trociny		return (p);
32216ea628trociny	} else if (procstat->type == PROCSTAT_CORE) {
32316ea628trociny		p = procstat_core_get(procstat->core, PSC_TYPE_PROC, NULL,
32416ea628trociny		    &len);
32516ea628trociny		if ((len % sizeof(*p)) != 0 || p->ki_structsize != sizeof(*p)) {
3265f9f795stas			warnx("kinfo_proc structure size mismatch");
3275f9f795stas			goto fail;
3285f9f795stas		}
3295f9f795stas		*count = len / sizeof(*p);
3305f9f795stas		return (p);
3315f9f795stas	} else {
33254b5af4jilles		warnx("unknown access method: %d", procstat->type);
3335f9f795stas		return (NULL);
3345f9f795stas	}
3355f9f795stasfail:
3365f9f795stas	if (p)
3375f9f795stas		free(p);
3385f9f795stas	return (NULL);
3395f9f795stas}
3405f9f795stas
3415f9f795stasvoid
3425f9f795stasprocstat_freeprocs(struct procstat *procstat __unused, struct kinfo_proc *p)
3435f9f795stas{
3445f9f795stas
3455f9f795stas	if (p != NULL)
3465f9f795stas		free(p);
3475f9f795stas	p = NULL;
3485f9f795stas}
3495f9f795stas
3505f9f795stasstruct filestat_list *
3515f9f795stasprocstat_getfiles(struct procstat *procstat, struct kinfo_proc *kp, int mmapped)
3525f9f795stas{
35316ea628trociny
35416ea628trociny	switch(procstat->type) {
35516ea628trociny	case PROCSTAT_KVM:
3566a2ccc4stas		return (procstat_getfiles_kvm(procstat, kp, mmapped));
35716ea628trociny	case PROCSTAT_SYSCTL:
35816ea628trociny	case PROCSTAT_CORE:
35916ea628trociny		return (procstat_getfiles_sysctl(procstat, kp, mmapped));
36016ea628trociny	default:
36116ea628trociny		warnx("unknown access method: %d", procstat->type);
3625f9f795stas		return (NULL);
36316ea628trociny	}
3645f9f795stas}
3655f9f795stas
3665f9f795stasvoid
3675f9f795stasprocstat_freefiles(struct procstat *procstat, struct filestat_list *head)
3685f9f795stas{
3695f9f795stas	struct filestat *fst, *tmp;
3705f9f795stas
3715f9f795stas	STAILQ_FOREACH_SAFE(fst, head, next, tmp) {
3725f9f795stas		if (fst->fs_path != NULL)
3735f9f795stas			free(fst->fs_path);
3745f9f795stas		free(fst);
3755f9f795stas	}
3765f9f795stas	free(head);
3775f9f795stas	if (procstat->vmentries != NULL) {
378fe5611bjilles		free(procstat->vmentries);
3795f9f795stas		procstat->vmentries = NULL;
380