GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: lib/libkvm/kvm_proc.c Lines: 0 227 0.0 %
Date: 2017-11-13 Branches: 0 152 0.0 %

Line Branch Exec Source
1
/*	$OpenBSD: kvm_proc.c,v 1.58 2016/11/07 00:26:33 guenther Exp $	*/
2
/*	$NetBSD: kvm_proc.c,v 1.30 1999/03/24 05:50:50 mrg Exp $	*/
3
/*-
4
 * Copyright (c) 1998 The NetBSD Foundation, Inc.
5
 * All rights reserved.
6
 *
7
 * This code is derived from software contributed to The NetBSD Foundation
8
 * by Charles M. Hannum.
9
 *
10
 * Redistribution and use in source and binary forms, with or without
11
 * modification, are permitted provided that the following conditions
12
 * are met:
13
 * 1. Redistributions of source code must retain the above copyright
14
 *    notice, this list of conditions and the following disclaimer.
15
 * 2. Redistributions in binary form must reproduce the above copyright
16
 *    notice, this list of conditions and the following disclaimer in the
17
 *    documentation and/or other materials provided with the distribution.
18
 *
19
 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20
 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21
 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22
 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23
 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29
 * POSSIBILITY OF SUCH DAMAGE.
30
 */
31
/*-
32
 * Copyright (c) 1994, 1995 Charles M. Hannum.  All rights reserved.
33
 * Copyright (c) 1989, 1992, 1993
34
 *	The Regents of the University of California.  All rights reserved.
35
 *
36
 * This code is derived from software developed by the Computer Systems
37
 * Engineering group at Lawrence Berkeley Laboratory under DARPA contract
38
 * BG 91-66 and contributed to Berkeley.
39
 *
40
 * Redistribution and use in source and binary forms, with or without
41
 * modification, are permitted provided that the following conditions
42
 * are met:
43
 * 1. Redistributions of source code must retain the above copyright
44
 *    notice, this list of conditions and the following disclaimer.
45
 * 2. Redistributions in binary form must reproduce the above copyright
46
 *    notice, this list of conditions and the following disclaimer in the
47
 *    documentation and/or other materials provided with the distribution.
48
 * 3. Neither the name of the University nor the names of its contributors
49
 *    may be used to endorse or promote products derived from this software
50
 *    without specific prior written permission.
51
 *
52
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
53
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
54
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
55
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
56
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
57
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
58
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
59
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
60
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
61
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
62
 * SUCH DAMAGE.
63
 */
64
65
/*
66
 * Proc traversal interface for kvm.  ps and w are (probably) the exclusive
67
 * users of this code, so we've factored it out into a separate module.
68
 * Thus, we keep this grunge out of the other kvm applications (i.e.,
69
 * most other applications are interested only in open/close/read/nlist).
70
 */
71
72
#define __need_process
73
#include <sys/param.h>
74
#include <sys/proc.h>
75
#include <sys/exec.h>
76
#include <sys/stat.h>
77
#include <sys/ioctl.h>
78
#include <sys/tty.h>
79
#include <stdlib.h>
80
#include <string.h>
81
#include <unistd.h>
82
#include <nlist.h>
83
#include <kvm.h>
84
#include <errno.h>
85
86
#include <uvm/uvm_extern.h>
87
#include <uvm/uvm_amap.h>
88
#include <machine/vmparam.h>
89
#include <machine/pmap.h>
90
91
#include <sys/sysctl.h>
92
93
#include <limits.h>
94
#include <db.h>
95
#include <paths.h>
96
97
#include "kvm_private.h"
98
99
100
static char	*_kvm_ureadm(kvm_t *, const struct kinfo_proc *, u_long, u_long *);
101
static ssize_t	kvm_ureadm(kvm_t *, const struct kinfo_proc *, u_long, char *, size_t);
102
103
static char	**kvm_argv(kvm_t *, const struct kinfo_proc *, u_long, int, int);
104
105
static char	**kvm_doargv(kvm_t *, const struct kinfo_proc *, int,
106
		    void (*)(struct ps_strings *, u_long *, int *));
