Bug Summary

File:kern/kern_ktrace.c
Warning:line 656, column 13
Array access (from variable 'data') results in a null pointer dereference

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple amd64-unknown-openbsd7.0 -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name kern_ktrace.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model static -mframe-pointer=all -relaxed-aliasing -fno-rounding-math -mconstructor-aliases -ffreestanding -mcmodel=kernel -target-cpu x86-64 -target-feature +retpoline-indirect-calls -target-feature +retpoline-indirect-branches -target-feature -sse2 -target-feature -sse -target-feature -3dnow -target-feature -mmx -target-feature +save-args -disable-red-zone -no-implicit-float -tune-cpu generic -debugger-tuning=gdb -fcoverage-compilation-dir=/usr/src/sys/arch/amd64/compile/GENERIC.MP/obj -nostdsysteminc -nobuiltininc -resource-dir /usr/local/lib/clang/13.0.0 -I /usr/src/sys -I /usr/src/sys/arch/amd64/compile/GENERIC.MP/obj -I /usr/src/sys/arch -I /usr/src/sys/dev/pci/drm/include -I /usr/src/sys/dev/pci/drm/include/uapi -I /usr/src/sys/dev/pci/drm/amd/include/asic_reg -I /usr/src/sys/dev/pci/drm/amd/include -I /usr/src/sys/dev/pci/drm/amd/amdgpu -I /usr/src/sys/dev/pci/drm/amd/display -I /usr/src/sys/dev/pci/drm/amd/display/include -I /usr/src/sys/dev/pci/drm/amd/display/dc -I /usr/src/sys/dev/pci/drm/amd/display/amdgpu_dm -I /usr/src/sys/dev/pci/drm/amd/pm/inc -I /usr/src/sys/dev/pci/drm/amd/pm/swsmu -I /usr/src/sys/dev/pci/drm/amd/pm/swsmu/smu11 -I /usr/src/sys/dev/pci/drm/amd/pm/swsmu/smu12 -I /usr/src/sys/dev/pci/drm/amd/pm/powerplay -I /usr/src/sys/dev/pci/drm/amd/pm/powerplay/hwmgr -I /usr/src/sys/dev/pci/drm/amd/pm/powerplay/smumgr -I /usr/src/sys/dev/pci/drm/amd/display/dc/inc -I /usr/src/sys/dev/pci/drm/amd/display/dc/inc/hw -I /usr/src/sys/dev/pci/drm/amd/display/dc/clk_mgr -I /usr/src/sys/dev/pci/drm/amd/display/modules/inc -I /usr/src/sys/dev/pci/drm/amd/display/modules/hdcp -I /usr/src/sys/dev/pci/drm/amd/display/dmub/inc -I /usr/src/sys/dev/pci/drm/i915 -D DDB -D DIAGNOSTIC -D KTRACE -D ACCOUNTING -D KMEMSTATS -D PTRACE -D POOL_DEBUG -D CRYPTO -D SYSVMSG -D SYSVSEM -D SYSVSHM -D UVM_SWAP_ENCRYPT -D FFS -D FFS2 -D FFS_SOFTUPDATES -D UFS_DIRHASH -D QUOTA -D EXT2FS -D MFS -D NFSCLIENT -D NFSSERVER -D CD9660 -D UDF -D MSDOSFS -D FIFO -D FUSE -D SOCKET_SPLICE -D TCP_ECN -D TCP_SIGNATURE -D INET6 -D IPSEC -D PPP_BSDCOMP -D PPP_DEFLATE -D PIPEX -D MROUTING -D MPLS -D BOOT_CONFIG -D USER_PCICONF -D APERTURE -D MTRR -D NTFS -D HIBERNATE -D PCIVERBOSE -D USBVERBOSE -D WSDISPLAY_COMPAT_USL -D WSDISPLAY_COMPAT_RAWKBD -D WSDISPLAY_DEFAULTSCREENS=6 -D X86EMU -D ONEWIREVERBOSE -D MULTIPROCESSOR -D MAXUSERS=80 -D _KERNEL -D CONFIG_DRM_AMD_DC_DCN3_0 -O2 -Wno-pointer-sign -Wno-address-of-packed-member -Wno-constant-conversion -Wno-unused-but-set-variable -Wno-gnu-folding-constant -fdebug-compilation-dir=/usr/src/sys/arch/amd64/compile/GENERIC.MP/obj -ferror-limit 19 -fwrapv -D_RET_PROTECTOR -ret-protector -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -fno-builtin-malloc -fno-builtin-calloc -fno-builtin-realloc -fno-builtin-valloc -fno-builtin-free -fno-builtin-strdup -fno-builtin-strndup -analyzer-output=html -faddrsig -o /usr/obj/sys/arch/amd64/compile/GENERIC.MP/scan-build/2022-01-12-131800-47421-1 -x c /usr/src/sys/kern/kern_ktrace.c
1/* $OpenBSD: kern_ktrace.c,v 1.105 2021/12/23 18:50:32 guenther Exp $ */
2/* $NetBSD: kern_ktrace.c,v 1.23 1996/02/09 18:59:36 christos Exp $ */
3
4/*
5 * Copyright (c) 1989, 1993
6 * The Regents of the University of California. All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. Neither the name of the University nor the names of its contributors
17 * may be used to endorse or promote products derived from this software
18 * without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 * SUCH DAMAGE.
31 *
32 * @(#)kern_ktrace.c 8.2 (Berkeley) 9/23/93
33 */
34
35#include <sys/param.h>
36#include <sys/systm.h>
37#include <sys/proc.h>
38#include <sys/sched.h>
39#include <sys/fcntl.h>
40#include <sys/namei.h>
41#include <sys/vnode.h>
42#include <sys/lock.h>
43#include <sys/ktrace.h>
44#include <sys/malloc.h>
45#include <sys/syslog.h>
46#include <sys/sysctl.h>
47#include <sys/pledge.h>
48
49#include <sys/mount.h>
50#include <sys/syscall.h>
51#include <sys/syscallargs.h>
52
53#include <uvm/uvm_extern.h>
54
55void ktrinitheaderraw(struct ktr_header *, uint, pid_t, pid_t);
56void ktrinitheader(struct ktr_header *, struct proc *, int);
57int ktrstart(struct proc *, struct vnode *, struct ucred *);
58int ktrops(struct proc *, struct process *, int, int, struct vnode *,
59 struct ucred *);
60int ktrsetchildren(struct proc *, struct process *, int, int,
61 struct vnode *, struct ucred *);
62int ktrwrite(struct proc *, struct ktr_header *, const void *, size_t);
63int ktrwrite2(struct proc *, struct ktr_header *, const void *, size_t,
64 const void *, size_t);
65int ktrwriteraw(struct proc *, struct vnode *, struct ucred *,
66 struct ktr_header *, struct iovec *);
67int ktrcanset(struct proc *, struct process *);
68
69/*
70 * Clear the trace settings in a correct way (to avoid races).
71 */
72void
73ktrcleartrace(struct process *pr)
74{
75 struct vnode *vp;
76 struct ucred *cred;
77
78 if (pr->ps_tracevp != NULL((void *)0)) {
79 vp = pr->ps_tracevp;
80 cred = pr->ps_tracecred;
81
82 pr->ps_traceflag = 0;
83 pr->ps_tracevp = NULL((void *)0);
84 pr->ps_tracecred = NULL((void *)0);
85
86 vp->v_writecount--;
87 vrele(vp);
88 crfree(cred);
89 }
90}
91
92/*
93 * Change the trace setting in a correct way (to avoid races).
94 */
95void
96ktrsettrace(struct process *pr, int facs, struct vnode *newvp,
97 struct ucred *newcred)
98{
99 struct vnode *oldvp;
100 struct ucred *oldcred;
101
102 KASSERT(newvp != NULL)((newvp != ((void *)0)) ? (void)0 : __assert("diagnostic ", "/usr/src/sys/kern/kern_ktrace.c"
, 102, "newvp != NULL"))
;
103 KASSERT(newcred != NULL)((newcred != ((void *)0)) ? (void)0 : __assert("diagnostic ",
"/usr/src/sys/kern/kern_ktrace.c", 103, "newcred != NULL"))
;
104
105 pr->ps_traceflag |= facs;
106
107 /* nothing to change about where the trace goes? */
108 if (pr->ps_tracevp == newvp && pr->ps_tracecred == newcred)
109 return;
110
111 vref(newvp);
112 crhold(newcred);
113 newvp->v_writecount++;
114
115 oldvp = pr->ps_tracevp;
116 oldcred = pr->ps_tracecred;
117
118 pr->ps_tracevp = newvp;
119 pr->ps_tracecred = newcred;
120
121 if (oldvp != NULL((void *)0)) {
122 oldvp->v_writecount--;
123 vrele(oldvp);
124 crfree(oldcred);
125 }
126}
127
128void
129ktrinitheaderraw(struct ktr_header *kth, uint type, pid_t pid, pid_t tid)
130{
131 memset(kth, 0, sizeof(struct ktr_header))__builtin_memset((kth), (0), (sizeof(struct ktr_header)));
132 kth->ktr_type = type;
133 nanotime(&kth->ktr_time);
134 kth->ktr_pid = pid;
135 kth->ktr_tid = tid;
136}
137
138void
139ktrinitheader(struct ktr_header *kth, struct proc *p, int type)
140{
141 struct process *pr = p->p_p;
142
143 ktrinitheaderraw(kth, type, pr->ps_pid, p->p_tid + THREAD_PID_OFFSET100000);
144 memcpy(kth->ktr_comm, pr->ps_comm, MAXCOMLEN)__builtin_memcpy((kth->ktr_comm), (pr->ps_comm), (16));
145}
146
147int
148ktrstart(struct proc *p, struct vnode *vp, struct ucred *cred)
149{
150 struct ktr_header kth;
151
152 ktrinitheaderraw(&kth, htobe32(KTR_START)(__uint32_t)(__builtin_constant_p(0x4b545200) ? (__uint32_t)(
((__uint32_t)(0x4b545200) & 0xff) << 24 | ((__uint32_t
)(0x4b545200) & 0xff00) << 8 | ((__uint32_t)(0x4b545200
) & 0xff0000) >> 8 | ((__uint32_t)(0x4b545200) &
0xff000000) >> 24) : __swap32md(0x4b545200))
, -1, -1);
21
'?' condition is true
153 return (ktrwriteraw(p, vp, cred, &kth, NULL((void *)0)));
22
Passing null pointer value via 5th parameter 'data'
23
Calling 'ktrwriteraw'
154}
155
156void
157ktrsyscall(struct proc *p, register_t code, size_t argsize, register_t args[])
158{
159 struct ktr_header kth;
160 struct ktr_syscall *ktp;
161 size_t len = sizeof(struct ktr_syscall) + argsize;
162 register_t *argp;
163 u_int nargs = 0;
164 int i;
165
166 if (code == SYS_sysctl202) {
167 /*
168 * The sysctl encoding stores the mib[]
169 * array because it is interesting.
170 */
171 if (args[1] > 0)
172 nargs = lmin(args[1], CTL_MAXNAME12);
173 len += nargs * sizeof(int);
174 }
175 atomic_setbits_intx86_atomic_setbits_u32(&p->p_flag, P_INKTR0x00000001);
176 ktrinitheader(&kth, p, KTR_SYSCALL1);
177 ktp = malloc(len, M_TEMP127, M_WAITOK0x0001);
178 ktp->ktr_code = code;
179 ktp->ktr_argsize = argsize;
180 argp = (register_t *)((char *)ktp + sizeof(struct ktr_syscall));
181 for (i = 0; i < (argsize / sizeof *argp); i++)
182 *argp++ = args[i];
183 if (nargs && copyin((void *)args[0], argp, nargs * sizeof(int)))
184 memset(argp, 0, nargs * sizeof(int))__builtin_memset((argp), (0), (nargs * sizeof(int)));
185 ktrwrite(p, &kth, ktp, len);
186 free(ktp, M_TEMP127, len);
187 atomic_clearbits_intx86_atomic_clearbits_u32(&p->p_flag, P_INKTR0x00000001);
188}
189
190void
191ktrsysret(struct proc *p, register_t code, int error,
192 const register_t retval[2])
193{
194 struct ktr_header kth;
195 struct ktr_sysret ktp;
196 int len;
197
198 atomic_setbits_intx86_atomic_setbits_u32(&p->p_flag, P_INKTR0x00000001);
199 ktrinitheader(&kth, p, KTR_SYSRET2);
200 ktp.ktr_code = code;
201 ktp.ktr_error = error;
202 if (error)
203 len = 0;
204 else if (code == SYS_lseek166)
205 /* the one exception: lseek on ILP32 needs more */
206 len = sizeof(long long);
207#if 1
208 else if (code == SYS_pad_lseek199)
209 len = sizeof(long long);
210#endif
211 else
212 len = sizeof(register_t);
213 ktrwrite2(p, &kth, &ktp, sizeof(ktp), retval, len);
214 atomic_clearbits_intx86_atomic_clearbits_u32(&p->p_flag, P_INKTR0x00000001);
215}
216
217void
218ktrnamei(struct proc *p, char *path)
219{
220 struct ktr_header kth;
221
222 atomic_setbits_intx86_atomic_setbits_u32(&p->p_flag, P_INKTR0x00000001);
223 ktrinitheader(&kth, p, KTR_NAMEI3);
224 ktrwrite(p, &kth, path, strlen(path));
225 atomic_clearbits_intx86_atomic_clearbits_u32(&p->p_flag, P_INKTR0x00000001);
226}
227
228void
229ktrgenio(struct proc *p, int fd, enum uio_rw rw, struct iovec *iov,
230 ssize_t len)
231{
232 struct ktr_header kth;
233 struct ktr_genio ktp;
234 caddr_t cp;
235 int count, error;
236 int buflen;
237
238 atomic_setbits_intx86_atomic_setbits_u32(&p->p_flag, P_INKTR0x00000001);
239
240 /* beware overflow */
241 if (len > PAGE_SIZE(1 << 12))
242 buflen = PAGE_SIZE(1 << 12);
243 else
244 buflen = len + sizeof(struct ktr_genio);
245
246 ktrinitheader(&kth, p, KTR_GENIO4);
247 ktp.ktr_fd = fd;
248 ktp.ktr_rw = rw;
249
250 cp = malloc(buflen, M_TEMP127, M_WAITOK0x0001);
251 while (len > 0) {
252 /*
253 * Don't allow this process to hog the cpu when doing
254 * huge I/O.
255 */
256 sched_pause(preempt)do { if (({struct cpu_info *__ci; asm volatile("movq %%gs:%P1,%0"
: "=r" (__ci) :"n" (__builtin_offsetof(struct cpu_info, ci_self
))); __ci;})->ci_schedstate.spc_schedflags & 0x0002) preempt
(); } while (0)
;
257
258 count = lmin(iov->iov_len, buflen);
259 if (count > len)
260 count = len;
261 if (copyin(iov->iov_base, cp, count))
262 break;
263
264 KERNEL_LOCK()_kernel_lock();
265 error = ktrwrite2(p, &kth, &ktp, sizeof(ktp), cp, count);
266 KERNEL_UNLOCK()_kernel_unlock();
267 if (error != 0)
268 break;
269
270 iov->iov_len -= count;
271 iov->iov_base = (caddr_t)iov->iov_base + count;
272
273 if (iov->iov_len == 0)
274 iov++;
275
276 len -= count;
277 }
278
279 free(cp, M_TEMP127, buflen);
280 atomic_clearbits_intx86_atomic_clearbits_u32(&p->p_flag, P_INKTR0x00000001);
281}
282
283void
284ktrpsig(struct proc *p, int sig, sig_t action, int mask, int code,
285 siginfo_t *si)
286{
287 struct ktr_header kth;
288 struct ktr_psig kp;
289
290 atomic_setbits_intx86_atomic_setbits_u32(&p->p_flag, P_INKTR0x00000001);
291 ktrinitheader(&kth, p, KTR_PSIG5);
292 kp.signo = (char)sig;
293 kp.action = action;
294 kp.mask = mask;
295 kp.code = code;
296 kp.si = *si;
297
298 KERNEL_LOCK()_kernel_lock();
299 ktrwrite(p, &kth, &kp, sizeof(kp));
300 KERNEL_UNLOCK()_kernel_unlock();
301 atomic_clearbits_intx86_atomic_clearbits_u32(&p->p_flag, P_INKTR0x00000001);
302}
303
304void
305ktrstruct(struct proc *p, const char *name, const void *data, size_t datalen)
306{
307 struct ktr_header kth;
308
309 atomic_setbits_intx86_atomic_setbits_u32(&p->p_flag, P_INKTR0x00000001);
310 ktrinitheader(&kth, p, KTR_STRUCT8);
311
312 if (data == NULL((void *)0))
313 datalen = 0;
314 KERNEL_LOCK()_kernel_lock();
315 ktrwrite2(p, &kth, name, strlen(name) + 1, data, datalen);
316 KERNEL_UNLOCK()_kernel_unlock();
317 atomic_clearbits_intx86_atomic_clearbits_u32(&p->p_flag, P_INKTR0x00000001);
318}
319
320int
321ktruser(struct proc *p, const char *id, const void *addr, size_t len)
322{
323 struct ktr_header kth;
324 struct ktr_user ktp;
325 int error;
326 void *memp;
327#define STK_PARAMS128 128
328 long long stkbuf[STK_PARAMS128 / sizeof(long long)];
329
330 if (!KTRPOINT(p, KTR_USER)((p)->p_p->ps_traceflag & (1<<(9)) &&
((p)->p_flag & 0x00000001) == 0)
)
331 return (0);
332 if (len > KTR_USER_MAXLEN2048)
333 return (EINVAL22);
334
335 atomic_setbits_intx86_atomic_setbits_u32(&p->p_flag, P_INKTR0x00000001);
336 ktrinitheader(&kth, p, KTR_USER9);
337 memset(ktp.ktr_id, 0, KTR_USER_MAXIDLEN)__builtin_memset((ktp.ktr_id), (0), (20));
338 error = copyinstr(id, ktp.ktr_id, KTR_USER_MAXIDLEN20, NULL((void *)0));
339 if (error == 0) {
340 if (len > sizeof(stkbuf))
341 memp = malloc(len, M_TEMP127, M_WAITOK0x0001);
342 else
343 memp = stkbuf;
344 error = copyin(addr, memp, len);
345 if (error == 0)
346 ktrwrite2(p, &kth, &ktp, sizeof(ktp), memp, len);
347 if (memp != stkbuf)
348 free(memp, M_TEMP127, len);
349 }
350 atomic_clearbits_intx86_atomic_clearbits_u32(&p->p_flag, P_INKTR0x00000001);
351 return (error);
352}
353
354void
355ktrexec(struct proc *p, int type, const char *data, ssize_t len)
356{
357 struct ktr_header kth;
358 int count;
359 int buflen;
360
361 assert(type == KTR_EXECARGS || type == KTR_EXECENV)((type == 10 || type == 11) ? (void)0 : __assert("", "/usr/src/sys/kern/kern_ktrace.c"
, 361, "type == KTR_EXECARGS || type == KTR_EXECENV"))
;
362 atomic_setbits_intx86_atomic_setbits_u32(&p->p_flag, P_INKTR0x00000001);
363
364 /* beware overflow */
365 if (len > PAGE_SIZE(1 << 12))
366 buflen = PAGE_SIZE(1 << 12);
367 else
368 buflen = len;
369
370 ktrinitheader(&kth, p, type);
371
372 while (len > 0) {
373 /*
374 * Don't allow this process to hog the cpu when doing
375 * huge I/O.
376 */
377 sched_pause(preempt)do { if (({struct cpu_info *__ci; asm volatile("movq %%gs:%P1,%0"
: "=r" (__ci) :"n" (__builtin_offsetof(struct cpu_info, ci_self
))); __ci;})->ci_schedstate.spc_schedflags & 0x0002) preempt
(); } while (0)
;
378
379 count = lmin(len, buflen);
380 if (ktrwrite(p, &kth, data, count) != 0)
381 break;
382
383 len -= count;
384 data += count;
385 }
386
387 atomic_clearbits_intx86_atomic_clearbits_u32(&p->p_flag, P_INKTR0x00000001);
388}
389
390void
391ktrpledge(struct proc *p, int error, uint64_t code, int syscall)
392{
393 struct ktr_header kth;
394 struct ktr_pledge kp;
395
396 atomic_setbits_intx86_atomic_setbits_u32(&p->p_flag, P_INKTR0x00000001);
397 ktrinitheader(&kth, p, KTR_PLEDGE12);
398 kp.error = error;
399 kp.code = code;
400 kp.syscall = syscall;
401
402 KERNEL_LOCK()_kernel_lock();
403 ktrwrite(p, &kth, &kp, sizeof(kp));
404 KERNEL_UNLOCK()_kernel_unlock();
405 atomic_clearbits_intx86_atomic_clearbits_u32(&p->p_flag, P_INKTR0x00000001);
406}
407
408/* Interface and common routines */
409
410int
411doktrace(struct vnode *vp, int ops, int facs, pid_t pid, struct proc *p)
412{
413 struct process *pr = NULL((void *)0);
414 struct ucred *cred = NULL((void *)0);
415 struct pgrp *pg;
416 int descend = ops & KTRFLAG_DESCEND4;
417 int ret = 0;
418 int error = 0;
419
420 facs = facs & ~((unsigned)KTRFAC_ROOT0x80000000U);
421 ops = KTROP(ops)((ops)&3);
422
423 if (ops != KTROP_CLEAR1) {
6
Assuming 'ops' is not equal to KTROP_CLEAR
7
Taking true branch
424 /*
425 * an operation which requires a file argument.
426 */
427 cred = p->p_ucred;
428 if (!vp) {
8
Assuming 'vp' is non-null
9
Taking false branch
429 error = EINVAL22;
430 goto done;
431 }
432 if (vp->v_type != VREG) {
10
Assuming field 'v_type' is equal to VREG
11
Taking false branch
433 error = EACCES13;
434 goto done;
435 }
436 }
437 /*
438 * Clear all uses of the tracefile
439 */
440 if (ops == KTROP_CLEARFILE2) {
12
Assuming 'ops' is not equal to KTROP_CLEARFILE
13
Taking false branch
441 LIST_FOREACH(pr, &allprocess, ps_list)for((pr) = ((&allprocess)->lh_first); (pr)!= ((void *)
0); (pr) = ((pr)->ps_list.le_next))
{
442 if (pr->ps_tracevp == vp) {
443 if (ktrcanset(p, pr))
444 ktrcleartrace(pr);
445 else
446 error = EPERM1;
447 }
448 }
449 goto done;
450 }
451 /*
452 * need something to (un)trace (XXX - why is this here?)
453 */
454 if (!facs) {
14
Assuming 'facs' is not equal to 0
15
Taking false branch
455 error = EINVAL22;
456 goto done;
457 }
458 if (ops == KTROP_SET0) {
16
Assuming 'ops' is equal to KTROP_SET
17
Taking true branch
459 if (suser(p) == 0)
18
Assuming the condition is false
19
Taking false branch
460 facs |= KTRFAC_ROOT0x80000000U;
461 error = ktrstart(p, vp, cred);
20
Calling 'ktrstart'
462 if (error != 0)
463 goto done;
464 }
465 /*
466 * do it
467 */
468 if (pid < 0) {
469 /*
470 * by process group
471 */
472 pg = pgfind(-pid);
473 if (pg == NULL((void *)0)) {
474 error = ESRCH3;
475 goto done;
476 }
477 LIST_FOREACH(pr, &pg->pg_members, ps_pglist)for((pr) = ((&pg->pg_members)->lh_first); (pr)!= ((
void *)0); (pr) = ((pr)->ps_pglist.le_next))
{
478 if (descend)
479 ret |= ktrsetchildren(p, pr, ops, facs, vp,
480 cred);
481 else
482 ret |= ktrops(p, pr, ops, facs, vp, cred);
483 }
484 } else {
485 /*
486 * by pid
487 */
488 pr = prfind(pid);
489 if (pr == NULL((void *)0)) {
490 error = ESRCH3;
491 goto done;
492 }
493 if (descend)
494 ret |= ktrsetchildren(p, pr, ops, facs, vp, cred);
495 else
496 ret |= ktrops(p, pr, ops, facs, vp, cred);
497 }
498 if (!ret)
499 error = EPERM1;
500done:
501 return (error);
502}
503
504/*
505 * ktrace system call
506 */
507int
508sys_ktrace(struct proc *p, void *v, register_t *retval)
509{
510 struct sys_ktrace_args /* {
511 syscallarg(const char *) fname;
512 syscallarg(int) ops;
513 syscallarg(int) facs;
514 syscallarg(pid_t) pid;
515 } */ *uap = v;
516 struct vnode *vp = NULL((void *)0);
517 const char *fname = SCARG(uap, fname)((uap)->fname.le.datum);
518 struct ucred *cred = NULL((void *)0);
519 int error;
520
521 if (fname) {
1
Assuming 'fname' is non-null
2
Taking true branch
522 struct nameidata nd;
523
524 cred = p->p_ucred;
525 NDINIT(&nd, 0, 0, UIO_USERSPACE, fname, p)ndinitat(&nd, 0, 0, UIO_USERSPACE, -100, fname, p);
526 nd.ni_pledge = PLEDGE_CPATH0x0000000000000004ULL | PLEDGE_WPATH0x0000000000000002ULL;
527 nd.ni_unveil = UNVEIL_CREATE0x04 | UNVEIL_WRITE0x02;
528 if ((error = vn_open(&nd, FWRITE0x0002|O_NOFOLLOW0x0100, 0)) != 0)
3
Assuming the condition is false
4
Taking false branch
529 return error;
530 vp = nd.ni_vp;
531
532 VOP_UNLOCK(vp);
533 }
534
535 error = doktrace(vp, SCARG(uap, ops)((uap)->ops.le.datum), SCARG(uap, facs)((uap)->facs.le.datum),
5
Calling 'doktrace'
536 SCARG(uap, pid)((uap)->pid.le.datum), p);
537 if (vp != NULL((void *)0))
538 (void)vn_close(vp, FWRITE0x0002, cred, p);
539
540 return error;
541}
542
543int
544ktrops(struct proc *curp, struct process *pr, int ops, int facs,
545 struct vnode *vp, struct ucred *cred)
546{
547 if (!ktrcanset(curp, pr))
548 return (0);
549 if (ops == KTROP_SET0)
550 ktrsettrace(pr, facs, vp, cred);
551 else {
552 /* KTROP_CLEAR */
553 pr->ps_traceflag &= ~facs;
554 if ((pr->ps_traceflag & KTRFAC_MASK0x00ffffff) == 0) {
555 /* cleared all the facility bits, so stop completely */
556 ktrcleartrace(pr);
557 }
558 }
559
560 return (1);
561}
562
563int
564ktrsetchildren(struct proc *curp, struct process *top, int ops, int facs,
565 struct vnode *vp, struct ucred *cred)
566{
567 struct process *pr;
568 int ret = 0;
569
570 pr = top;
571 for (;;) {
572 ret |= ktrops(curp, pr, ops, facs, vp, cred);
573 /*
574 * If this process has children, descend to them next,
575 * otherwise do any siblings, and if done with this level,
576 * follow back up the tree (but not past top).
577 */
578 if (!LIST_EMPTY(&pr->ps_children)(((&pr->ps_children)->lh_first) == ((void *)0)))
579 pr = LIST_FIRST(&pr->ps_children)((&pr->ps_children)->lh_first);
580 else for (;;) {
581 if (pr == top)
582 return (ret);
583 if (LIST_NEXT(pr, ps_sibling)((pr)->ps_sibling.le_next) != NULL((void *)0)) {
584 pr = LIST_NEXT(pr, ps_sibling)((pr)->ps_sibling.le_next);
585 break;
586 }
587 pr = pr->ps_pptr;
588 }
589 }
590 /*NOTREACHED*/
591}
592
593int
594ktrwrite(struct proc *p, struct ktr_header *kth, const void *aux, size_t len)
595{
596 struct vnode *vp = p->p_p->ps_tracevp;
597 struct ucred *cred = p->p_p->ps_tracecred;
598 struct iovec data[2];
599 int error;
600
601 if (vp == NULL((void *)0))
602 return 0;
603 crhold(cred);
604 data[0].iov_base = (void *)aux;
605 data[0].iov_len = len;
606 data[1].iov_len = 0;
607 kth->ktr_len = len;
608 error = ktrwriteraw(p, vp, cred, kth, data);
609 crfree(cred);
610 return (error);
611}
612
613int
614ktrwrite2(struct proc *p, struct ktr_header *kth, const void *aux1,
615 size_t len1, const void *aux2, size_t len2)
616{
617 struct vnode *vp = p->p_p->ps_tracevp;
618 struct ucred *cred = p->p_p->ps_tracecred;
619 struct iovec data[2];
620 int error;
621
622 if (vp == NULL((void *)0))
623 return 0;
624 crhold(cred);
625 data[0].iov_base = (void *)aux1;
626 data[0].iov_len = len1;
627 data[1].iov_base = (void *)aux2;
628 data[1].iov_len = len2;
629 kth->ktr_len = len1 + len2;
630 error = ktrwriteraw(p, vp, cred, kth, data);
631 crfree(cred);
632 return (error);
633}
634
635int
636ktrwriteraw(struct proc *curp, struct vnode *vp, struct ucred *cred,
637 struct ktr_header *kth, struct iovec *data)
638{
639 struct uio auio;
640 struct iovec aiov[3];
641 struct process *pr;
642 int error;
643
644 KERNEL_ASSERT_LOCKED()((_kernel_lock_held()) ? (void)0 : __assert("diagnostic ", "/usr/src/sys/kern/kern_ktrace.c"
, 644, "_kernel_lock_held()"))
;
24
Assuming the condition is true
25
'?' condition is true
645
646 auio.uio_iov = &aiov[0];
647 auio.uio_offset = 0;
648 auio.uio_segflg = UIO_SYSSPACE;
649 auio.uio_rw = UIO_WRITE;
650 aiov[0].iov_base = (caddr_t)kth;
651 aiov[0].iov_len = sizeof(struct ktr_header);
652 auio.uio_resid = sizeof(struct ktr_header);
653 auio.uio_iovcnt = 1;
654 auio.uio_procp = curp;
655 if (kth->ktr_len > 0) {
26
Assuming field 'ktr_len' is > 0
27
Taking true branch
656 aiov[1] = data[0];
28
Array access (from variable 'data') results in a null pointer dereference
657 aiov[2] = data[1];
658 auio.uio_iovcnt++;
659 if (aiov[2].iov_len > 0)
660 auio.uio_iovcnt++;
661 auio.uio_resid += kth->ktr_len;
662 }
663 error = vget(vp, LK_EXCLUSIVE0x0001UL | LK_RETRY0x2000UL);
664 if (error)
665 goto bad;
666 error = VOP_WRITE(vp, &auio, IO_UNIT0x01|IO_APPEND0x02, cred);
667 vput(vp);
668 if (error)
669 goto bad;
670
671 return (0);
672
673bad:
674 /*
675 * If error encountered, give up tracing on this vnode.
676 */
677 log(LOG_NOTICE5, "ktrace write failed, errno %d, tracing stopped\n",
678 error);
679 LIST_FOREACH(pr, &allprocess, ps_list)for((pr) = ((&allprocess)->lh_first); (pr)!= ((void *)
0); (pr) = ((pr)->ps_list.le_next))
{
680 if (pr == curp->p_p)
681 continue;
682 if (pr->ps_tracevp == vp && pr->ps_tracecred == cred)
683 ktrcleartrace(pr);
684 }
685 ktrcleartrace(curp->p_p);
686 return (error);
687}
688
689/*
690 * Return true if caller has permission to set the ktracing state
691 * of target. Essentially, the target can't possess any
692 * more permissions than the caller. KTRFAC_ROOT signifies that
693 * root previously set the tracing status on the target process, and
694 * so, only root may further change it.
695 *
696 * TODO: check groups. use caller effective gid.
697 */
698int
699ktrcanset(struct proc *callp, struct process *targetpr)
700{
701 struct ucred *caller = callp->p_ucred;
702 struct ucred *target = targetpr->ps_ucred;
703
704 if ((caller->cr_uid == target->cr_ruid &&
705 target->cr_ruid == target->cr_svuid &&
706 caller->cr_rgid == target->cr_rgid && /* XXX */
707 target->cr_rgid == target->cr_svgid &&
708 (targetpr->ps_traceflag & KTRFAC_ROOT0x80000000U) == 0 &&
709 !ISSET(targetpr->ps_flags, PS_SUGID)((targetpr->ps_flags) & (0x00000010))) ||
710 caller->cr_uid == 0)
711 return (1);
712
713 return (0);
714}