root/fs/exec.c

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

DEFINITIONS

This source file includes following definitions.
  1. read_head
  2. read_ind
  3. read_area
  4. create_tables
  5. count
  6. copy_strings
  7. change_ldt
  8. do_execve

   1 /*
   2  *  linux/fs/exec.c
   3  *
   4  *  (C) 1991  Linus Torvalds
   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  * MAX_ARG_PAGES defines the number of pages allocated for arguments
  23  * and envelope for the new program. 32 should suffice, this gives
  24  * a maximum env+arg of 128kB !
  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  * read_head() reads blocks 1-6 (not 0). Block 0 has already been
  41  * read for header information.
  42  */
  43 int read_head(struct m_inode * inode,int blocks)
     /* [previous][next][first][last][top][bottom][index][help] */
  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)
     /* [previous][next][first][last][top][bottom][index][help] */
  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  * read_area() reads an area into %fs:mem.
  93  */
  94 int read_area(struct m_inode * inode,long size)
     /* [previous][next][first][last][top][bottom][index][help] */
  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  * create_tables() parses the env- and arg-strings in new user
 120  * memory and creates the pointer tables from them, and puts their
 121  * addresses on the "stack", returning the new stack pointer value.
 122  */
 123 static unsigned long * create_tables(char * p,int argc,int envc)
     /* [previous][next][first][last][top][bottom][index][help] */
 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++)) /* nothing */ ;
 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++)) /* nothing */ ;
 144         }
 145         put_fs_long(0,envp);
 146         return sp;
 147 }
 148 
 149 /*
 150  * count() counts the number of arguments/envelopes
 151  */
 152 static int count(char ** argv)
     /* [previous][next][first][last][top][bottom][index][help] */
 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  * 'copy_string()' copies argument/envelope strings from user
 166  * memory to free pages in kernel mem. These are in a format ready
 167  * to be put directly into the top of new user memory.
 168  *
 169  * Modified by TYT, 11/24/91 to add the from_kmem argument, which specifies
 170  * whether the string and the string array are from user or kernel segments:
 171  * 
 172  * from_kmem     argv *        argv **
 173  *    0          user space    user space
 174  *    1          kernel space  user space
 175  *    2          kernel space  kernel space
 176  * 
 177  * We do this by playing games with the fs segment register.  Since it
 178  * it is expensive to load a segment register, we try to avoid calling
 179  * set_fs() unless we absolutely have to.
 180  */
 181 static unsigned long copy_strings(int argc,char ** argv,unsigned long *page,
     /* [previous][next][first][last][top][bottom][index][help] */
 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;       /* bullet-proofing */
 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;          /* remember zero-padding */
 202                 do {
 203                         len++;
 204                 } while (get_fs_byte(tmp++));
 205                 if (p-len < 0) {        /* this shouldn't happen - 128kB */
 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)
     /* [previous][next][first][last][top][bottom][index][help] */
 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 /* make sure fs points to the NEW data segment */
 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  * 'do_execve()' executes a new program.
 258  */
 259 int do_execve(unsigned long * eip,long tmp,char * filename,
     /* [previous][next][first][last][top][bottom][index][help] */
 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++)       /* clear page-table */
 276                 page[i]=0;
 277         if (!(inode=namei(filename)))           /* get executables inode */
 278                 return -ENOENT;
 279         argc = count(argv);
 280         envc = count(envp);
 281         
 282 restart_interp:
 283         if (!S_ISREG(inode->i_mode)) {  /* must be regular file */
 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);     /* read exec-header */
 304         if ((bh->b_data[0] == '#') && (bh->b_data[1] == '!') && (!sh_bang)) {
 305                 /*
 306                  * This section does the #! interpretation.
 307                  * Sorta complicated, but hopefully it will work.  -TYT
 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; /* No interpreter name found */
 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                  * OK, we've parsed out the interpreter name and
 339                  * (optional) argument.
 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                  * Splice in (1) the interpreter's name for argv[0]
 347                  *           (2) (optional) argument to interpreter
 348                  *           (3) filename of shell script
 349                  *
 350                  * This is done in reverse order, because of how the
 351                  * user environment and arguments are stored.
 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                  * OK, now restart the process with the interpreter's inode.
 367                  */
 368                 old_fs = get_fs();
 369                 set_fs(get_ds());
 370                 if (!(inode=namei(interp))) { /* get executables inode */
 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 /* OK, This is the point of no return */
 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;            /* eip, magic happens :-) */
 428         eip[3] = p;                     /* stack pointer */
 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 }

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