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