107
static int	proc_verify(kvm_t *, const struct kinfo_proc *);
108
static void	ps_str_a(struct ps_strings *, u_long *, int *);
109
static void	ps_str_e(struct ps_strings *, u_long *, int *);
110
111
static struct vm_anon *
112
_kvm_findanon(kvm_t *kd, struct vm_amap *amapp, int slot)
113
{
114
	u_long addr;
115
	int bucket;
116
	struct vm_amap amap;
117
	struct vm_amap_chunk chunk, *chunkp;
118
	struct vm_anon *anonp;
119
120
	addr = (u_long)amapp;
121
	if (KREAD(kd, addr, &amap))
122
		return (NULL);
123
124
	/* sanity-check slot number */
125
	if (slot > amap.am_nslot)
126
		return (NULL);
127
128
	if (UVM_AMAP_SMALL(&amap))
129
		chunkp = &amapp->am_small;
130
	else {
131
		bucket = UVM_AMAP_BUCKET(&amap, slot);
132
		addr = (u_long)(amap.am_buckets + bucket);
133
		if (KREAD(kd, addr, &chunkp))
134
			return (NULL);
135
136
		while (chunkp != NULL) {
137
			addr = (u_long)chunkp;
138
			if (KREAD(kd, addr, &chunk))
139
				return (NULL);
140
141
			if (UVM_AMAP_BUCKET(&amap, chunk.ac_baseslot) !=
142
			    bucket)
143
				return (NULL);
144
			if (slot >= chunk.ac_baseslot &&
145
			    slot < chunk.ac_baseslot + chunk.ac_nslot)
146
				break;
147
148
			chunkp = TAILQ_NEXT(&chunk, ac_list);
149
		}
150
		if (chunkp == NULL)
151
			return (NULL);
152
	}
153
154
	addr = (u_long)&chunkp->ac_anon[UVM_AMAP_SLOTIDX(slot)];
155
	if (KREAD(kd, addr, &anonp))
156
		return (NULL);
157
158
	return (anonp);
159
}
160
161
static char *
162
_kvm_ureadm(kvm_t *kd, const struct kinfo_proc *p, u_long va, u_long *cnt)
163
{
164
	u_long addr, offset, slot;
165
	struct vmspace vm;
166
	struct vm_anon *anonp, anon;
167
	struct vm_map_entry vme;
168
	struct vm_page pg;
169
	unsigned long rboff;
170
171
	if (kd->swapspc == 0) {
172
		kd->swapspc = _kvm_malloc(kd, kd->nbpg);
173
		if (kd->swapspc == 0)
174
			return (NULL);
175
	}
176
177
	rboff = (unsigned long)&vme.daddrs.addr_entry - (unsigned long)&vme;
178
179
	/*
180
	 * Look through the address map for the memory object
181
	 * that corresponds to the given virtual address.
182
	 */
183
	if (KREAD(kd, (u_long)p->p_vmspace, &vm))
184
		return (NULL);
185
	addr = (u_long)&vm.vm_map.addr.rbh_root.rbt_root;
186
	while (1) {
187
		if (addr == 0)
188
			return (NULL);
189
		addr -= rboff;
190
		if (KREAD(kd, addr, &vme))
191
			return (NULL);
192
193
		if (va < vme.start)
194
			addr = (u_long)vme.daddrs.addr_entry.rbt_left;
195
		else if (va >= vme.end + vme.guard + vme.fspace)
196
			addr = (u_long)vme.daddrs.addr_entry.rbt_right;
197
		else if (va >= vme.end)
198
			return (NULL);
199
		else
200
			break;
201
	}
202
203
	/*
204
	 * we found the map entry, now to find the object...
205
	 */
206
	if (vme.aref.ar_amap == NULL)
207
		return (NULL);
208
209
	offset = va - vme.start;
210
	slot = offset / kd->nbpg + vme.aref.ar_pageoff;
211
212
	anonp = _kvm_findanon(kd, vme.aref.ar_amap, slot);
213
	if (anonp == NULL)
214
		return (NULL);
215
216
	addr = (u_long)anonp;
217
	if (KREAD(kd, addr, &anon))
218
		return (NULL);
219
220
	addr = (u_long)anon.an_page;
221
	if (addr) {
222
		if (KREAD(kd, addr, &pg))
223
			return (NULL);
224
225
		if (_kvm_pread(kd, kd->pmfd, (void *)kd->swapspc,
226
		    (size_t)kd->nbpg, (off_t)pg.phys_addr) != kd->nbpg)
227
			return (NULL);
228
	} else {
229
		if (kd->swfd == -1 ||
230
		    _kvm_pread(kd, kd->swfd, (void *)kd->swapspc,
231
		    (size_t)kd->nbpg,
232
		    (off_t)(anon.an_swslot * kd->nbpg)) != kd->nbpg)
233
			return (NULL);
234
	}
235
236
	/* Found the page. */
237
	offset %= kd->nbpg;
238
	*cnt = kd->nbpg - offset;
239
	return (&kd->swapspc[offset]);
240
}
241
242
void *
243
_kvm_reallocarray(kvm_t *kd, void *p, size_t i, size_t n)
244
{
245
	void *np = reallocarray(p, i, n);
246
247
	if (np == 0)
248
		_kvm_err(kd, kd->program, "out of memory");
249
	return (np);
250
}
251
252
/*
253
 * Read in an argument vector from the user address space of process p.
254
 * addr if the user-space base address of narg null-terminated contiguous
255
 * strings.  This is used to read in both the command arguments and
256
 * environment strings.  Read at most maxcnt characters of strings.
257
 */
