]> CyberLeo.Net >> Repos - FreeBSD/stable/9.git/blob - sys/dev/filemon/filemon_wrapper.c
MFC r336438
[FreeBSD/stable/9.git] / sys / dev / filemon / filemon_wrapper.c
1 /*-
2  * Copyright (c) 2011, David E. O'Brien.
3  * Copyright (c) 2009-2011, Juniper Networks, Inc.
4  * Copyright (c) 2015, 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$");
31
32 #include <sys/imgact.h>
33 #include <sys/eventhandler.h>
34 #include <sys/sx.h>
35 #include <sys/vnode.h>
36
37 #include "opt_compat.h"
38
39 static eventhandler_tag filemon_exec_tag;
40 static eventhandler_tag filemon_exit_tag;
41 static eventhandler_tag filemon_fork_tag;
42
43 static void
44 filemon_output(struct filemon *filemon, char *msg, size_t len)
45 {
46         struct uio auio;
47         struct iovec aiov;
48
49         if (filemon->fp == NULL)
50                 return;
51
52         aiov.iov_base = msg;
53         aiov.iov_len = len;
54         auio.uio_iov = &aiov;
55         auio.uio_iovcnt = 1;
56         auio.uio_resid = len;
57         auio.uio_segflg = UIO_SYSSPACE;
58         auio.uio_rw = UIO_WRITE;
59         auio.uio_td = curthread;
60         auio.uio_offset = (off_t) -1;
61
62         if (filemon->fp->f_type == DTYPE_VNODE)
63                 bwillwrite();
64
65         fo_write(filemon->fp, &auio, curthread->td_ucred, 0, curthread);
66 }
67
68 static struct filemon *
69 filemon_pid_check(struct proc *p)
70 {
71         struct filemon *filemon;
72
73         filemon_lock_read();
74         if (TAILQ_EMPTY(&filemons_inuse)) {
75                 filemon_unlock_read();
76                 return (NULL);
77         }
78         sx_slock(&proctree_lock);
79         while (p->p_pid != 0) {
80                 TAILQ_FOREACH(filemon, &filemons_inuse, link) {
81                         if (p == filemon->p) {
82                                 sx_sunlock(&proctree_lock);
83                                 sx_xlock(&filemon->lock);
84                                 filemon_unlock_read();
85                                 return (filemon);
86                         }
87                 }
88                 p = proc_realparent(p);
89         }
90         sx_sunlock(&proctree_lock);
91         filemon_unlock_read();
92         return (NULL);
93 }
94
95 static int
96 filemon_wrapper_chdir(struct thread *td, struct chdir_args *uap)
97 {
98         int ret;
99         size_t done;
100         size_t len;
101         struct filemon *filemon;
102
103         if ((ret = sys_chdir(td, uap)) == 0) {
104                 if ((filemon = filemon_pid_check(curproc)) != NULL) {
105                         copyinstr(uap->path, filemon->fname1,
106                             sizeof(filemon->fname1), &done);
107
108                         len = snprintf(filemon->msgbufr,
109                             sizeof(filemon->msgbufr), "C %d %s\n",
110                             curproc->p_pid, filemon->fname1);
111
112                         filemon_output(filemon, filemon->msgbufr, len);
113
114                         sx_xunlock(&filemon->lock);
115                 }
116         }
117
118         return (ret);
119 }
120
121 static void
122 filemon_event_process_exec(void *arg __unused, struct proc *p,
123     struct image_params *imgp)
124 {
125         struct filemon *filemon;
126         char *fullpath, *freepath;
127         size_t len;
128
129         if ((filemon = filemon_pid_check(p)) != NULL) {
130                 fullpath = "<unknown>";
131                 freepath = NULL;
132
133                 vn_fullpath(FIRST_THREAD_IN_PROC(p), imgp->vp, &fullpath,
134                     &freepath);
135
136                 len = snprintf(filemon->msgbufr,
137                     sizeof(filemon->msgbufr), "E %d %s\n",
138                     p->p_pid, fullpath);
139
140                 filemon_output(filemon, filemon->msgbufr, len);
141
142                 sx_xunlock(&filemon->lock);
143
144                 free(freepath, M_TEMP);
145         }
146 }
147
148 static int
149 filemon_wrapper_open(struct thread *td, struct open_args *uap)
150 {
151         int ret;
152         size_t done;
153         size_t len;
154         struct filemon *filemon;
155
156         if ((ret = sys_open(td, uap)) == 0) {
157                 if ((filemon = filemon_pid_check(curproc)) != NULL) {
158                         copyinstr(uap->path, filemon->fname1,
159                             sizeof(filemon->fname1), &done);
160
161                         if (uap->flags & O_RDWR) {
162                                 /*
163                                  * We'll get the W record below, but need
164                                  * to also output an R to distingish from
165                                  * O_WRONLY.
166                                  */
167                                 len = snprintf(filemon->msgbufr,
168                                     sizeof(filemon->msgbufr), "R %d %s\n",
169                                     curproc->p_pid, filemon->fname1);
170                                 filemon_output(filemon, filemon->msgbufr, len);
171                         }
172
173
174                         len = snprintf(filemon->msgbufr,
175                             sizeof(filemon->msgbufr), "%c %d %s\n",
176                             (uap->flags & O_ACCMODE) ? 'W':'R',
177                             curproc->p_pid, filemon->fname1);
178                         filemon_output(filemon, filemon->msgbufr, len);
179
180                         sx_xunlock(&filemon->lock);
181                 }
182         }
183
184         return (ret);
185 }
186
187 static int
188 filemon_wrapper_openat(struct thread *td, struct openat_args *uap)
189 {
190         int ret;
191         size_t done;
192         size_t len;
193         struct filemon *filemon;
194
195         if ((ret = sys_openat(td, uap)) == 0) {
196                 if ((filemon = filemon_pid_check(curproc)) != NULL) {
197                         copyinstr(uap->path, filemon->fname1,
198                             sizeof(filemon->fname1), &done);
199
200                         filemon->fname2[0] = '\0';
201                         if (filemon->fname1[0] != '/' && uap->fd != AT_FDCWD) {
202                                 /*
203                                  * rats - we cannot do too much about this.
204                                  * the trace should show a dir we read
205                                  * recently.. output an A record as a clue
206                                  * until we can do better.
207                                  */
208                                 len = snprintf(filemon->msgbufr,
209                                     sizeof(filemon->msgbufr), "A %d %s\n",
210                                     curproc->p_pid, filemon->fname1);
211                                 filemon_output(filemon, filemon->msgbufr, len);
212                         }
213                         if (uap->flag & O_RDWR) {
214                                 /*
215                                  * We'll get the W record below, but need
216                                  * to also output an R to distingish from
217                                  * O_WRONLY.
218                                  */
219                                 len = snprintf(filemon->msgbufr,
220                                     sizeof(filemon->msgbufr), "R %d %s%s\n",
221                                     curproc->p_pid, filemon->fname2, filemon->fname1);
222                                 filemon_output(filemon, filemon->msgbufr, len);
223                         }
224
225
226                         len = snprintf(filemon->msgbufr,
227                             sizeof(filemon->msgbufr), "%c %d %s%s\n",
228                             (uap->flag & O_ACCMODE) ? 'W':'R',
229                             curproc->p_pid, filemon->fname2, filemon->fname1);
230                         filemon_output(filemon, filemon->msgbufr, len);
231
232                         sx_xunlock(&filemon->lock);
233                 }
234         }
235
236         return (ret);
237 }
238
239 static int
240 filemon_wrapper_rename(struct thread *td, struct rename_args *uap)
241 {
242         int ret;
243         size_t done;
244         size_t len;
245         struct filemon *filemon;
246
247         if ((ret = sys_rename(td, uap)) == 0) {
248                 if ((filemon = filemon_pid_check(curproc)) != NULL) {
249                         copyinstr(uap->from, filemon->fname1,
250                             sizeof(filemon->fname1), &done);
251                         copyinstr(uap->to, filemon->fname2,
252                             sizeof(filemon->fname2), &done);
253
254                         len = snprintf(filemon->msgbufr,
255                             sizeof(filemon->msgbufr), "M %d '%s' '%s'\n",
256                             curproc->p_pid, filemon->fname1, filemon->fname2);
257
258                         filemon_output(filemon, filemon->msgbufr, len);
259
260                         sx_xunlock(&filemon->lock);
261                 }
262         }
263
264         return (ret);
265 }
266
267 static int
268 filemon_wrapper_link(struct thread *td, struct link_args *uap)
269 {
270         int ret;
271         size_t done;
272         size_t len;
273         struct filemon *filemon;
274
275         if ((ret = sys_link(td, uap)) == 0) {
276                 if ((filemon = filemon_pid_check(curproc)) != NULL) {
277                         copyinstr(uap->path, filemon->fname1,
278                             sizeof(filemon->fname1), &done);
279                         copyinstr(uap->link, filemon->fname2,
280                             sizeof(filemon->fname2), &done);
281
282                         len = snprintf(filemon->msgbufr,
283                             sizeof(filemon->msgbufr), "L %d '%s' '%s'\n",
284                             curproc->p_pid, filemon->fname1, filemon->fname2);
285
286                         filemon_output(filemon, filemon->msgbufr, len);
287
288                         sx_xunlock(&filemon->lock);
289                 }
290         }
291
292         return (ret);
293 }
294
295 static int
296 filemon_wrapper_symlink(struct thread *td, struct symlink_args *uap)
297 {
298         int ret;
299         size_t done;
300         size_t len;
301         struct filemon *filemon;
302
303         if ((ret = sys_symlink(td, uap)) == 0) {
304                 if ((filemon = filemon_pid_check(curproc)) != NULL) {
305                         copyinstr(uap->path, filemon->fname1,
306                             sizeof(filemon->fname1), &done);
307                         copyinstr(uap->link, filemon->fname2,
308                             sizeof(filemon->fname2), &done);
309
310                         len = snprintf(filemon->msgbufr,
311                             sizeof(filemon->msgbufr), "L %d '%s' '%s'\n",
312                             curproc->p_pid, filemon->fname1, filemon->fname2);
313
314                         filemon_output(filemon, filemon->msgbufr, len);
315
316                         sx_xunlock(&filemon->lock);
317                 }
318         }
319
320         return (ret);
321 }
322
323 static int
324 filemon_wrapper_linkat(struct thread *td, struct linkat_args *uap)
325 {
326         int ret;
327         size_t done;
328         size_t len;
329         struct filemon *filemon;
330
331         if ((ret = sys_linkat(td, uap)) == 0) {
332                 if ((filemon = filemon_pid_check(curproc)) != NULL) {
333                         copyinstr(uap->path1, filemon->fname1,
334                             sizeof(filemon->fname1), &done);
335                         copyinstr(uap->path2, filemon->fname2,
336                             sizeof(filemon->fname2), &done);
337
338                         len = snprintf(filemon->msgbufr,
339                             sizeof(filemon->msgbufr), "L %d '%s' '%s'\n",
340                             curproc->p_pid, filemon->fname1, filemon->fname2);
341
342                         filemon_output(filemon, filemon->msgbufr, len);
343
344                         sx_xunlock(&filemon->lock);
345                 }
346         }
347
348         return (ret);
349 }
350
351 static int
352 filemon_wrapper_stat(struct thread *td, struct stat_args *uap)
353 {
354         int ret;
355         size_t done;
356         size_t len;
357         struct filemon *filemon;
358
359         if ((ret = sys_stat(td, uap)) == 0) {
360                 if ((filemon = filemon_pid_check(curproc)) != NULL) {
361                         copyinstr(uap->path, filemon->fname1,
362                             sizeof(filemon->fname1), &done);
363
364                         len = snprintf(filemon->msgbufr,
365                             sizeof(filemon->msgbufr), "S %d %s\n",
366                             curproc->p_pid, filemon->fname1);
367
368                         filemon_output(filemon, filemon->msgbufr, len);
369
370                         sx_xunlock(&filemon->lock);
371                 }
372         }
373
374         return (ret);
375 }
376
377 #if defined(COMPAT_IA32) || defined(COMPAT_FREEBSD32) || defined(COMPAT_ARCH32)
378 static int
379 filemon_wrapper_freebsd32_stat(struct thread *td,
380     struct freebsd32_stat_args *uap)
381 {
382         int ret;
383         size_t done;
384         size_t len;
385         struct filemon *filemon;
386
387         if ((ret = freebsd32_stat(td, uap)) == 0) {
388                 if ((filemon = filemon_pid_check(curproc)) != NULL) {
389                         copyinstr(uap->path, filemon->fname1,
390                             sizeof(filemon->fname1), &done);
391
392                         len = snprintf(filemon->msgbufr,
393                             sizeof(filemon->msgbufr), "S %d %s\n",
394                             curproc->p_pid, filemon->fname1);
395
396                         filemon_output(filemon, filemon->msgbufr, len);
397
398                         sx_xunlock(&filemon->lock);
399                 }
400         }
401
402         return (ret);
403 }
404 #endif
405
406 static void
407 filemon_event_process_exit(void *arg __unused, struct proc *p)
408 {
409         size_t len;
410         struct filemon *filemon;
411         struct timeval now;
412
413         /* Get timestamp before locking. */
414         getmicrotime(&now);
415
416         if ((filemon = filemon_pid_check(p)) != NULL) {
417                 len = snprintf(filemon->msgbufr, sizeof(filemon->msgbufr),
418                     "X %d %d\n", p->p_pid, W_EXITCODE(p->p_xstat, 0));
419
420                 filemon_output(filemon, filemon->msgbufr, len);
421
422                 /* Check if the monitored process is about to exit. */
423                 if (filemon->p == p) {
424                         len = snprintf(filemon->msgbufr,
425                             sizeof(filemon->msgbufr),
426                             "# Stop %ju.%06ju\n# Bye bye\n",
427                             (uintmax_t)now.tv_sec, (uintmax_t)now.tv_usec);
428
429                         filemon_output(filemon, filemon->msgbufr, len);
430                         filemon->p = NULL;
431                 }
432
433                 sx_xunlock(&filemon->lock);
434         }
435 }
436
437 static int
438 filemon_wrapper_unlink(struct thread *td, struct unlink_args *uap)
439 {
440         int ret;
441         size_t done;
442         size_t len;
443         struct filemon *filemon;
444
445         if ((ret = sys_unlink(td, uap)) == 0) {
446                 if ((filemon = filemon_pid_check(curproc)) != NULL) {
447                         copyinstr(uap->path, filemon->fname1,
448                             sizeof(filemon->fname1), &done);
449
450                         len = snprintf(filemon->msgbufr,
451                             sizeof(filemon->msgbufr), "D %d %s\n",
452                             curproc->p_pid, filemon->fname1);
453
454                         filemon_output(filemon, filemon->msgbufr, len);
455
456                         sx_xunlock(&filemon->lock);
457                 }
458         }
459
460         return (ret);
461 }
462
463 static void
464 filemon_event_process_fork(void *arg __unused, struct proc *p1,
465     struct proc *p2, int flags __unused)
466 {
467         size_t len;
468         struct filemon *filemon;
469
470         if ((filemon = filemon_pid_check(p1)) != NULL) {
471                 len = snprintf(filemon->msgbufr,
472                     sizeof(filemon->msgbufr), "F %d %d\n",
473                     p1->p_pid, p2->p_pid);
474
475                 filemon_output(filemon, filemon->msgbufr, len);
476
477                 sx_xunlock(&filemon->lock);
478         }
479 }
480
481 static void
482 filemon_wrapper_install(void)
483 {
484 #if defined(__i386__)
485         struct sysent *sv_table = elf32_freebsd_sysvec.sv_table;
486 #elif defined(__amd64__)
487         struct sysent *sv_table = elf64_freebsd_sysvec.sv_table;
488 #else
489 #error Machine type not supported
490 #endif
491
492         sv_table[SYS_chdir].sy_call = (sy_call_t *) filemon_wrapper_chdir;
493         sv_table[SYS_open].sy_call = (sy_call_t *) filemon_wrapper_open;
494         sv_table[SYS_openat].sy_call = (sy_call_t *) filemon_wrapper_openat;
495         sv_table[SYS_rename].sy_call = (sy_call_t *) filemon_wrapper_rename;
496         sv_table[SYS_stat].sy_call = (sy_call_t *) filemon_wrapper_stat;
497         sv_table[SYS_unlink].sy_call = (sy_call_t *) filemon_wrapper_unlink;
498         sv_table[SYS_link].sy_call = (sy_call_t *) filemon_wrapper_link;
499         sv_table[SYS_symlink].sy_call = (sy_call_t *) filemon_wrapper_symlink;
500         sv_table[SYS_linkat].sy_call = (sy_call_t *) filemon_wrapper_linkat;
501
502 #if defined(COMPAT_IA32) || defined(COMPAT_FREEBSD32) || defined(COMPAT_ARCH32)
503         sv_table = ia32_freebsd_sysvec.sv_table;
504
505         sv_table[FREEBSD32_SYS_chdir].sy_call = (sy_call_t *) filemon_wrapper_chdir;
506         sv_table[FREEBSD32_SYS_open].sy_call = (sy_call_t *) filemon_wrapper_open;
507         sv_table[FREEBSD32_SYS_openat].sy_call = (sy_call_t *) filemon_wrapper_openat;
508         sv_table[FREEBSD32_SYS_rename].sy_call = (sy_call_t *) filemon_wrapper_rename;
509         sv_table[FREEBSD32_SYS_freebsd32_stat].sy_call = (sy_call_t *) filemon_wrapper_freebsd32_stat;
510         sv_table[FREEBSD32_SYS_unlink].sy_call = (sy_call_t *) filemon_wrapper_unlink;
511         sv_table[FREEBSD32_SYS_link].sy_call = (sy_call_t *) filemon_wrapper_link;
512         sv_table[FREEBSD32_SYS_symlink].sy_call = (sy_call_t *) filemon_wrapper_symlink;
513         sv_table[FREEBSD32_SYS_linkat].sy_call = (sy_call_t *) filemon_wrapper_linkat;
514 #endif  /* COMPAT_ARCH32 */
515
516         filemon_exec_tag = EVENTHANDLER_REGISTER(process_exec,
517             filemon_event_process_exec, NULL, EVENTHANDLER_PRI_LAST);
518         filemon_exit_tag = EVENTHANDLER_REGISTER(process_exit,
519             filemon_event_process_exit, NULL, EVENTHANDLER_PRI_LAST);
520         filemon_fork_tag = EVENTHANDLER_REGISTER(process_fork,
521             filemon_event_process_fork, NULL, EVENTHANDLER_PRI_LAST);
522 }
523
524 static void
525 filemon_wrapper_deinstall(void)
526 {
527 #if defined(__i386__)
528         struct sysent *sv_table = elf32_freebsd_sysvec.sv_table;
529 #elif defined(__amd64__)
530         struct sysent *sv_table = elf64_freebsd_sysvec.sv_table;
531 #else
532 #error Machine type not supported
533 #endif
534
535         sv_table[SYS_chdir].sy_call = (sy_call_t *)sys_chdir;
536         sv_table[SYS_open].sy_call = (sy_call_t *)sys_open;
537         sv_table[SYS_openat].sy_call = (sy_call_t *)sys_openat;
538         sv_table[SYS_rename].sy_call = (sy_call_t *)sys_rename;
539         sv_table[SYS_stat].sy_call = (sy_call_t *)sys_stat;
540         sv_table[SYS_unlink].sy_call = (sy_call_t *)sys_unlink;
541         sv_table[SYS_link].sy_call = (sy_call_t *)sys_link;
542         sv_table[SYS_symlink].sy_call = (sy_call_t *)sys_symlink;
543         sv_table[SYS_linkat].sy_call = (sy_call_t *)sys_linkat;
544
545 #if defined(COMPAT_IA32) || defined(COMPAT_FREEBSD32) || defined(COMPAT_ARCH32)
546         sv_table = ia32_freebsd_sysvec.sv_table;
547
548         sv_table[FREEBSD32_SYS_chdir].sy_call = (sy_call_t *)sys_chdir;
549         sv_table[FREEBSD32_SYS_open].sy_call = (sy_call_t *)sys_open;
550         sv_table[FREEBSD32_SYS_openat].sy_call = (sy_call_t *)sys_openat;
551         sv_table[FREEBSD32_SYS_rename].sy_call = (sy_call_t *)sys_rename;
552         sv_table[FREEBSD32_SYS_freebsd32_stat].sy_call = (sy_call_t *)freebsd32_stat;
553         sv_table[FREEBSD32_SYS_unlink].sy_call = (sy_call_t *)sys_unlink;
554         sv_table[FREEBSD32_SYS_link].sy_call = (sy_call_t *)sys_link;
555         sv_table[FREEBSD32_SYS_symlink].sy_call = (sy_call_t *)sys_symlink;
556         sv_table[FREEBSD32_SYS_linkat].sy_call = (sy_call_t *)sys_linkat;
557 #endif  /* COMPAT_ARCH32 */
558
559         EVENTHANDLER_DEREGISTER(process_exec, filemon_exec_tag);
560         EVENTHANDLER_DEREGISTER(process_exit, filemon_exit_tag);
561         EVENTHANDLER_DEREGISTER(process_fork, filemon_fork_tag);
562 }