Bug Summary

File:kern/kern_ktrace.c
Warning:line 672, 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.4 -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name kern_ktrace.c -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 -ffp-contract=on -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 -target-feature +retpoline-external-thunk -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/llvm16/lib/clang/16 -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/legacy-dpm -I /usr/src/sys/dev/pci/drm/amd/pm/swsmu -I /usr/src/sys/dev/pci/drm/amd/pm/swsmu/inc -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/swsmu/smu13 -I /usr/src/sys/dev/pci/drm/amd/pm/powerplay/inc -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/pm/swsmu/inc -I /usr/src/sys/dev/pci/drm/amd/pm/swsmu/inc/pmfw_if -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 SUSPEND -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 -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 -fcf-protection=branch -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 /home/ben/Projects/scan/2024-01-11-110808-61670-1 -x c /usr/src/sys/kern/kern_ktrace.c
1/* $OpenBSD: kern_ktrace.c,v 1.114 2023/12/15 15:12:08 deraadt 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
53void ktrinitheaderraw(struct ktr_header *, uint, pid_t, pid_t);
54void ktrinitheader(struct ktr_header *, struct proc *, int);
55int ktrstart(struct proc *, struct vnode *, struct ucred *);
56int ktrops(struct proc *, struct process *, int, int, struct vnode *,
57 struct ucred *);
58int ktrsetchildren(struct proc *, struct process *, int, int,
59 struct vnode *, struct ucred *);
60int ktrwrite(struct proc *, struct ktr_header *, const void *, size_t);
61int ktrwrite2(struct proc *, struct ktr_header *, const void *, size_t,
62 const void *, size_t);
63int ktrwriteraw(struct proc *, struct vnode *, struct ucred *,
64 struct ktr_header *, struct iovec *);
65int ktrcanset(struct proc *, struct process *);
66
67/*
68 * Clear the trace settings in a correct way (to avoid races).
69 */
70void
71ktrcleartrace(struct process *pr)
72{
73 struct vnode *vp;
74 struct ucred *cred;
75
76 if (pr->ps_tracevp != NULL((void *)0)) {
77 vp = pr->ps_tracevp;
78 cred = pr->ps_tracecred;
79
80 pr->ps_traceflag = 0;
81 pr->ps_tracevp = NULL((void *)0);
82 pr->ps_tracecred = NULL((void *)0);
83
84 vp->v_writecount--;
85 vrele(vp);
86 crfree(cred);
87 }
88}
89
90/*
91 * Change the trace setting in a correct way (to avoid races).
92 */
93void
94ktrsettrace(struct process *pr, int facs, struct vnode *newvp,
95 struct ucred *newcred)
96{
97 struct vnode *oldvp;
98 struct ucred *oldcred;
99
100 KASSERT(newvp != NULL)((newvp != ((void *)0)) ? (void)0 : __assert("diagnostic ", "/usr/src/sys/kern/kern_ktrace.c"
, 100, "newvp != NULL"))
;
101 KASSERT(newcred != NULL)((newcred != ((void *)0)) ? (void)0 : __assert("diagnostic ",
"/usr/src/sys/kern/kern_ktrace.c", 101, "newcred != NULL"))
;
102
103 pr->ps_traceflag |= facs;
104
105 /* nothing to change about where the trace goes? */
106 if (pr->ps_tracevp == newvp && pr->ps_tracecred == newcred)
107 return;
108
109 vref(newvp);
110 crhold(newcred);
111 newvp->v_writecount++;
112
113 oldvp = pr->ps_tracevp;
114 oldcred = pr->ps_tracecred;
115
116 pr->ps_tracevp = newvp;
117 pr->ps_tracecred = newcred;
118
119 if (oldvp != NULL((void *)0)) {
120 oldvp->v_writecount--;
121 vrele(oldvp);
122 crfree(oldcred);
123 }
124}
125
126void
127ktrinitheaderraw(struct ktr_header *kth, uint type, pid_t pid, pid_t tid)
128{
129 memset(kth, 0, sizeof(struct ktr_header))__builtin_memset((kth), (0), (sizeof(struct ktr_header)));
130 kth->ktr_type = type;
131 kth->ktr_pid = pid;
132 kth->ktr_tid = tid;
133}
134
135void
136ktrinitheader(struct ktr_header *kth, struct proc *p, int type)
137{
138 struct process *pr = p->p_p;
139
140 ktrinitheaderraw(kth, type, pr->ps_pid, p->p_tid + THREAD_PID_OFFSET100000);
141 memcpy(kth->ktr_comm, pr->ps_comm, sizeof(kth->ktr_comm))__builtin_memcpy((kth->ktr_comm), (pr->ps_comm), (sizeof
(kth->ktr_comm)))
;
142}
143
144int
145ktrstart(struct proc *p, struct vnode *vp, struct ucred *cred)
146{
147 struct ktr_header kth;
148
149 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
150 return (ktrwriteraw(p, vp, cred, &kth, NULL((void *)0)));
22
Passing null pointer value via 5th parameter 'data'
23
Calling 'ktrwriteraw'
151}
152
153void
154ktrsyscall(struct proc *p, register_t code, size_t argsize, register_t args[])
155{
156 struct ktr_header kth;
157 struct ktr_syscall *ktp;
158 size_t len = sizeof(struct ktr_syscall) + argsize;
159 register_t *argp;
160 u_int nargs = 0;
161 int i;
162
163 if (code == SYS_sysctl202) {
164 /*
165 * The sysctl encoding stores the mib[]
166 * array because it is interesting.
167 */
168 if (args[1] > 0)
169 nargs = lmin(args[1], CTL_MAXNAME12);
170 len += nargs * sizeof(int);
171 }
172 atomic_setbits_intx86_atomic_setbits_u32(&p->p_flag, P_INKTR0x00000001);
173 ktrinitheader(&kth, p, KTR_SYSCALL1);
174 ktp = malloc(len, M_TEMP127, M_WAITOK0x0001);
175 ktp->ktr_code = code;
176 ktp->ktr_argsize = argsize;
177 argp = (register_t *)((char *)ktp + sizeof(struct ktr_syscall));
178 for (i = 0; i < (argsize / sizeof *argp); i++)
179 *argp++ = args[i];
180 if (nargs && copyin((void *)args[0], argp, nargs * sizeof(int)))
181 memset(argp, 0, nargs * sizeof(int))__builtin_memset((argp), (0), (nargs * sizeof(int)));
182 ktrwrite(p, &kth, ktp, len);
183 free(ktp, M_TEMP127, len);
184 atomic_clearbits_intx86_atomic_clearbits_u32(&p->p_flag, P_INKTR0x00000001);
185}
186
187void
188ktrsysret(struct proc *p, register_t code, int error,
189 const register_t retval[2])
190{
191 struct ktr_header kth;
192 struct ktr_sysret ktp;
193 int len;
194
195 atomic_setbits_intx86_atomic_setbits_u32(&p->p_flag, P_INKTR0x00000001);
196 ktrinitheader(&kth, p, KTR_SYSRET2);
197 ktp.ktr_code = code;
198 ktp.ktr_error = error;
199 if (error)
200 len = 0;
201 else if (code == SYS_lseek166)
202 /* the one exception: lseek on ILP32 needs more */
203 len = sizeof(long long);
204 else
205 len = sizeof(register_t);
206 ktrwrite2(p, &kth, &ktp, sizeof(ktp), retval, len);
207 atomic_clearbits_intx86_atomic_clearbits_u32(&p->p_flag, P_INKTR0x00000001);
208}
209
210void
211ktrnamei(struct proc *p, char *path)
212{
213 struct ktr_header kth;
214
215 atomic_setbits_intx86_atomic_setbits_u32(&p->p_flag, P_INKTR0x00000001);
216 ktrinitheader(&kth, p, KTR_NAMEI3);
217 ktrwrite(p, &kth, path, strlen(path));
218 atomic_clearbits_intx86_atomic_clearbits_u32(&p->p_flag, P_INKTR0x00000001);
219}
220
221void
222ktrgenio(struct proc *p, int fd, enum uio_rw rw, struct iovec *iov,
223 ssize_t len)
224{
225 struct ktr_header kth;
226 struct ktr_genio ktp;
227 caddr_t cp;
228 int count, error;
229 int buflen;
230
231 atomic_setbits_intx86_atomic_setbits_u32(&p->p_flag, P_INKTR0x00000001);
232
233 /* beware overflow */
234 if (len > PAGE_SIZE(1 << 12))
235 buflen = PAGE_SIZE(1 << 12);
236 else
237 buflen = len + sizeof(struct ktr_genio);
238
239 ktrinitheader(&kth, p, KTR_GENIO4);
240 ktp.ktr_fd = fd;
241 ktp.ktr_rw = rw;
242
243 cp = malloc(buflen, M_TEMP127, M_WAITOK0x0001);
244 while (len > 0) {
245 /*
246 * Don't allow this process to hog the cpu when doing
247 * huge I/O.
248 */
249 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)
;
250
251 count = lmin(iov->iov_len, buflen);
252 if (count > len)
253 count = len;
254 if (copyin(iov->iov_base, cp, count))
255 break;
256
257 KERNEL_LOCK()_kernel_lock();
258 error = ktrwrite2(p, &kth, &ktp, sizeof(ktp), cp, count);
259 KERNEL_UNLOCK()_kernel_unlock();
260 if (error != 0)
261 break;
262
263 iov->iov_len -= count;
264 iov->iov_base = (caddr_t)iov->iov_base + count;
265
266 if (iov->iov_len == 0)
267 iov++;
268
269 len -= count;
270 }
271
272 free(cp, M_TEMP127, buflen);
273 atomic_clearbits_intx86_atomic_clearbits_u32(&p->p_flag, P_INKTR0x00000001);
274}
275
276void
277ktrpsig(struct proc *p, int sig, sig_t action, int mask, int code,
278 siginfo_t *si)
279{
280 struct ktr_header kth;
281 struct ktr_psig kp;
282
283 atomic_setbits_intx86_atomic_setbits_u32(&p->p_flag, P_INKTR0x00000001);
284 ktrinitheader(&kth, p, KTR_PSIG5);
285 kp.signo = (char)sig;
286 kp.action = action;
287 kp.mask = mask;
288 kp.code = code;
289 kp.si = *si;
290
291 KERNEL_LOCK()_kernel_lock();
292 ktrwrite(p, &kth, &kp, sizeof(kp));
293 KERNEL_UNLOCK()_kernel_unlock();
294 atomic_clearbits_intx86_atomic_clearbits_u32(&p->p_flag, P_INKTR0x00000001);
295}
296
297void
298ktrstruct(struct proc *p, const char *name, const void *data, size_t datalen)
299{
300 struct ktr_header kth;
301
302 atomic_setbits_intx86_atomic_setbits_u32(&p->p_flag, P_INKTR0x00000001);
303 ktrinitheader(&kth, p, KTR_STRUCT8);
304
305 if (data == NULL((void *)0))
306 datalen = 0;
307 KERNEL_LOCK()_kernel_lock();
308 ktrwrite2(p, &kth, name, strlen(name) + 1, data, datalen);
309 KERNEL_UNLOCK()_kernel_unlock();
310 atomic_clearbits_intx86_atomic_clearbits_u32(&p->p_flag, P_INKTR0x00000001);
311}
312
313int
314ktruser(struct proc *p, const char *id, const void *addr, size_t len)
315{
316 struct ktr_header kth;
317 struct ktr_user ktp;
318 int error;
319 void *memp;
320#define STK_PARAMS128 128
321 long long stkbuf[STK_PARAMS128 / sizeof(long long)];
322
323 if (!KTRPOINT(p, KTR_USER)((p)->p_p->ps_traceflag & (1<<(9)) &&
((p)->p_flag & 0x00000001) == 0)
)
324 return (0);
325 if (len > KTR_USER_MAXLEN2048)
326 return (EINVAL22);
327
328 atomic_setbits_intx86_atomic_setbits_u32(&p->p_flag, P_INKTR0x00000001);
329 ktrinitheader(&kth, p, KTR_USER9);
330 memset(ktp.ktr_id, 0, KTR_USER_MAXIDLEN)__builtin_memset((ktp.ktr_id), (0), (20));
331 error = copyinstr(id, ktp.ktr_id, KTR_USER_MAXIDLEN20, NULL((void *)0));
332 if (error == 0) {
333 if (len > sizeof(stkbuf))
334 memp = malloc(len, M_TEMP127, M_WAITOK0x0001);
335 else
336 memp = stkbuf;
337 error = copyin(addr, memp, len);
338 if (error == 0) {
339 KERNEL_LOCK()_kernel_lock();
340 ktrwrite2(p, &kth, &ktp, sizeof(ktp), memp, len);
341 KERNEL_UNLOCK()_kernel_unlock();
342 }
343 if (memp != stkbuf)
344 free(memp, M_TEMP127, len);
345 }
346 atomic_clearbits_intx86_atomic_clearbits_u32(&p->p_flag, P_INKTR0x00000001);
347 return (error);
348}
349
350void
351ktrexec(struct proc *p, int type, const char *data, ssize_t len)
352{
353 struct ktr_header kth;
354 int count;
355 int buflen;
356
357 assert(type == KTR_EXECARGS || type == KTR_EXECENV)((type == 10 || type == 11) ? (void)0 : __assert("", "/usr/src/sys/kern/kern_ktrace.c"
, 357, "type == KTR_EXECARGS || type == KTR_EXECENV"))
;
358 atomic_setbits_intx86_atomic_setbits_u32(&p->p_flag, P_INKTR0x00000001);
359
360 /* beware overflow */
361 if (len > PAGE_SIZE(1 << 12))
362 buflen = PAGE_SIZE(1 << 12);
363 else
364 buflen = len;
365
366 ktrinitheader(&kth, p, type);
367
368 while (len > 0) {
369 /*
370 * Don't allow this process to hog the cpu when doing
371 * huge I/O.
372 */
373 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)
;
374
375 count = lmin(len, buflen);
376 if (ktrwrite(p, &kth, data, count) != 0)
377 break;
378
379 len -= count;
380 data += count;
381 }
382
383 atomic_clearbits_intx86_atomic_clearbits_u32(&p->p_flag, P_INKTR0x00000001);
384}
385
386void
387ktrpledge(struct proc *p, int error, uint64_t code, int syscall)
388{
389 struct ktr_header kth;
390 struct ktr_pledge kp;
391
392 atomic_setbits_intx86_atomic_setbits_u32(&p->p_flag, P_INKTR0x00000001);
393 ktrinitheader(&kth, p, KTR_PLEDGE12);
394 kp.error = error;
395 kp.code = code;
396 kp.syscall = syscall;
397
398 KERNEL_LOCK()_kernel_lock();
399 ktrwrite(p, &kth, &kp, sizeof(kp));
400 KERNEL_UNLOCK()_kernel_unlock();
401 atomic_clearbits_intx86_atomic_clearbits_u32(&p->p_flag, P_INKTR0x00000001);
402}
403
404void
405ktrpinsyscall(struct proc *p, int error, int syscall, vaddr_t addr)
406{
407 struct ktr_header kth;
408 struct ktr_pinsyscall kp;
409
410 atomic_setbits_intx86_atomic_setbits_u32(&p->p_flag, P_INKTR0x00000001);
411 ktrinitheader(&kth, p, KTR_PINSYSCALL13);
412 kp.error = error;
413 kp.syscall = syscall;
414 kp.addr = addr;
415
416 KERNEL_LOCK()_kernel_lock();
417 ktrwrite(p, &kth, &kp, sizeof(kp));
418 KERNEL_UNLOCK()_kernel_unlock();
419 atomic_clearbits_intx86_atomic_clearbits_u32(&p->p_flag, P_INKTR0x00000001);
420}
421
422/* Interface and common routines */
423
424int
425doktrace(struct vnode *vp, int ops, int facs, pid_t pid, struct proc *p)
426{
427 struct process *pr = NULL((void *)0);
428 struct ucred *cred = NULL((void *)0);
429 struct pgrp *pg;
430 int descend = ops & KTRFLAG_DESCEND4;
431 int ret = 0;
432 int error = 0;
433
434 facs = facs & ~((unsigned)KTRFAC_ROOT0x80000000U);
435 ops = KTROP(ops)((ops)&3);
436
437 if (ops != KTROP_CLEAR1) {
6
Assuming 'ops' is not equal to KTROP_CLEAR
7
Taking true branch
438 /*
439 * an operation which requires a file argument.
440 */
441 cred = p->p_ucred;
442 if (!vp) {
8
Assuming 'vp' is non-null
9
Taking false branch
443 error = EINVAL22;
444 goto done;
445 }
446 if (vp->v_type != VREG) {
10
Assuming field 'v_type' is equal to VREG
11
Taking false branch
447 error = EACCES13;
448 goto done;
449 }
450 }
451 /*
452 * Clear all uses of the tracefile
453 */
454 if (ops == KTROP_CLEARFILE2) {
12
Assuming 'ops' is not equal to KTROP_CLEARFILE
13
Taking false branch
455 LIST_FOREACH(pr, &allprocess, ps_list)for((pr) = ((&allprocess)->lh_first); (pr)!= ((void *)
0); (pr) = ((pr)->ps_list.le_next))
{
456 if (pr->ps_tracevp == vp) {
457 if (ktrcanset(p, pr))
458 ktrcleartrace(pr);
459 else
460 error = EPERM1;
461 }
462 }
463 goto done;
464 }
465 /*
466 * need something to (un)trace (XXX - why is this here?)
467 */
468 if (!facs) {
14
Assuming 'facs' is not equal to 0
15
Taking false branch
469 error = EINVAL22;
470 goto done;
471 }
472 if (ops == KTROP_SET0) {
16
Assuming 'ops' is equal to KTROP_SET
17
Taking true branch
473 if (suser(p) == 0)
18
Assuming the condition is false
19
Taking false branch
474 facs |= KTRFAC_ROOT0x80000000U;
475 error = ktrstart(p, vp, cred);
20
Calling 'ktrstart'
476 if (error != 0)
477 goto done;
478 }
479 /*
480 * do it
481 */
482 if (pid < 0) {
483 /*
484 * by process group
485 */
486 pg = pgfind(-pid);
487 if (pg == NULL((void *)0)) {
488 error = ESRCH3;
489 goto done;
490 }
491 LIST_FOREACH(pr, &pg->pg_members, ps_pglist)for((pr) = ((&pg->pg_members)->lh_first); (pr)!= ((
void *)0); (pr) = ((pr)->ps_pglist.le_next))
{
492 if (descend)
493 ret |= ktrsetchildren(p, pr, ops, facs, vp,
494 cred);
495 else
496 ret |= ktrops(p, pr, ops, facs, vp, cred);
497 }
498 } else {
499 /*
500 * by pid
501 */
502 pr = prfind(pid);
503 if (pr == NULL((void *)0)) {
504 error = ESRCH3;
505 goto done;
506 }
507 if (descend)
508 ret |= ktrsetchildren(p, pr, ops, facs, vp, cred);
509 else
510 ret |= ktrops(p, pr, ops, facs, vp, cred);
511 }
512 if (!ret)
513 error = EPERM1;
514done:
515 return (error);
516}
517
518/*
519 * ktrace system call
520 */
521int
522sys_ktrace(struct proc *p, void *v, register_t *retval)
523{
524 struct sys_ktrace_args /* {
525 syscallarg(const char *) fname;
526 syscallarg(int) ops;
527 syscallarg(int) facs;
528 syscallarg(pid_t) pid;
529 } */ *uap = v;
530 struct vnode *vp = NULL((void *)0);
531 const char *fname = SCARG(uap, fname)((uap)->fname.le.datum);
532 struct ucred *cred = NULL((void *)0);
533 int error;
534
535 if (fname) {
1
Assuming 'fname' is non-null
2
Taking true branch
536 struct nameidata nd;
537
538 cred = p->p_ucred;
539 NDINIT(&nd, 0, 0, UIO_USERSPACE, fname, p)ndinitat(&nd, 0, 0, UIO_USERSPACE, -100, fname, p);
540 nd.ni_pledge = PLEDGE_CPATH0x0000000000000004ULL | PLEDGE_WPATH0x0000000000000002ULL;
541 nd.ni_unveil = UNVEIL_CREATE0x04 | UNVEIL_WRITE0x02;
542 if ((error = vn_open(&nd, FWRITE0x0002|O_NOFOLLOW0x0100, 0)) != 0)
3
Assuming the condition is false
4
Taking false branch
543 return error;
544 vp = nd.ni_vp;
545
546 VOP_UNLOCK(vp);
547 }
548
549 error = doktrace(vp, SCARG(uap, ops)((uap)->ops.le.datum), SCARG(uap, facs)((uap)->facs.le.datum),
5
Calling 'doktrace'
550 SCARG(uap, pid)((uap)->pid.le.datum), p);
551 if (vp != NULL((void *)0))
552 (void)vn_close(vp, FWRITE0x0002, cred, p);
553
554 return error;
555}
556
557int
558ktrops(struct proc *curp, struct process *pr, int ops, int facs,
559 struct vnode *vp, struct ucred *cred)
560{
561 if (!ktrcanset(curp, pr))
562 return (0);
563 if (ops == KTROP_SET0)
564 ktrsettrace(pr, facs, vp, cred);
565 else {
566 /* KTROP_CLEAR */
567 pr->ps_traceflag &= ~facs;
568 if ((pr->ps_traceflag & KTRFAC_MASK0x00ffffff) == 0) {
569 /* cleared all the facility bits, so stop completely */
570 ktrcleartrace(pr);
571 }
572 }
573
574 return (1);
575}
576
577int
578ktrsetchildren(struct proc *curp, struct process *top, int ops, int facs,
579 struct vnode *vp, struct ucred *cred)
580{
581 struct process *pr;
582 int ret = 0;
583
584 pr = top;
585 for (;;) {
586 ret |= ktrops(curp, pr, ops, facs, vp, cred);
587 /*
588 * If this process has children, descend to them next,
589 * otherwise do any siblings, and if done with this level,
590 * follow back up the tree (but not past top).
591 */
592 if (!LIST_EMPTY(&pr->ps_children)(((&pr->ps_children)->lh_first) == ((void *)0)))
593 pr = LIST_FIRST(&pr->ps_children)((&pr->ps_children)->lh_first);
594 else for (;;) {
595 if (pr == top)
596 return (ret);
597 if (LIST_NEXT(pr, ps_sibling)((pr)->ps_sibling.le_next) != NULL((void *)0)) {
598 pr = LIST_NEXT(pr, ps_sibling)((pr)->ps_sibling.le_next);
599 break;
600 }
601 pr = pr->ps_pptr;
602 }
603 }
604 /*NOTREACHED*/
605}
606
607int
608ktrwrite(struct proc *p, struct ktr_header *kth, const void *aux, size_t len)
609{
610 struct vnode *vp = p->p_p->ps_tracevp;
611 struct ucred *cred = p->p_p->ps_tracecred;
612 struct iovec data[2];
613 int error;
614
615 if (vp == NULL((void *)0))
616 return 0;
617 crhold(cred);
618 data[0].iov_base = (void *)aux;
619 data[0].iov_len = len;
620 data[1].iov_len = 0;
621 kth->ktr_len = len;
622 error = ktrwriteraw(p, vp, cred, kth, data);
623 crfree(cred);
624 return (error);
625}
626
627int
628ktrwrite2(struct proc *p, struct ktr_header *kth, const void *aux1,
629 size_t len1, const void *aux2, size_t len2)
630{
631 struct vnode *vp = p->p_p->ps_tracevp;
632 struct ucred *cred = p->p_p->ps_tracecred;
633 struct iovec data[2];
634 int error;
635
636 if (vp == NULL((void *)0))
637 return 0;
638 crhold(cred);
639 data[0].iov_base = (void *)aux1;
640 data[0].iov_len = len1;
641 data[1].iov_base = (void *)aux2;
642 data[1].iov_len = len2;
643 kth->ktr_len = len1 + len2;
644 error = ktrwriteraw(p, vp, cred, kth, data);
645 crfree(cred);
646 return (error);
647}
648
649int
650ktrwriteraw(struct proc *curp, struct vnode *vp, struct ucred *cred,
651 struct ktr_header *kth, struct iovec *data)
652{
653 struct uio auio;
654 struct iovec aiov[3];
655 struct process *pr;
656 int error;
657
658 nanotime(&kth->ktr_time);
659
660 KERNEL_ASSERT_LOCKED()((_kernel_lock_held()) ? (void)0 : __assert("diagnostic ", "/usr/src/sys/kern/kern_ktrace.c"
, 660, "_kernel_lock_held()"))
;
24
Assuming the condition is true
25
'?' condition is true
661
662 auio.uio_iov = &aiov[0];
663 auio.uio_offset = 0;
664 auio.uio_segflg = UIO_SYSSPACE;
665 auio.uio_rw = UIO_WRITE;
666 aiov[0].iov_base = (caddr_t)kth;
667 aiov[0].iov_len = sizeof(struct ktr_header);
668 auio.uio_resid = sizeof(struct ktr_header);
669 auio.uio_iovcnt = 1;
670 auio.uio_procp = curp;
671 if (kth->ktr_len > 0) {
26
Assuming field 'ktr_len' is > 0
27
Taking true branch
672 aiov[1] = data[0];
28
Array access (from variable 'data') results in a null pointer dereference
673 aiov[2] = data[1];
674 auio.uio_iovcnt++;
675 if (aiov[2].iov_len > 0)
676 auio.uio_iovcnt++;
677 auio.uio_resid += kth->ktr_len;
678 }
679 error = vget(vp, LK_EXCLUSIVE0x0001UL | LK_RETRY0x2000UL);
680 if (error)
681 goto bad;
682 error = VOP_WRITE(vp, &auio, IO_UNIT0x01|IO_APPEND0x02, cred);
683 vput(vp);
684 if (error)
685 goto bad;
686
687 return (0);
688
689bad:
690 /*
691 * If error encountered, give up tracing on this vnode.
692 */
693 log(LOG_NOTICE5, "ktrace write failed, errno %d, tracing stopped\n",
694 error);
695 LIST_FOREACH(pr, &allprocess, ps_list)for((pr) = ((&allprocess)->lh_first); (pr)!= ((void *)
0); (pr) = ((pr)->ps_list.le_next))
{
696 if (pr == curp->p_p)
697 continue;
698 if (pr->ps_tracevp == vp && pr->ps_tracecred == cred)
699 ktrcleartrace(pr);
700 }
701 ktrcleartrace(curp->p_p);
702 return (error);
703}
704
705/*
706 * Return true if caller has permission to set the ktracing state
707 * of target. Essentially, the target can't possess any
708 * more permissions than the caller. KTRFAC_ROOT signifies that
709 * root previously set the tracing status on the target process, and
710 * so, only root may further change it.
711 *
712 * TODO: check groups. use caller effective gid.
713 */
714int
715ktrcanset(struct proc *callp, struct process *targetpr)
716{
717 struct ucred *caller = callp->p_ucred;
718 struct ucred *target = targetpr->ps_ucred;
719
720 if ((caller->cr_uid == target->cr_ruid &&
721 target->cr_ruid == target->cr_svuid &&
722 caller->cr_rgid == target->cr_rgid && /* XXX */
723 target->cr_rgid == target->cr_svgid &&
724 (targetpr->ps_traceflag & KTRFAC_ROOT0x80000000U) == 0 &&
725 !ISSET(targetpr->ps_flags, PS_SUGID)((targetpr->ps_flags) & (0x00000010))) ||
726 caller->cr_uid == 0)
727 return (1);
728
729 return (0);
730}