[source navigation] [diff markup] [identifier search] [freetext search] [file search]

Oldlinux Cross Reference
Linux/fs/exec.c

Version: [1.0] [0.99.11] [0.99] [0.98] [0.97] [0.96a] [0.95] [0.12] [0.11] [0.01]
Architecture: [i386]

  1 /*
  2  *  linux/fs/exec.c
  3  *
  4  *  (C) 1991  Linus Torvalds
  5  */
  6 
  7 /*
  8  * #!-checking implemented by tytso.
  9  */
 10 
 11 /*
 12  * Demand-loading implemented 01.12.91 - no need to read anything but
 13  * the header into memory. The inode of the executable is put into
 14  * "current->executable", and page faults do the actual loading. Clean.
 15  *
 16  * Once more I can proudly say that linux stood up to being changed: it
 17  * was less than 2 hours work to get demand-loading completely implemented.
 18  */
 19 
 20 #include <errno.h>
 21 #include <string.h>
 22 #include <sys/stat.h>
 23 #include <a.out.h>
 24 
 25 #include <linux/fs.h>
 26 #include <linux/sched.h>
 27 #include <linux/kernel.h>
 28 #include <linux/mm.h>
 29 #include <asm/segment.h>
 30 
 31 extern int sys_exit(int exit_code);
 32 extern int sys_close(int fd);
 33 
 34 /*
 35  * MAX_ARG_PAGES defines the number of pages allocated for arguments
 36  * and envelope for the new program. 32 should suffice, this gives
 37  * a maximum env+arg of 128kB !
 38  */
 39 #define MAX_ARG_PAGES 32
 40 
 41 /*
 42  * create_tables() parses the env- and arg-strings in new user
 43  * memory and creates the pointer tables from them, and puts their
 44  * addresses on the "stack", returning the new stack pointer value.
 45  */
 46 static unsigned long * create_tables(char * p,int argc,int envc)
 47 {
 48         unsigned long *argv,*envp;
 49         unsigned long * sp;
 50 
 51         sp = (unsigned long *) (0xfffffffc & (unsigned long) p);
 52         sp -= envc+1;
 53         envp = sp;
 54         sp -= argc+1;
 55         argv = sp;
 56         put_fs_long((unsigned long)envp,--sp);
 57         put_fs_long((unsigned long)argv,--sp);
 58         put_fs_long((unsigned long)argc,--sp);
 59         while (argc-->0) {
 60                 put_fs_long((unsigned long) p,argv++);
 61                 while (get_fs_byte(p++)) /* nothing */ ;
 62         }
 63         put_fs_long(0,argv);
 64         while (envc-->0) {
 65                 put_fs_long((unsigned long) p,envp++);
 66                 while (get_fs_byte(p++)) /* nothing */ ;
 67         }
 68         put_fs_long(0,envp);
 69         return sp;
 70 }
 71 
 72 /*
 73  * count() counts the number of arguments/envelopes
 74  */
 75 static int count(char ** argv)
 76 {
 77         int i=0;
 78         char ** tmp;
 79 
 80         if (tmp = argv)
 81                 while (get_fs_long((unsigned long *) (tmp++)))
 82                         i++;
 83 
 84         return i;
 85 }
 86 
 87 /*
 88  * 'copy_string()' copies argument/envelope strings from user
 89  * memory to free pages in kernel mem. These are in a format ready
 90  * to be put directly into the top of new user memory.
 91  *
 92  * Modified by TYT, 11/24/91 to add the from_kmem argument, which specifies
 93  * whether the string and the string array are from user or kernel segments:
 94  * 
 95  * from_kmem     argv *        argv **
 96  *    0          user space    user space
 97  *    1          kernel space  user space
 98  *    2          kernel space  kernel space
 99  * 
100  * We do this by playing games with the fs segment register.  Since it
101  * it is expensive to load a segment register, we try to avoid calling
102  * set_fs() unless we absolutely have to.
103  */
104 static unsigned long copy_strings(int argc,char ** argv,unsigned long *page,
105                 unsigned long p, int from_kmem)
106 {
107         char *tmp, *pag;
108         int len, offset = 0;
109         unsigned long old_fs, new_fs;
110 
111         if (!p)
112                 return 0;       /* bullet-proofing */
113         new_fs = get_ds();
114         old_fs = get_fs();
115         if (from_kmem==2)
116                 set_fs(new_fs);
117         while (argc-- > 0) {
118                 if (from_kmem == 1)
119                         set_fs(new_fs);
120                 if (!(tmp = (char *)get_fs_long(((unsigned long *)argv)+argc)))
121                         panic("argc is wrong");
122                 if (from_kmem == 1)
123                         set_fs(old_fs);
124                 len=0;          /* remember zero-padding */
125                 do {
126                         len++;
127                 } while (get_fs_byte(tmp++));
128                 if (p-len < 0) {        /* this shouldn't happen - 128kB */
129                         set_fs(old_fs);
130                         return 0;
131                 }
132                 while (len) {
133                         --p; --tmp; --len;
134                         if (--offset < 0) {
135                                 offset = p % PAGE_SIZE;
136                                 if (from_kmem==2)
137                                         set_fs(old_fs);
138                                 if (!(pag = (char *) page[p/PAGE_SIZE]) &&
139                                     !(pag = (char *) page[p/PAGE_SIZE] =
140                                       (unsigned long *) get_free_page())) 
141                                         return 0;
142                                 if (from_kmem==2)
143                                         set_fs(new_fs);
144 
145                         }
146                         *(pag + offset) = get_fs_byte(tmp);
147                 }
148         }
149         if (from_kmem==2)
150                 set_fs(old_fs);
151         return p;
152 }
153 
154 static unsigned long change_ldt(unsigned long text_size,unsigned long * page)
155 {
156         unsigned long code_limit,data_limit,code_base,data_base;
157         int i;
158 
159         code_limit = text_size+PAGE_SIZE -1;
160         code_limit &= 0xFFFFF000;
161         data_limit = 0x4000000;
162         code_base = get_base(current->ldt[1]);
163         data_base = code_base;
164         set_base(current->ldt[1],code_base);
165         set_limit(current->ldt[1],code_limit);
166         set_base(current->ldt[2],data_base);
167         set_limit(current->ldt[2],data_limit);
168 /* make sure fs points to the NEW data segment */
169         __asm__("pushl $0x17\n\tpop %%fs"::);
170         data_base += data_limit;
171         for (i=MAX_ARG_PAGES-1 ; i>=0 ; i--) {
172                 data_base -= PAGE_SIZE;
173                 if (page[i])
174                         put_page(page[i],data_base);
175         }
176         return data_limit;
177 }
178 
179 /*
180  * 'do_execve()' executes a new program.
181  */
182 int do_execve(unsigned long * eip,long tmp,char * filename,
183         char ** argv, char ** envp)
184 {
185         struct m_inode * inode;
186         struct buffer_head * bh;
187         struct exec ex;
188         unsigned long page[MAX_ARG_PAGES];
189         int i,argc,envc;
190         int e_uid, e_gid;
191         int retval;
192         int sh_bang = 0;
193         unsigned long p=PAGE_SIZE*MAX_ARG_PAGES-4;
194 
195         if ((0xffff & eip[1]) != 0x000f)
196                 panic("execve called from supervisor mode");
197         for (i=0 ; i<MAX_ARG_PAGES ; i++)       /* clear page-table */
198                 page[i]=0;
199         if (!(inode=namei(filename)))           /* get executables inode */
200                 return -ENOENT;
201         argc = count(argv);
202         envc = count(envp);
203         
204 restart_interp:
205         if (!S_ISREG(inode->i_mode)) {  /* must be regular file */
206                 retval = -EACCES;
207                 goto exec_error2;
208         }
209         i = inode->i_mode;
210         e_uid = (i & S_ISUID) ? inode->i_uid : current->euid;
211         e_gid = (i & S_ISGID) ? inode->i_gid : current->egid;
212         if (current->euid == inode->i_uid)
213                 i >>= 6;
214         else if (current->egid == inode->i_gid)
215                 i >>= 3;
216         if (!(i & 1) &&
217             !((inode->i_mode & 0111) && suser())) {
218                 retval = -ENOEXEC;
219                 goto exec_error2;
220         }
221         if (!(bh = bread(inode->i_dev,inode->i_zone[0]))) {
222                 retval = -EACCES;
223                 goto exec_error2;
224         }
225         ex = *((struct exec *) bh->b_data);     /* read exec-header */
226         if ((bh->b_data[0] == '#') && (bh->b_data[1] == '!') && (!sh_bang)) {
227                 /*
228                  * This section does the #! interpretation.
229                  * Sorta complicated, but hopefully it will work.  -TYT
230                  */
231 
232                 char buf[1023], *cp, *interp, *i_name, *i_arg;
233                 unsigned long old_fs;
234 
235                 strncpy(buf, bh->b_data+2, 1022);
236                 brelse(bh);
237                 iput(inode);
238                 buf[1022] = '\0';
239                 if (cp = strchr(buf, '\n')) {
240                         *cp = '\0';
241                         for (cp = buf; (*cp == ' ') || (*cp == '\t'); cp++);
242                 }
243                 if (!cp || *cp == '\0') {
244                         retval = -ENOEXEC; /* No interpreter name found */
245                         goto exec_error1;
246                 }
247                 interp = i_name = cp;
248                 i_arg = 0;
249                 for ( ; *cp && (*cp != ' ') && (*cp != '\t'); cp++) {
250                         if (*cp == '/')
251                                 i_name = cp+1;
252                 }
253                 if (*cp) {
254                         *cp++ = '\0';
255                         i_arg = cp;
256                 }
257                 /*
258                  * OK, we've parsed out the interpreter name and
259                  * (optional) argument.
260                  */
261                 if (sh_bang++ == 0) {
262                         p = copy_strings(envc, envp, page, p, 0);
263                         p = copy_strings(--argc, argv+1, page, p, 0);
264                 }
265                 /*
266                  * Splice in (1) the interpreter's name for argv[0]
267                  *           (2) (optional) argument to interpreter
268                  *           (3) filename of shell script
269                  *
270                  * This is done in reverse order, because of how the
271                  * user environment and arguments are stored.
272                  */
273                 p = copy_strings(1, &filename, page, p, 1);
274                 argc++;
275                 if (i_arg) {
276                         p = copy_strings(1, &i_arg, page, p, 2);
277                         argc++;
278                 }
279                 p = copy_strings(1, &i_name, page, p, 2);
280                 argc++;
281                 if (!p) {
282                         retval = -ENOMEM;
283                         goto exec_error1;
284                 }
285                 /*
286                  * OK, now restart the process with the interpreter's inode.
287                  */
288                 old_fs = get_fs();
289                 set_fs(get_ds());
290                 if (!(inode=namei(interp))) { /* get executables inode */
291                         set_fs(old_fs);
292                         retval = -ENOENT;
293                         goto exec_error1;
294                 }
295                 set_fs(old_fs);
296                 goto restart_interp;
297         }
298         brelse(bh);
299         if (N_MAGIC(ex) != ZMAGIC || ex.a_trsize || ex.a_drsize ||
300                 ex.a_text+ex.a_data+ex.a_bss>0x3000000 ||
301                 inode->i_size < ex.a_text+ex.a_data+ex.a_syms+N_TXTOFF(ex)) {
302                 retval = -ENOEXEC;
303                 goto exec_error2;
304         }
305         if (N_TXTOFF(ex) != BLOCK_SIZE) {
306                 printk("%s: N_TXTOFF != BLOCK_SIZE. See a.out.h.", filename);
307                 retval = -ENOEXEC;
308                 goto exec_error2;
309         }
310         if (!sh_bang) {
311                 p = copy_strings(envc,envp,page,p,0);
312                 p = copy_strings(argc,argv,page,p,0);
313                 if (!p) {
314                         retval = -ENOMEM;
315                         goto exec_error2;
316                 }
317         }
318 /* OK, This is the point of no return */
319         if (current->executable)
320                 iput(current->executable);
321         current->executable = inode;
322         for (i=0 ; i<32 ; i++)
323                 current->sigaction[i].sa_handler = NULL;
324         for (i=0 ; i<NR_OPEN ; i++)
325                 if ((current->close_on_exec>>i)&1)
326                         sys_close(i);
327         current->close_on_exec = 0;
328         free_page_tables(get_base(current->ldt[1]),get_limit(0x0f));
329         free_page_tables(get_base(current->ldt[2]),get_limit(0x17));
330         if (last_task_used_math == current)
331                 last_task_used_math = NULL;
332         current->used_math = 0;
333         p += change_ldt(ex.a_text,page)-MAX_ARG_PAGES*PAGE_SIZE;
334         p = (unsigned long) create_tables((char *)p,argc,envc);
335         current->brk = ex.a_bss +
336                 (current->end_data = ex.a_data +
337                 (current->end_code = ex.a_text));
338         current->start_stack = p & 0xfffff000;
339         current->euid = e_uid;
340         current->egid = e_gid;
341         i = ex.a_text+ex.a_data;
342         while (i&0xfff)
343                 put_fs_byte(0,(char *) (i++));
344         eip[0] = ex.a_entry;            /* eip, magic happens :-) */
345         eip[3] = p;                     /* stack pointer */
346         return 0;
347 exec_error2:
348         iput(inode);
349 exec_error1:
350         for (i=0 ; i<MAX_ARG_PAGES ; i++)
351                 free_page(page[i]);
352         return(retval);
353 }
354 

[source navigation] [diff markup] [identifier search] [freetext search] [file search]

This page was automatically generated by the LXR engine.
Visit the LXR main site for more information.