proot: Work around inability to use change syscall (#390)
* proot: Work around inability to use change syscall * Use -1 as SYSCALL_AVOIDER on aarch64
This commit is contained in:
parent
7892fa9703
commit
22e490e751
14
packages/proot/src-arch.h.patch
Normal file
14
packages/proot/src-arch.h.patch
Normal file
@ -0,0 +1,14 @@
|
||||
diff -r -u PRoot-next/src/arch.h src/src/arch.h
|
||||
--- PRoot-next/src/arch.h 2015-07-23 21:50:10.000000000 +0200
|
||||
+++ src/src/arch.h 2016-08-17 16:15:24.197684187 +0200
|
||||
@@ -133,6 +133,10 @@
|
||||
#define EXEC_PIC_ADDRESS 0x3000000000
|
||||
#define INTERP_PIC_ADDRESS 0x3f00000000
|
||||
|
||||
+ /* Syscall -2 appears to cause some odd side effects, use -1 */
|
||||
+ #undef SYSCALL_AVOIDER
|
||||
+ #define SYSCALL_AVOIDER ((word_t) -1)
|
||||
+
|
||||
#elif defined(ARCH_X86)
|
||||
|
||||
#define SYSNUMS_HEADER1 "syscall/sysnums-i386.h"
|
272
packages/proot/workaround-NT_ARM_SYSTEM_CALL.patch
Normal file
272
packages/proot/workaround-NT_ARM_SYSTEM_CALL.patch
Normal file
@ -0,0 +1,272 @@
|
||||
diff -r -u src/src/syscall/chain.c src_set_syscall_workaround/src/syscall/chain.c
|
||||
--- src/src/syscall/chain.c 2015-07-23 21:50:10.000000000 +0200
|
||||
+++ src_set_syscall_workaround/src/syscall/chain.c 2016-08-12 19:33:13.920471000 +0200
|
||||
@@ -39,17 +39,10 @@
|
||||
|
||||
STAILQ_HEAD(chained_syscalls, chained_syscall);
|
||||
|
||||
-/**
|
||||
- * Append a new syscall (@sysnum, @sysarg_*) to the list of
|
||||
- * "unrequested" syscalls for the given @tracee. These new syscalls
|
||||
- * will be triggered in order once the current syscall is done. The
|
||||
- * caller is free to force the last result of this syscall chain in
|
||||
- * @tracee->chain.final_result. This function returns -errno if an
|
||||
- * error occurred, otherwise 0.
|
||||
- */
|
||||
-int register_chained_syscall(Tracee *tracee, Sysnum sysnum,
|
||||
+static int register_chained_syscall_internal(Tracee *tracee, Sysnum sysnum,
|
||||
word_t sysarg_1, word_t sysarg_2, word_t sysarg_3,
|
||||
- word_t sysarg_4, word_t sysarg_5, word_t sysarg_6)
|
||||
+ word_t sysarg_4, word_t sysarg_5, word_t sysarg_6,
|
||||
+ bool at_front)
|
||||
{
|
||||
struct chained_syscall *syscall;
|
||||
|
||||
@@ -73,12 +66,35 @@
|
||||
syscall->sysargs[4] = sysarg_5;
|
||||
syscall->sysargs[5] = sysarg_6;
|
||||
|
||||
- STAILQ_INSERT_TAIL(tracee->chain.syscalls, syscall, link);
|
||||
+ if (at_front) {
|
||||
+ STAILQ_INSERT_HEAD(tracee->chain.syscalls, syscall, link);
|
||||
+ } else {
|
||||
+ STAILQ_INSERT_TAIL(tracee->chain.syscalls, syscall, link);
|
||||
+ }
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
+ * Append a new syscall (@sysnum, @sysarg_*) to the list of
|
||||
+ * "unrequested" syscalls for the given @tracee. These new syscalls
|
||||
+ * will be triggered in order once the current syscall is done. The
|
||||
+ * caller is free to force the last result of this syscall chain in
|
||||
+ * @tracee->chain.final_result. This function returns -errno if an
|
||||
+ * error occurred, otherwise 0.
|
||||
+ */
|
||||
+int register_chained_syscall(Tracee *tracee, Sysnum sysnum,
|
||||
+ word_t sysarg_1, word_t sysarg_2, word_t sysarg_3,
|
||||
+ word_t sysarg_4, word_t sysarg_5, word_t sysarg_6) {
|
||||
+ return register_chained_syscall_internal(
|
||||
+ tracee, sysnum,
|
||||
+ sysarg_1, sysarg_2, sysarg_3,
|
||||
+ sysarg_4, sysarg_5, sysarg_6,
|
||||
+ false
|
||||
+ );
|
||||
+}
|
||||
+
|
||||
+/**
|
||||
* Use/remove the first element of @tracee->chain.syscalls to forge a
|
||||
* new syscall. This function should be called only at the end of in
|
||||
* the sysexit stage.
|
||||
@@ -126,6 +142,9 @@
|
||||
/* Move the instruction pointer back to the original trap. */
|
||||
instr_pointer = peek_reg(tracee, CURRENT, INSTR_POINTER);
|
||||
poke_reg(tracee, INSTR_POINTER, instr_pointer - SYSTRAP_SIZE);
|
||||
+
|
||||
+ /* Break after exit from syscall, there may be another one in chain */
|
||||
+ tracee->restart_how = PTRACE_SYSCALL;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -154,3 +173,18 @@
|
||||
peek_reg(tracee, ORIGINAL, SYSARG_5),
|
||||
peek_reg(tracee, ORIGINAL, SYSARG_6));
|
||||
}
|
||||
+
|
||||
+int restart_current_syscall_as_chained(Tracee *tracee)
|
||||
+{
|
||||
+ assert(tracee->chain.sysnum_workaround_state == SYSNUM_WORKAROUND_INACTIVE);
|
||||
+ tracee->chain.sysnum_workaround_state = SYSNUM_WORKAROUND_PROCESS_FAULTY_CALL;
|
||||
+ return register_chained_syscall_internal(tracee,
|
||||
+ get_sysnum(tracee, CURRENT),
|
||||
+ peek_reg(tracee, CURRENT, SYSARG_1),
|
||||
+ peek_reg(tracee, CURRENT, SYSARG_2),
|
||||
+ peek_reg(tracee, CURRENT, SYSARG_3),
|
||||
+ peek_reg(tracee, CURRENT, SYSARG_4),
|
||||
+ peek_reg(tracee, CURRENT, SYSARG_5),
|
||||
+ peek_reg(tracee, CURRENT, SYSARG_6),
|
||||
+ true);
|
||||
+}
|
||||
diff -r -u src/src/syscall/chain.h src_set_syscall_workaround/src/syscall/chain.h
|
||||
--- src/src/syscall/chain.h 2015-07-23 21:50:10.000000000 +0200
|
||||
+++ src_set_syscall_workaround/src/syscall/chain.h 2016-08-09 17:12:36.448471000 +0200
|
||||
@@ -37,5 +37,7 @@
|
||||
|
||||
extern void chain_next_syscall(Tracee *tracee);
|
||||
|
||||
+extern int restart_current_syscall_as_chained(Tracee *tracee);
|
||||
+
|
||||
|
||||
#endif /* CHAIN_H */
|
||||
diff -r -u src/src/syscall/syscall.c src_set_syscall_workaround/src/syscall/syscall.c
|
||||
--- src/src/syscall/syscall.c 2015-07-23 21:50:10.000000000 +0200
|
||||
+++ src_set_syscall_workaround/src/syscall/syscall.c 2016-08-12 19:32:35.199527000 +0200
|
||||
@@ -31,6 +31,7 @@
|
||||
#include "tracee/tracee.h"
|
||||
#include "tracee/reg.h"
|
||||
#include "tracee/mem.h"
|
||||
+#include "cli/note.h"
|
||||
|
||||
/**
|
||||
* Copy in @path a C string (PATH_MAX bytes max.) from the @tracee's
|
||||
@@ -126,7 +127,9 @@
|
||||
save_current_regs(tracee, MODIFIED);
|
||||
}
|
||||
else {
|
||||
- status = notify_extensions(tracee, SYSCALL_CHAINED_ENTER, 0, 0);
|
||||
+ if (tracee->chain.sysnum_workaround_state != SYSNUM_WORKAROUND_PROCESS_REPLACED_CALL) {
|
||||
+ status = notify_extensions(tracee, SYSCALL_CHAINED_ENTER, 0, 0);
|
||||
+ }
|
||||
tracee->restart_how = PTRACE_SYSCALL;
|
||||
}
|
||||
|
||||
@@ -159,8 +162,13 @@
|
||||
/* Translate the syscall only if it was actually
|
||||
* requested by the tracee, it is not a syscall
|
||||
* chained by PRoot. */
|
||||
- if (tracee->chain.syscalls == NULL)
|
||||
+ if (tracee->chain.syscalls == NULL || tracee->chain.sysnum_workaround_state == SYSNUM_WORKAROUND_PROCESS_REPLACED_CALL) {
|
||||
+ tracee->chain.sysnum_workaround_state = SYSNUM_WORKAROUND_INACTIVE;
|
||||
translate_syscall_exit(tracee);
|
||||
+ }
|
||||
+ else if (tracee->chain.sysnum_workaround_state == SYSNUM_WORKAROUND_PROCESS_FAULTY_CALL) {
|
||||
+ tracee->chain.sysnum_workaround_state = SYSNUM_WORKAROUND_PROCESS_REPLACED_CALL;
|
||||
+ }
|
||||
else
|
||||
(void) notify_extensions(tracee, SYSCALL_CHAINED_EXIT, 0, 0);
|
||||
|
||||
@@ -172,7 +180,42 @@
|
||||
chain_next_syscall(tracee);
|
||||
}
|
||||
|
||||
- (void) push_regs(tracee);
|
||||
+ bool override_sysnum = is_enter_stage && tracee->chain.syscalls == NULL;
|
||||
+ int push_regs_status = push_specific_regs(tracee, override_sysnum);
|
||||
+
|
||||
+ /* Handle inability to change syscall number */
|
||||
+ if (push_regs_status < 0 && override_sysnum) {
|
||||
+ word_t orig_sysnum = peek_reg(tracee, ORIGINAL, SYSARG_NUM);
|
||||
+ word_t current_sysnum = peek_reg(tracee, CURRENT, SYSARG_NUM);
|
||||
+ if (orig_sysnum != current_sysnum) {
|
||||
+ /* Restart current syscall as chained */
|
||||
+ if (current_sysnum != SYSCALL_AVOIDER) {
|
||||
+ restart_current_syscall_as_chained(tracee);
|
||||
+ }
|
||||
+
|
||||
+ /* Set syscall arguments to make it fail
|
||||
+ * TODO: More reliable way to make invalid arguments */
|
||||
+ if (get_sysnum(tracee, ORIGINAL) == PR_brk) {
|
||||
+ /* For brk() we pass 0 as first arg; this is used to query value without changing it */
|
||||
+ poke_reg(tracee, SYSARG_1, 0);
|
||||
+ } else {
|
||||
+ /* For other syscalls we set all args to -1
|
||||
+ * Hoping there is among them invalid request/address/fd/value that will make syscall fail */
|
||||
+ poke_reg(tracee, SYSARG_1, -1);
|
||||
+ poke_reg(tracee, SYSARG_2, -1);
|
||||
+ poke_reg(tracee, SYSARG_3, -1);
|
||||
+ poke_reg(tracee, SYSARG_4, -1);
|
||||
+ poke_reg(tracee, SYSARG_5, -1);
|
||||
+ poke_reg(tracee, SYSARG_6, -1);
|
||||
+ }
|
||||
+
|
||||
+ /* Push regs again without changing syscall */
|
||||
+ push_regs_status = push_specific_regs(tracee, false);
|
||||
+ if (push_regs_status != 0) {
|
||||
+ note(tracee, WARNING, SYSTEM, "can't set tracee registers in workaround");
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
|
||||
if (is_enter_stage)
|
||||
print_current_regs(tracee, 5, "sysenter end" );
|
||||
diff -r -u src/src/tracee/reg.c src_set_syscall_workaround/src/tracee/reg.c
|
||||
--- src/src/tracee/reg.c 2015-07-23 21:50:10.000000000 +0200
|
||||
+++ src_set_syscall_workaround/src/tracee/reg.c 2016-08-12 14:48:31.410423000 +0200
|
||||
@@ -262,12 +262,7 @@
|
||||
return 0;
|
||||
}
|
||||
|
||||
-/**
|
||||
- * Copy the cached values of all @tracee's general purpose registers
|
||||
- * back to the process, if necessary. This function returns -errno if
|
||||
- * an error occured, 0 otherwise.
|
||||
- */
|
||||
-int push_regs(Tracee *tracee)
|
||||
+int push_specific_regs(Tracee *tracee, bool including_sysnum)
|
||||
{
|
||||
int status;
|
||||
|
||||
@@ -306,12 +301,14 @@
|
||||
/* Update syscall number if needed. On arm64, a new
|
||||
* subcommand has been added to PTRACE_{S,G}ETREGSET
|
||||
* to allow write/read of current sycall number. */
|
||||
- if (current_sysnum != REG(tracee, ORIGINAL, SYSARG_NUM)) {
|
||||
+ if (including_sysnum && current_sysnum != REG(tracee, ORIGINAL, SYSARG_NUM)) {
|
||||
regs.iov_base = ¤t_sysnum;
|
||||
regs.iov_len = sizeof(current_sysnum);
|
||||
status = ptrace(PTRACE_SETREGSET, tracee->pid, NT_ARM_SYSTEM_CALL, ®s);
|
||||
- if (status < 0)
|
||||
- note(tracee, WARNING, SYSTEM, "can't set the syscall number");
|
||||
+ if (status < 0) {
|
||||
+ //note(tracee, WARNING, SYSTEM, "can't set the syscall number");
|
||||
+ return status;
|
||||
+ }
|
||||
}
|
||||
|
||||
/* Update other registers. */
|
||||
@@ -325,10 +322,12 @@
|
||||
* change effectively the syscall number during a
|
||||
* ptrace-stop. */
|
||||
word_t current_sysnum = REG(tracee, CURRENT, SYSARG_NUM);
|
||||
- if (current_sysnum != REG(tracee, ORIGINAL, SYSARG_NUM)) {
|
||||
+ if (including_sysnum && current_sysnum != REG(tracee, ORIGINAL, SYSARG_NUM)) {
|
||||
status = ptrace(PTRACE_SET_SYSCALL, tracee->pid, 0, current_sysnum);
|
||||
- if (status < 0)
|
||||
- note(tracee, WARNING, SYSTEM, "can't set the syscall number");
|
||||
+ if (status < 0) {
|
||||
+ //note(tracee, WARNING, SYSTEM, "can't set the syscall number");
|
||||
+ return status;
|
||||
+ }
|
||||
}
|
||||
# endif
|
||||
|
||||
@@ -340,3 +339,12 @@
|
||||
|
||||
return 0;
|
||||
}
|
||||
+
|
||||
+/**
|
||||
+ * Copy the cached values of all @tracee's general purpose registers
|
||||
+ * back to the process, if necessary. This function returns -errno if
|
||||
+ * an error occured, 0 otherwise.
|
||||
+ */
|
||||
+int push_regs(Tracee *tracee) {
|
||||
+ return push_specific_regs(tracee, true);
|
||||
+}
|
||||
diff -r -u src/src/tracee/reg.h src_set_syscall_workaround/src/tracee/reg.h
|
||||
--- src/src/tracee/reg.h 2015-07-23 21:50:10.000000000 +0200
|
||||
+++ src_set_syscall_workaround/src/tracee/reg.h 2016-08-09 21:38:03.863456000 +0200
|
||||
@@ -43,6 +43,7 @@
|
||||
} Reg;
|
||||
|
||||
extern int fetch_regs(Tracee *tracee);
|
||||
+extern int push_specific_regs(Tracee *tracee, bool including_sysnum);
|
||||
extern int push_regs(Tracee *tracee);
|
||||
|
||||
extern word_t peek_reg(const Tracee *tracee, RegVersion version, Reg reg);
|
||||
diff -r -u src/src/tracee/tracee.h src_set_syscall_workaround/src/tracee/tracee.h
|
||||
--- src/src/tracee/tracee.h 2016-08-12 19:44:07.301407472 +0200
|
||||
+++ src_set_syscall_workaround/src/tracee/tracee.h 2016-08-12 19:52:43.554712737 +0200
|
||||
@@ -193,6 +193,11 @@
|
||||
struct chained_syscalls *syscalls;
|
||||
bool force_final_result;
|
||||
word_t final_result;
|
||||
+ enum {
|
||||
+ SYSNUM_WORKAROUND_INACTIVE,
|
||||
+ SYSNUM_WORKAROUND_PROCESS_FAULTY_CALL,
|
||||
+ SYSNUM_WORKAROUND_PROCESS_REPLACED_CALL
|
||||
+ } sysnum_workaround_state;
|
||||
} chain;
|
||||
|
||||
/* Load info generated during execve sysenter and used during
|
Loading…
Reference in New Issue
Block a user