On Sat, Jan 16, 2010 at 09:01:37PM +0200, Ali Polatel wrote:
> Hey everyone,
> 
> Problem: ptrace's PT_SETREGS request can't alter system calls.
> Code: http://alip.github.com/code/ptrace-freebsd-deny.c
> Expected: The file foo.bar shouldn't be created.
> Got: The file is created. Other efforts like replacing
> PT_GETREGS/PT_SETREGS calls with PT_KILL doesn't help, the file is
> created nevertheless.
> 
> I'm inclined to call this a bug but I can't be sure.
> Any comments appreciated.
> TIA

It may be a missed feature, not a bug. There is obvious hack value
in ability to modify syscall arguments from the debugger.

Do you know whether other operating systems allow this ?

I was around this code today, and wrote the patch for i386, amd64
and ia32 on amd64. Other architectures need to be handled.

diff --git a/sys/amd64/amd64/trap.c b/sys/amd64/amd64/trap.c
index df301d1..bd7ee63 100644
--- a/sys/amd64/amd64/trap.c
+++ b/sys/amd64/amd64/trap.c
@@ -885,95 +885,131 @@ dblfault_handler(struct trapframe *frame)
        panic("double fault");
 }
 
-/*
- *     syscall -       system call request C handler
- *
- *     A system call is essentially treated as a trap.
- */
-void
-syscall(struct trapframe *frame)
-{
-       caddr_t params;
+struct syscall_args {
+       u_int code;
        struct sysent *callp;
-       struct thread *td = curthread;
-       struct proc *p = td->td_proc;
-       register_t orig_tf_rflags;
-       int error;
-       int narg;
        register_t args[8];
        register_t *argp;
-       u_int code;
-       int reg, regcnt;
-       ksiginfo_t ksi;
-
-       PCPU_INC(cnt.v_syscall);
+       int narg;
+};
 
-#ifdef DIAGNOSTIC
-       if (ISPL(frame->tf_cs) != SEL_UPL) {
-               panic("syscall");
-               /* NOT REACHED */
-       }
-#endif
+static int
+fetch_syscall_args(struct thread *td, struct syscall_args *sa)
+{
+       struct proc *p;
+       struct trapframe *frame;
+       caddr_t params;
+       int reg, regcnt, error;
 
+       p = td->td_proc;
+       frame = td->td_frame;
        reg = 0;
        regcnt = 6;
-       td->td_pticks = 0;
-       td->td_frame = frame;
-       if (td->td_ucred != p->p_ucred) 
-               cred_update_thread(td);
+
        params = (caddr_t)frame->tf_rsp + sizeof(register_t);
-       code = frame->tf_rax;
-       orig_tf_rflags = frame->tf_rflags;
+       sa->code = frame->tf_rax;
 
        if (p->p_sysent->sv_prepsyscall) {
-               (*p->p_sysent->sv_prepsyscall)(frame, (int *)args, &code, 
&params);
+               (*p->p_sysent->sv_prepsyscall)(frame, (int *)sa->args,
+                   &sa->code, &params);
        } else {
-               if (code == SYS_syscall || code == SYS___syscall) {
-                       code = frame->tf_rdi;
+               if (sa->code == SYS_syscall || sa->code == SYS___syscall) {
+                       sa->code = frame->tf_rdi;
                        reg++;
                        regcnt--;
                }
        }
-
        if (p->p_sysent->sv_mask)
-               code &= p->p_sysent->sv_mask;
+               sa->code &= p->p_sysent->sv_mask;
 
-       if (code >= p->p_sysent->sv_size)
-               callp = &p->p_sysent->sv_table[0];
+       if (sa->code >= p->p_sysent->sv_size)
+               sa->callp = &p->p_sysent->sv_table[0];
        else
-               callp = &p->p_sysent->sv_table[code];
+               sa->callp = &p->p_sysent->sv_table[sa->code];
 
-       narg = callp->sy_narg;
-       KASSERT(narg <= sizeof(args) / sizeof(args[0]),
+       sa->narg = sa->callp->sy_narg;
+       KASSERT(sa->narg <= sizeof(sa->args) / sizeof(sa->args[0]),
            ("Too many syscall arguments!"));
        error = 0;
-       argp = &frame->tf_rdi;
-       argp += reg;
-       bcopy(argp, args, sizeof(args[0]) * regcnt);
-       if (narg > regcnt) {
+       sa->argp = &frame->tf_rdi;
+       sa->argp += reg;
+       bcopy(sa->argp, sa->args, sizeof(sa->args[0]) * regcnt);
+       if (sa->narg > regcnt) {
                KASSERT(params != NULL, ("copyin args with no params!"));
-               error = copyin(params, &args[regcnt],
-                       (narg - regcnt) * sizeof(args[0]));
+               error = copyin(params, &sa->args[regcnt],
+                   (sa->narg - regcnt) * sizeof(sa->args[0]));
        }
-       argp = &args[0];
+       sa->argp = &sa->args[0];
 
+       /*
+        * This may result in two records if debugger modified
+        * registers or memory during sleep at stop/ptrace point.
+        */
 #ifdef KTRACE
        if (KTRPOINT(td, KTR_SYSCALL))
-               ktrsyscall(code, narg, argp);
+               ktrsyscall(sa->code, sa->narg, sa->argp);
 #endif
+       return (error);
+}
 
-       CTR4(KTR_SYSC, "syscall enter thread %p pid %d proc %s code %d", td,
-           td->td_proc->p_pid, td->td_name, code);
+/*
+ *     syscall -       system call request C handler
+ *
+ *     A system call is essentially treated as a trap.
+ */
+void
+syscall(struct trapframe *frame)
+{
+       struct thread *td;
+       struct proc *p;
+       struct syscall_args sa;
+       register_t orig_tf_rflags;
+       int error;
+       ksiginfo_t ksi;
 
+       PCPU_INC(cnt.v_syscall);
+       td = curthread;
+       p = td->td_proc;
        td->td_syscalls++;
 
+#ifdef DIAGNOSTIC
+       if (ISPL(frame->tf_cs) != SEL_UPL) {
+               panic("syscall");
+               /* NOT REACHED */
+       }
+#endif
+
+       td->td_pticks = 0;
+       td->td_frame = frame;
+       if (td->td_ucred != p->p_ucred) 
+               cred_update_thread(td);
+       orig_tf_rflags = frame->tf_rflags;
+       if (p->p_flag & P_TRACED) {
+               PROC_LOCK(p);
+               td->td_dbgflags &= ~TDB_USERWR;
+               PROC_UNLOCK(p);
+       }
+       error = fetch_syscall_args(td, &sa);
+
+       CTR4(KTR_SYSC, "syscall enter thread %p pid %d proc %s code %d", td,
+           td->td_proc->p_pid, td->td_name, sa.code);
+
        if (error == 0) {
                td->td_retval[0] = 0;
                td->td_retval[1] = frame->tf_rdx;
 
-               STOPEVENT(p, S_SCE, narg);
-
+               STOPEVENT(p, S_SCE, sa.narg);
                PTRACESTOP_SC(p, td, S_PT_SCE);
+               if (td->td_dbgflags & TDB_USERWR) {
+                       /*
+                        * Reread syscall number and arguments if
+                        * debugger modified registers or memory.
+                        */
+                       error = fetch_syscall_args(td, &sa);
+                       if (error != 0)
+                               goto retval;
+                       td->td_retval[1] = frame->tf_rdx;
+               }
 
 #ifdef KDTRACE_HOOKS
                /*
@@ -981,13 +1017,13 @@ syscall(struct trapframe *frame)
                 * callback and if there is a probe active for the
                 * syscall 'entry', process the probe.
                 */
-               if (systrace_probe_func != NULL && callp->sy_entry != 0)
-                       (*systrace_probe_func)(callp->sy_entry, code, callp,
-                           args);
+               if (systrace_probe_func != NULL && sa.callp->sy_entry != 0)
+                       (*systrace_probe_func)(sa.callp->sy_entry, sa.code,
+                           sa.callp, sa.args);
 #endif
 
-               AUDIT_SYSCALL_ENTER(code, td);
-               error = (*callp->sy_call)(td, argp);
+               AUDIT_SYSCALL_ENTER(sa.code, td);
+               error = (*sa.callp->sy_call)(td, sa.argp);
                AUDIT_SYSCALL_EXIT(error, td);
 
                /* Save the latest error return value. */
@@ -999,12 +1035,12 @@ syscall(struct trapframe *frame)
                 * callback and if there is a probe active for the
                 * syscall 'return', process the probe.
                 */
-               if (systrace_probe_func != NULL && callp->sy_return != 0)
-                       (*systrace_probe_func)(callp->sy_return, code, callp,
-                           args);
+               if (systrace_probe_func != NULL && sa.callp->sy_return != 0)
+                       (*systrace_probe_func)(sa.callp->sy_return, sa.code,
+                           sa.callp, sa.args);
 #endif
        }
-
+ retval:
        cpu_set_syscall_retval(td, error);
 
        /*
@@ -1023,14 +1059,16 @@ syscall(struct trapframe *frame)
         * Check for misbehavior.
         */
        WITNESS_WARN(WARN_PANIC, NULL, "System call %s returning",
-           (code >= 0 && code < SYS_MAXSYSCALL) ? syscallnames[code] : "???");
+           (sa.code >= 0 && sa.code < SYS_MAXSYSCALL) ?
+            syscallnames[sa.code] : "???");
        KASSERT(td->td_critnest == 0,
            ("System call %s returning in a critical section",
-           (code >= 0 && code < SYS_MAXSYSCALL) ? syscallnames[code] : "???"));
+           (sa.code >= 0 && sa.code < SYS_MAXSYSCALL) ?
+            syscallnames[sa.code] : "???"));
        KASSERT(td->td_locks == 0,
            ("System call %s returning with %d locks held",
-           (code >= 0 && code < SYS_MAXSYSCALL) ? syscallnames[code] : "???",
-           td->td_locks));
+           (sa.code >= 0 && sa.code < SYS_MAXSYSCALL) ?
+            syscallnames[sa.code] : "???", td->td_locks));
 
        /*
         * Handle reschedule and other end-of-syscall issues
@@ -1038,11 +1076,11 @@ syscall(struct trapframe *frame)
        userret(td, frame);
 
        CTR4(KTR_SYSC, "syscall exit thread %p pid %d proc %s code %d", td,
-           td->td_proc->p_pid, td->td_name, code);
+           td->td_proc->p_pid, td->td_name, sa.code);
 
 #ifdef KTRACE
        if (KTRPOINT(td, KTR_SYSRET))
-               ktrsysret(code, error, td->td_retval[0]);
+               ktrsysret(sa.code, error, td->td_retval[0]);
 #endif
 
        /*
@@ -1050,7 +1088,7 @@ syscall(struct trapframe *frame)
         * register set.  If we ever support an emulation where this
         * is not the case, this code will need to be revisited.
         */