258
static char **
259
kvm_argv(kvm_t *kd, const struct kinfo_proc *p, u_long addr, int narg,
260
    int maxcnt)
261
{
262
	char *np, *cp, *ep, *ap, **argv;
263
	u_long oaddr = -1;
264
	int len, cc;
265
266
	/*
267
	 * Check that there aren't an unreasonable number of arguments,
268
	 * and that the address is in user space.
269
	 */
270
	if (narg > ARG_MAX || addr < VM_MIN_ADDRESS || addr >= VM_MAXUSER_ADDRESS)
271
		return (0);
272
273
	if (kd->argv == 0) {
274
		/*
275
		 * Try to avoid reallocs.
276
		 */
277
		kd->argc = MAX(narg + 1, 32);
278
		kd->argv = _kvm_reallocarray(kd, NULL, kd->argc,
279
		    sizeof(*kd->argv));
280
		if (kd->argv == 0)
281
			return (0);
282
	} else if (narg + 1 > kd->argc) {
283
		kd->argc = MAX(2 * kd->argc, narg + 1);
284
		kd->argv = (char **)_kvm_reallocarray(kd, kd->argv, kd->argc,
285
		    sizeof(*kd->argv));
286
		if (kd->argv == 0)
287
			return (0);
288
	}
289
	if (kd->argspc == 0) {
290
		kd->argspc = _kvm_malloc(kd, kd->nbpg);
291
		if (kd->argspc == 0)
292
			return (0);
293
		kd->arglen = kd->nbpg;
294
	}
295
	if (kd->argbuf == 0) {
296
		kd->argbuf = _kvm_malloc(kd, kd->nbpg);
297
		if (kd->argbuf == 0)
298
			return (0);
299
	}
300
	cc = sizeof(char *) * narg;
301
	if (kvm_ureadm(kd, p, addr, (char *)kd->argv, cc) != cc)
302
		return (0);
303
	ap = np = kd->argspc;
304
	argv = kd->argv;
305
	len = 0;
306
307
	/*
308
	 * Loop over pages, filling in the argument vector.
309
	 */
310
	while (argv < kd->argv + narg && *argv != 0) {
311
		addr = (u_long)*argv & ~(kd->nbpg - 1);
312
		if (addr != oaddr) {
313
			if (kvm_ureadm(kd, p, addr, kd->argbuf, kd->nbpg) !=
314
			    kd->nbpg)
315
				return (0);
316
			oaddr = addr;
317
		}
318
		addr = (u_long)*argv & (kd->nbpg - 1);
319
		cp = kd->argbuf + addr;
320
		cc = kd->nbpg - addr;
321
		if (maxcnt > 0 && cc > maxcnt - len)
322
			cc = maxcnt - len;
323
		ep = memchr(cp, '\0', cc);
324
		if (ep != 0)
325
			cc = ep - cp + 1;
326
		if (len + cc > kd->arglen) {
327
			int off;
328
			char **pp;
329
			char *op = kd->argspc;
330
			char *newp;
331
332
			newp = _kvm_reallocarray(kd, kd->argspc,
333
			    kd->arglen, 2);
334
			if (newp == 0)
335
				return (0);
336
			kd->argspc = newp;
337
			kd->arglen *= 2;
338
			/*
339
			 * Adjust argv pointers in case realloc moved
340
			 * the string space.
341
			 */
342
			off = kd->argspc - op;
343
			for (pp = kd->argv; pp < argv; pp++)
344
				*pp += off;
345
			ap += off;
346
			np += off;
347
		}
348
		memcpy(np, cp, cc);
349
		np += cc;
350
		len += cc;
351
		if (ep != 0) {
352
			*argv++ = ap;
353
			ap = np;
354
		} else
355
			*argv += cc;
356
		if (maxcnt > 0 && len >= maxcnt) {
357
			/*
358
			 * We're stopping prematurely.  Terminate the
359
			 * current string.
360
			 */
361
			if (ep == 0) {
362
				*np = '\0';
363
				*argv++ = ap;
364
			}
365
			break;
366
		}
367
	}
368
	/* Make sure argv is terminated. */
369
	*argv = 0;
370
	return (kd->argv);
371
}
372
373
static void
374
ps_str_a(struct ps_strings *p, u_long *addr, int *n)
375
{
376
	*addr = (u_long)p->ps_argvstr;
377
	*n = p->ps_nargvstr;
378
}
379
380
static void
381
ps_str_e(struct ps_strings *p, u_long *addr, int *n)
382
{
383
	*addr = (u_long)p->ps_envstr;
384
	*n = p->ps_nenvstr;
385
}
386
387
/*
388
 * Determine if the proc indicated by p is still active.
389
 * This test is not 100% foolproof in theory, but chances of
390
 * being wrong are very low.
391
 */
