Fork me on GitHub

root/kernel/syscalls/execve.c

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

DEFINITIONS

This source file includes following definitions.
  1. initialize_barg
  2. free_barg_pages
  3. add_strings
  4. copy_strings
  5. do_execve
  6. sys_execve

   1 /*
   2  * fiwix/kernel/syscalls/execve.c
   3  *
   4  * Copyright 2018-2021, Jordi Sanfeliu. All rights reserved.
   5  * Distributed under the terms of the Fiwix License.
   6  */
   7 
   8 #include <fiwix/syscalls.h>
   9 #include <fiwix/stat.h>
  10 #include <fiwix/buffer.h>
  11 #include <fiwix/mm.h>
  12 #include <fiwix/process.h>
  13 #include <fiwix/fcntl.h>
  14 #include <fiwix/errno.h>
  15 #include <fiwix/string.h>
  16 
  17 #ifdef __DEBUG__
  18 #include <fiwix/stdio.h>
  19 #endif /*__DEBUG__ */
  20 
  21 static int initialize_barg(struct binargs *barg, char *argv[], char *envp[])
  22 {
  23         int n, errno;
  24 
  25         for(n = 0; n < ARG_MAX; n++) {
  26                 barg->page[n] = 0;
  27         }
  28         barg->argv_len = barg->envp_len = 0;
  29 
  30         for(n = 0; argv[n]; n++) {
  31                 if((errno = check_user_area(VERIFY_READ, argv[n], sizeof(char *)))) {
  32                         return errno;
  33                 }
  34                 barg->argv_len += strlen(argv[n]) + 1;
  35         }
  36         barg->argc = n;
  37 
  38         for(n = 0; envp[n]; n++) {
  39                 if((errno = check_user_area(VERIFY_READ, envp[n], sizeof(char *)))) {
  40                         return errno;
  41                 }
  42                 barg->envp_len += strlen(envp[n]) + 1;
  43         }
  44         barg->envc = n;
  45 
  46         return 0;
  47 }
  48 
  49 static void free_barg_pages(struct binargs *barg)
  50 {
  51         int n;
  52 
  53         for(n = 0; n < ARG_MAX; n++) {
  54                 if(barg->page[n]) {
  55                         kfree(barg->page[n]);
  56                 }
  57         }
  58 }
  59 
  60 static int add_strings(struct binargs *barg, char *filename, char *interpreter, char *args)
  61 {
  62         int n, p, offset;
  63         unsigned int ae_str_len;
  64         char *page;
  65 
  66         /*
  67          * For a script we need to substitute the saved argv[0] by the original
  68          * 'filename' supplied in execve(), otherwise the interpreter won't be
  69          * able to find the script file.
  70          */
  71         p = ARG_MAX - 1;
  72         ae_str_len = barg->argv_len + barg->envp_len + 4;
  73         p -= ae_str_len / PAGE_SIZE;
  74         offset = PAGE_SIZE - (ae_str_len % PAGE_SIZE);
  75         if(offset == PAGE_SIZE) {
  76                 offset = 0;
  77                 p++;
  78         }
  79         page = (char *)barg->page[p];
  80         while(*(page + offset)) {
  81                 offset++;
  82                 barg->argv_len--;
  83                 if(offset == PAGE_SIZE) {
  84                         p++;
  85                         offset = 0;
  86                         page = (char *)barg->page[p];
  87                 }
  88         }
  89         barg->argv_len--;
  90 
  91 
  92         p = ARG_MAX - 1;
  93         barg->argv_len += strlen(interpreter) + 1;
  94         barg->argv_len += strlen(args) ? strlen(args) + 1 : 0;
  95         barg->argv_len += strlen(filename) + 1;
  96         barg->argc++;
  97         if(*args) {
  98                 barg->argc++;
  99         }
 100         ae_str_len = barg->argv_len + barg->envp_len + 4;
 101         p -= ae_str_len / PAGE_SIZE;
 102         offset = PAGE_SIZE - (ae_str_len % PAGE_SIZE);
 103         if(offset == PAGE_SIZE) {
 104                 offset = 0;
 105                 p++;
 106         }
 107         barg->offset = offset;
 108         for(n = p; n < ARG_MAX; n++) {
 109                 if(!barg->page[n]) {
 110                         if(!(barg->page[n] = kmalloc())) {
 111                                 free_barg_pages(barg);
 112                                 return -ENOMEM;
 113                         }
 114                 }
 115         }
 116 
 117         /* interpreter */
 118         page = (char *)barg->page[p];
 119         while(*interpreter) {
 120                 *(page + offset) = *interpreter;
 121                 offset++;
 122                 interpreter++;
 123                 if(offset == PAGE_SIZE) {
 124                         p++;
 125                         offset = 0;
 126                         page = (char *)barg->page[p];
 127                 }
 128         }
 129         *(page + offset++) = NULL;
 130         if(offset == PAGE_SIZE) {
 131                 p++;
 132                 offset = 0;
 133         }
 134 
 135         /* args */
 136         page = (char *)barg->page[p];
 137         if(*args) {
 138                 while(*args) {
 139                         *(page + offset) = *args;
 140                         offset++;
 141                         args++;
 142                         if(offset == PAGE_SIZE) {
 143                                 p++;
 144                                 offset = 0;
 145                                 page = (char *)barg->page[p];
 146                         }
 147                 }
 148                 *(page + offset++) = NULL;
 149                 if(offset == PAGE_SIZE) {
 150                         p++;
 151                         offset = 0;
 152                 }
 153         }
 154 
 155         /* original script ('filename' with path) at argv[0] */
 156         page = (char *)barg->page[p];
 157         while(*filename) {
 158                 *(page + offset) = *filename;
 159                 offset++;
 160                 filename++;
 161                 if(offset == PAGE_SIZE) {
 162                         p++;
 163                         offset = 0;
 164                         page = (char *)barg->page[p];
 165                 }
 166         }
 167         *(page + offset) = NULL;
 168 
 169         return 0;
 170 }
 171 
 172 static int copy_strings(struct binargs *barg, char *argv[], char *envp[])
 173 {
 174         int n, p, offset;
 175         unsigned int ae_str_len;
 176         char *page, *str;
 177 
 178         p = ARG_MAX - 1;
 179         ae_str_len = barg->argv_len + barg->envp_len + 4;
 180         p -= ae_str_len / PAGE_SIZE;
 181         offset = PAGE_SIZE - (ae_str_len % PAGE_SIZE);
 182         if(offset == PAGE_SIZE) {
 183                 offset = 0;
 184                 p++;
 185         }
 186         barg->offset = offset;
 187         for(n = p; n < ARG_MAX; n++) {
 188                 if(!(barg->page[n] = kmalloc())) {
 189                         free_barg_pages(barg);
 190                         return -ENOMEM;
 191                 }
 192         }
 193         for(n = 0; n < barg->argc; n++) {
 194                 str = argv[n];
 195                 page = (char *)barg->page[p];
 196                 while(*str) {
 197                         *(page + offset) = *str;
 198                         offset++;
 199                         str++;
 200                         if(offset == PAGE_SIZE) {
 201                                 p++;
 202                                 offset = 0;
 203                                 page = (char *)barg->page[p];
 204                         }
 205                 }
 206                 *(page + offset++) = NULL;
 207                 if(offset == PAGE_SIZE) {
 208                         p++;
 209                         offset = 0;
 210                 }
 211         }
 212         for(n = 0; n < barg->envc; n++) {
 213                 str = envp[n];
 214                 page = (char *)barg->page[p];
 215                 while(*str) {
 216                         *(page + offset) = *str;
 217                         offset++;
 218                         str++;
 219                         if(offset == PAGE_SIZE) {
 220                                 p++;
 221                                 offset = 0;
 222                                 page = (char *)barg->page[p];
 223                         }
 224                 }
 225                 *(page + offset++) = NULL;
 226                 if(offset == PAGE_SIZE) {
 227                         p++;
 228                         offset = 0;
 229                 }
 230         }
 231 
 232         return 0;
 233 }
 234 
 235 static int do_execve(const char *filename, char *argv[], char *envp[], struct sigcontext *sc)
 236 {
 237         char interpreter[NAME_MAX + 1], args[NAME_MAX + 1], name[NAME_MAX + 1];
 238         __blk_t block;
 239         struct buffer *buf;
 240         struct inode *i;
 241         struct binargs barg;
 242         char *data, *tmp_name;
 243         int errno;
 244 
 245         if((errno = initialize_barg(&barg, &(*argv), &(*envp))) < 0) {
 246                 return errno;
 247         }
 248 
 249         /* save 'argv' and 'envp' into the kernel address space */
 250         if((errno = copy_strings(&barg, &(*argv), &(*envp)))) {
 251                 return errno;
 252         }
 253 
 254         if(!(data = (void *)kmalloc())) {
 255                 return -ENOMEM;
 256         }
 257 
 258         if((errno = malloc_name(filename, &tmp_name)) < 0) {
 259                 kfree((unsigned int)data);
 260                 free_barg_pages(&barg);
 261                 return errno;
 262         }
 263         strcpy(name, tmp_name);
 264         free_name(tmp_name);
 265 
 266 
 267 loop:
 268         if((errno = namei(name, &i, NULL, FOLLOW_LINKS))) {
 269                 free_barg_pages(&barg);
 270                 kfree((unsigned int)data);
 271                 return errno;
 272         }
 273 
 274         if(!S_ISREG(i->i_mode)) {
 275                 iput(i);
 276                 free_barg_pages(&barg);
 277                 kfree((unsigned int)data);
 278                 return -EACCES;
 279         }
 280         if(check_permission(TO_EXEC, i) < 0) {
 281                 iput(i);
 282                 free_barg_pages(&barg);
 283                 kfree((unsigned int)data);
 284                 return -EACCES;
 285         }
 286 
 287         if((block = bmap(i, 0, FOR_READING)) < 0) {
 288                 iput(i);
 289                 free_barg_pages(&barg);
 290                 kfree((unsigned int)data);
 291                 return block;
 292         }
 293         if(!(buf = bread(i->dev, block, i->sb->s_blocksize))) {
 294                 iput(i);
 295                 free_barg_pages(&barg);
 296                 kfree((unsigned int)data);
 297                 return -EIO;
 298         }
 299 
 300         /*
 301          * The contents of the buffer is copied and then freed immediately to
 302          * make sure that it won't conflict while zeroing the BSS fractional
 303          * page, in case that the same block is requested during the page fault.
 304          */
 305         memcpy_b(data, buf->data, i->sb->s_blocksize);
 306         brelse(buf);
 307 
 308         errno = elf_load(i, &barg, sc, data);
 309         if(errno == -ENOEXEC) {
 310                 /* OK, looks like it was not an ELF binary; let's see if it is a script */
 311                 memset_b(interpreter, 0, NAME_MAX + 1);
 312                 memset_b(args, 0, NAME_MAX + 1);
 313                 errno = script_load(interpreter, args, data);
 314                 if(!errno) {
 315                         /* yes, it is! */
 316                         iput(i);
 317                         if((errno = add_strings(&barg, name, interpreter, args))) {
 318                                 free_barg_pages(&barg);
 319                                 kfree((unsigned int)data);
 320                                 return errno;
 321                         }
 322                         strcpy(name, interpreter);
 323                         goto loop;
 324                 }
 325         }
 326 
 327         if(!errno) {
 328                 if(i->i_mode & S_ISUID) {
 329                         current->euid = i->i_uid;
 330                 }
 331                 if(i->i_mode & S_ISGID) {
 332                         current->egid = i->i_gid;
 333                 }
 334         }
 335 
 336         iput(i);
 337         free_barg_pages(&barg);
 338         kfree((unsigned int)data);
 339         return errno;
 340 }
 341 
 342 int sys_execve(const char *filename, char *argv[], char *envp[], int arg4, int arg5, struct sigcontext *sc)
 343 {
 344         char argv0[NAME_MAX + 1];
 345         int n, errno;
 346 
 347 #ifdef __DEBUG__
 348         printk("(pid %d) sys_execve('%s', ...)\n", current->pid, filename);
 349 #endif /*__DEBUG__ */
 350 
 351         /* copy filename into kernel address space */
 352         strncpy(argv0, argv[0], NAME_MAX);
 353         if((errno = do_execve(filename, &(*argv), &(*envp), sc))) {
 354                 return errno;
 355         }
 356 
 357         strncpy(current->argv0, argv0, NAME_MAX);
 358         for(n = 0; n < OPEN_MAX; n++) {
 359                 if(current->fd[n] && (current->fd_flags[n] & FD_CLOEXEC)) {
 360                         sys_close(n);
 361                 }
 362         }
 363 
 364         current->suid = current->euid;
 365         current->sgid = current->egid;
 366         current->sigpending = 0;
 367         current->sigexecuting = 0;
 368         for(n = 0; n < NSIG; n++) {
 369                 current->sigaction[n].sa_mask = 0;
 370                 current->sigaction[n].sa_flags = 0;
 371                 if(current->sigaction[n].sa_handler != SIG_IGN) {
 372                         current->sigaction[n].sa_handler = SIG_DFL;
 373                 }
 374         }
 375         current->sleep_address = NULL;
 376         current->flags |= PF_PEXEC;
 377         return 0;
 378 }

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