-       STOPEVENT(p, S_SCX, code);
+       STOPEVENT(p, S_SCX, sa.code);
 
        PTRACESTOP_SC(p, td, S_PT_SCX);
 }
diff --git a/sys/amd64/ia32/ia32_syscall.c b/sys/amd64/ia32/ia32_syscall.c
index 5e20876..aa1ae6c 100644
--- a/sys/amd64/ia32/ia32_syscall.c
+++ b/sys/amd64/ia32/ia32_syscall.c
@@ -88,101 +88,136 @@ extern const char *freebsd32_syscallnames[];
 
 void ia32_syscall(struct trapframe *frame);    /* Called from asm code */
 
-void
-ia32_syscall(struct trapframe *frame)
-{
+struct ia32_syscall_args {
+       u_int code;
        caddr_t params;
-       int i;
        struct sysent *callp;
-       struct thread *td = curthread;
-       struct proc *p = td->td_proc;
-       register_t orig_tf_rflags;
-       int error;
+       u_int64_t args64[8];
        int narg;
+};
+
+static int
+fetch_ia32_syscall_args(struct thread *td, struct ia32_syscall_args *sa)
+{
+       struct proc *p;
+       struct trapframe *frame;
        u_int32_t args[8];
-       u_int64_t args64[8];
-       u_int code;
-       ksiginfo_t ksi;
+       int error, i;
 
-       PCPU_INC(cnt.v_syscall);
-       td->td_pticks = 0;
-       td->td_frame = frame;
-       if (td->td_ucred != p->p_ucred) 
-               cred_update_thread(td);
-       params = (caddr_t)frame->tf_rsp + sizeof(u_int32_t);
-       code = frame->tf_rax;
-       orig_tf_rflags = frame->tf_rflags;
+       p = td->td_proc;
+       frame = td->td_frame;
+
+       sa->params = (caddr_t)frame->tf_rsp + sizeof(u_int32_t);
+       sa->code = frame->tf_rax;
 
        if (p->p_sysent->sv_prepsyscall) {
                /*
                 * The prep code is MP aware.
                 */
-               (*p->p_sysent->sv_prepsyscall)(frame, args, &code, &params);
+               (*p->p_sysent->sv_prepsyscall)(frame, args, &sa->code,
+                   &sa->params);
        } else {
                /*
                 * Need to check if this is a 32 bit or 64 bit syscall.
                 * fuword is MP aware.
                 */
-               if (code == SYS_syscall) {
+               if (sa->code == SYS_syscall) {
                        /*
                         * Code is first argument, followed by actual args.
                         */
-                       code = fuword32(params);
-                       params += sizeof(int);
-               } else if (code == SYS___syscall) {
+                       sa->code = fuword32(sa->params);
+                       sa->params += sizeof(int);
+               } else if (sa->code == SYS___syscall) {
                        /*
                         * Like syscall, but code is a quad, so as to maintain
                         * quad alignment for the rest of the arguments.
                         * We use a 32-bit fetch in case params is not
                         * aligned.
                         */
-                       code = fuword32(params);
-                       params += sizeof(quad_t);
+                       sa->code = fuword32(sa->params);
+                       sa->params += sizeof(quad_t);
                }
        }
-
        if (p->p_sysent->sv_mask)
-               code &= p->p_sysent->sv_mask;
-
-       if (code >= p->p_sysent->sv_size)
-               callp = &p->p_sysent->sv_table[0];
+               sa->code &= p->p_sysent->sv_mask;
+       if (sa->code >= p->p_sysent->sv_size)
+               sa->callp = &p->p_sysent->sv_table[0];
        else
-               callp = &p->p_sysent->sv_table[code];
-
-       narg = callp->sy_narg;
+               sa->callp = &p->p_sysent->sv_table[sa->code];
+       sa->narg = sa->callp->sy_narg;
 
-       /*
-        * copyin and the ktrsyscall()/ktrsysret() code is MP-aware
-        */
-       if (params != NULL && narg != 0)
-               error = copyin(params, (caddr_t)args,
-                   (u_int)(narg * sizeof(int)));
+       if (sa->params != NULL && sa->narg != 0)
+               error = copyin(sa->params, (caddr_t)args,
+                   (u_int)(sa->narg * sizeof(int)));
        else
                error = 0;
 
-       for (i = 0; i < narg; i++)
-               args64[i] = args[i];
+       for (i = 0; i < sa->narg; i++)
+               sa->args64[i] = args[i];
 
 #ifdef KTRACE
        if (KTRPOINT(td, KTR_SYSCALL))
-               ktrsyscall(code, narg, args64);
+               ktrsyscall(sa->code, sa->narg, sa->args64);
 #endif
+
+       return (error);
+}
+
+void
+ia32_syscall(struct trapframe *frame)
+{
+       struct thread *td;
+       struct proc *p;
+       struct ia32_syscall_args sa;
+       register_t orig_tf_rflags;
+       int error;
+       ksiginfo_t ksi;
+
+       PCPU_INC(cnt.v_syscall);
+       td = curthread;
+       p = td->td_proc;
+       td->td_syscalls++;
+
+       td->td_pticks = 0;
+       td->td_frame = frame;
+       if (td->td_ucred != p->p_ucred) 
+               cred_update_thread(td);
+       orig_tf_rflags = frame->tf_rflags;
+       if (p->p_flag & P_TRACED) {
+               PROC_LOCK(p);
+               td->td_dbgflags &= ~TDB_USERWR;
+               PROC_UNLOCK(p);
+       }
+       error = fetch_ia32_syscall_args(td, &sa);
+
        CTR4(KTR_SYSC, "syscall enter thread %p pid %d proc %s code %d", td,
-           td->td_proc->p_pid, td->td_proc->p_comm, code);
+           td->td_proc->p_pid, td->td_name, sa.code);
 
        if (error == 0) {
                td->td_retval[0] = 0;
                td->td_retval[1] = frame->tf_rdx;
 
-               STOPEVENT(p, S_SCE, narg);
-
+               STOPEVENT(p, S_SCE, sa.narg);
                PTRACESTOP_SC(p, td, S_PT_SCE);
+               if (td->td_dbgflags & TDB_USERWR) {
+                       /*
+                        * Reread syscall number and arguments if
+                        * debugger modified registers or memory.
+                        */
+                       error = fetch_ia32_syscall_args(td, &sa);
+                       if (error != 0)
+                               goto retval;
+                       td->td_retval[1] = frame->tf_rdx;
+               }
 
-               AUDIT_SYSCALL_ENTER(code, td);
-               error = (*callp->sy_call)(td, args64);
+               AUDIT_SYSCALL_ENTER(sa.code, td);
+               error = (*sa.callp->sy_call)(td, sa.args64);
                AUDIT_SYSCALL_EXIT(error, td);
-       }
 
+               /* Save the latest error return value. */
+               td->td_errno = error;
+       }
+ retval:
        cpu_set_syscall_retval(td, error);
 
        /*
@@ -201,14 +236,16 @@ ia32_syscall(struct trapframe *frame)
         * Check for misbehavior.
         */
        WITNESS_WARN(WARN_PANIC, NULL, "System call %s returning",
-           (code >= 0 && code < SYS_MAXSYSCALL) ? freebsd32_syscallnames[code] 
: "???");
+           (sa.code >= 0 && sa.code < SYS_MAXSYSCALL) ?
+            freebsd32_syscallnames[sa.code] : "???");
        KASSERT(td->td_critnest == 0,
            ("System call %s returning in a critical section",
-           (code >= 0 && code < SYS_MAXSYSCALL) ? freebsd32_syscallnames[code] 
: "???"));
+           (sa.code >= 0 && sa.code < SYS_MAXSYSCALL) ?
+            freebsd32_syscallnames[sa.code] : "???"));
        KASSERT(td->td_locks == 0,
            ("System call %s returning with %d locks held",
-           (code >= 0 && code < SYS_MAXSYSCALL) ? freebsd32_syscallnames[code] 
: "???",
-           td->td_locks));
+           (sa.code >= 0 && sa.code < SYS_MAXSYSCALL) ?
+            freebsd32_syscallnames[sa.code] : "???", td->td_locks));
 
        /*
         * Handle reschedule and other end-of-syscall issues
@@ -216,10 +253,10 @@ ia32_syscall(struct trapframe *frame)
        userret(td, frame);
 
        CTR4(KTR_SYSC, "syscall exit thread %p pid %d proc %s code %d", td,
-           td->td_proc->p_pid, td->td_proc->p_comm, code);
+           td->td_proc->p_pid, td->td_proc->p_comm, sa.code);
 #ifdef KTRACE
        if (KTRPOINT(td, KTR_SYSRET))
-               ktrsysret(code, error, td->td_retval[0]);
+               ktrsysret(sa.code, error, td->td_retval[0]);
 #endif
 
        /*
@@ -227,7 +264,7 @@ ia32_syscall(struct trapframe *frame)
         * register set.  If we ever support an emulation where this
         * is not the case, this code will need to be revisited.
         */
