This source file includes following definitions.
- sys_uselib
- create_tables
- count
- copy_strings
- change_ldt
- do_execve
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 #include <signal.h>
21 #include <errno.h>
22 #include <linux/string.h>
23 #include <sys/stat.h>
24 #include <a.out.h>
25
26 #include <linux/fs.h>
27 #include <linux/sched.h>
28 #include <linux/kernel.h>
29 #include <linux/mm.h>
30 #include <asm/segment.h>
31
32 extern int sys_exit(int exit_code);
33 extern int sys_close(int fd);
34
35
36
37
38
39
40 #define MAX_ARG_PAGES 32
41
42
43
44
45
46
47
48 int sys_uselib(const char * library)
49 {
50 #define libnum (current->numlibraries)
51 struct inode * inode;
52 struct buffer_head * bh;
53 struct exec ex;
54
55 if (get_limit(0x17) != TASK_SIZE)
56 return -EINVAL;
57 if ((libnum >= MAX_SHARED_LIBS) || (libnum < 0))
58 return -EINVAL;
59 if (library)
60 inode = namei(library);
61 else
62 inode = NULL;
63 if (!inode)
64 return -ENOENT;
65 if (!S_ISREG(inode->i_mode) || !permission(inode,MAY_READ|MAY_EXEC)) {
66 iput(inode);
67 return -EACCES;
68 }
69 if (!(bh = bread(inode->i_dev,inode->i_data[0]))) {
70 iput(inode);
71 return -EACCES;
72 }
73 ex = *(struct exec *) bh->b_data;
74 brelse(bh);
75 if (N_MAGIC(ex) != ZMAGIC || ex.a_trsize || ex.a_drsize ||
76 ex.a_text+ex.a_data+ex.a_bss>0x3000000 ||
77 inode->i_size < ex.a_text+ex.a_data+ex.a_syms+N_TXTOFF(ex)) {
78 iput(inode);
79 return -ENOEXEC;
80 }
81 current->libraries[libnum].library = inode;
82 current->libraries[libnum].start = ex.a_entry;
83 current->libraries[libnum].length = (ex.a_data+ex.a_text+0xfff) & 0xfffff000;
84 #if 0
85 printk("Loaded library %d at %08x, length %08x\n",
86 libnum,
87 current->libraries[libnum].start,
88 current->libraries[libnum].length);
89 #endif
90 libnum++;
91 return 0;
92 #undef libnum
93 }
94
95
96
97
98
99
100 static unsigned long * create_tables(char * p,int argc,int envc)
101 {
102 unsigned long *argv,*envp;
103 unsigned long * sp;
104
105 sp = (unsigned long *) (0xfffffffc & (unsigned long) p);
106 sp -= envc+1;
107 envp = sp;
108 sp -= argc+1;
109 argv = sp;
110 put_fs_long((unsigned long)envp,--sp);
111 put_fs_long((unsigned long)argv,--sp);
112 put_fs_long((unsigned long)argc,--sp);
113 while (argc-->0) {
114 put_fs_long((unsigned long) p,argv++);
115 while (get_fs_byte(p++)) ;
116 }
117 put_fs_long(0,argv);
118 while (envc-->0) {
119 put_fs_long((unsigned long) p,envp++);
120 while (get_fs_byte(p++)) ;
121 }
122 put_fs_long(0,envp);
123 return sp;
124 }
125
126
127
128
129 static int count(char ** argv)
130 {
131 int i=0;
132 char ** tmp;
133
134 if (tmp = argv)
135 while (get_fs_long((unsigned long *) (tmp++)))
136 i++;
137
138 return i;
139 }
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158 static unsigned long copy_strings(int argc,char ** argv,unsigned long *page,
159 unsigned long p, int from_kmem)
160 {
161 char *tmp, *pag;
162 int len, offset = 0;
163 unsigned long old_fs, new_fs;
164
165 if (!p)
166 return 0;
167 new_fs = get_ds();
168 old_fs = get_fs();
169 if (from_kmem==2)
170 set_fs(new_fs);
171 while (argc-- > 0) {
172 if (from_kmem == 1)
173 set_fs(new_fs);
174 if (!(tmp = (char *)get_fs_long(((unsigned long *)argv)+argc)))
175 panic("argc is wrong");
176 if (from_kmem == 1)
177 set_fs(old_fs);
178 len=0;
179 do {
180 len++;
181 } while (get_fs_byte(tmp++));
182 if (p < len) {
183 set_fs(old_fs);
184 return 0;
185 }
186 while (len) {
187 --p; --tmp; --len;
188 if (--offset < 0) {
189 offset = p % PAGE_SIZE;
190 if (from_kmem==2)
191 set_fs(old_fs);
192 if (!(pag = (char *) page[p/PAGE_SIZE]) &&
193 !(pag = (char *) page[p/PAGE_SIZE] =
194 (unsigned long *) get_free_page()))
195 return 0;
196 if (from_kmem==2)
197 set_fs(new_fs);
198
199 }
200 *(pag + offset) = get_fs_byte(tmp);
201 }
202 }
203 if (from_kmem==2)
204 set_fs(old_fs);
205 return p;
206 }
207
208 static unsigned long change_ldt(unsigned long text_size,unsigned long * page)
209 {
210 unsigned long code_limit,data_limit,code_base,data_base;
211 int i;
212
213 code_limit = TASK_SIZE;
214 data_limit = TASK_SIZE;
215 code_base = get_base(current->ldt[1]);
216 data_base = code_base;
217 set_base(current->ldt[1],code_base);
218 set_limit(current->ldt[1],code_limit);
219 set_base(current->ldt[2],data_base);
220 set_limit(current->ldt[2],data_limit);
221
222 __asm__("pushl $0x17\n\tpop %%fs"::);
223 data_base += data_limit - LIBRARY_SIZE;
224 for (i=MAX_ARG_PAGES-1 ; i>=0 ; i--) {
225 data_base -= PAGE_SIZE;
226 if (page[i])
227 put_dirty_page(page[i],data_base);
228 }
229 return data_limit;
230 }
231
232
233
234
235
236
237
238 int do_execve(unsigned long * eip,long tmp,char * filename,
239 char ** argv, char ** envp)
240 {
241 struct inode * inode;
242 struct buffer_head * bh;
243 struct exec ex;
244 unsigned long page[MAX_ARG_PAGES];
245 int i,argc,envc;
246 int e_uid, e_gid;
247 int retval;
248 int sh_bang = 0;
249 unsigned long p=PAGE_SIZE*MAX_ARG_PAGES-4;
250 int ch;
251
252 if ((0xffff & eip[1]) != 0x000f)
253 panic("execve called from supervisor mode");
254 for (i=0 ; i<MAX_ARG_PAGES ; i++)
255 page[i]=0;
256 if (!(inode=namei(filename)))
257 return -ENOENT;
258 argc = count(argv);
259 envc = count(envp);
260
261 restart_interp:
262 if (!S_ISREG(inode->i_mode)) {
263 retval = -EACCES;
264 goto exec_error2;
265 }
266 i = inode->i_mode;
267
268 if (current->flags & PF_PTRACED) {
269 e_uid = current->euid;
270 e_gid = current->egid;
271 } else {
272 e_uid = (i & S_ISUID) ? inode->i_uid : current->euid;
273 e_gid = (i & S_ISGID) ? inode->i_gid : current->egid;
274 }
275 if (current->euid == inode->i_uid)
276 i >>= 6;
277 else if (in_group_p(inode->i_gid))
278 i >>= 3;
279 if (!(i & 1) &&
280 !((inode->i_mode & 0111) && suser())) {
281 retval = -EACCES;
282 goto exec_error2;
283 }
284 if (!(bh = bread(inode->i_dev,inode->i_data[0]))) {
285 retval = -EACCES;
286 goto exec_error2;
287 }
288 ex = *((struct exec *) bh->b_data);
289 if ((bh->b_data[0] == '#') && (bh->b_data[1] == '!') && (!sh_bang)) {
290
291
292
293
294
295 char buf[128], *cp, *interp, *i_name, *i_arg;
296 unsigned long old_fs;
297
298 strncpy(buf, bh->b_data+2, 127);
299 brelse(bh);
300 iput(inode);
301 buf[127] = '\0';
302 if (cp = strchr(buf, '\n')) {
303 *cp = '\0';
304 for (cp = buf; (*cp == ' ') || (*cp == '\t'); cp++);
305 }
306 if (!cp || *cp == '\0') {
307 retval = -ENOEXEC;
308 goto exec_error1;
309 }
310 interp = i_name = cp;
311 i_arg = 0;
312 for ( ; *cp && (*cp != ' ') && (*cp != '\t'); cp++) {
313 if (*cp == '/')
314 i_name = cp+1;
315 }
316 if (*cp) {
317 *cp++ = '\0';
318 i_arg = cp;
319 }
320
321
322
323
324 if (sh_bang++ == 0) {
325 p = copy_strings(envc, envp, page, p, 0);
326 p = copy_strings(--argc, argv+1, page, p, 0);
327 }
328
329
330
331
332
333
334
335
336 p = copy_strings(1, &filename, page, p, 1);
337 argc++;
338 if (i_arg) {
339 p = copy_strings(1, &i_arg, page, p, 2);
340 argc++;
341 }
342 p = copy_strings(1, &i_name, page, p, 2);
343 argc++;
344 if (!p) {
345 retval = -ENOMEM;
346 goto exec_error1;
347 }
348
349
350
351 old_fs = get_fs();
352 set_fs(get_ds());
353 if (!(inode=namei(interp))) {
354 set_fs(old_fs);
355 retval = -ENOENT;
356 goto exec_error1;
357 }
358 set_fs(old_fs);
359 goto restart_interp;
360 }
361 brelse(bh);
362 if (N_MAGIC(ex) != ZMAGIC || ex.a_trsize || ex.a_drsize ||
363 ex.a_text+ex.a_data+ex.a_bss>0x3000000 ||
364 inode->i_size < ex.a_text+ex.a_data+ex.a_syms+N_TXTOFF(ex)) {
365 retval = -ENOEXEC;
366 goto exec_error2;
367 }
368 if (N_TXTOFF(ex) != BLOCK_SIZE) {
369 printk("%s: N_TXTOFF != BLOCK_SIZE. See a.out.h.", filename);
370 retval = -ENOEXEC;
371 goto exec_error2;
372 }
373 if (!sh_bang) {
374 p = copy_strings(envc,envp,page,p,0);
375 p = copy_strings(argc,argv,page,p,0);
376 if (!p) {
377 retval = -ENOMEM;
378 goto exec_error2;
379 }
380 }
381
382 for (i=0; (ch = get_fs_byte(filename++)) != '\0';)
383 if (ch == '/')
384 i = 0;
385 else
386 if (i < 8)
387 current->comm[i++] = ch;
388 if (i < 8)
389 current->comm[i] = '\0';
390 if (current->executable)
391 iput(current->executable);
392 i = current->numlibraries;
393 while (i-- > 0) {
394 iput(current->libraries[i].library);
395 current->libraries[i].library = NULL;
396 }
397 current->numlibraries = 0;
398 current->executable = inode;
399 current->signal = 0;
400 for (i=0 ; i<32 ; i++) {
401 current->sigaction[i].sa_mask = 0;
402 current->sigaction[i].sa_flags = 0;
403 if (current->sigaction[i].sa_handler != SIG_IGN)
404 current->sigaction[i].sa_handler = NULL;
405 }
406 for (i=0 ; i<NR_OPEN ; i++)
407 if ((current->close_on_exec>>i)&1)
408 sys_close(i);
409 current->close_on_exec = 0;
410 free_page_tables(get_base(current->ldt[1]),get_limit(0x0f));
411 free_page_tables(get_base(current->ldt[2]),get_limit(0x17));
412 if (last_task_used_math == current)
413 last_task_used_math = NULL;
414 current->used_math = 0;
415 p += change_ldt(ex.a_text,page);
416 p -= LIBRARY_SIZE + MAX_ARG_PAGES*PAGE_SIZE;
417 p = (unsigned long) create_tables((char *)p,argc,envc);
418 current->brk = ex.a_bss +
419 (current->end_data = ex.a_data +
420 (current->end_code = ex.a_text));
421 current->start_stack = p;
422 current->rss = (LIBRARY_OFFSET - p + PAGE_SIZE-1) / PAGE_SIZE;
423 current->suid = current->euid = e_uid;
424 current->sgid = current->egid = e_gid;
425 eip[0] = ex.a_entry;
426 eip[3] = p;
427 if (current->flags & PF_PTRACED)
428 send_sig(SIGTRAP, current, 0);
429 return 0;
430 exec_error2:
431 iput(inode);
432 exec_error1:
433 for (i=0 ; i<MAX_ARG_PAGES ; i++)
434 free_page(page[i]);
435 return(retval);
436 }