|
|
1.1 root 1: #include <errno.h>
2: #include <sys/stat.h>
3: #include <a.out.h>
4:
5: #include <linux/fs.h>
6: #include <linux/sched.h>
7: #include <linux/kernel.h>
8: #include <linux/mm.h>
9: #include <asm/segment.h>
10:
11: extern int sys_exit(int exit_code);
12: extern int sys_close(int fd);
13:
14: /*
15: * MAX_ARG_PAGES defines the number of pages allocated for arguments
16: * and envelope for the new program. 32 should suffice, this gives
17: * a maximum env+arg of 128kB !
18: */
19: #define MAX_ARG_PAGES 32
20:
21: #define cp_block(from,to) \
22: __asm__("pushl $0x10\n\t" \
23: "pushl $0x17\n\t" \
24: "pop %%es\n\t" \
25: "cld\n\t" \
26: "rep\n\t" \
27: "movsl\n\t" \
28: "pop %%es" \
29: ::"c" (BLOCK_SIZE/4),"S" (from),"D" (to) \
30: :"cx","di","si")
31:
32: /*
33: * read_head() reads blocks 1-6 (not 0). Block 0 has already been
34: * read for header information.
35: */
36: int read_head(struct m_inode * inode,int blocks)
37: {
38: struct buffer_head * bh;
39: int count;
40:
41: if (blocks>6)
42: blocks=6;
43: for(count = 0 ; count<blocks ; count++) {
44: if (!inode->i_zone[count+1])
45: continue;
46: if (!(bh=bread(inode->i_dev,inode->i_zone[count+1])))
47: return -1;
48: cp_block(bh->b_data,count*BLOCK_SIZE);
49: brelse(bh);
50: }
51: return 0;
52: }
53:
54: int read_ind(int dev,int ind,long size,unsigned long offset)
55: {
56: struct buffer_head * ih, * bh;
57: unsigned short * table,block;
58:
59: if (size<=0)
60: panic("size<=0 in read_ind");
61: if (size>512*BLOCK_SIZE)
62: size=512*BLOCK_SIZE;
63: if (!ind)
64: return 0;
65: if (!(ih=bread(dev,ind)))
66: return -1;
67: table = (unsigned short *) ih->b_data;
68: while (size>0) {
69: if (block=*(table++))
70: if (!(bh=bread(dev,block))) {
71: brelse(ih);
72: return -1;
73: } else {
74: cp_block(bh->b_data,offset);
75: brelse(bh);
76: }
77: size -= BLOCK_SIZE;
78: offset += BLOCK_SIZE;
79: }
80: brelse(ih);
81: return 0;
82: }
83:
84: /*
85: * read_area() reads an area into %fs:mem.
86: */
87: int read_area(struct m_inode * inode,long size)
88: {
89: struct buffer_head * dind;
90: unsigned short * table;
91: int i,count;
92:
93: if ((i=read_head(inode,(size+BLOCK_SIZE-1)/BLOCK_SIZE)) ||
94: (size -= BLOCK_SIZE*6)<=0)
95: return i;
96: if ((i=read_ind(inode->i_dev,inode->i_zone[7],size,BLOCK_SIZE*6)) ||
97: (size -= BLOCK_SIZE*512)<=0)
98: return i;
99: if (!(i=inode->i_zone[8]))
100: return 0;
101: if (!(dind = bread(inode->i_dev,i)))
102: return -1;
103: table = (unsigned short *) dind->b_data;
104: for(count=0 ; count<512 ; count++)
105: if ((i=read_ind(inode->i_dev,*(table++),size,
106: BLOCK_SIZE*(518+count))) || (size -= BLOCK_SIZE*512)<=0)
107: return i;
108: panic("Impossibly long executable");
109: }
110:
111: /*
112: * create_tables() parses the env- and arg-strings in new user
113: * memory and creates the pointer tables from them, and puts their
114: * addresses on the "stack", returning the new stack pointer value.
115: */
116: static unsigned long * create_tables(char * p,int argc,int envc)
117: {
118: unsigned long *argv,*envp;
119: unsigned long * sp;
120:
121: sp = (unsigned long *) (0xfffffffc & (unsigned long) p);
122: sp -= envc+1;
123: envp = sp;
124: sp -= argc+1;
125: argv = sp;
126: put_fs_long((unsigned long)envp,--sp);
127: put_fs_long((unsigned long)argv,--sp);
128: put_fs_long((unsigned long)argc,--sp);
129: while (argc-->0) {
130: put_fs_long((unsigned long) p,argv++);
131: while (get_fs_byte(p++)) /* nothing */ ;
132: }
133: put_fs_long(0,argv);
134: while (envc-->0) {
135: put_fs_long((unsigned long) p,envp++);
136: while (get_fs_byte(p++)) /* nothing */ ;
137: }
138: put_fs_long(0,envp);
139: return sp;
140: }
141:
142: /*
143: * count() counts the number of arguments/envelopes
144: */
145: static int count(char ** argv)
146: {
147: int i=0;
148: char ** tmp;
149:
150: if (tmp = argv)
151: while (get_fs_long((unsigned long *) (tmp++)))
152: i++;
153:
154: return i;
155: }
156:
157: /*
158: * 'copy_string()' copies argument/envelope strings from user
159: * memory to free pages in kernel mem. These are in a format ready
160: * to be put directly into the top of new user memory.
161: */
162: static unsigned long copy_strings(int argc,char ** argv,unsigned long *page,
163: unsigned long p)
164: {
165: int len,i;
166: char *tmp;
167:
168: while (argc-- > 0) {
169: if (!(tmp = (char *)get_fs_long(((unsigned long *) argv)+argc)))
170: panic("argc is wrong");
171: len=0; /* remember zero-padding */
172: do {
173: len++;
174: } while (get_fs_byte(tmp++));
175: if (p-len < 0) /* this shouldn't happen - 128kB */
176: return 0;
177: i = ((unsigned) (p-len)) >> 12;
178: while (i<MAX_ARG_PAGES && !page[i]) {
179: if (!(page[i]=get_free_page()))
180: return 0;
181: i++;
182: }
183: do {
184: --p;
185: if (!page[p/PAGE_SIZE])
186: panic("nonexistent page in exec.c");
187: ((char *) page[p/PAGE_SIZE])[p%PAGE_SIZE] =
188: get_fs_byte(--tmp);
189: } while (--len);
190: }
191: return p;
192: }
193:
194: static unsigned long change_ldt(unsigned long text_size,unsigned long * page)
195: {
196: unsigned long code_limit,data_limit,code_base,data_base;
197: int i;
198:
199: code_limit = text_size+PAGE_SIZE -1;
200: code_limit &= 0xFFFFF000;
201: data_limit = 0x4000000;
202: code_base = get_base(current->ldt[1]);
203: data_base = code_base;
204: set_base(current->ldt[1],code_base);
205: set_limit(current->ldt[1],code_limit);
206: set_base(current->ldt[2],data_base);
207: set_limit(current->ldt[2],data_limit);
208: /* make sure fs points to the NEW data segment */
209: __asm__("pushl $0x17\n\tpop %%fs"::);
210: data_base += data_limit;
211: for (i=MAX_ARG_PAGES-1 ; i>=0 ; i--) {
212: data_base -= PAGE_SIZE;
213: if (page[i])
214: put_page(page[i],data_base);
215: }
216: return data_limit;
217: }
218:
219: /*
220: * 'do_execve()' executes a new program.
221: */
222: int do_execve(unsigned long * eip,long tmp,char * filename,
223: char ** argv, char ** envp)
224: {
225: struct m_inode * inode;
226: struct buffer_head * bh;
227: struct exec ex;
228: unsigned long page[MAX_ARG_PAGES];
229: int i,argc,envc;
230: unsigned long p;
231:
232: if ((0xffff & eip[1]) != 0x000f)
233: panic("execve called from supervisor mode");
234: for (i=0 ; i<MAX_ARG_PAGES ; i++) /* clear page-table */
235: page[i]=0;
236: if (!(inode=namei(filename))) /* get executables inode */
237: return -ENOENT;
238: if (!S_ISREG(inode->i_mode)) { /* must be regular file */
239: iput(inode);
240: return -EACCES;
241: }
242: i = inode->i_mode;
243: if (current->uid && current->euid) {
244: if (current->euid == inode->i_uid)
245: i >>= 6;
246: else if (current->egid == inode->i_gid)
247: i >>= 3;
248: } else if (i & 0111)
249: i=1;
250: if (!(i & 1)) {
251: iput(inode);
252: return -ENOEXEC;
253: }
254: if (!(bh = bread(inode->i_dev,inode->i_zone[0]))) {
255: iput(inode);
256: return -EACCES;
257: }
258: ex = *((struct exec *) bh->b_data); /* read exec-header */
259: brelse(bh);
260: if (N_MAGIC(ex) != ZMAGIC || ex.a_trsize || ex.a_drsize ||
261: ex.a_text+ex.a_data+ex.a_bss>0x3000000 ||
262: inode->i_size < ex.a_text+ex.a_data+ex.a_syms+N_TXTOFF(ex)) {
263: iput(inode);
264: return -ENOEXEC;
265: }
266: if (N_TXTOFF(ex) != BLOCK_SIZE)
267: panic("N_TXTOFF != BLOCK_SIZE. See a.out.h.");
268: argc = count(argv);
269: envc = count(envp);
270: p = copy_strings(envc,envp,page,PAGE_SIZE*MAX_ARG_PAGES-4);
271: p = copy_strings(argc,argv,page,p);
272: if (!p) {
273: for (i=0 ; i<MAX_ARG_PAGES ; i++)
274: free_page(page[i]);
275: iput(inode);
276: return -1;
277: }
278: /* OK, This is the point of no return */
279: for (i=0 ; i<32 ; i++)
280: current->sig_fn[i] = NULL;
281: for (i=0 ; i<NR_OPEN ; i++)
282: if ((current->close_on_exec>>i)&1)
283: sys_close(i);
284: current->close_on_exec = 0;
285: free_page_tables(get_base(current->ldt[1]),get_limit(0x0f));
286: free_page_tables(get_base(current->ldt[2]),get_limit(0x17));
287: if (last_task_used_math == current)
288: last_task_used_math = NULL;
289: current->used_math = 0;
290: p += change_ldt(ex.a_text,page)-MAX_ARG_PAGES*PAGE_SIZE;
291: p = (unsigned long) create_tables((char *)p,argc,envc);
292: current->brk = ex.a_bss +
293: (current->end_data = ex.a_data +
294: (current->end_code = ex.a_text));
295: current->start_stack = p & 0xfffff000;
296: i = read_area(inode,ex.a_text+ex.a_data);
297: iput(inode);
298: if (i<0)
299: sys_exit(-1);
300: i = ex.a_text+ex.a_data;
301: while (i&0xfff)
302: put_fs_byte(0,(char *) (i++));
303: eip[0] = ex.a_entry; /* eip, magic happens :-) */
304: eip[3] = p; /* stack pointer */
305: return 0;
306: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.