-       STOPEVENT(p, S_SCX, code);
+       STOPEVENT(p, S_SCX, sa.code);
  
        PTRACESTOP_SC(p, td, S_PT_SCX);
 }
diff --git a/sys/i386/i386/trap.c b/sys/i386/i386/trap.c
index 1d3dc3b..305cfd2 100644
--- a/sys/i386/i386/trap.c
+++ b/sys/i386/i386/trap.c
@@ -969,97 +969,130 @@ dblfault_handler()
        panic("double fault");
 }
 
-/*
- *     syscall -       system call request C handler
- *
- *     A system call is essentially treated as a trap.
- */
-void
-syscall(struct trapframe *frame)
-{
-       caddr_t params;
+struct syscall_args {
+       u_int code;
        struct sysent *callp;
-       struct thread *td = curthread;
-       struct proc *p = td->td_proc;
-       register_t orig_tf_eflags;
-       int error;
-       int narg;
        int args[8];
-       u_int code;
-       ksiginfo_t ksi;
+       register_t *argp;
+       int narg;
+};
 
-       PCPU_INC(cnt.v_syscall);
+static int
+fetch_syscall_args(struct thread *td, struct syscall_args *sa)
+{
+       struct proc *p;
+       struct trapframe *frame;
+       caddr_t params;
+       int error;
 
-#ifdef DIAGNOSTIC
-       if (ISPL(frame->tf_cs) != SEL_UPL) {
-               panic("syscall");
-               /* NOT REACHED */
-       }
-#endif
+       p = td->td_proc;
+       frame = td->td_frame;
 
-       td->td_pticks = 0;
-       td->td_frame = frame;
-       if (td->td_ucred != p->p_ucred) 
-               cred_update_thread(td);
        params = (caddr_t)frame->tf_esp + sizeof(int);
-       code = frame->tf_eax;
-       orig_tf_eflags = frame->tf_eflags;
+       sa->code = frame->tf_eax;
 
        if (p->p_sysent->sv_prepsyscall) {
-               (*p->p_sysent->sv_prepsyscall)(frame, args, &code, &params);
+               (*p->p_sysent->sv_prepsyscall)(frame, sa->args, &sa->code,
+                   &params);
        } else {
                /*
                 * Need to check if this is a 32 bit or 64 bit syscall.
                 */
-               if (code == SYS_syscall) {
+               if (sa->code == SYS_syscall) {
                        /*
                         * Code is first argument, followed by actual args.
                         */
-                       code = fuword(params);
+                       sa->code = fuword(params);
                        params += sizeof(int);
-               } else if (code == SYS___syscall) {
+               } else if (sa->code == SYS___syscall) {
                        /*
                         * Like syscall, but code is a quad, so as to maintain
                         * quad alignment for the rest of the arguments.
                         */
-                       code = fuword(params);
+                       sa->code = fuword(params);
                        params += sizeof(quad_t);
                }
        }
 
        if (p->p_sysent->sv_mask)
-               code &= p->p_sysent->sv_mask;
-
-       if (code >= p->p_sysent->sv_size)
-               callp = &p->p_sysent->sv_table[0];
+               sa->code &= p->p_sysent->sv_mask;
+       if (sa->code >= p->p_sysent->sv_size)
+               sa->callp = &p->p_sysent->sv_table[0];
        else
-               callp = &p->p_sysent->sv_table[code];
-
-       narg = callp->sy_narg;
+               sa->callp = &p->p_sysent->sv_table[sa->code];
+       sa->narg = sa->callp->sy_narg;
 
-       if (params != NULL && narg != 0)
-               error = copyin(params, (caddr_t)args,
-                   (u_int)(narg * sizeof(int)));
+       if (params != NULL && sa->narg != 0)
+               error = copyin(params, (caddr_t)sa->args,
+                   (u_int)(sa->narg * sizeof(int)));
        else
                error = 0;
                
 #ifdef KTRACE
        if (KTRPOINT(td, KTR_SYSCALL))
-               ktrsyscall(code, narg, args);
+               ktrsyscall(sa->code, sa->narg, sa->args);
 #endif
+       return (error);
+}
 
-       CTR4(KTR_SYSC, "syscall enter thread %p pid %d proc %s code %d", td,
-           td->td_proc->p_pid, td->td_name, code);
+/*
+ *     syscall -       system call request C handler
+ *
+ *     A system call is essentially treated as a trap.
+ */
+void
+syscall(struct trapframe *frame)
+{
+       struct thread *td;
+       struct proc *p;
+       struct syscall_args sa;
+       register_t orig_tf_eflags;
+       int error;
+       ksiginfo_t ksi;
 
+       PCPU_INC(cnt.v_syscall);
+       td = curthread;
+       p = td->td_proc;
        td->td_syscalls++;
 
+#ifdef DIAGNOSTIC
+       if (ISPL(frame->tf_cs) != SEL_UPL) {
+               panic("syscall");
+               /* NOT REACHED */
+       }
+#endif
+
+       td->td_pticks = 0;
+       td->td_frame = frame;
+       if (td->td_ucred != p->p_ucred) 
+               cred_update_thread(td);
+       orig_tf_eflags = frame->tf_eflags;
+       if (p->p_flag & P_TRACED) {
+               PROC_LOCK(p);
+               td->td_dbgflags &= ~TDB_USERWR;
+               PROC_UNLOCK(p);
+       }
+       error = fetch_syscall_args(td, &sa);
+
+       CTR4(KTR_SYSC, "syscall enter thread %p pid %d proc %s code %d", td,
+           td->td_proc->p_pid, td->td_name, sa.code);
+
        if (error == 0) {
                td->td_retval[0] = 0;
                td->td_retval[1] = frame->tf_edx;
 
-               STOPEVENT(p, S_SCE, narg);
-
+               STOPEVENT(p, S_SCE, sa.narg);
                PTRACESTOP_SC(p, td, S_PT_SCE);
+               if (td->td_dbgflags & TDB_USERWR) {
+                       /*
+                        * Reread syscall number and arguments if
+                        * debugger modified registers or memory.
+                        */
+                       error = fetch_syscall_args(td, &sa);
+                       if (error != 0)
+                               goto retval;
+                       td->td_retval[1] = frame->tf_edx;
+               }
 
 #ifdef KDTRACE_HOOKS
                /*
@@ -1067,13 +1100,13 @@ syscall(struct trapframe *frame)
                 * callback and if there is a probe active for the
                 * syscall 'entry', process the probe.
                 */
-               if (systrace_probe_func != NULL && callp->sy_entry != 0)
-                       (*systrace_probe_func)(callp->sy_entry, code, callp,
-                           args);
+               if (systrace_probe_func != NULL && sa.callp->sy_entry != 0)
+                       (*systrace_probe_func)(sa.callp->sy_entry, sa.code,
+                           sa.callp, sa.args);
 #endif
 
-               AUDIT_SYSCALL_ENTER(code, td);
-               error = (*callp->sy_call)(td, args);
+               AUDIT_SYSCALL_ENTER(sa.code, td);
+               error = (*sa.callp->sy_call)(td, sa.args);
                AUDIT_SYSCALL_EXIT(error, td);
 
                /* Save the latest error return value. */
@@ -1085,12 +1118,12 @@ syscall(struct trapframe *frame)
                 * callback and if there is a probe active for the
                 * syscall 'return', process the probe.
                 */
-               if (systrace_probe_func != NULL && callp->sy_return != 0)
-                       (*systrace_probe_func)(callp->sy_return, code, callp,
-                           args);
+               if (systrace_probe_func != NULL && sa.callp->sy_return != 0)
+                       (*systrace_probe_func)(sa.callp->sy_return, sa.code,
+                           sa.callp, sa.args);
 #endif
        }
-
+ retval:
        cpu_set_syscall_retval(td, error);
 
        /*
@@ -1109,14 +1142,16 @@ syscall(struct trapframe *frame)
         * Check for misbehavior.
         */
        WITNESS_WARN(WARN_PANIC, NULL, "System call %s returning",
-           (code >= 0 && code < SYS_MAXSYSCALL) ? syscallnames[code] : "???");
+           (sa.code >= 0 && sa.code < SYS_MAXSYSCALL) ?
+            syscallnames[sa.code] : "???");
        KASSERT(td->td_critnest == 0,
            ("System call %s returning in a critical section",
-           (code >= 0 && code < SYS_MAXSYSCALL) ? syscallnames[code] : "???"));
+           (sa.code >= 0 && sa.code < SYS_MAXSYSCALL) ?
+            syscallnames[sa.code] : "???"));
        KASSERT(td->td_locks == 0,
            ("System call %s returning with %d locks held",
-           (code >= 0 && code < SYS_MAXSYSCALL) ? syscallnames[code] : "???",
-           td->td_locks));
+           (sa.code >= 0 && sa.code < SYS_MAXSYSCALL) ?
+            syscallnames[sa.code] : "???", td->td_locks));
 
        /*
         * Handle reschedule and other end-of-syscall issues
@@ -1124,11 +1159,11 @@ syscall(struct trapframe *frame)
        userret(td, frame);
 
        CTR4(KTR_SYSC, "syscall exit thread %p pid %d proc %s code %d", td,
-           td->td_proc->p_pid, td->td_name, code);
+           td->td_proc->p_pid, td->td_name, sa.code);
 
 #ifdef KTRACE
        if (KTRPOINT(td, KTR_SYSRET))
-               ktrsysret(code, error, td->td_retval[0]);
+               ktrsysret(sa.code, error, td->td_retval[0]);
 #endif
 
        /*
@@ -1136,7 +1171,7 @@ syscall(struct trapframe *frame)
         * register set.  If we ever support an emulation where this
         * is not the case, this code will need to be revisited.
         */
