proot: Work around inability to use change syscall (#390)
[termux-packages] / packages / proot / workaround-NT_ARM_SYSTEM_CALL.patch
1 diff -r -u src/src/syscall/chain.c src_set_syscall_workaround/src/syscall/chain.c
2 --- src/src/syscall/chain.c 2015-07-23 21:50:10.000000000 +0200
3 +++ src_set_syscall_workaround/src/syscall/chain.c 2016-08-12 19:33:13.920471000 +0200
4 @@ -39,17 +39,10 @@
5
6 STAILQ_HEAD(chained_syscalls, chained_syscall);
7
8 -/**
9 - * Append a new syscall (@sysnum, @sysarg_*) to the list of
10 - * "unrequested" syscalls for the given @tracee. These new syscalls
11 - * will be triggered in order once the current syscall is done. The
12 - * caller is free to force the last result of this syscall chain in
13 - * @tracee->chain.final_result. This function returns -errno if an
14 - * error occurred, otherwise 0.
15 - */
16 -int register_chained_syscall(Tracee *tracee, Sysnum sysnum,
17 +static int register_chained_syscall_internal(Tracee *tracee, Sysnum sysnum,
18 word_t sysarg_1, word_t sysarg_2, word_t sysarg_3,
19 - word_t sysarg_4, word_t sysarg_5, word_t sysarg_6)
20 + word_t sysarg_4, word_t sysarg_5, word_t sysarg_6,
21 + bool at_front)
22 {
23 struct chained_syscall *syscall;
24
25 @@ -73,12 +66,35 @@
26 syscall->sysargs[4] = sysarg_5;
27 syscall->sysargs[5] = sysarg_6;
28
29 - STAILQ_INSERT_TAIL(tracee->chain.syscalls, syscall, link);
30 + if (at_front) {
31 + STAILQ_INSERT_HEAD(tracee->chain.syscalls, syscall, link);
32 + } else {
33 + STAILQ_INSERT_TAIL(tracee->chain.syscalls, syscall, link);
34 + }
35
36 return 0;
37 }
38
39 /**
40 + * Append a new syscall (@sysnum, @sysarg_*) to the list of
41 + * "unrequested" syscalls for the given @tracee. These new syscalls
42 + * will be triggered in order once the current syscall is done. The
43 + * caller is free to force the last result of this syscall chain in
44 + * @tracee->chain.final_result. This function returns -errno if an
45 + * error occurred, otherwise 0.
46 + */
47 +int register_chained_syscall(Tracee *tracee, Sysnum sysnum,
48 + word_t sysarg_1, word_t sysarg_2, word_t sysarg_3,
49 + word_t sysarg_4, word_t sysarg_5, word_t sysarg_6) {
50 + return register_chained_syscall_internal(
51 + tracee, sysnum,
52 + sysarg_1, sysarg_2, sysarg_3,
53 + sysarg_4, sysarg_5, sysarg_6,
54 + false
55 + );
56 +}
57 +
58 +/**
59 * Use/remove the first element of @tracee->chain.syscalls to forge a
60 * new syscall. This function should be called only at the end of in
61 * the sysexit stage.
62 @@ -126,6 +142,9 @@
63 /* Move the instruction pointer back to the original trap. */
64 instr_pointer = peek_reg(tracee, CURRENT, INSTR_POINTER);
65 poke_reg(tracee, INSTR_POINTER, instr_pointer - SYSTRAP_SIZE);
66 +
67 + /* Break after exit from syscall, there may be another one in chain */
68 + tracee->restart_how = PTRACE_SYSCALL;
69 }
70
71 /**
72 @@ -154,3 +173,18 @@
73 peek_reg(tracee, ORIGINAL, SYSARG_5),
74 peek_reg(tracee, ORIGINAL, SYSARG_6));
75 }
76 +
77 +int restart_current_syscall_as_chained(Tracee *tracee)
78 +{
79 + assert(tracee->chain.sysnum_workaround_state == SYSNUM_WORKAROUND_INACTIVE);
80 + tracee->chain.sysnum_workaround_state = SYSNUM_WORKAROUND_PROCESS_FAULTY_CALL;
81 + return register_chained_syscall_internal(tracee,
82 + get_sysnum(tracee, CURRENT),
83 + peek_reg(tracee, CURRENT, SYSARG_1),
84 + peek_reg(tracee, CURRENT, SYSARG_2),
85 + peek_reg(tracee, CURRENT, SYSARG_3),
86 + peek_reg(tracee, CURRENT, SYSARG_4),
87 + peek_reg(tracee, CURRENT, SYSARG_5),
88 + peek_reg(tracee, CURRENT, SYSARG_6),
89 + true);
90 +}
91 diff -r -u src/src/syscall/chain.h src_set_syscall_workaround/src/syscall/chain.h
92 --- src/src/syscall/chain.h 2015-07-23 21:50:10.000000000 +0200
93 +++ src_set_syscall_workaround/src/syscall/chain.h 2016-08-09 17:12:36.448471000 +0200
94 @@ -37,5 +37,7 @@
95
96 extern void chain_next_syscall(Tracee *tracee);
97
98 +extern int restart_current_syscall_as_chained(Tracee *tracee);
99 +
100
101 #endif /* CHAIN_H */
102 diff -r -u src/src/syscall/syscall.c src_set_syscall_workaround/src/syscall/syscall.c
103 --- src/src/syscall/syscall.c 2015-07-23 21:50:10.000000000 +0200
104 +++ src_set_syscall_workaround/src/syscall/syscall.c 2016-08-12 19:32:35.199527000 +0200
105 @@ -31,6 +31,7 @@
106 #include "tracee/tracee.h"
107 #include "tracee/reg.h"
108 #include "tracee/mem.h"
109 +#include "cli/note.h"
110
111 /**
112 * Copy in @path a C string (PATH_MAX bytes max.) from the @tracee's
113 @@ -126,7 +127,9 @@
114 save_current_regs(tracee, MODIFIED);
115 }
116 else {
117 - status = notify_extensions(tracee, SYSCALL_CHAINED_ENTER, 0, 0);
118 + if (tracee->chain.sysnum_workaround_state != SYSNUM_WORKAROUND_PROCESS_REPLACED_CALL) {
119 + status = notify_extensions(tracee, SYSCALL_CHAINED_ENTER, 0, 0);
120 + }
121 tracee->restart_how = PTRACE_SYSCALL;
122 }
123
124 @@ -159,8 +162,13 @@
125 /* Translate the syscall only if it was actually
126 * requested by the tracee, it is not a syscall
127 * chained by PRoot. */
128 - if (tracee->chain.syscalls == NULL)
129 + if (tracee->chain.syscalls == NULL || tracee->chain.sysnum_workaround_state == SYSNUM_WORKAROUND_PROCESS_REPLACED_CALL) {
130 + tracee->chain.sysnum_workaround_state = SYSNUM_WORKAROUND_INACTIVE;
131 translate_syscall_exit(tracee);
132 + }
133 + else if (tracee->chain.sysnum_workaround_state == SYSNUM_WORKAROUND_PROCESS_FAULTY_CALL) {
134 + tracee->chain.sysnum_workaround_state = SYSNUM_WORKAROUND_PROCESS_REPLACED_CALL;
135 + }
136 else
137 (void) notify_extensions(tracee, SYSCALL_CHAINED_EXIT, 0, 0);
138
139 @@ -172,7 +180,42 @@
140 chain_next_syscall(tracee);
141 }
142
143 - (void) push_regs(tracee);
144 + bool override_sysnum = is_enter_stage && tracee->chain.syscalls == NULL;
145 + int push_regs_status = push_specific_regs(tracee, override_sysnum);
146 +
147 + /* Handle inability to change syscall number */
148 + if (push_regs_status < 0 && override_sysnum) {
149 + word_t orig_sysnum = peek_reg(tracee, ORIGINAL, SYSARG_NUM);
150 + word_t current_sysnum = peek_reg(tracee, CURRENT, SYSARG_NUM);
151 + if (orig_sysnum != current_sysnum) {
152 + /* Restart current syscall as chained */
153 + if (current_sysnum != SYSCALL_AVOIDER) {
154 + restart_current_syscall_as_chained(tracee);
155 + }
156 +
157 + /* Set syscall arguments to make it fail
158 + * TODO: More reliable way to make invalid arguments */
159 + if (get_sysnum(tracee, ORIGINAL) == PR_brk) {
160 + /* For brk() we pass 0 as first arg; this is used to query value without changing it */
161 + poke_reg(tracee, SYSARG_1, 0);
162 + } else {
163 + /* For other syscalls we set all args to -1
164 + * Hoping there is among them invalid request/address/fd/value that will make syscall fail */
165 + poke_reg(tracee, SYSARG_1, -1);
166 + poke_reg(tracee, SYSARG_2, -1);
167 + poke_reg(tracee, SYSARG_3, -1);
168 + poke_reg(tracee, SYSARG_4, -1);
169 + poke_reg(tracee, SYSARG_5, -1);
170 + poke_reg(tracee, SYSARG_6, -1);
171 + }
172 +
173 + /* Push regs again without changing syscall */
174 + push_regs_status = push_specific_regs(tracee, false);
175 + if (push_regs_status != 0) {
176 + note(tracee, WARNING, SYSTEM, "can't set tracee registers in workaround");
177 + }
178 + }
179 + }
180
181 if (is_enter_stage)
182 print_current_regs(tracee, 5, "sysenter end" );
183 diff -r -u src/src/tracee/reg.c src_set_syscall_workaround/src/tracee/reg.c
184 --- src/src/tracee/reg.c 2015-07-23 21:50:10.000000000 +0200
185 +++ src_set_syscall_workaround/src/tracee/reg.c 2016-08-12 14:48:31.410423000 +0200
186 @@ -262,12 +262,7 @@
187 return 0;
188 }
189
190 -/**
191 - * Copy the cached values of all @tracee's general purpose registers
192 - * back to the process, if necessary. This function returns -errno if
193 - * an error occured, 0 otherwise.
194 - */
195 -int push_regs(Tracee *tracee)
196 +int push_specific_regs(Tracee *tracee, bool including_sysnum)
197 {
198 int status;
199
200 @@ -306,12 +301,14 @@
201 /* Update syscall number if needed. On arm64, a new
202 * subcommand has been added to PTRACE_{S,G}ETREGSET
203 * to allow write/read of current sycall number. */
204 - if (current_sysnum != REG(tracee, ORIGINAL, SYSARG_NUM)) {
205 + if (including_sysnum && current_sysnum != REG(tracee, ORIGINAL, SYSARG_NUM)) {
206 regs.iov_base = &current_sysnum;
207 regs.iov_len = sizeof(current_sysnum);
208 status = ptrace(PTRACE_SETREGSET, tracee->pid, NT_ARM_SYSTEM_CALL, &regs);
209 - if (status < 0)
210 - note(tracee, WARNING, SYSTEM, "can't set the syscall number");
211 + if (status < 0) {
212 + //note(tracee, WARNING, SYSTEM, "can't set the syscall number");
213 + return status;
214 + }
215 }
216
217 /* Update other registers. */
218 @@ -325,10 +322,12 @@
219 * change effectively the syscall number during a
220 * ptrace-stop. */
221 word_t current_sysnum = REG(tracee, CURRENT, SYSARG_NUM);
222 - if (current_sysnum != REG(tracee, ORIGINAL, SYSARG_NUM)) {
223 + if (including_sysnum && current_sysnum != REG(tracee, ORIGINAL, SYSARG_NUM)) {
224 status = ptrace(PTRACE_SET_SYSCALL, tracee->pid, 0, current_sysnum);
225 - if (status < 0)
226 - note(tracee, WARNING, SYSTEM, "can't set the syscall number");
227 + if (status < 0) {
228 + //note(tracee, WARNING, SYSTEM, "can't set the syscall number");
229 + return status;
230 + }
231 }
232 # endif
233
234 @@ -340,3 +339,12 @@
235
236 return 0;
237 }
238 +
239 +/**
240 + * Copy the cached values of all @tracee's general purpose registers
241 + * back to the process, if necessary. This function returns -errno if
242 + * an error occured, 0 otherwise.
243 + */
244 +int push_regs(Tracee *tracee) {
245 + return push_specific_regs(tracee, true);
246 +}
247 diff -r -u src/src/tracee/reg.h src_set_syscall_workaround/src/tracee/reg.h
248 --- src/src/tracee/reg.h 2015-07-23 21:50:10.000000000 +0200
249 +++ src_set_syscall_workaround/src/tracee/reg.h 2016-08-09 21:38:03.863456000 +0200
250 @@ -43,6 +43,7 @@
251 } Reg;
252
253 extern int fetch_regs(Tracee *tracee);
254 +extern int push_specific_regs(Tracee *tracee, bool including_sysnum);
255 extern int push_regs(Tracee *tracee);
256
257 extern word_t peek_reg(const Tracee *tracee, RegVersion version, Reg reg);
258 diff -r -u src/src/tracee/tracee.h src_set_syscall_workaround/src/tracee/tracee.h
259 --- src/src/tracee/tracee.h 2016-08-12 19:44:07.301407472 +0200
260 +++ src_set_syscall_workaround/src/tracee/tracee.h 2016-08-12 19:52:43.554712737 +0200
261 @@ -193,6 +193,11 @@
262 struct chained_syscalls *syscalls;
263 bool force_final_result;
264 word_t final_result;
265 + enum {
266 + SYSNUM_WORKAROUND_INACTIVE,
267 + SYSNUM_WORKAROUND_PROCESS_FAULTY_CALL,
268 + SYSNUM_WORKAROUND_PROCESS_REPLACED_CALL
269 + } sysnum_workaround_state;
270 } chain;
271
272 /* Load info generated during execve sysenter and used during