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         int ch;
 220 
 221         if ((0xffff & eip[1]) != 0x000f)
 222                 panic("execve called from supervisor mode");
 223         for (i=0 ; i<MAX_ARG_PAGES ; i++)       /* clear page-table */
 224                 page[i]=0;
 225         if (!(inode=namei(filename)))           /* get executables inode */
 226                 return -ENOENT;
 227         argc = count(argv);
 228         envc = count(envp);
 229         
 230 restart_interp:
 231         if (!S_ISREG(inode->i_mode)) {  /* must be regular file */
 232                 retval = -EACCES;
 233                 goto exec_error2;
 234         }
 235         i = inode->i_mode;
 236         /* make sure we don't let suid, sgid files be ptraced. */
 237         if (current->flags & PF_PTRACED) {
 238                 e_uid = current->euid;
 239                 e_gid = current->egid;
 240         } else {
 241                 e_uid = (i & S_ISUID) ? inode->i_uid : current->euid;
 242                 e_gid = (i & S_ISGID) ? inode->i_gid : current->egid;
 243         }
 244         if (current->euid == inode->i_uid)
 245                 i >>= 6;
 246         else if (in_group_p(inode->i_gid))
 247                 i >>= 3;
 248         if (!(i & 1) &&
 249             !((inode->i_mode & 0111) && suser())) {
 250                 retval = -EACCES;
 251                 goto exec_error2;
 252         }
 253         if (!(bh = bread(inode->i_dev,inode->i_data[0]))) {
 254                 retval = -EACCES;
 255                 goto exec_error2;
 256         }
 257         ex = *((struct exec *) bh->b_data);     /* read exec-header */
 258         if ((bh->b_data[0] == '#') && (bh->b_data[1] == '!') && (!sh_bang)) {
 259                 /*
 260                  * This section does the #! interpretation.
 261                  * Sorta complicated, but hopefully it will work.  -TYT
 262                  */
 263 
 264                 char buf[128], *cp, *interp, *i_name, *i_arg;
 265                 unsigned long old_fs;
 266 
 267                 strncpy(buf, bh->b_data+2, 127);
 268                 brelse(bh);
 269                 iput(inode);
 270                 buf[127] = '\0';
 271                 if (cp = strchr(buf, '\n')) {
 272                         *cp = '\0';
 273                         for (cp = buf; (*cp == ' ') || (*cp == '\t'); cp++);
 274                 }
 275                 if (!cp || *cp == '\0') {
 276                         retval = -ENOEXEC; /* No interpreter name found */
 277                         goto exec_error1;
 278                 }
 279                 interp = i_name = cp;
 280                 i_arg = 0;
 281                 for ( ; *cp && (*cp != ' ') && (*cp != '\t'); cp++) {
 282                         if (*cp == '/')
 283                                 i_name = cp+1;
 284                 }
 285                 if (*cp) {
 286                         *cp++ = '\0';
 287                         i_arg = cp;
 288                 }
 289                 /*
 290                  * OK, we've parsed out the interpreter name and
 291                  * (optional) argument.
 292                  */
 293                 if (sh_bang++ == 0) {
 294                         p = copy_strings(envc, envp, page, p, 0);
 295                         p = copy_strings(--argc, argv+1, page, p, 0);
 296                 }
 297                 /*
 298                  * Splice in (1) the interpreter's name for argv[0]
 299                  *           (2) (optional) argument to interpreter
 300                  *           (3) filename of shell script
 301                  *
 302                  * This is done in reverse order, because of how the
 303                  * user environment and arguments are stored.
 304                  */
 305                 p = copy_strings(1, &filename, page, p, 1);
 306                 argc++;
 307                 if (i_arg) {
 308                         p = copy_strings(1, &i_arg, page, p, 2);
 309                         argc++;
 310                 }
 311                 p = copy_strings(1, &i_name, page, p, 2);
 312                 argc++;
 313                 if (!p) {
 314                         retval = -ENOMEM;
 315                         goto exec_error1;
 316                 }
 317                 /*
 318                  * OK, now restart the process with the interpreter's inode.
 319                  */
 320                 old_fs = get_fs();
 321                 set_fs(get_ds());
 322                 if (!(inode=namei(interp))) { /* get executables inode */
 323                         set_fs(old_fs);
 324                         retval = -ENOENT;
 325                         goto exec_error1;
 326                 }
 327                 set_fs(old_fs);
 328                 goto restart_interp;
 329         }
 330         brelse(bh);
 331         if (N_MAGIC(ex) != ZMAGIC || ex.a_trsize || ex.a_drsize ||
 332                 ex.a_text+ex.a_data+ex.a_bss>0x3000000 ||
 333                 inode->i_size < ex.a_text+ex.a_data+ex.a_syms+N_TXTOFF(ex)) {
 334                 retval = -ENOEXEC;
 335                 goto exec_error2;
 336         }
 337         if (N_TXTOFF(ex) != BLOCK_SIZE) {
 338                 printk("%s: N_TXTOFF != BLOCK_SIZE. See a.out.h.", filename);
 339                 retval = -ENOEXEC;
 340                 goto exec_error2;
 341         }
 342         if (!sh_bang) {
 343                 p = copy_strings(envc,envp,page,p,0);
 344                 p = copy_strings(argc,argv,page,p,0);
 345                 if (!p) {
 346                         retval = -ENOMEM;
 347                         goto exec_error2;
 348                 }
 349         }
 350 /* OK, This is the point of no return */
 351 /* note that current->library stays unchanged by an exec */
 352         for (i=0; (ch = get_fs_byte(filename++)) != '\0';)
 353                 if (ch == '/')
 354                         i = 0;
 355                 else
 356                         if (i < 8)
 357                                 current->comm[i++] = ch;
 358         if (i < 8)
 359                 current->comm[i] = '\0';
 360         
 361         if (current->executable)
 362                 iput(current->executable);
 363         current->executable = inode;
 364         current->signal = 0;
 365         for (i=0 ; i<32 ; i++) {
 366                 current->sigaction[i].sa_mask = 0;
 367                 current->sigaction[i].sa_flags = 0;
 368                 if (current->sigaction[i].sa_handler != SIG_IGN)
 369                         current->sigaction[i].sa_handler = NULL;
 370         }
 371         for (i=0 ; i<NR_OPEN ; i++)
 372                 if ((current->close_on_exec>>i)&1)
 373                         sys_close(i);
 374         current->close_on_exec = 0;
 375         free_page_tables(get_base(current->ldt[1]),get_limit(0x0f));
 376         free_page_tables(get_base(current->ldt[2]),get_limit(0x17));
 377         if (last_task_used_math == current)
 378                 last_task_used_math = NULL;
 379         current->used_math = 0;
 380         p += change_ldt(ex.a_text,page);
 381         p -= LIBRARY_SIZE + MAX_ARG_PAGES*PAGE_SIZE;
 382         p = (unsigned long) create_tables((char *)p,argc,envc);
 383         current->brk = ex.a_bss +
 384                 (current->end_data = ex.a_data +
 385                 (current->end_code = ex.a_text));
 386         current->start_stack = p;
 387         current->rss = (LIBRARY_OFFSET - p + PAGE_SIZE-1) / PAGE_SIZE;
 388         current->suid = current->euid = e_uid;
 389         current->sgid = current->egid = e_gid;
 390         eip[0] = ex.a_entry;            /* eip, magic happens :-) */
 391         eip[3] = p;                     /* stack pointer */
 392         if (current->flags & PF_PTRACED)
 393           send_sig(SIGTRAP, current, 0);
 394         return 0;
 395 exec_error2:
 396         iput(inode);
 397 exec_error1:
 398         for (i=0 ; i<MAX_ARG_PAGES ; i++)
 399                 free_page(page[i]);
 400         return(retval);
 401 }

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