-       STOPEVENT(p, S_SCX, code);
+       STOPEVENT(p, S_SCX, sa.code);
 
        PTRACESTOP_SC(p, td, S_PT_SCX);
 }
diff --git a/sys/kern/sys_process.c b/sys/kern/sys_process.c
index dfc36ba..3c6394c 100644
--- a/sys/kern/sys_process.c
+++ b/sys/kern/sys_process.c
@@ -816,6 +816,7 @@ kern_ptrace(struct thread *td, int req, pid_t pid, void 
*addr, int data)
 
        case PT_WRITE_I:
        case PT_WRITE_D:
+               td2->td_dbgflags |= TDB_USERWR;
                write = 1;
                /* FALLTHROUGH */
        case PT_READ_I:
@@ -884,6 +885,7 @@ kern_ptrace(struct thread *td, int req, pid_t pid, void 
*addr, int data)
                        break;
                case PIOD_WRITE_D:
                case PIOD_WRITE_I:
+                       td2->td_dbgflags |= TDB_USERWR;
                        uio.uio_rw = UIO_WRITE;
                        break;
                default:
@@ -906,6 +908,7 @@ kern_ptrace(struct thread *td, int req, pid_t pid, void 
*addr, int data)
                goto sendsig;   /* in PT_CONTINUE above */
 
        case PT_SETREGS:
+               td2->td_dbgflags |= TDB_USERWR;
                error = PROC_WRITE(regs, td2, addr);
                break;
 
@@ -914,6 +917,7 @@ kern_ptrace(struct thread *td, int req, pid_t pid, void 
*addr, int data)
                break;
 
        case PT_SETFPREGS:
+               td2->td_dbgflags |= TDB_USERWR;
                error = PROC_WRITE(fpregs, td2, addr);
                break;
 
@@ -922,6 +926,7 @@ kern_ptrace(struct thread *td, int req, pid_t pid, void 
*addr, int data)
                break;
 
        case PT_SETDBREGS:
+               td2->td_dbgflags |= TDB_USERWR;
                error = PROC_WRITE(dbregs, td2, addr);
                break;
 
diff --git a/sys/sys/proc.h b/sys/sys/proc.h
index 0ae36af..dd9efae 100644
--- a/sys/sys/proc.h
+++ b/sys/sys/proc.h
@@ -341,6 +341,7 @@ do {                                                        
                \
 /* Userland debug flags */
 #define        TDB_SUSPEND     0x00000001 /* Thread is suspended by debugger */
 #define        TDB_XSIG        0x00000002 /* Thread is exchanging signal under 
trace */
+#define        TDB_USERWR      0x00000004 /* Debugger modified memory or 
registers */
 
 /*
  * "Private" flags kept in td_pflags:

Attachment: pgpnskFXwYKF1.pgp
Description: PGP signature

Reply via email to