1 /*-
2 * Copyright (c) 2011, David E. O'Brien.
3 * Copyright (c) 2009-2011, Juniper Networks, Inc.
4 * Copyright (c) 2015-2016, EMC Corp.
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY JUNIPER NETWORKS AND CONTRIBUTORS ``AS IS'' AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL JUNIPER NETWORKS OR CONTRIBUTORS BE LIABLE
20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
27 */
28
29 #include <sys/cdefs.h>
30 __FBSDID("$FreeBSD: releng/11.2/sys/dev/filemon/filemon_wrapper.c 331722 2018-03-29 02:50:57Z eadler $");
31
32 #include <sys/eventhandler.h>
33 #include <sys/filedesc.h>
34 #include <sys/imgact.h>
35 #include <sys/priv.h>
36 #include <sys/sx.h>
37 #include <sys/sysent.h>
38 #include <sys/vnode.h>
39
40 #include "opt_compat.h"
41
42 static eventhandler_tag filemon_exec_tag;
43 static eventhandler_tag filemon_exit_tag;
44 static eventhandler_tag filemon_fork_tag;
45
46 static void
47 filemon_output(struct filemon *filemon, char *msg, size_t len)
48 {
49 struct uio auio;
50 struct iovec aiov;
51 int error;
52
53 if (filemon->fp == NULL)
54 return;
55
56 aiov.iov_base = msg;
57 aiov.iov_len = len;
58 auio.uio_iov = &aiov;
59 auio.uio_iovcnt = 1;
60 auio.uio_resid = len;
61 auio.uio_segflg = UIO_SYSSPACE;
62 auio.uio_rw = UIO_WRITE;
63 auio.uio_td = curthread;
64 auio.uio_offset = (off_t) -1;
65
66 if (filemon->fp->f_type == DTYPE_VNODE)
67 bwillwrite();
68
69 error = fo_write(filemon->fp, &auio, filemon->cred, 0, curthread);
70 if (error != 0 && filemon->error == 0)
71 filemon->error = error;
72 }
73
74 static int
75 filemon_wrapper_chdir(struct thread *td, struct chdir_args *uap)
76 {
77 int error, ret;
78 size_t len;
79 struct filemon *filemon;
80
81 if ((ret = sys_chdir(td, uap)) == 0) {
82 if ((filemon = filemon_proc_get(curproc)) != NULL) {
83 if ((error = copyinstr(uap->path, filemon->fname1,
84 sizeof(filemon->fname1), NULL)) != 0) {
85 filemon->error = error;
86 goto copyfail;
87 }
88
89 len = snprintf(filemon->msgbufr,
90 sizeof(filemon->msgbufr), "C %d %s\n",
91 curproc->p_pid, filemon->fname1);
92
93 filemon_output(filemon, filemon->msgbufr, len);
94 copyfail:
95 filemon_drop(filemon);
96 }
97 }
98
99 return (ret);
100 }
101
102 static void
103 filemon_event_process_exec(void *arg __unused, struct proc *p,
104 struct image_params *imgp)
105 {
106 struct filemon *filemon;
107 size_t len;
108
109 if ((filemon = filemon_proc_get(p)) != NULL) {
110 len = snprintf(filemon->msgbufr,
111 sizeof(filemon->msgbufr), "E %d %s\n",
112 p->p_pid,
113 imgp->execpath != NULL ? imgp->execpath : "<unknown>");
114
115 filemon_output(filemon, filemon->msgbufr, len);
116
117 /* If the credentials changed then cease tracing. */
118 if (imgp->newcred != NULL &&
119 imgp->credential_setid &&
120 priv_check_cred(filemon->cred,
121 PRIV_DEBUG_DIFFCRED, 0) != 0) {
122 /*
123 * It may have changed to NULL already, but
124 * will not be re-attached by anything else.
125 */
126 if (p->p_filemon != NULL) {
127 KASSERT(p->p_filemon == filemon,
128 ("%s: proc %p didn't have expected"
129 " filemon %p", __func__, p, filemon));
130 filemon_proc_drop(p);
131 }
132 }
133
134
135 filemon_drop(filemon);
136 }
137 }
138
139 static void
140 _filemon_wrapper_openat(struct thread *td, char *upath, int flags, int fd)
141 {
142 int error;
143 size_t len;
144 struct file *fp;
145 struct filemon *filemon;
146 char *atpath, *freepath;
147 cap_rights_t rights;
148
149 if ((filemon = filemon_proc_get(curproc)) != NULL) {
150 atpath = "";
151 freepath = NULL;
152 fp = NULL;
153
154 if ((error = copyinstr(upath, filemon->fname1,
155 sizeof(filemon->fname1), NULL)) != 0) {
156 filemon->error = error;
157 goto copyfail;
158 }
159
160 if (filemon->fname1[0] != '/' && fd != AT_FDCWD) {
161 /*
162 * rats - we cannot do too much about this.
163 * the trace should show a dir we read
164 * recently.. output an A record as a clue
165 * until we can do better.
166 * XXX: This may be able to come out with
167 * the namecache lookup now.
168 */
169 len = snprintf(filemon->msgbufr,
170 sizeof(filemon->msgbufr), "A %d %s\n",
171 curproc->p_pid, filemon->fname1);
172 filemon_output(filemon, filemon->msgbufr, len);
173 /*
174 * Try to resolve the path from the vnode using the
175 * namecache. It may be inaccurate, but better
176 * than nothing.
177 */
178 if (getvnode(td, fd,
179 cap_rights_init(&rights, CAP_LOOKUP), &fp) == 0) {
180 vn_fullpath(td, fp->f_vnode, &atpath,
181 &freepath);
182 }
183 }
184 if (flags & O_RDWR) {
185 /*
186 * We'll get the W record below, but need
187 * to also output an R to distinguish from
188 * O_WRONLY.
189 */
190 len = snprintf(filemon->msgbufr,
191 sizeof(filemon->msgbufr), "R %d %s%s%s\n",
192 curproc->p_pid, atpath,
193 atpath[0] != '\0' ? "/" : "", filemon->fname1);
194 filemon_output(filemon, filemon->msgbufr, len);
195 }
196
197 len = snprintf(filemon->msgbufr,
198 sizeof(filemon->msgbufr), "%c %d %s%s%s\n",
199 (flags & O_ACCMODE) ? 'W':'R',
200 curproc->p_pid, atpath,
201 atpath[0] != '\0' ? "/" : "", filemon->fname1);
202 filemon_output(filemon, filemon->msgbufr, len);
203 copyfail:
204 filemon_drop(filemon);
205 if (fp != NULL)
206 fdrop(fp, td);
207 free(freepath, M_TEMP);
208 }
209 }
210
211 static int
212 filemon_wrapper_open(struct thread *td, struct open_args *uap)
213 {
214 int ret;
215
216 if ((ret = sys_open(td, uap)) == 0)
217 _filemon_wrapper_openat(td, uap->path, uap->flags, AT_FDCWD);
218
219 return (ret);
220 }
221
222 static int
223 filemon_wrapper_openat(struct thread *td, struct openat_args *uap)
224 {
225 int ret;
226
227 if ((ret = sys_openat(td, uap)) == 0)
228 _filemon_wrapper_openat(td, uap->path, uap->flag, uap->fd);
229
230 return (ret);
231 }
232
233 static int
234 filemon_wrapper_rename(struct thread *td, struct rename_args *uap)
235 {
236 int error, ret;
237 size_t len;
238 struct filemon *filemon;
239
240 if ((ret = sys_rename(td, uap)) == 0) {
241 if ((filemon = filemon_proc_get(curproc)) != NULL) {
242 if (((error = copyinstr(uap->from, filemon->fname1,
243 sizeof(filemon->fname1), NULL)) != 0) ||
244 ((error = copyinstr(uap->to, filemon->fname2,
245 sizeof(filemon->fname2), NULL)) != 0)) {
246 filemon->error = error;
247 goto copyfail;
248 }
249
250 len = snprintf(filemon->msgbufr,
251 sizeof(filemon->msgbufr), "M %d '%s' '%s'\n",
252 curproc->p_pid, filemon->fname1, filemon->fname2);
253
254 filemon_output(filemon, filemon->msgbufr, len);
255 copyfail:
256 filemon_drop(filemon);
257 }
258 }
259
260 return (ret);
261 }
262
263 static void
264 _filemon_wrapper_link(struct thread *td, char *upath1, char *upath2)
265 {
266 struct filemon *filemon;
267 size_t len;
268 int error;
269
270 if ((filemon = filemon_proc_get(curproc)) != NULL) {
271 if (((error = copyinstr(upath1, filemon->fname1,
272 sizeof(filemon->fname1), NULL)) != 0) ||
273 ((error = copyinstr(upath2, filemon->fname2,
274 sizeof(filemon->fname2), NULL)) != 0)) {
275 filemon->error = error;
276 goto copyfail;
277 }
278
279 len = snprintf(filemon->msgbufr,
280 sizeof(filemon->msgbufr), "L %d '%s' '%s'\n",
281 curproc->p_pid, filemon->fname1, filemon->fname2);
282
283 filemon_output(filemon, filemon->msgbufr, len);
284 copyfail:
285 filemon_drop(filemon);
286 }
287 }
288
289 static int
290 filemon_wrapper_link(struct thread *td, struct link_args *uap)
291 {
292 int ret;
293
294 if ((ret = sys_link(td, uap)) == 0)
295 _filemon_wrapper_link(td, uap->path, uap->link);
296
297 return (ret);
298 }
299
300 static int
301 filemon_wrapper_symlink(struct thread *td, struct symlink_args *uap)
302 {
303 int ret;
304
305 if ((ret = sys_symlink(td, uap)) == 0)
306 _filemon_wrapper_link(td, uap->path, uap->link);
307
308 return (ret);
309 }
310
311 static int
312 filemon_wrapper_linkat(struct thread *td, struct linkat_args *uap)
313 {
314 int ret;
315
316 if ((ret = sys_linkat(td, uap)) == 0)
317 _filemon_wrapper_link(td, uap->path1, uap->path2);
318
319 return (ret);
320 }
321
322 static void
323 filemon_event_process_exit(void *arg __unused, struct proc *p)
324 {
325 size_t len;
326 struct filemon *filemon;
327
328 if ((filemon = filemon_proc_get(p)) != NULL) {
329 len = snprintf(filemon->msgbufr, sizeof(filemon->msgbufr),
330 "X %d %d %d\n", p->p_pid, p->p_xexit, p->p_xsig);
331
332 filemon_output(filemon, filemon->msgbufr, len);
333
334 /*
335 * filemon_untrack_processes() may have dropped this p_filemon
336 * already while in filemon_proc_get() before acquiring the
337 * filemon lock.
338 */
339 KASSERT(p->p_filemon == NULL || p->p_filemon == filemon,
340 ("%s: p %p was attached while exiting, expected "
341 "filemon %p or NULL", __func__, p, filemon));
342 if (p->p_filemon == filemon)
343 filemon_proc_drop(p);
344
345 filemon_drop(filemon);
346 }
347 }
348
349 static int
350 filemon_wrapper_unlink(struct thread *td, struct unlink_args *uap)
351 {
352 int error, ret;
353 size_t len;
354 struct filemon *filemon;
355
356 if ((ret = sys_unlink(td, uap)) == 0) {
357 if ((filemon = filemon_proc_get(curproc)) != NULL) {
358 if ((error = copyinstr(uap->path, filemon->fname1,
359 sizeof(filemon->fname1), NULL)) != 0) {
360 filemon->error = error;
361 goto copyfail;
362 }
363
364 len = snprintf(filemon->msgbufr,
365 sizeof(filemon->msgbufr), "D %d %s\n",
366 curproc->p_pid, filemon->fname1);
367
368 filemon_output(filemon, filemon->msgbufr, len);
369 copyfail:
370 filemon_drop(filemon);
371 }
372 }
373
374 return (ret);
375 }
376
377 static void
378 filemon_event_process_fork(void *arg __unused, struct proc *p1,
379 struct proc *p2, int flags __unused)
380 {
381 size_t len;
382 struct filemon *filemon;
383
384 if ((filemon = filemon_proc_get(p1)) != NULL) {
385 len = snprintf(filemon->msgbufr,
386 sizeof(filemon->msgbufr), "F %d %d\n",
387 p1->p_pid, p2->p_pid);
388
389 filemon_output(filemon, filemon->msgbufr, len);
390
391 /*
392 * filemon_untrack_processes() or
393 * filemon_ioctl(FILEMON_SET_PID) may have changed the parent's
394 * p_filemon while in filemon_proc_get() before acquiring the
395 * filemon lock. Only inherit if the parent is still traced by
396 * this filemon.
397 */
398 if (p1->p_filemon == filemon) {
399 PROC_LOCK(p2);
400 /*
401 * It may have been attached to already by a new
402 * filemon.
403 */
404 if (p2->p_filemon == NULL) {
405 p2->p_filemon = filemon_acquire(filemon);
406 ++filemon->proccnt;
407 }
408 PROC_UNLOCK(p2);
409 }
410
411 filemon_drop(filemon);
412 }
413 }
414
415 static void
416 filemon_wrapper_install(void)
417 {
418
419 sysent[SYS_chdir].sy_call = (sy_call_t *) filemon_wrapper_chdir;
420 sysent[SYS_open].sy_call = (sy_call_t *) filemon_wrapper_open;
421 sysent[SYS_openat].sy_call = (sy_call_t *) filemon_wrapper_openat;
422 sysent[SYS_rename].sy_call = (sy_call_t *) filemon_wrapper_rename;
423 sysent[SYS_unlink].sy_call = (sy_call_t *) filemon_wrapper_unlink;
424 sysent[SYS_link].sy_call = (sy_call_t *) filemon_wrapper_link;
425 sysent[SYS_symlink].sy_call = (sy_call_t *) filemon_wrapper_symlink;
426 sysent[SYS_linkat].sy_call = (sy_call_t *) filemon_wrapper_linkat;
427
428 #if defined(COMPAT_FREEBSD32)
429 freebsd32_sysent[FREEBSD32_SYS_chdir].sy_call = (sy_call_t *) filemon_wrapper_chdir;
430 freebsd32_sysent[FREEBSD32_SYS_open].sy_call = (sy_call_t *) filemon_wrapper_open;
431 freebsd32_sysent[FREEBSD32_SYS_openat].sy_call = (sy_call_t *) filemon_wrapper_openat;
432 freebsd32_sysent[FREEBSD32_SYS_rename].sy_call = (sy_call_t *) filemon_wrapper_rename;
433 freebsd32_sysent[FREEBSD32_SYS_unlink].sy_call = (sy_call_t *) filemon_wrapper_unlink;
434 freebsd32_sysent[FREEBSD32_SYS_link].sy_call = (sy_call_t *) filemon_wrapper_link;
435 freebsd32_sysent[FREEBSD32_SYS_symlink].sy_call = (sy_call_t *) filemon_wrapper_symlink;
436 freebsd32_sysent[FREEBSD32_SYS_linkat].sy_call = (sy_call_t *) filemon_wrapper_linkat;
437 #endif /* COMPAT_FREEBSD32 */
438
439 filemon_exec_tag = EVENTHANDLER_REGISTER(process_exec,
440 filemon_event_process_exec, NULL, EVENTHANDLER_PRI_LAST);
441 filemon_exit_tag = EVENTHANDLER_REGISTER(process_exit,
442 filemon_event_process_exit, NULL, EVENTHANDLER_PRI_LAST);
443 filemon_fork_tag = EVENTHANDLER_REGISTER(process_fork,
444 filemon_event_process_fork, NULL, EVENTHANDLER_PRI_LAST);
445 }
446
447 static void
448 filemon_wrapper_deinstall(void)
449 {
450
451 sysent[SYS_chdir].sy_call = (sy_call_t *)sys_chdir;
452 sysent[SYS_open].sy_call = (sy_call_t *)sys_open;
453 sysent[SYS_openat].sy_call = (sy_call_t *)sys_openat;
454 sysent[SYS_rename].sy_call = (sy_call_t *)sys_rename;
455 sysent[SYS_unlink].sy_call = (sy_call_t *)sys_unlink;
456 sysent[SYS_link].sy_call = (sy_call_t *)sys_link;
457 sysent[SYS_symlink].sy_call = (sy_call_t *)sys_symlink;
458 sysent[SYS_linkat].sy_call = (sy_call_t *)sys_linkat;
459
460 #if defined(COMPAT_FREEBSD32)
461 freebsd32_sysent[FREEBSD32_SYS_chdir].sy_call = (sy_call_t *)sys_chdir;
462 freebsd32_sysent[FREEBSD32_SYS_open].sy_call = (sy_call_t *)sys_open;
463 freebsd32_sysent[FREEBSD32_SYS_openat].sy_call = (sy_call_t *)sys_openat;
464 freebsd32_sysent[FREEBSD32_SYS_rename].sy_call = (sy_call_t *)sys_rename;
465 freebsd32_sysent[FREEBSD32_SYS_unlink].sy_call = (sy_call_t *)sys_unlink;
466 freebsd32_sysent[FREEBSD32_SYS_link].sy_call = (sy_call_t *)sys_link;
467 freebsd32_sysent[FREEBSD32_SYS_symlink].sy_call = (sy_call_t *)sys_symlink;
468 freebsd32_sysent[FREEBSD32_SYS_linkat].sy_call = (sy_call_t *)sys_linkat;
469 #endif /* COMPAT_FREEBSD32 */
470
471 EVENTHANDLER_DEREGISTER(process_exec, filemon_exec_tag);
472 EVENTHANDLER_DEREGISTER(process_exit, filemon_exit_tag);
473 EVENTHANDLER_DEREGISTER(process_fork, filemon_fork_tag);
474 }
Cache object: d987d505eede8a09d706baa74bd3b89e
|