summaryrefslogtreecommitdiff
blob: e74cfaa7807b78b09f5d0d9f8342ba4e9faf7351 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
commit 77d5ba4e5bb35f91d026a3240ad0a91a2d4b662a
Author: Cédric VINCENT <cedric.vincent@st.com>
Date:   Fri Feb 20 14:28:55 2015 +0100

    Set tracee's stack executable when the loaded program requires this.
    
    This is required for UMEQ and for some older versions of PRoot.  For
    example:
    
        $ proot -q umeq-arm64-dce01957 -R ~/gentoo-arm64-20140718
    
    Before:
    
        proot info: vpid 1 terminated with signal 11
    
    Now, it is OK.

diff --git a/src/compat.h b/src/compat.h
index 2b603f1..5009490 100644
--- a/src/compat.h
+++ b/src/compat.h
@@ -243,5 +243,17 @@
 #    ifndef MAP_ANONYMOUS
 #        define MAP_ANONYMOUS			0x20
 #    endif
+#    ifndef PROT_READ
+#        define PROT_READ		0x1
+#    endif
+#    ifndef PROT_WRITE
+#        define PROT_WRITE		0x2
+#    endif
+#    ifndef PROT_EXEC
+#        define PROT_EXEC		0x4
+#    endif
+#    ifndef PROT_GROWSDOWN
+#        define PROT_GROWSDOWN		0x01000000
+#    endif
 
 #endif /* COMPAT_H */
