summaryrefslogtreecommitdiff
path: root/sys/dev/filemon
diff options
context:
space:
mode:
authorpgoyette <pgoyette@NetBSD.org>2015-11-25 07:34:49 +0000
committerpgoyette <pgoyette@NetBSD.org>2015-11-25 07:34:49 +0000
commit2d4e18234e3417e1cab7d799add869aef6cdfb53 (patch)
tree5352bb164ad7d373f6148edae6f75e6f429925ae /sys/dev/filemon
parentaa0fabc545fb02a2010bfd8b4d37e50106030924 (diff)
Be a bit more paranoid about hijacking (and restoring) syscall function
pointers. Ensure that we have the correct "old" values before setting new values, for both "intall" and "deinstall". XXX This is NOT intended to encourage additional cases of hijacking! If XXX some other hijack feature ever gets committed, this code should be XXX moved to (most likely) kern/kern_syscall.c.
Diffstat (limited to 'sys/dev/filemon')
-rw-r--r--sys/dev/filemon/filemon.c15
-rw-r--r--sys/dev/filemon/filemon.h10
-rw-r--r--sys/dev/filemon/filemon_wrapper.c121
3 files changed, 109 insertions, 37 deletions
diff --git a/sys/dev/filemon/filemon.c b/sys/dev/filemon/filemon.c
index b8e710d6e23..fe87d6e1e2e 100644
--- a/sys/dev/filemon/filemon.c
+++ b/sys/dev/filemon/filemon.c
@@ -1,4 +1,4 @@
-/* $NetBSD: filemon.c,v 1.21 2015/11/24 01:05:50 pgoyette Exp $ */
+/* $NetBSD: filemon.c,v 1.22 2015/11/25 07:34:49 pgoyette Exp $ */
/*
* Copyright (c) 2010, Juniper Networks, Inc.
*
@@ -25,7 +25,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: filemon.c,v 1.21 2015/11/24 01:05:50 pgoyette Exp $");
+__KERNEL_RCSID(0, "$NetBSD: filemon.c,v 1.22 2015/11/25 07:34:49 pgoyette Exp $");
#include <sys/param.h>
#include <sys/kernel.h>
@@ -340,13 +340,13 @@ filemon_ioctl(struct file * fp, u_long cmd, void *data)
return (error);
}
-static void
+static int
filemon_load(void *dummy __unused)
{
rw_init(&filemon_mtx);
/* Install the syscall wrappers. */
- filemon_wrapper_install();
+ return filemon_wrapper_install();
}
/*
@@ -400,9 +400,10 @@ filemon_modcmd(modcmd_t cmd, void *data)
logLevel = LOG_INFO;
#endif
- filemon_load(data);
- error = devsw_attach("filemon", NULL, &bmajor,
- &filemon_cdevsw, &cmajor);
+ error = filemon_load(data);
+ if (!error)
+ error = devsw_attach("filemon", NULL, &bmajor,
+ &filemon_cdevsw, &cmajor);
break;
case MODULE_CMD_FINI:
diff --git a/sys/dev/filemon/filemon.h b/sys/dev/filemon/filemon.h
index 544f61ff982..1f8f8e0b1eb 100644
--- a/sys/dev/filemon/filemon.h
+++ b/sys/dev/filemon/filemon.h
@@ -1,4 +1,4 @@
-/* $NetBSD: filemon.h,v 1.7 2015/09/06 06:01:00 dholland Exp $ */
+/* $NetBSD: filemon.h,v 1.8 2015/11/25 07:34:49 pgoyette Exp $ */
/*
* Copyright (c) 2010, Juniper Networks, Inc.
*
@@ -47,9 +47,15 @@ struct filemon {
TAILQ_ENTRY(filemon) fm_link; /* Link into the in-use list. */
};
+struct hijack {
+ int hj_index;
+ sy_call_t *hj_funcs[2]; /* [0] = original, [1] = hijack */
+};
+
struct filemon * filemon_lookup(struct proc *);
void filemon_output(struct filemon *, char *, size_t);
-void filemon_wrapper_install(void);
+int syscall_hijack(struct sysent *, const struct hijack *, bool);
+int filemon_wrapper_install(void);
int filemon_wrapper_deinstall(void);
void filemon_printf(struct filemon *, const char *, ...) __printflike(2, 3);
#endif
diff --git a/sys/dev/filemon/filemon_wrapper.c b/sys/dev/filemon/filemon_wrapper.c
index 7d2bea07a01..ed43f29d58a 100644
--- a/sys/dev/filemon/filemon_wrapper.c
+++ b/sys/dev/filemon/filemon_wrapper.c
@@ -1,4 +1,4 @@
-/* $NetBSD: filemon_wrapper.c,v 1.10 2015/11/23 00:47:43 pgoyette Exp $ */
+/* $NetBSD: filemon_wrapper.c,v 1.11 2015/11/25 07:34:49 pgoyette Exp $ */
/*
* Copyright (c) 2010, Juniper Networks, Inc.
@@ -26,7 +26,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: filemon_wrapper.c,v 1.10 2015/11/23 00:47:43 pgoyette Exp $");
+__KERNEL_RCSID(0, "$NetBSD: filemon_wrapper.c,v 1.11 2015/11/25 07:34:49 pgoyette Exp $");
#include <sys/param.h>
#include <sys/types.h>
@@ -39,6 +39,83 @@ __KERNEL_RCSID(0, "$NetBSD: filemon_wrapper.c,v 1.10 2015/11/23 00:47:43 pgoyett
#include "filemon.h"
+static int filemon_wrapper_chdir(struct lwp *, const struct sys_chdir_args *,
+ register_t *);
+static int filemon_wrapper_execve(struct lwp *, struct sys_execve_args *,
+ register_t *);
+static void filemon_wrapper_sys_exit(struct lwp *, struct sys_exit_args *,
+ register_t *);
+static int filemon_wrapper_fork(struct lwp *, const void *, register_t *);
+static int filemon_wrapper_link(struct lwp *, struct sys_link_args *,
+ register_t *);
+static int filemon_wrapper_open(struct lwp *, struct sys_open_args *,
+ register_t *);
+static int filemon_wrapper_openat(struct lwp *, struct sys_openat_args *,
+ register_t *);
+static int filemon_wrapper_rename(struct lwp *, struct sys_rename_args *,
+ register_t *);
+static int filemon_wrapper_symlink(struct lwp *, struct sys_symlink_args *,
+ register_t *);
+static int filemon_wrapper_unlink(struct lwp *, struct sys_unlink_args *,
+ register_t *);
+static int filemon_wrapper_vfork(struct lwp *, const void *, register_t *);
+
+const struct hijack filemon_hijack[] = {
+ { SYS_chdir,
+ { (sy_call_t *)sys_chdir, (sy_call_t *)filemon_wrapper_chdir } },
+ { SYS_execve,
+ { (sy_call_t *)sys_execve, (sy_call_t *)filemon_wrapper_execve } },
+ { SYS_exit,
+ { (sy_call_t *)sys_exit, (sy_call_t *)filemon_wrapper_sys_exit } },
+ { SYS_fork,
+ { (sy_call_t *)sys_fork, (sy_call_t *)filemon_wrapper_fork } },
+ { SYS_link,
+ { (sy_call_t *)sys_link, (sy_call_t *)filemon_wrapper_link } },
+ { SYS_open,
+ { (sy_call_t *)sys_open, (sy_call_t *)filemon_wrapper_open } },
+ { SYS_openat,
+ { (sy_call_t *)sys_openat, (sy_call_t *)filemon_wrapper_openat } },
+ { SYS_rename,
+ { (sy_call_t *)sys_rename, (sy_call_t *)filemon_wrapper_rename } },
+ { SYS_symlink,
+ { (sy_call_t *)sys_symlink, (sy_call_t *)filemon_wrapper_symlink } },
+ { SYS_unlink,
+ { (sy_call_t *)sys_unlink, (sy_call_t *)filemon_wrapper_unlink } },
+ { SYS_vfork,
+ { (sy_call_t *)sys_vfork, (sy_call_t *)filemon_wrapper_vfork } },
+ { -1, {NULL, NULL } }
+};
+
+int
+syscall_hijack(struct sysent *sv_table, const struct hijack *hj_pkg,
+ bool restore)
+{
+ int from, to;
+ const struct hijack *entry;
+
+ if (restore) /* Which entry should currently match? */
+ from = 1;
+ else
+ from = 0;
+ to = 1 - from; /* Which entry will we replace with? */
+
+ KASSERT(kernconfig_is_held());
+
+ /* First, make sure that all of the old values match */
+ for (entry = hj_pkg; entry->hj_index >= 0; entry++)
+ if (sv_table[entry->hj_index].sy_call != entry->hj_funcs[from])
+ break;
+
+ if (entry->hj_index >= 0)
+ return EBUSY;
+
+ /* Now replace the old values with the new ones */
+ for (entry = hj_pkg; entry->hj_index >= 0; entry++)
+ sv_table[entry->hj_index].sy_call = entry->hj_funcs[to];
+
+ return 0;
+}
+
static int
filemon_wrapper_chdir(struct lwp * l, const struct sys_chdir_args * uap,
register_t * retval)
@@ -322,6 +399,7 @@ filemon_wrapper_sys_exit(struct lwp * l, struct sys_exit_args * uap,
rw_exit(&filemon->fm_mtx);
}
sys_exit(l, uap, retval);
+ /* NOT REACHED */
}
static int
@@ -352,41 +430,28 @@ out:
}
-void
+int
filemon_wrapper_install(void)
{
+ int error;
struct sysent *sv_table = emul_netbsd.e_sysent;
- sv_table[SYS_chdir].sy_call = (sy_call_t *) filemon_wrapper_chdir;
- sv_table[SYS_execve].sy_call = (sy_call_t *) filemon_wrapper_execve;
- sv_table[SYS_exit].sy_call = (sy_call_t *) filemon_wrapper_sys_exit;
- sv_table[SYS_fork].sy_call = (sy_call_t *) filemon_wrapper_fork;
- sv_table[SYS_link].sy_call = (sy_call_t *) filemon_wrapper_link;
- sv_table[SYS_open].sy_call = (sy_call_t *) filemon_wrapper_open;
- sv_table[SYS_openat].sy_call = (sy_call_t *) filemon_wrapper_openat;
- sv_table[SYS_rename].sy_call = (sy_call_t *) filemon_wrapper_rename;
- sv_table[SYS_symlink].sy_call = (sy_call_t *) filemon_wrapper_symlink;
- sv_table[SYS_unlink].sy_call = (sy_call_t *) filemon_wrapper_unlink;
- sv_table[SYS_vfork].sy_call = (sy_call_t *) filemon_wrapper_vfork;
+ kernconfig_lock();
+ error = syscall_hijack(sv_table, filemon_hijack, false);
+ kernconfig_unlock();
+
+ return error;
}
int
filemon_wrapper_deinstall(void)
{
+ int error;
struct sysent *sv_table = emul_netbsd.e_sysent;
- if (sv_table[SYS_chdir].sy_call != (sy_call_t *) filemon_wrapper_chdir)
- return EBUSY;
- sv_table[SYS_chdir].sy_call = (sy_call_t *) sys_chdir;
- sv_table[SYS_execve].sy_call = (sy_call_t *) sys_execve;
- sv_table[SYS_exit].sy_call = (sy_call_t *) sys_exit;
- sv_table[SYS_fork].sy_call = (sy_call_t *) sys_fork;
- sv_table[SYS_link].sy_call = (sy_call_t *) sys_link;
- sv_table[SYS_open].sy_call = (sy_call_t *) sys_open;
- sv_table[SYS_openat].sy_call = (sy_call_t *) sys_openat;
- sv_table[SYS_rename].sy_call = (sy_call_t *) sys_rename;
- sv_table[SYS_symlink].sy_call = (sy_call_t *) sys_symlink;
- sv_table[SYS_unlink].sy_call = (sy_call_t *) sys_unlink;
- sv_table[SYS_vfork].sy_call = (sy_call_t *) sys_vfork;
- return 0;
+ kernconfig_lock();
+ error = syscall_hijack(sv_table, filemon_hijack, true);
+ kernconfig_unlock();
+
+ return error;
}