root/fs/exec.c

/* [previous][next][first][last][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. sys_uselib
  2. create_tables
  3. count
  4. copy_strings
  5. change_ldt
  6. do_execve

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

/* [previous][next][first][last][top][bottom][index][help] */