summaryrefslogtreecommitdiff
path: root/sys/dev
diff options
context:
space:
mode:
authorNiels Provos <provos@cvs.openbsd.org>2002-06-21 15:07:05 +0000
committerNiels Provos <provos@cvs.openbsd.org>2002-06-21 15:07:05 +0000
commitab636641a14766506bddd6c38591baa9f6c9b4ac (patch)
tree101581d6d66f48045caee3b374354eb815cd75fc /sys/dev
parente0b415773b3ca8e90150d127abdf13a0613d1fc6 (diff)
system call argument rewriting framework via stackgap; okay art@
Diffstat (limited to 'sys/dev')
-rw-r--r--sys/dev/systrace.c136
-rw-r--r--sys/dev/systrace.h11
2 files changed, 135 insertions, 12 deletions
diff --git a/sys/dev/systrace.c b/sys/dev/systrace.c
index 5ea950900b8..c1b352f4148 100644
--- a/sys/dev/systrace.c
+++ b/sys/dev/systrace.c
@@ -45,6 +45,8 @@
#include <sys/pool.h>
#include <sys/mount.h>
+#include <compat/common/compat_util.h>
+
#include <miscfs/procfs/procfs.h>
#include <dev/systrace.h>
@@ -94,6 +96,8 @@ struct str_process {
struct fsystrace *parent;
struct str_policy *policy;
+ struct systrace_replace *replace;
+
int flags;
short answer;
short error;
@@ -111,6 +115,8 @@ int systrace_detach(struct str_process *);
int systrace_answer(struct str_process *, struct systrace_answer *);
int systrace_io(struct str_process *, struct systrace_io *);
int systrace_policy(struct fsystrace *, struct systrace_policy *);
+int systrace_preprepl(struct str_process *, struct systrace_replace *);
+int systrace_replace(struct str_process *, size_t, register_t []);
int systrace_getcwd(struct fsystrace *, struct str_process *);
int systrace_processready(struct str_process *);
@@ -281,6 +287,11 @@ systracef_ioctl(fp, cmd, data, p)
break;
case STRIOCPOLICY:
break;
+ case STRIOCREPLACE:
+ pid = ((struct systrace_replace *)data)->strr_pid;
+ if (!pid)
+ ret = EINVAL;
+ break;
default:
ret = EINVAL;
break;
@@ -314,6 +325,9 @@ systracef_ioctl(fp, cmd, data, p)
case STRIOCPOLICY:
ret = systrace_policy(fst, (struct systrace_policy *)data);
break;
+ case STRIOCREPLACE:
+ ret = systrace_preprepl(strp, (struct systrace_replace *)data);
+ break;
case STRIOCGETCWD:
ret = systrace_getcwd(fst, strp);
break;
@@ -661,9 +675,15 @@ systrace_redirect(int code, struct proc *p, void *v, register_t *retval)
/* XXX - do I need to lock here? */
if (strp->answer == SYSTR_POLICY_NEVER)
error = strp->error;
- else if (ISSET(strp->flags, STR_PROC_SYSCALLRES)) {
- CLR(strp->flags, STR_PROC_SYSCALLRES);
- report = 1;
+ else {
+ if (ISSET(strp->flags, STR_PROC_SYSCALLRES)) {
+ CLR(strp->flags, STR_PROC_SYSCALLRES);
+ report = 1;
+ }
+ /* Replace the arguments if necessary */
+ if (strp->replace != NULL) {
+ error = systrace_replace(strp, callp->sy_argsize, v);
+ }
}
}
break;
@@ -749,14 +769,8 @@ systrace_answer(struct str_process *strp, struct systrace_answer *ans)
goto out;
}
- if (ISSET(strp->flags, STR_PROC_ONQUEUE)) {
- error = EINVAL;
+ if ((error = systrace_processready(strp)) != 0)
goto out;
- }
- if (!ISSET(strp->flags, STR_PROC_WAITANSWER)) {
- error = EINVAL;
- goto out;
- }
strp->answer = ans->stra_policy;
strp->error = ans->stra_error;
@@ -1001,6 +1015,102 @@ systrace_attach(struct fsystrace *fst, pid_t pid)
return (error);
}
+/* Prepare to replace arguments */
+
+int
+systrace_preprepl(struct str_process *strp, struct systrace_replace *repl)
+{
+ size_t len;
+ int i, ret = 0;
+
+ ret = systrace_processready(strp);
+ if (ret)
+ return (ret);
+
+ if (strp->replace != NULL)
+ free(strp->replace, M_XDATA);
+
+ if (repl->strr_nrepl < 0 || repl->strr_nrepl > SYSTR_MAXARGS)
+ return (EINVAL);
+
+ for (i = 0, len = 0; i < repl->strr_nrepl; i++) {
+ len += repl->strr_offlen[i];
+ if (repl->strr_offlen[i] == 0)
+ continue;
+ if (repl->strr_offlen[i] + repl->strr_off[i] > len)
+ return (EINVAL);
+ }
+
+ /* Make sure that the length adds up */
+ if (repl->strr_len != len)
+ return (EINVAL);
+
+ /* Check against a maximum length */
+ if (repl->strr_len > 2048)
+ return (EINVAL);
+
+ strp->replace = (struct systrace_replace *)
+ malloc(sizeof(struct systrace_replace) + len, M_XDATA, M_WAITOK);
+
+ memcpy(strp->replace, repl, sizeof(struct systrace_replace));
+ ret = copyin(repl->strr_base, strp->replace + 1, len);
+ if (ret) {
+ free(strp->replace, M_XDATA);
+ strp->replace = NULL;
+ return (ret);
+ }
+
+ /* Adjust the offset */
+ repl = strp->replace;
+ repl->strr_base = (caddr_t)(repl + 1);
+
+ return (0);
+}
+
+/*
+ * Replace the arguments with arguments from the monitoring process.
+ */
+
+int
+systrace_replace(struct str_process *strp, size_t argsize, register_t args[])
+{
+ struct proc *p = strp->proc;
+ struct systrace_replace *repl = strp->replace;
+ caddr_t sg, kdata, udata, kbase, ubase;
+ int i, maxarg, ind, ret = 0;
+
+ maxarg = argsize/sizeof(register_t);
+ sg = stackgap_init(p->p_emul);
+ ubase = stackgap_alloc(&sg, repl->strr_len);
+
+ kbase = repl->strr_base;
+ for (i = 0; i < maxarg && i < repl->strr_nrepl; i++) {
+ ind = repl->strr_argind[i];
+ if (ind < 0 || ind >= maxarg) {
+ ret = EINVAL;
+ goto out;
+ }
+ if (repl->strr_offlen[i] == 0) {
+ args[ind] = repl->strr_off[i];
+ continue;
+ }
+ kdata = kbase + repl->strr_off[i];
+ udata = ubase + repl->strr_off[i];
+ if (copyout(kdata, udata, repl->strr_offlen[i])) {
+ ret = EINVAL;
+ goto out;
+ }
+
+ /* Replace the argument with the new address */
+ args[ind] = (register_t)udata;
+ }
+
+ out:
+ free(repl, M_XDATA);
+ strp->replace = NULL;
+ return (ret);
+}
+
struct str_process *
systrace_findpid(struct fsystrace *fst, pid_t pid)
{
@@ -1050,6 +1160,8 @@ systrace_detach(struct str_process *strp)
if (strp->policy)
systrace_closepolicy(fst, strp->policy);
+ if (strp->replace)
+ free(strp->replace, M_XDATA);
pool_put(&systr_proc_pl, strp);
return (error);
@@ -1064,7 +1176,7 @@ systrace_closepolicy(struct fsystrace *fst, struct str_policy *policy)
fst->npolicies--;
if (policy->nsysent)
- FREE(policy->sysent, M_XDATA);
+ free(policy->sysent, M_XDATA);
TAILQ_REMOVE(&fst->policies, policy, next);
@@ -1113,7 +1225,7 @@ systrace_newpolicy(struct fsystrace *fst, int maxents)
memset((caddr_t)pol, 0, sizeof(struct str_policy));
- MALLOC(pol->sysent, u_char *, maxents * sizeof(u_char),
+ pol->sysent = (u_char *)malloc(maxents * sizeof(u_char),
M_XDATA, M_WAITOK);
pol->nsysent = maxents;
for (i = 0; i < maxents; i++)
diff --git a/sys/dev/systrace.h b/sys/dev/systrace.h
index a4dfe08b4f5..bd1bd369597 100644
--- a/sys/dev/systrace.h
+++ b/sys/dev/systrace.h
@@ -118,6 +118,16 @@ struct systrace_policy {
#define strp_code strp_data.assign.code
#define strp_policy strp_data.assign.policy
+struct systrace_replace {
+ pid_t strr_pid;
+ int strr_nrepl;
+ caddr_t strr_base; /* Base memory */
+ size_t strr_len; /* Length of memory */
+ int strr_argind[SYSTR_MAXARGS];
+ size_t strr_off[SYSTR_MAXARGS];
+ size_t strr_offlen[SYSTR_MAXARGS];
+};
+
#define STRIOCATTACH _IOW('s', 101, pid_t)
#define STRIOCDETACH _IOW('s', 102, pid_t)
#define STRIOCANSWER _IOW('s', 103, struct systrace_answer)
@@ -126,6 +136,7 @@ struct systrace_policy {
#define STRIOCGETCWD _IOW('s', 106, pid_t)
#define STRIOCRESCWD _IO('s', 107)
#define STRIOCREPORT _IOW('s', 108, pid_t)
+#define STRIOCREPLACE _IOW('s', 109, struct systrace_replace)
#define SYSTR_POLICY_ASK 0
#define SYSTR_POLICY_PERMIT 1