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