Linux 0.10 (November 11, 1991 ???)
[davej-history.git] / fs / exec.c~
blobe4b12286cd35aba217a11e3a21fb7791c625b52f
1 /*
2  *  linux/fs/exec.c
3  *
4  *  (C) 1991  Linus Torvalds
5  */
7 #include <errno.h>
8 #include <sys/stat.h>
9 #include <a.out.h>
11 #include <linux/fs.h>
12 #include <linux/sched.h>
13 #include <linux/kernel.h>
14 #include <linux/mm.h>
15 #include <asm/segment.h>
17 extern int sys_exit(int exit_code);
18 extern int sys_close(int fd);
21  * MAX_ARG_PAGES defines the number of pages allocated for arguments
22  * and envelope for the new program. 32 should suffice, this gives
23  * a maximum env+arg of 128kB !
24  */
25 #define MAX_ARG_PAGES 32
27 #define cp_block(from,to) \
28 __asm__("pushl $0x10\n\t" \
29         "pushl $0x17\n\t" \
30         "pop %%es\n\t" \
31         "cld\n\t" \
32         "rep\n\t" \
33         "movsl\n\t" \
34         "pop %%es" \
35         ::"c" (BLOCK_SIZE/4),"S" (from),"D" (to) \
36         :"cx","di","si")
39  * read_head() reads blocks 1-6 (not 0). Block 0 has already been
40  * read for header information.
41  */
42 int read_head(struct m_inode * inode,int blocks)
44         struct buffer_head * bh;
45         int count;
47         if (blocks>6)
48                 blocks=6;
49         for(count = 0 ; count<blocks ; count++) {
50                 if (!inode->i_zone[count+1])
51                         continue;
52                 if (!(bh=bread(inode->i_dev,inode->i_zone[count+1])))
53                         return -1;
54                 cp_block(bh->b_data,count*BLOCK_SIZE);
55                 brelse(bh);
56         }
57         return 0;
60 int read_ind(int dev,int ind,long size,unsigned long offset)
62         struct buffer_head * ih, * bh;
63         unsigned short * table,block;
65         if (size<=0)
66                 panic("size<=0 in read_ind");
67         if (size>512*BLOCK_SIZE)
68                 size=512*BLOCK_SIZE;
69         if (!ind)
70                 return 0;
71         if (!(ih=bread(dev,ind)))
72                 return -1;
73         table = (unsigned short *) ih->b_data;
74         while (size>0) {
75                 if (block=*(table++))
76                         if (!(bh=bread(dev,block))) {
77                                 brelse(ih);
78                                 return -1;
79                         } else {
80                                 cp_block(bh->b_data,offset);
81                                 brelse(bh);
82                         }
83                 size -= BLOCK_SIZE;
84                 offset += BLOCK_SIZE;
85         }
86         brelse(ih);
87         return 0;
91  * read_area() reads an area into %fs:mem.
92  */
93 int read_area(struct m_inode * inode,long size)
95         struct buffer_head * dind;
96         unsigned short * table;
97         int i,count;
99         if ((i=read_head(inode,(size+BLOCK_SIZE-1)/BLOCK_SIZE)) ||
100             (size -= BLOCK_SIZE*6)<=0)
101                 return i;
102         if ((i=read_ind(inode->i_dev,inode->i_zone[7],size,BLOCK_SIZE*6)) ||
103             (size -= BLOCK_SIZE*512)<=0)
104                 return i;
105         if (!(i=inode->i_zone[8]))
106                 return 0;
107         if (!(dind = bread(inode->i_dev,i)))
108                 return -1;
109         table = (unsigned short *) dind->b_data;
110         for(count=0 ; count<512 ; count++)
111                 if ((i=read_ind(inode->i_dev,*(table++),size,
112                     BLOCK_SIZE*(518+count))) || (size -= BLOCK_SIZE*512)<=0)
113                         return i;
114         panic("Impossibly long executable");
118  * create_tables() parses the env- and arg-strings in new user
119  * memory and creates the pointer tables from them, and puts their
120  * addresses on the "stack", returning the new stack pointer value.
121  */
122 static unsigned long * create_tables(char * p,int argc,int envc)
124         unsigned long *argv,*envp;
125         unsigned long * sp;
127         sp = (unsigned long *) (0xfffffffc & (unsigned long) p);
128         sp -= envc+1;
129         envp = sp;
130         sp -= argc+1;
131         argv = sp;
132         put_fs_long((unsigned long)envp,--sp);
133         put_fs_long((unsigned long)argv,--sp);
134         put_fs_long((unsigned long)argc,--sp);
135         while (argc-->0) {
136                 put_fs_long((unsigned long) p,argv++);
137                 while (get_fs_byte(p++)) /* nothing */ ;
138         }
139         put_fs_long(0,argv);
140         while (envc-->0) {
141                 put_fs_long((unsigned long) p,envp++);
142                 while (get_fs_byte(p++)) /* nothing */ ;
143         }
144         put_fs_long(0,envp);
145         return sp;
149  * count() counts the number of arguments/envelopes
150  */
151 static int count(char ** argv)
153         int i=0;
154         char ** tmp;
156         if (tmp = argv)
157                 while (get_fs_long((unsigned long *) (tmp++)))
158                         i++;
160         return i;
164  * 'copy_string()' copies argument/envelope strings from user
165  * memory to free pages in kernel mem. These are in a format ready
166  * to be put directly into the top of new user memory.
167  */
168 static unsigned long copy_strings(int argc,char ** argv,unsigned long *page,
169                 unsigned long p)
171         int len,i;
172         char *tmp;
174         while (argc-- > 0) {
175                 if (!(tmp = (char *)get_fs_long(((unsigned long *) argv)+argc)))
176                         panic("argc is wrong");
177                 len=0;          /* remember zero-padding */
178                 do {
179                         len++;
180                 } while (get_fs_byte(tmp++));
181                 if (p-len < 0)          /* this shouldn't happen - 128kB */
182                         return 0;
183                 i = ((unsigned) (p-len)) >> 12;
184                 while (i<MAX_ARG_PAGES && !page[i]) {
185                         if (!(page[i]=get_free_page()))
186                                 return 0;
187                         i++;
188                 }
189                 do {
190                         --p;
191                         if (!page[p/PAGE_SIZE])
192                                 panic("nonexistent page in exec.c");
193                         ((char *) page[p/PAGE_SIZE])[p%PAGE_SIZE] =
194                                 get_fs_byte(--tmp);
195                 } while (--len);
196         }
197         return p;
200 static unsigned long change_ldt(unsigned long text_size,unsigned long * page)
202         unsigned long code_limit,data_limit,code_base,data_base;
203         int i;
205         code_limit = text_size+PAGE_SIZE -1;
206         code_limit &= 0xFFFFF000;
207         data_limit = 0x4000000;
208         code_base = get_base(current->ldt[1]);
209         data_base = code_base;
210         set_base(current->ldt[1],code_base);
211         set_limit(current->ldt[1],code_limit);
212         set_base(current->ldt[2],data_base);
213         set_limit(current->ldt[2],data_limit);
214 /* make sure fs points to the NEW data segment */
215         __asm__("pushl $0x17\n\tpop %%fs"::);
216         data_base += data_limit;
217         for (i=MAX_ARG_PAGES-1 ; i>=0 ; i--) {
218                 data_base -= PAGE_SIZE;
219                 if (page[i])
220                         put_page(page[i],data_base);
221         }
222         return data_limit;
226  * 'do_execve()' executes a new program.
227  */
228 int do_execve(unsigned long * eip,long tmp,char * filename,
229         char ** argv, char ** envp)
231         struct m_inode * inode;
232         struct buffer_head * bh;
233         struct exec ex;
234         unsigned long page[MAX_ARG_PAGES];
235         int i,argc,envc;
236         int e_uid, e_gid;
237         unsigned long p;
238         int retval;
239         int interp = 0;
241         if ((0xffff & eip[1]) != 0x000f)
242                 panic("execve called from supervisor mode");
243         for (i=0 ; i<MAX_ARG_PAGES ; i++)       /* clear page-table */
244                 page[i]=0;
245         if (!(inode=namei(filename))) {         /* get executables inode */
246                 retval = -ENOENT;
247                 goto exec_error1;
248         }
249         argc = count(argv);
250         envc = count(envp);
251         
252 restart_interp:
253         e_uid = current->euid;  /* Note this means no setuid */
254         e_gid = current->egid;  /* shell scripts! */
255         if (!S_ISREG(inode->i_mode)) {  /* must be regular file */
256                 retval = -EACCES;
257                 goto exec_error2;
258         }
259         i = inode->i_mode;
260         if (i & S_ISUID)
261                 e_uid = inode->i_uid;
262         if (i & S_ISGID)
263                 e_gid = inode->i_gid;
264         if (current->euid == inode->i_uid)
265                 i >>= 6;
266         else if (current->egid == inode->i_gid)
267                 i >>= 3;
268         if (!(i & 1) &&
269             !((inode->i_mode & 111) && suser())) {
270                 retval = -ENOEXEC;
271                 goto exec_error2;
272         }
273         if (!(bh = bread(inode->i_dev,inode->i_zone[0]))) {
274                 retval = -EACCES;
275                 goto exec_error2;
276         }
277         ex = *((struct exec *) bh->b_data);     /* read exec-header */
278         if ((bh->b_data[0] == '#') && (bh->b_data[1] == '!') && (interp > 3)) {
279                 /*
280                  * This section does the #! interpretation.
281                  * Gee, I hope the C compiler is intelligent about this,
282                  * and only activates this sub-frame when necessary.
283                  */
284                 char buf[1023], *cp, *interp, *i_name, *i_arg;
285                 int len;
287                 strncpy(buf, bh->b_data+2, 1022);
288                 brelse(bh);
289                 iput(inode);
290                 buf[1022] = '\0';
291                 if (!(cp = strchr(buf, '\n'))) {
292                         retval = -ENOEXEC;
293                         goto exec_error1;
294                 }
295                 *cp = '\0';
296                 for (cp = buf; (*cp == ' ') || (*cp == '\t'); cp++) ;
297                 if (*cp == '\0') {
298                         retval = -ENOEXEC; /* No interpreter name found */
299                         goto exec_error1;
300                 }
301                 interp = i_name = cp;
302                 for ( ; *cp && (*cp != ' ') && (*cp != '\t'); cp++) {
303                         if (*cp == '/')
304                                 i_name = cp;
305                 }
306                 if (*cp) {
307                         *cp++ = '\0';
308                         i_arg = cp;
309                 } else
310                         i_arg = 0;
311                 /*
312                  * OK, we've parsed out the interpreter name and
313                  * (optional) argument.
314                  */
315                 if (interp++ == 0) {
316                         p = copy_strings(envc,envp,page,
317                                          PAGE_SIZE*MAX_ARG_PAGES-4);
318                         p = copy_strings(--argc,argv+1,page,p);
319                 }
320                 /*
321                  * Copy in interpreter name
322                  */
323                 len = strlen(i_name) + 1;
324                 i = ((unsigned) (p-len)) >> 12;
325                 while (i<MAX_ARG_PAGES && !page[i]) {
326                         if (!(page[i]=get_free_page())) {
327                                 retval = -ENOMEM;
328                                 goto exec_error1;
329                         }
330                         i++;
331                 }
332                 do {
333                         --p;
334                         if (!page[p/PAGE_SIZE])
335                                 panic("nonexistent page in exec.c");
336                         ((char *) page[p/PAGE_SIZE])[p%PAGE_SIZE] =
337                                 i_name[--len];
338                 } while (len);
339                 /*
340                  * OK, now restart the process with the interpreter's inode.
341                  */
342                 if (!(inode=namei(interpreter))) { /* get executables inode */
343                         retval = -ENOENT;
344                         goto exec_error1;
345                 }
346                 goto restart_interp;
347         } else
348                 brelse(bh);
349         if (N_MAGIC(ex) != ZMAGIC || ex.a_trsize || ex.a_drsize ||
350                 ex.a_text+ex.a_data+ex.a_bss>0x3000000 ||
351                 inode->i_size < ex.a_text+ex.a_data+ex.a_syms+N_TXTOFF(ex)) {
352                 retval = -ENOEXEC;
353                 goto exec_error2;
354         }
355         if (N_TXTOFF(ex) != BLOCK_SIZE) {
356                 printk("%s: N_TXTOFF != BLOCK_SIZE. See a.out.h.", filename);
357                 retval = -ENOEXEC;
358                 goto exec_error2;
359         }
360         if (!interp) {
361                 p = copy_strings(envc,envp,page,PAGE_SIZE*MAX_ARG_PAGES-4);
362                 p = copy_strings(argc,argv,page,p);
363         }
364         if (!p) {
365                 for (i=0 ; i<MAX_ARG_PAGES ; i++)
366                         free_page(page[i]);
367                 retval = -ENOMEM;
368                 goto exec_error2;
369         }
370 /* OK, This is the point of no return */
371         for (i=0 ; i<32 ; i++)
372                 current->sigaction[i].sa_handler = NULL;
373         for (i=0 ; i<NR_OPEN ; i++)
374                 if ((current->close_on_exec>>i)&1)
375                         sys_close(i);
376         current->close_on_exec = 0;
377         free_page_tables(get_base(current->ldt[1]),get_limit(0x0f));
378         free_page_tables(get_base(current->ldt[2]),get_limit(0x17));
379         if (last_task_used_math == current)
380                 last_task_used_math = NULL;
381         current->used_math = 0;
382         p += change_ldt(ex.a_text,page)-MAX_ARG_PAGES*PAGE_SIZE;
383         p = (unsigned long) create_tables((char *)p,argc,envc);
384         current->brk = ex.a_bss +
385                 (current->end_data = ex.a_data +
386                 (current->end_code = ex.a_text));
387         current->start_stack = p & 0xfffff000;
388         current->euid = e_uid;
389         current->egid = e_gid;
390         i = read_area(inode,ex.a_text+ex.a_data);
391         iput(inode);
392         if (i<0)
393                 sys_exit(-1);
394         i = ex.a_text+ex.a_data;
395         while (i&0xfff)
396                 put_fs_byte(0,(char *) (i++));
397         eip[0] = ex.a_entry;            /* eip, magic happens :-) */
398         eip[3] = p;                     /* stack pointer */
399         return 0;
400 exec_error2:
401         iput(inode);
402 exec_error1:
403         for (i=0 ; i<MAX_ARG_PAGES ; i++)
404                 free_page(page[i]);
405         return(retval);