Skip to content
Browse files

Merge branch '32-on-64'

  • Loading branch information...
2 parents 66888f4 + 8701cf6 commit e17b77ad9aac7664055913299e96275a37d8e1db @nelhage committed May 13, 2011
Showing with 258 additions and 98 deletions.
  1. +74 −11 arch/amd64.h
  2. +15 −12 arch/arm.h
  3. +32 −0 arch/default-syscalls.h
  4. +19 −11 arch/i386.h
  5. +23 −5 arch/x86_common.h
  6. +36 −51 attach.c
  7. +40 −8 ptrace.c
  8. +19 −0 ptrace.h
View
85 arch/amd64.h
@@ -19,16 +19,79 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
-#define orig_ax orig_rax
-#define reg_ax rax
-#define reg_ip rip
+#include "x86_common.h"
-#define syscall_rv rax
-#define syscall_arg0 rdi
-#define syscall_arg1 rsi
-#define syscall_arg2 rdx
-#define syscall_arg3 r10
-#define syscall_arg4 r8
-#define syscall_arg5 r9
+#define ARCH_HAVE_MULTIPLE_PERSONALITIES
-#include "x86_common.h"
+static struct ptrace_personality arch_personality[2] = {
+ {
+ offsetof(struct user, regs.rax),
+ offsetof(struct user, regs.rdi),
+ offsetof(struct user, regs.rsi),
+ offsetof(struct user, regs.rdx),
+ offsetof(struct user, regs.r10),
+ offsetof(struct user, regs.r8),
+ offsetof(struct user, regs.r9),
+ offsetof(struct user, regs.rip),
+ },
+ {
+ offsetof(struct user, regs.rax),
+ offsetof(struct user, regs.rbx),
+ offsetof(struct user, regs.rcx),
+ offsetof(struct user, regs.rdx),
+ offsetof(struct user, regs.rsi),
+ offsetof(struct user, regs.rdi),
+ offsetof(struct user, regs.rbp),
+ offsetof(struct user, regs.rip),
+ },
+};
+
+struct x86_personality x86_personality[2] = {
+ {
+ offsetof(struct user, regs.orig_rax),
+ offsetof(struct user, regs.rax),
+ },
+ {
+ offsetof(struct user, regs.orig_rax),
+ offsetof(struct user, regs.rax),
+ },
+};
+
+struct syscall_numbers arch_syscall_numbers[2] = {
+#include "default-syscalls.h"
+ {
+ /*
+ * These don't seem to be available in any convenient header. We could
+ * include unistd_32.h, but those definitions would conflict with the
+ * standard ones. So, let's just hardcode the values for now. Probably
+ * we should generate this from unistd_32.h during the build process or
+ * soemthing.
+ */
+ .nr_mmap = 90,
+ .nr_mmap2 = 192,
+ .nr_munmap = 91,
+ .nr_getsid = 147,
+ .nr_setsid = 66,
+ .nr_setpgid = 57,
+ .nr_fork = 2,
+ .nr_wait4 = 114,
+ .nr_signal = 48,
+ .nr_rt_sigaction = 173,
+ .nr_open = 5,
+ .nr_close = 6,
+ .nr_ioctl = 54,
+ .nr_dup2 = 63
+ }
+};
+
+int arch_get_personality(struct ptrace_child *child) {
+ unsigned long cs;
+
+ cs = ptrace_command(child, PTRACE_PEEKUSER,
+ offsetof(struct user, regs.cs));
+ if (child->error)
+ return -1;
+ if (cs == 0x23)
+ child->personality = 1;
+ return 0;
+}
View
27 arch/arm.h
@@ -19,18 +19,21 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
-#define reg_ip ARM_pc
+static struct ptrace_personality arch_personality[1] = {
+ {
+ offsetof(struct user, regs.uregs[0]),
+ offsetof(struct user, regs.uregs[0]),
+ offsetof(struct user, regs.uregs[1]),
+ offsetof(struct user, regs.uregs[2]),
+ offsetof(struct user, regs.uregs[3]),
+ offsetof(struct user, regs.uregs[4]),
+ offsetof(struct user, regs.uregs[5]),
+ offsetof(struct user, regs.ARM_pc),
+ }
+};
-#define syscall_rv uregs[0]
-#define syscall_arg0 uregs[0]
-#define syscall_arg1 uregs[1]
-#define syscall_arg2 uregs[2]
-#define syscall_arg3 uregs[3]
-#define syscall_arg4 uregs[4]
-#define syscall_arg5 uregs[5]
-
-static inline void arch_fixup_regs(struct user *user) {
- user->regs.reg_ip -= 4;
+static inline void arch_fixup_regs(struct ptrace_child *child) {
+ child->user.regs.ARM_pc -= 4;
}
static inline int arch_set_syscall(struct ptrace_child *child,
@@ -40,7 +43,7 @@ static inline int arch_set_syscall(struct ptrace_child *child,
static inline int arch_save_syscall(struct ptrace_child *child) {
unsigned long swi;
- swi = ptrace_command(child, PTRACE_PEEKTEXT, child->user.regs.reg_ip);
+ swi = ptrace_command(child, PTRACE_PEEKTEXT, child->user.regs.ARM_pc);
if (child->error)
return -1;
if (swi == 0xef000000)
View
32 arch/default-syscalls.h
@@ -0,0 +1,32 @@
+#define SC(name) .nr_##name = __NR_##name
+
+{
+#ifdef __NR_mmap
+ SC(mmap),
+#else
+ .nr_mmap = -1,
+#endif
+#ifdef __NR_mmap2
+ SC(mmap2),
+#else
+ .nr_mmap2 = -1,
+#endif
+ SC(munmap),
+ SC(getsid),
+ SC(setsid),
+ SC(setpgid),
+ SC(fork),
+ SC(wait4),
+#ifdef __NR_signal
+ SC(signal),
+#else
+ .nr_signal = -1,
+#endif
+ SC(rt_sigaction),
+ SC(open),
+ SC(close),
+ SC(ioctl),
+ SC(dup2),
+},
+
+#undef SC
View
30 arch/i386.h
@@ -19,16 +19,24 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
-#define orig_ax orig_eax
-#define reg_ax eax
-#define reg_ip eip
+#include "x86_common.h"
-#define syscall_rv eax
-#define syscall_arg0 ebx
-#define syscall_arg1 ecx
-#define syscall_arg2 edx
-#define syscall_arg3 esi
-#define syscall_arg4 edi
-#define syscall_arg5 ebp
+static struct ptrace_personality arch_personality[1] = {
+ {
+ offsetof(struct user, regs.eax),
+ offsetof(struct user, regs.ebx),
+ offsetof(struct user, regs.ecx),
+ offsetof(struct user, regs.edx),
+ offsetof(struct user, regs.esi),
+ offsetof(struct user, regs.edi),
+ offsetof(struct user, regs.ebp),
+ offsetof(struct user, regs.eip),
+ }
+};
-#include "x86_common.h"
+struct x86_personality x86_personality[1] = {
+ {
+ offsetof(struct user, regs.orig_eax),
+ offsetof(struct user, regs.eax),
+ }
+};
View
28 arch/x86_common.h
@@ -19,23 +19,41 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
-static inline void arch_fixup_regs(struct user *user) {
- user->regs.reg_ip -= 2;
- user->regs.reg_ax = user->regs.orig_ax;
+
+struct x86_personality {
+ size_t orig_ax;
+ size_t ax;
+};
+
+struct x86_personality x86_personality[];
+
+static inline struct x86_personality *x86_pers(struct ptrace_child *child) {
+ return &x86_personality[child->personality];
+}
+
+static inline void arch_fixup_regs(struct ptrace_child *child) {
+ struct x86_personality *x86pers = x86_pers(child);
+ struct ptrace_personality *pers = personality(child);
+ struct user *user = &child->user;
+#define ptr(user, off) ((unsigned long*)((void*)(user)+(off)))
+ *ptr(user, pers->reg_ip) -= 2;
+ *ptr(user, x86pers->ax) = *ptr(user, x86pers->orig_ax);
}
static inline int arch_set_syscall(struct ptrace_child *child,
unsigned long sysno) {
return ptrace_command(child, PTRACE_POKEUSER,
- offsetof(struct user, regs.orig_ax),
+ x86_pers(child)->orig_ax,
sysno);
}
static inline int arch_save_syscall(struct ptrace_child *child) {
- child->saved_syscall = child->user.regs.orig_ax;
+ child->saved_syscall = *ptr(&child->user, x86_pers(child)->orig_ax);
return 0;
}
static inline int arch_restore_syscall(struct ptrace_child *child) {
return 0;
}
+
+#undef ptr
View
87 attach.c
@@ -40,12 +40,6 @@
#include "ptrace.h"
#include "reptyr.h"
-#ifdef __NR_mmap2
-#define mmap_syscall __NR_mmap2
-#else
-#define mmap_syscall __NR_mmap
-#endif
-
#define TASK_COMM_LENGTH 16
struct proc_stat {
pid_t pid;
@@ -55,6 +49,10 @@ struct proc_stat {
dev_t ctty;
};
+#define do_syscall(child, name, a0, a1, a2, a3, a4, a5) \
+ ptrace_remote_syscall((child), ptrace_syscall_numbers((child))->nr_##name, \
+ a0, a1, a2, a3, a4, a5)
+
int parse_proc_stat(int statfd, struct proc_stat *out) {
char buf[1024];
int n;
@@ -78,7 +76,7 @@ int parse_proc_stat(int statfd, struct proc_stat *out) {
static void do_unmap(struct ptrace_child *child, child_addr_t addr, unsigned long len) {
if (addr == (unsigned long)-1)
return;
- ptrace_remote_syscall(child, __NR_munmap, addr, len, 0, 0, 0, 0);
+ do_syscall(child, munmap, addr, len, 0, 0, 0, 0);
}
int *get_child_tty_fds(struct ptrace_child *child, int statfd, int *count) {
@@ -152,9 +150,7 @@ void move_process_group(struct ptrace_child *child, pid_t from, pid_t to) {
if (*p) continue;
if (getpgid(pid) == from) {
debug("Change pgid for pid %d", pid);
- err = ptrace_remote_syscall(child, __NR_setpgid,
- pid, to,
- 0, 0, 0, 0);
+ err = do_syscall(child, setpgid, pid, to, 0, 0, 0, 0);
if (err < 0)
error(" failed: %s", strerror(-err));
}
@@ -166,8 +162,7 @@ int do_setsid(struct ptrace_child *child) {
int err = 0;
struct ptrace_child dummy;
- err = ptrace_remote_syscall(child, __NR_fork,
- 0, 0, 0, 0, 0, 0);
+ err = do_syscall(child, fork, 0, 0, 0, 0, 0, 0);
if (err < 0)
return err;
@@ -184,17 +179,15 @@ int do_setsid(struct ptrace_child *child) {
goto out_kill;
}
- err = ptrace_remote_syscall(&dummy, __NR_setpgid,
- 0, 0, 0, 0, 0, 0);
+ err = do_syscall(&dummy, setpgid, 0, 0, 0, 0, 0, 0);
if (err < 0) {
error("Failed to setpgid: %s", strerror(-err));
goto out_kill;
}
move_process_group(child, child->pid, dummy.pid);
- err = ptrace_remote_syscall(child, __NR_setsid,
- 0, 0, 0, 0, 0, 0);
+ err = do_syscall(child, setsid, 0, 0, 0, 0, 0, 0);
if (err < 0) {
error("Failed to setsid: %s", strerror(-err));
move_process_group(child, dummy.pid, child->pid);
@@ -207,30 +200,26 @@ int do_setsid(struct ptrace_child *child) {
kill(dummy.pid, SIGKILL);
ptrace_detach_child(&dummy);
ptrace_wait(&dummy);
- ptrace_remote_syscall(child, __NR_wait4,
- dummy.pid, 0, WNOHANG,
- 0, 0, 0);
+ do_syscall(child, wait4, dummy.pid, 0, WNOHANG, 0, 0, 0);
return err;
}
int ignore_hup(struct ptrace_child *child, unsigned long scratch_page) {
int err;
-#ifdef __NR_signal
- err = ptrace_remote_syscall(child, __NR_signal,
- SIGHUP, (unsigned long)SIG_IGN,
- 0, 0, 0, 0);
-#else
- struct sigaction act = {
- .sa_handler = SIG_IGN,
- };
- err = ptrace_memcpy_to_child(child, scratch_page,
- &act, sizeof act);
- if (err < 0)
- return err;
- err = ptrace_remote_syscall(child, __NR_rt_sigaction,
- SIGHUP, scratch_page,
- 0, 8, 0, 0);
-#endif
+ if (ptrace_syscall_numbers(child)->nr_signal != -1) {
+ err = do_syscall(child, signal, SIGHUP, (unsigned long)SIG_IGN, 0, 0, 0, 0);
+ } else {
+ struct sigaction act = {
+ .sa_handler = SIG_IGN,
+ };
+ err = ptrace_memcpy_to_child(child, scratch_page,
+ &act, sizeof act);
+ if (err < 0)
+ return err;
+ err = do_syscall(child, rt_sigaction,
+ SIGHUP, scratch_page,
+ 0, 8, 0, 0);
+ }
return err;
}
@@ -319,6 +308,7 @@ int attach_child(pid_t pid, const char *pty, int force_stdio) {
int err = 0;
long page_size = sysconf(_SC_PAGE_SIZE);
char stat_path[PATH_MAX];
+ long mmap_syscall;
if ((err = copy_tty_state(pid, pty))) {
if (err == ENOTTY && !force_stdio) {
@@ -352,6 +342,9 @@ int attach_child(pid_t pid, const char *pty, int force_stdio) {
goto out_detach;
}
+ mmap_syscall = ptrace_syscall_numbers(&child)->nr_mmap2;
+ if (mmap_syscall == -1)
+ mmap_syscall = ptrace_syscall_numbers(&child)->nr_mmap;
scratch_page = ptrace_remote_syscall(&child, mmap_syscall, 0,
page_size, PROT_READ|PROT_WRITE,
MAP_ANONYMOUS|MAP_PRIVATE, 0, 0);
@@ -387,9 +380,9 @@ int attach_child(pid_t pid, const char *pty, int force_stdio) {
goto out_free_fds;
}
- child_fd = ptrace_remote_syscall(&child, __NR_open,
- scratch_page, O_RDWR|O_NOCTTY,
- 0, 0, 0, 0);
+ child_fd = do_syscall(&child, open,
+ scratch_page, O_RDWR|O_NOCTTY,
+ 0, 0, 0, 0);
if (child_fd < 0) {
err = child_fd;
error("Unable to open the tty in the child.");
@@ -402,22 +395,17 @@ int attach_child(pid_t pid, const char *pty, int force_stdio) {
if (err < 0)
goto out_close;
- err = ptrace_remote_syscall(&child, __NR_getsid,
- 0, 0, 0, 0, 0, 0);
+ err = do_syscall(&child, getsid, 0, 0, 0, 0, 0, 0);
if (err != child.pid) {
debug("Target is not a session leader, attempting to setsid.");
err = do_setsid(&child);
} else {
- ptrace_remote_syscall(&child, __NR_ioctl,
- child_tty_fds[0], TIOCNOTTY,
- 0, 0, 0, 0);
+ do_syscall(&child, ioctl, child_tty_fds[0], TIOCNOTTY, 0, 0, 0, 0);
}
if (err < 0)
goto out_close;
- err = ptrace_remote_syscall(&child, __NR_ioctl,
- child_fd, TIOCSCTTY,
- 0, 0, 0, 0);
+ err = do_syscall(&child, ioctl, child_fd, TIOCSCTTY, 0, 0, 0, 0);
if (err < 0) {
error("Unable to set controlling terminal.");
goto out_close;
@@ -426,16 +414,13 @@ int attach_child(pid_t pid, const char *pty, int force_stdio) {
debug("Set the controlling tty");
for (i = 0; i < n_fds; i++)
- ptrace_remote_syscall(&child, __NR_dup2,
- child_fd, child_tty_fds[i],
- 0, 0, 0, 0);
+ do_syscall(&child, dup2, child_fd, child_tty_fds[i], 0, 0, 0, 0);
err = 0;
out_close:
- ptrace_remote_syscall(&child, __NR_close, child_fd,
- 0, 0, 0, 0, 0);
+ do_syscall(&child, close, child_fd, 0, 0, 0, 0, 0);
out_free_fds:
free(child_tty_fds);
View
48 ptrace.c
@@ -64,6 +64,20 @@ static long __ptrace_command(struct ptrace_child *child, enum __ptrace_request r
#define ptrace_command(cld, req, ...) _ptrace_command(cld, req, ## __VA_ARGS__, NULL, NULL)
#define _ptrace_command(cld, req, addr, data, ...) __ptrace_command((cld), (req), (void*)(addr), (void*)(data))
+
+struct ptrace_personality {
+ size_t syscall_rv;
+ size_t syscall_arg0;
+ size_t syscall_arg1;
+ size_t syscall_arg2;
+ size_t syscall_arg3;
+ size_t syscall_arg4;
+ size_t syscall_arg5;
+ size_t reg_ip;
+};
+
+static struct ptrace_personality *personality(struct ptrace_child *child);
+
#if defined(__amd64__)
#include "arch/amd64.h"
#elif defined(__i386__)
@@ -74,6 +88,24 @@ static long __ptrace_command(struct ptrace_child *child, enum __ptrace_request r
#error Unsupported architecture.
#endif
+#ifndef ARCH_HAVE_MULTIPLE_PERSONALITIES
+int arch_get_personality(struct ptrace_child *child) {
+ return 0;
+}
+
+struct syscall_numbers arch_syscall_numbers[] = {
+#include "arch/default-syscalls.h"
+};
+#endif
+
+static struct ptrace_personality *personality(struct ptrace_child *child) {
+ return &arch_personality[child->personality];
+}
+
+struct syscall_numbers *ptrace_syscall_numbers(struct ptrace_child *child) {
+ return &arch_syscall_numbers[child->personality];
+}
+
int ptrace_attach_child(struct ptrace_child *child, pid_t pid) {
memset(child, 0, sizeof *child);
child->pid = pid;
@@ -91,6 +123,9 @@ int ptrace_finish_attach(struct ptrace_child *child, pid_t pid) {
if (ptrace_wait(child) < 0)
goto detach;
+ if (arch_get_personality(child))
+ goto detach;
+
if (ptrace_command(child, PTRACE_SETOPTIONS, 0,
PTRACE_O_TRACESYSGOOD|PTRACE_O_TRACEFORK) < 0)
goto detach;
@@ -168,16 +203,12 @@ int ptrace_advance_to_state(struct ptrace_child *child,
}
-static void reset_user_struct(struct user *user) {
- arch_fixup_regs(user);
-}
-
int ptrace_save_regs(struct ptrace_child *child) {
if (ptrace_advance_to_state(child, ptrace_at_syscall) < 0)
return -1;
if (ptrace_command(child, PTRACE_GETREGS, 0, &child->user) < 0)
return -1;
- reset_user_struct(&child->user);
+ arch_fixup_regs(child);
if (arch_save_syscall(child) < 0)
return -1;
return 0;
@@ -202,7 +233,7 @@ unsigned long ptrace_remote_syscall(struct ptrace_child *child,
#define setreg(r, v) do { \
if (ptrace_command(child, PTRACE_POKEUSER, \
- offsetof(struct user, regs.r), \
+ personality(child)->r, \
(v)) < 0) \
return -1; \
} while (0)
@@ -220,11 +251,12 @@ unsigned long ptrace_remote_syscall(struct ptrace_child *child,
return -1;
rv = ptrace_command(child, PTRACE_PEEKUSER,
- offsetof(struct user, regs.syscall_rv));
+ personality(child)->syscall_rv);
if (child->error)
return -1;
- setreg(reg_ip, child->user.regs.reg_ip);
+ setreg(reg_ip, *(unsigned long*)((void*)&child->user +
+ personality(child)->reg_ip));
#undef setreg
View
19 ptrace.h
@@ -35,13 +35,31 @@ enum child_state {
struct ptrace_child {
pid_t pid;
enum child_state state;
+ int personality;
int status;
int error;
unsigned long forked_pid;
struct user user;
unsigned long saved_syscall;
};
+struct syscall_numbers {
+ long nr_mmap;
+ long nr_mmap2;
+ long nr_munmap;
+ long nr_getsid;
+ long nr_setsid;
+ long nr_setpgid;
+ long nr_fork;
+ long nr_wait4;
+ long nr_signal;
+ long nr_rt_sigaction;
+ long nr_open;
+ long nr_close;
+ long nr_ioctl;
+ long nr_dup2;
+};
+
typedef unsigned long child_addr_t;
int ptrace_wait(struct ptrace_child *child);
@@ -61,3 +79,4 @@ unsigned long ptrace_remote_syscall(struct ptrace_child *child,
int ptrace_memcpy_to_child(struct ptrace_child *, child_addr_t, const void*, size_t);
int ptrace_memcpy_from_child(struct ptrace_child *, void*, child_addr_t, size_t);
+struct syscall_numbers *ptrace_syscall_numbers(struct ptrace_child *child);

0 comments on commit e17b77a

Please sign in to comment.
Something went wrong with that request. Please try again.