392
static int
393
proc_verify(kvm_t *kd, const struct kinfo_proc *p)
394
{
395
	struct proc kernproc;
396
	struct process kernprocess;
397
398
	if (p->p_psflags & (PS_EMBRYO | PS_ZOMBIE))
399
		return (0);
400
401
	/*
402
	 * Just read in the whole proc.  It's not that big relative
403
	 * to the cost of the read system call.
404
	 */
405
	if (KREAD(kd, (u_long)p->p_paddr, &kernproc))
406
		return (0);
407
	if (KREAD(kd, (u_long)kernproc.p_p, &kernprocess))
408
		return (0);
409
	if (p->p_pid != kernprocess.ps_pid)
410
		return (0);
411
	return ((kernprocess.ps_flags & (PS_EMBRYO | PS_ZOMBIE)) == 0);
412
}
413
414
static char **
415
kvm_doargv(kvm_t *kd, const struct kinfo_proc *p, int nchr,
416
    void (*info)(struct ps_strings *, u_long *, int *))
417
{
418
	static struct ps_strings *ps;
419
	struct ps_strings arginfo;
420
	u_long addr;
421
	char **ap;
422
	int cnt;
423
424
	if (ps == NULL) {
425
		struct _ps_strings _ps;
426
		int mib[2];
427
		size_t len;
428
429
		mib[0] = CTL_VM;
430
		mib[1] = VM_PSSTRINGS;
431
		len = sizeof(_ps);
432
		sysctl(mib, 2, &_ps, &len, NULL, 0);
433
		ps = (struct ps_strings *)_ps.val;
434
	}
435
436
	/*
437
	 * Pointers are stored at the top of the user stack.
438
	 */
439
	if (p->p_psflags & (PS_EMBRYO | PS_ZOMBIE) ||
440
	    kvm_ureadm(kd, p, (u_long)ps, (char *)&arginfo,
441
	    sizeof(arginfo)) != sizeof(arginfo))
442
		return (0);
443
444
	(*info)(&arginfo, &addr, &cnt);
445
	if (cnt == 0)
446
		return (0);
447
	ap = kvm_argv(kd, p, addr, cnt, nchr);
448
	/*
449
	 * For live kernels, make sure this process didn't go away.
450
	 */
451
	if (ap != 0 && ISALIVE(kd) && !proc_verify(kd, p))
452
		ap = 0;
453
	return (ap);
454
}
455
456
static char **
457
kvm_arg_sysctl(kvm_t *kd, pid_t pid, int nchr, int env)
458
{
459
	size_t len, orglen;
460
	int mib[4], ret;
461
	char *buf;
462
463
	orglen = env ? kd->nbpg : 8 * kd->nbpg;	/* XXX - should be ARG_MAX */
464
	if (kd->argbuf == NULL &&
465
	    (kd->argbuf = _kvm_malloc(kd, orglen)) == NULL)
466
		return (NULL);
467
468
again:
469
	mib[0] = CTL_KERN;
470
	mib[1] = KERN_PROC_ARGS;
471
	mib[2] = (int)pid;
472
	mib[3] = env ? KERN_PROC_ENV : KERN_PROC_ARGV;
473
474
	len = orglen;
475
	ret = (sysctl(mib, 4, kd->argbuf, &len, NULL, 0) < 0);
476
	if (ret && errno == ENOMEM) {
477
		buf = _kvm_reallocarray(kd, kd->argbuf, orglen, 2);
478
		if (buf == NULL)
479
			return (NULL);
480
		orglen *= 2;
481
		kd->argbuf = buf;
482
		goto again;
483
	}
484
485
	if (ret) {
486
		free(kd->argbuf);
487
		kd->argbuf = NULL;
488
		_kvm_syserr(kd, kd->program, "kvm_arg_sysctl");
489
		return (NULL);
490
	}
491
#if 0
492
	for (argv = (char **)kd->argbuf; *argv != NULL; argv++)
493
		if (strlen(*argv) > nchr)
494
			*argv[nchr] = '\0';
495
#endif
496
497
	return (char **)(kd->argbuf);
498
}
499
500
/*
501
 * Get the command args.  This code is now machine independent.
502
 */
