/** * Rezerwuje ciągły obszar w danym segmencie. * @param vseg deskryptor segmentu. * @param size rozmiar ciągłego obszaru. * @param _res adres zmiennej, do uzupełnienia przydzielonym adresem. */ int vm_seg_reserve(vm_seg_t *vseg, vm_size_t size, void *_res) { int expand = EXPAND_UP; vm_addr_t *res = _res; size = PAGE_ROUND(size); vm_region_t *region = list_head(&vseg->regions); if (region == NULL) { if (do_first_region(vseg, ®ion)) return -1; } // sprawdzamy czy istnieje dziura pomiędzy początkiem segmentu // a pierwszym regionem if (size < region->begin - vseg->base) { *res = region->begin - size; return expand_region(vseg, region, size, EXPAND_DOWN, _res); } // Ok, no to szukamy dziury za regionem region = list_find(&vseg->regions, has_hole_after_reg, size); if (region == NULL) { if (vseg->flags & VM_SEG_EXPDOWN) { expand = EXPAND_DOWN; region = list_head(&vseg->regions); *res = region->begin - size; } else { region = list_tail(&vseg->regions); *res = region->end; } } else { *res = region->end; } return expand_region(vseg, region, size, expand, _res); }
int set_stack(vm_space_t *vs, vm_seg_t *STACK, vm_seg_t *DATA, vm_addr_t *res, vm_size_t s) { KASSERT(s > 0); s = PAGE_ROUND(s); vm_size_t stackspace = STACK->end - (DATA->base + DATA->limit) + PAGE_SIZE; if (stackspace < s) { if ((DATA->limit - DATA->size) < s) return -1; DATA->limit -= (s-stackspace); } STACK->limit += s; return vm_seg_alloc(STACK, s, res); }
static int load_svr3_binary (struct linux_binprm *bprm, struct pt_regs *regs) { struct file *file; int error, retval, i, j, shlibs; int fd[1+SHLIB_MAX]; long entry; unsigned long rlim; unsigned long p = bprm->p; struct filehdr *fh; struct aouthdr *ah; struct scnhdr *sh; char *buf, *libs_buf; /* Main binary + SHLIB_MAX */ struct bin_info bin_info[SHLIB_MAX + 1]; /* Cheking accessable headers by bprm->buf (128 bytes). */ fh = (struct filehdr *) bprm->buf; if (fh->f_magic != MC68MAGIC || fh->f_opthdr < AOUTSZ || fh->f_nscns < 3 || !(fh->f_flags & F_AR32W) || !(fh->f_flags & F_EXEC) ) return -ENOEXEC; ah = (struct aouthdr *) ((char *) bprm->buf + FILHSZ); if (ah->magic == SHMAGIC) return -ELIBEXEC; if ((ah->magic != DMAGIC && ah->magic != ZMAGIC) || !ah->tsize || ah->tsize + ah->dsize + FILHSZ + fh->f_opthdr + SCNHSZ * fh->f_nscns > bprm->inode->i_size || ah->text_start + ah->tsize > ah->data_start ) return -ENOEXEC; if (fh->f_nscns > 24) { printk ("Too many sections in svr3 binary file\n"); return -ENOEXEC; } /* Touch main binary file (which has # 0). */ fd[0] = open_inode (bprm->inode, O_RDONLY); if (fd[0] < 0) return fd[0]; buf = (char *) kmalloc (2*1024, GFP_KERNEL); if (!buf) { sys_close (fd[0]); return -ENOMEM; } libs_buf = buf + 1024; retval = touch_svr3_binary (fd[0], buf, &bin_info[0], 0); if (retval < 0) { sys_close(fd[0]); kfree (buf); return retval; } /* Looking for STYP_LIB section for shared libraries. */ sh = (struct scnhdr *) (buf + FILHSZ + fh->f_opthdr); for (i = 0; i < fh->f_nscns; i++) if (sh[i].s_flags == STYP_LIB) break; if (i == fh->f_nscns) shlibs = 0; else shlibs = sh[i].s_nlib; /* Touch target shared library binary files (## 1--SHLIB_MAX). */ if (shlibs) { void *p; int slib_size = sh[i].s_size; if (shlibs > SHLIB_MAX) { retval = -ELIBMAX; goto error_close; } file = bin_info[0].file; retval = sys_lseek (fd[0], sh[i].s_scnptr, 0); if (retval < 0) goto error_close; if (retval != sh[i].s_scnptr) { retval = -EACCES; goto error_close; } set_fs (KERNEL_DS); retval = file->f_op->read (file->f_inode, file, libs_buf, 1024); set_fs (USER_DS); if (retval < 0) goto error_close; if (retval < slib_size) { retval = -ELIBSCN; goto error_close; } for (p = libs_buf, j = 1; j <= shlibs; j++) { int len; char *name; struct slib *slibh = (struct slib *) p; p += slibh->sl_pathndx * 4; len = (slibh->sl_entsz - slibh->sl_pathndx) * 4; if (len <= 0 || p + len > (void *) libs_buf + slib_size) { retval = -ELIBSCN; goto error_close; } /* Target shared library path name. Must be followed by one or more zeroes. */ name = (char *) p; /* Try to access this library. */ set_fs (KERNEL_DS); fd[j] = sys_open (name, 0, 0); set_fs (USER_DS); if (fd[j] < 0) { retval = fd[j]; goto error_close; } retval = touch_svr3_binary (fd[j],buf,&bin_info[j],SHMAGIC); if (retval < 0) { /* Renumbering for shared library context. */ if (retval == -ENOEXEC) retval = -ELIBBAD; else if (retval == -EACCES) retval = -ELIBACC; goto error_close; } p += len; } } /* if (shlibs) .... */ /* Check initial limits. This avoids letting people circumvent * size limits imposed on them by creating programs with large * arrays in the data or bss. */ rlim = current->rlim[RLIMIT_DATA].rlim_cur; if (rlim >= RLIM_INFINITY) rlim = ~0; if (ah->dsize + ah->bsize > rlim) { /* XXX: but in shlibs too */ retval = -ENOMEM; goto error_close; } kfree (buf); /* OK, this is the point of noreturn. */ entry = ah->entry & ~0x1; /* Avoids possibly hult after `rte' ??? */ flush_old_exec (bprm); current->personality = PER_SVR3; current->mm->end_code = bin_info[0].text_len + (current->mm->start_code = bin_info[0].text_addr); current->mm->end_data = bin_info[0].data_len + (current->mm->start_data = bin_info[0].data_addr); current->mm->brk = bin_info[0].bss_len + (current->mm->start_brk = current->mm->end_data); current->mm->rss = 0; current->mm->mmap = NULL; current->suid = current->euid = current->fsuid = bprm->e_uid; current->sgid = current->egid = current->fsgid = bprm->e_gid; current->flags &= ~PF_FORKNOEXEC; /* mmap all binaries */ for (i = 0; i < 1 + shlibs; i++) { struct bin_info *binf = &bin_info[i]; unsigned int blocksize = binf->file->f_inode->i_sb->s_blocksize; unsigned int start_bss, end_bss; if (binf->text_addr & (PAGE_SIZE - 1) || binf->data_addr & (PAGE_SIZE - 1) || binf->text_offs & (blocksize - 1) || binf->data_offs & (blocksize - 1) || !binf->file->f_op->mmap ) { /* cannot mmap immediatly */ do_mmap (NULL, PAGE_ROUND(binf->text_addr), binf->text_len + (binf->text_addr - PAGE_ROUND(binf->text_addr)), PROT_READ | PROT_WRITE | PROT_EXEC, MAP_FIXED | MAP_PRIVATE, 0); read_exec (binf->file->f_inode, binf->text_offs, (char *) binf->text_addr, binf->text_len, 0); do_mmap (NULL, PAGE_ROUND(binf->data_addr), binf->data_len + (binf->data_addr - PAGE_ROUND(binf->data_addr)), PROT_READ | PROT_WRITE | PROT_EXEC, MAP_FIXED | MAP_PRIVATE, 0); read_exec (binf->file->f_inode, binf->data_offs, (char *) binf->data_addr, binf->data_len, 0); /* there's no nice way of flushing a number of user pages to ram 8*( */ flush_cache_all(); } else { error = do_mmap (binf->file, binf->text_addr, binf->text_len, PROT_READ | PROT_EXEC, MAP_FIXED | MAP_PRIVATE | MAP_DENYWRITE | MAP_EXECUTABLE, binf->text_offs); if (error != binf->text_addr) goto error_kill_close; error = do_mmap (binf->file, binf->data_addr, binf->data_len, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_FIXED | MAP_PRIVATE | MAP_DENYWRITE | MAP_EXECUTABLE, binf->data_offs); if (error != binf->data_addr) goto error_kill_close; #ifdef DMAGIC_NODEMAND /* DMAGIC is for pure executable (not demand loading). But let the shared libraries be demand load ??? */ if (i == 0 && ah->magic == DMAGIC) { volatile char c; unsigned long addr; /* Touch all pages in .text and .data segments. */ for (addr = binf->text_addr; addr < binf->text_addr + binf->text_len; addr += PAGE_SIZE ) c = get_fs_byte ((char *) addr); for (addr = binf->data_addr; addr < binf->data_addr + binf->data_len; addr += PAGE_SIZE ) c = get_fs_byte ((char *) addr); } #endif } sys_close (fd[i]); start_bss = PAGE_ALIGN(binf->data_addr + binf->data_len); end_bss = PAGE_ALIGN(binf->data_addr + binf->data_len + binf->bss_len); /* svr3 binaries very hope that .bss section had been initialized by zeroes. Oh... */ if (binf->bss_len != 0) { /* Because there may be skipped heap by alignment. */ int addr = binf->data_addr + binf->data_len; int i = start_bss - addr; /* start_bss is aligned, addr may be no */ while (i & 0x3) { put_fs_byte (0, (char *) addr); addr++; i--; } i >>= 2; while (i--) { put_fs_long (0, (long *) addr); addr += sizeof (long); } } if (end_bss >= start_bss) do_mmap (NULL, start_bss, end_bss - start_bss, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_FIXED | MAP_PRIVATE, 0); #ifdef DMAGIC_NODEMAND /* The same reason as above. */ if (i == 0 && ah->magic == DMAGIC) { volatile char c; unsigned long addr; for (addr = start_bss; addr < end_bss; addr += PAGE_SIZE) c = get_fs_byte ((char *) addr); } #endif /* OK, now all is mmapped for binary # i */ } /* for (i = ... ) */