diff --git a/src/execve/elf.h b/src/execve/elf.h
index 3ced10c..a5b367b 100644
--- a/src/execve/elf.h
+++ b/src/execve/elf.h
@@ -108,7 +108,8 @@ typedef union {
 typedef enum {
 	PT_LOAD    = 1,
 	PT_DYNAMIC = 2,
-	PT_INTERP  = 3
+	PT_INTERP  = 3,
+	PT_GNU_STACK = 0x6474e551,
 } SegmentType;
 
 typedef struct {
diff --git a/src/execve/enter.c b/src/execve/enter.c
index cb84ec6..f0f3e7f 100644
--- a/src/execve/enter.c
+++ b/src/execve/enter.c
@@ -252,6 +252,11 @@ static int add_load_info(const ElfHeader *elf_header,
 			return status;
 		break;
 
+	case PT_GNU_STACK:
+		data->load_info->needs_executable_stack |=
+			((PROGRAM_FIELD(*elf_header, *program_header, flags) & PF_X) != 0);
+		break;
+
 	default:
 		break;
 	}
diff --git a/src/execve/execve.h b/src/execve/execve.h
index 11eca10..98b8d03 100644
--- a/src/execve/execve.h
+++ b/src/execve/execve.h
@@ -49,6 +49,7 @@ typedef struct load_info {
 	char *raw_path;
 	Mapping *mappings;
 	ElfHeader elf_header;
+	bool needs_executable_stack;
 
 	struct load_info *interp;
 } LoadInfo;
diff --git a/src/execve/exit.c b/src/execve/exit.c
index e6eff44..36cc51f 100644
--- a/src/execve/exit.c
+++ b/src/execve/exit.c
@@ -174,6 +174,9 @@ static void *transcript_mappings(void *cursor, const Mapping *mappings)
 static int transfer_load_script(Tracee *tracee)
 {
 	const word_t stack_pointer = peek_reg(tracee, CURRENT, STACK_POINTER);
+	static word_t page_size = 0;
+	static word_t page_mask = 0;
+
 	word_t entry_point;
 
 	size_t script_size;
@@ -190,10 +193,22 @@ static int transfer_load_script(Tracee *tracee)
 	void *buffer;
 	size_t buffer_size;
 
+	bool needs_executable_stack;
 	LoadStatement *statement;
 	void *cursor;
 	int status;
 
+	if (page_size == 0) {
+		page_size = sysconf(_SC_PAGE_SIZE);
+		if ((int) page_size <= 0)
+			page_size = 0x1000;
+		page_mask = ~(page_size - 1);
+	}
+
+	needs_executable_stack = (tracee->load_info->needs_executable_stack
+				|| (   tracee->load_info->interp != NULL
+				    && tracee->load_info->interp->needs_executable_stack));
+
 	/* Strings addresses are required to generate the load script,
 	 * for "open" actions.  Since I want to generate it in one
 	 * pass, these strings will be put right below the current
@@ -208,7 +223,7 @@ static int transfer_load_script(Tracee *tracee)
 			: strlen(tracee->load_info->raw_path) + 1);
 
 	/* A padding will be appended at the end of the load script
-	 * (a.k.a "strings area") to ensure this latter is aligned on
+	 * (a.k.a "strings area") to ensure this latter is aligned to
 	 * a word boundary, for sake of performance.  */
 	padding_size = (stack_pointer - string1_size - string2_size - string3_size)
 			% sizeof_word(tracee);
@@ -229,6 +244,7 @@ static int transfer_load_script(Tracee *tracee)
 			: LOAD_STATEMENT_SIZE(*statement, open)
 			+ (LOAD_STATEMENT_SIZE(*statement, mmap)
 				* talloc_array_length(tracee->load_info->interp->mappings)))
+		+ (needs_executable_stack ? LOAD_STATEMENT_SIZE(*statement, make_stack_exec) : 0)
 		+ LOAD_STATEMENT_SIZE(*statement, start);
 
 	/* Allocate enough room for both the load script and the
@@ -266,6 +282,16 @@ static int transfer_load_script(Tracee *tracee)
 	else
 		entry_point = ELF_FIELD(tracee->load_info->elf_header, entry);
 
+	if (needs_executable_stack) {
+		/* Load script statement: stack_exec.  */
+		statement = cursor;
+
+		statement->action = LOAD_ACTION_MAKE_STACK_EXEC;
+		statement->make_stack_exec.start = stack_pointer & page_mask;
+
+		cursor += LOAD_STATEMENT_SIZE(*statement, make_stack_exec);
+	}
+
 	/* Load script statement: start.  */
 	statement = cursor;
 
@@ -352,7 +378,7 @@ static int transfer_load_script(Tracee *tracee)
 	 *   | mmap file  |
 	 *   +------------+
 	 *   |   open     |
-	 *   +------------+ <- stack pointer, sysarg1 (word aligned)
+	 *   +------------+ <- stack pointer, userarg1 (word aligned)
 	 */
 
 	/* Remember we are in the sysexit stage, so be sure the
diff --git a/src/loader/assembly-arm.h b/src/loader/assembly-arm.h
index ee5bb85..59a7fe0 100644
--- a/src/loader/assembly-arm.h
+++ b/src/loader/assembly-arm.h
@@ -89,4 +89,5 @@
 #define EXECVE	11
 #define EXIT	1
 #define PRCTL	172
+#define MPROTECT 125
 
diff --git a/src/loader/assembly-x86.h b/src/loader/assembly-x86.h
index c83b3ef..4045144 100644
--- a/src/loader/assembly-x86.h
+++ b/src/loader/assembly-x86.h
@@ -65,3 +65,4 @@ extern word_t syscall_1(word_t number, word_t arg1);
 #define EXECVE	11
 #define EXIT	1
 #define PRCTL	172
+#define MPROTECT 125
diff --git a/src/loader/assembly-x86_64.h b/src/loader/assembly-x86_64.h
index c581208..6f431be 100644
--- a/src/loader/assembly-x86_64.h
+++ b/src/loader/assembly-x86_64.h
@@ -93,3 +93,4 @@
 #define EXECVE	59
 #define EXIT	60
 #define PRCTL	157
+#define MPROTECT 10
diff --git a/src/loader/loader.c b/src/loader/loader.c
index 5b31b02..9c2037b 100644
--- a/src/loader/loader.c
+++ b/src/loader/loader.c
@@ -171,6 +171,14 @@ void _start(void *cursor)
 			cursor += LOAD_STATEMENT_SIZE(*stmt, mmap);
 			break;
 
+		case LOAD_ACTION_MAKE_STACK_EXEC:
+			SYSCALL(MPROTECT, 3,
+				stmt->make_stack_exec.start, 1,
+				PROT_READ | PROT_WRITE | PROT_EXEC | PROT_GROWSDOWN);
+
+			cursor += LOAD_STATEMENT_SIZE(*stmt, make_stack_exec);
+			break;
+
 		case LOAD_ACTION_START_TRACED:
 			traced = true;
 			/* Fall through.  */
diff --git a/src/loader/script.h b/src/loader/script.h
index bb48af5..6ae7621 100644
--- a/src/loader/script.h
+++ b/src/loader/script.h
@@ -42,6 +42,10 @@ struct load_statement {
 			word_t clear_length;
 		} mmap;
 
+		struct {
+			word_t start;
+		} make_stack_exec;
+
 		struct {
 			word_t stack_pointer;
 			word_t entry_point;
@@ -67,7 +71,8 @@ typedef struct load_statement LoadStatement;
 #define LOAD_ACTION_OPEN		1
 #define LOAD_ACTION_MMAP_FILE		2
 #define LOAD_ACTION_MMAP_ANON		3
-#define LOAD_ACTION_START_TRACED	4
-#define LOAD_ACTION_START		5
+#define LOAD_ACTION_MAKE_STACK_EXEC	4
+#define LOAD_ACTION_START_TRACED	5
+#define LOAD_ACTION_START		6
 
 #endif /* SCRIPT */

commit d649854ddb66779950954aac99d960379c631a71
Author: Nicolas Cornu <ncornu@aldebaran.com>
Date:   Wed Jul 29 14:52:57 2015 +0200

    Fix use of size

diff --git a/src/execve/enter.c b/src/execve/enter.c
index 8f22d9c..4c163a1 100644
--- a/src/execve/enter.c
+++ b/src/execve/enter.c
@@ -454,10 +454,10 @@ static int expand_runner(Tracee* tracee, char host_path[PATH_MAX], char user_pat
 }
 
 extern unsigned char _binary_loader_exe_start;
-extern unsigned char _binary_loader_exe_size;
+extern unsigned char _binary_loader_exe_end;
 
 extern unsigned char WEAK _binary_loader_m32_exe_start;
-extern unsigned char WEAK _binary_loader_m32_exe_size;
+extern unsigned char WEAK _binary_loader_m32_exe_end;
 
 /**
  * Extract the built-in loader.  This function returns NULL if an
@@ -483,11 +483,11 @@ static char *extract_loader(const Tracee *tracee, bool wants_32bit_version)
 
 	if (wants_32bit_version) {
 		start = (void *) &_binary_loader_m32_exe_start;
-		size  = (size_t) &_binary_loader_m32_exe_size;
+		size  = (size_t)(&_binary_loader_m32_exe_end-&_binary_loader_m32_exe_start);
 	}
 	else {
 		start = (void *) &_binary_loader_exe_start;
-		size  = (size_t) &_binary_loader_exe_size;
+		size  = (size_t) (&_binary_loader_exe_end-&_binary_loader_exe_start);
 	}
 
 	status2 = write(fd, start, size);