503
char **
504
kvm_getargv(kvm_t *kd, const struct kinfo_proc *kp, int nchr)
505
{
506
	if (ISALIVE(kd))
507
		return (kvm_arg_sysctl(kd, kp->p_pid, nchr, 0));
508
	return (kvm_doargv(kd, kp, nchr, ps_str_a));
509
}
510
511
char **
512
kvm_getenvv(kvm_t *kd, const struct kinfo_proc *kp, int nchr)
513
{
514
	if (ISALIVE(kd))
515
		return (kvm_arg_sysctl(kd, kp->p_pid, nchr, 1));
516
	return (kvm_doargv(kd, kp, nchr, ps_str_e));
517
}
518
519
/*
520
 * Read from user space.  The user context is given by p.
521
 */
522
static ssize_t
523
kvm_ureadm(kvm_t *kd, const struct kinfo_proc *p, u_long uva, char *buf,
524
    size_t len)
525
{
526
	char *cp = buf;
527
528
	while (len > 0) {
529
		u_long cnt;
530
		size_t cc;
531
		char *dp;
532
533
		dp = _kvm_ureadm(kd, p, uva, &cnt);
534
		if (dp == 0) {
535
			_kvm_err(kd, 0, "invalid address (%lx)", uva);
536
			return (0);
537
		}
538
		cc = (size_t)MIN(cnt, len);
539
		memcpy(cp, dp, cc);
540
		cp += cc;
541
		uva += cc;
542
		len -= cc;
543
	}
544
	return (ssize_t)(cp - buf);
545
}