inoptr newfile(inoptr pino, char *name) { inoptr nindex; uint8_t j; /* First see if parent is writeable */ if(!(getperm(pino) & OTH_WR)) goto nogood; if(!(nindex = i_open(pino->c_dev, 0))) goto nogood; /* BUG FIX: user/group setting was missing SN */ nindex->c_node.i_uid = udata.u_euid; nindex->c_node.i_gid = udata.u_egid; nindex->c_node.i_mode = F_REG; /* For the time being */ nindex->c_node.i_nlink = 1; nindex->c_node.i_size = 0; for(j=0; j <20; j++) nindex->c_node.i_addr[j] = 0; wr_inode(nindex); if(!ch_link(pino, "", name, nindex)) { i_deref(nindex); goto nogood; } i_deref(pino); return nindex; nogood: i_deref(pino); return NULLINODE; }
static arg_t chdiroot_op(inoptr ino, inoptr * p) { if (getmode(ino) != F_DIR) { udata.u_error = ENOTDIR; i_deref(ino); return (-1); } i_deref(*p); *p = ino; return 0; }
int16_t _stat(void) { inoptr ino; if (!(ino = n_open(path, NULLINOPTR))) return (-1); stcpy(ino, buf); i_deref(ino); return (0); }
void oft_deref(int8_t of) { struct oft *ofptr; ofptr = of_tab + of; if(!(--ofptr->o_refs) && ofptr->o_inode) { i_deref(ofptr->o_inode); ofptr->o_inode = NULLINODE; } }
arg_t _stat(void) { inoptr ino; int err; if (!(ino = n_open(path, NULLINOPTR))) return (-1); err = stcpy(ino, buf); i_deref(ino); return err; }
arg_t _mknod(void) { inoptr ino; inoptr parent; char fname[FILENAME_LEN + 1]; udata.u_error = 0; if (!super() && ((mode & F_MASK) != F_PIPE)) { udata.u_error = EPERM; goto nogood3; } if ((ino = n_open(name, &parent)) != NULL) { udata.u_error = EEXIST; goto nogood; } if (!parent) { udata.u_error = ENOENT; return (-1); } filename(name, fname); ino = newfile(parent, fname); if(!ino) goto nogood3; /* parent inode is derefed in newfile. SN */ /* Initialize mode and dev */ ino->c_node.i_mode = mode & ~udata.u_mask; ino->c_node.i_addr[0] = isdevice(ino) ? dev : 0; setftime(ino, A_TIME | M_TIME | C_TIME); wr_inode(ino); i_deref(ino); return (0); nogood: i_deref(ino); i_deref(parent); nogood3: return (-1); }
arg_t _chown(void) { inoptr ino; int ret; if (!(ino = n_open(path, NULLINOPTR))) return (-1); ret = chown_op(ino); i_deref(ino); return ret; }
static int chown_op(inoptr ino) { if (ino->c_node.i_uid != udata.u_euid && esuper()) { i_deref(ino); return (-1); } ino->c_node.i_uid = owner; ino->c_node.i_gid = group; setftime(ino, C_TIME); return 0; }
arg_t _unlink(void) { inoptr ino; inoptr pino; int r; char fname[FILENAME_LEN + 1]; ino = n_open(path, &pino); if (!(pino && ino)) { if (pino) /* parent exist */ i_deref(pino); udata.u_error = ENOENT; return (-1); } filename(path, fname); r = unlinki(ino, pino, fname); i_deref(pino); i_deref(ino); return r; }
static int16_t chmod_op(inoptr ino) { if (ino->c_node.i_uid != udata.u_euid && esuper()) { i_deref(ino); return (-1); } ino->c_node.i_mode = (mode & MODE_MASK) | (ino->c_node.i_mode & F_MASK); setftime(ino, C_TIME); return 0; }
uint8_t write_core_image(void) { inoptr parent = NULLINODE; inoptr ino; udata.u_error = 0; /* FIXME: need to think more about the case sp is lala */ if (uput("core", (uint8_t *)udata.u_syscall_sp - 5, 5)) return 0; ino = n_open((char *)udata.u_syscall_sp - 5, &parent); if (ino) { i_deref(parent); return 0; } if (parent) { i_lock(parent); if ((ino = newfile(parent, "core")) != NULL) { ino->c_node.i_mode = F_REG | 0400; setftime(ino, A_TIME | M_TIME | C_TIME); wr_inode(ino); f_trunc(ino); #if 0 /* FIXME address ranges for different models - move core writer for address spaces into helpers ? */ /* FIXME: need to add some arch specific header bits, and also pull stuff like the true sp and registers out of the return stack properly */ corehdr.ch_base = pagemap_base; corehdr.ch_break = udata.u_break; corehdr.ch_sp = udata.u_syscall_sp; corehdr.ch_top = PROGTOP; udata.u_offset = 0; udata.u_base = (uint8_t *)&corehdr; udata.u_sysio = true; udata.u_count = sizeof(corehdr); writei(ino, 0); udata.u_sysio = false; udata.u_base = (uint8_t *)pagemap_base; udata.u_count = udata.u_break - pagemap_base; writei(ino, 0); udata.u_base = udata.u_sp; udata.u_count = PROGTOP - (uint32_t)udata.u_sp; writei(ino, 0); #endif i_unlock_deref(ino); return W_COREDUMP; } } return 0; }
arg_t _link(void) { inoptr ino; inoptr ino2; inoptr parent2; char fname[FILENAME_LEN + 1]; if (!(ino = n_open(name1, NULLINOPTR))) return (-1); if (getmode(ino) == F_DIR && esuper()) goto nogood; if (ino->c_node.i_nlink == 0xFFFF) { udata.u_error = EMLINK; goto nogood; } /* Make sure file2 doesn't exist, and get its parent */ if ((ino2 = n_open(name2, &parent2)) != NULL) { i_deref(ino2); i_deref(parent2); udata.u_error = EEXIST; goto nogood; } if (!parent2) goto nogood; if (ino->c_dev != parent2->c_dev) { i_deref(parent2); udata.u_error = EXDEV; goto nogood; } filename(name2, fname); if (!ch_link(parent2, "", fname, ino)) { i_deref(parent2); goto nogood; } /* Update the link count. */ ++ino->c_node.i_nlink; wr_inode(ino); setftime(ino, C_TIME); i_deref(parent2); i_deref(ino); return 0; nogood: i_deref(ino); return -1; }
int16_t _utime(void) { inoptr ino; time_t t[2]; if (!valaddr(buf, 2 * sizeof(time_t))) return (-1); if (!(ino = n_open(file, NULLINOPTR))) return (-1); if (ino->c_node.i_uid != udata.u_euid && esuper()) { i_deref(ino); return (-1); } uget(buf, t, 2 * sizeof(time_t)); /* FIXME: needs updating once we pack top bits elsewhere in the inode */ ino->c_node.i_atime = t[0]; ino->c_node.i_mtime = t[1]; setftime(ino, C_TIME); i_deref(ino); return (0); }
inoptr srch_mt(inoptr ino) { uint8_t j; struct mount *m = &fs_tab[0]; for(j=0; j < NMOUNTS; ++j){ if(m->m_dev != NO_DEVICE && m->m_fs->s_mntpt == ino) { i_deref(ino); return i_open(m->m_dev, ROOTINODE); } m++; }; return ino; }
uint8_t write_core_image(void) { inoptr parent = NULLINODE; inoptr ino; udata.u_error = 0; /* FIXME: need to think more about the case sp is lala */ if (uput("core", udata.u_syscall_sp - 5, 5)) return 0; ino = n_open(udata.u_syscall_sp - 5, &parent); if (ino) { i_deref(parent); return 0; } if (parent) { i_lock(parent); if (ino = newfile(parent, "core")) { ino->c_node.i_mode = F_REG | 0400; setftime(ino, A_TIME | M_TIME | C_TIME); wr_inode(ino); f_trunc(ino); /* FIXME: need to add some arch specific header bits, and also pull stuff like the true sp and registers out of the return stack properly */ corehdr.ch_base = MAPBASE; corehdr.ch_break = udata.u_break; corehdr.ch_sp = udata.u_syscall_sp; corehdr.ch_top = PROGTOP; udata.u_offset = 0; udata.u_base = (uint8_t *)&corehdr; udata.u_sysio = true; udata.u_count = sizeof(corehdr); writei(ino, 0); udata.u_sysio = false; udata.u_base = MAPBASE; udata.u_count = udata.u_break - MAPBASE; writei(ino, 0); udata.u_base = udata.u_sp; udata.u_count = PROGTOP - (uint16_t)udata.u_sp; writei(ino, 0); i_unlock_deref(ino); return W_COREDUMP; } } return 0; }
arg_t _utime(void) { inoptr ino; time_t t[2]; if (!(ino = n_open(file, NULLINOPTR))) return (-1); if (ino->c_flags & CRDONLY) { udata.u_error = EROFS; goto out2; } /* Special case in the Unix API - NULL means now */ if (buf) { if (ino->c_node.i_uid != udata.u_euid && esuper()) goto out; if (!valaddr(buf, 2 * sizeof(time_t))) goto out2; uget(buf, t, 2 * sizeof(time_t)); } else { if (!(getperm(ino) & OTH_WR)) goto out; rdtime(&t[0]); memcpy(&t[1], &t[0], sizeof(t[1])); } /* FIXME: needs updating once we pack top bits elsewhere in the inode */ ino->c_node.i_atime = t[0].low; ino->c_node.i_mtime = t[1].low; setftime(ino, C_TIME); i_deref(ino); return (0); out: udata.u_error = EPERM; out2: i_deref(ino); return -1; }
arg_t _access(void) { inoptr ino; uint16_t euid; uint16_t egid; int16_t retval; if ((mode & 07) && !ugetc(path)) { udata.u_error = ENOENT; return (-1); } /* Temporarily make eff. id real id. */ euid = udata.u_euid; egid = udata.u_egid; udata.u_euid = udata.u_ptab->p_uid; udata.u_egid = udata.u_gid; if (!(ino = n_open(path, NULLINOPTR))) { retval = -1; goto nogood; } retval = 0; if (~getperm(ino) & (mode & 07)) { udata.u_error = EACCES; retval = -1; } i_deref(ino); nogood: udata.u_euid = euid; udata.u_egid = egid; return (retval); }
void doexit(int16_t val, int16_t val2) { int16_t j; ptptr p; irqflags_t irq; #ifdef DEBUG kprintf("process %d exiting\n", udata.u_ptab->p_pid); kprintf ("udata.u_page %u, udata.u_ptab %x, udata.u_ptab->p_page %u\n", udata.u_page, udata.u_ptab, udata.u_ptab->p_page); #endif if (udata.u_ptab->p_pid == 1) panic("killed init"); _sync(); /* Not necessary, but a good idea. */ irq = di(); /* Discard our memory before we blow away and reuse the memory */ pagemap_free(udata.u_ptab); for (j = 0; j < UFTSIZE; ++j) { if (udata.u_files[j] != NO_FILE) doclose(j); } udata.u_ptab->p_exitval = (val << 8) | (val2 & 0xff); i_deref(udata.u_cwd); i_deref(udata.u_root); /* Stash away child's execution tick counts in process table, * overlaying some no longer necessary stuff. * * Pedantically POSIX says we should do this at the point of wait() */ udata.u_utime += udata.u_cutime; udata.u_stime += udata.u_cstime; memcpy(&(udata.u_ptab->p_priority), &udata.u_utime, 2 * sizeof(clock_t)); for (p = ptab; p < ptab_end; ++p) { if (p->p_status == P_EMPTY || p == udata.u_ptab) continue; /* Set any child's parents to our parent */ if (p->p_pptr == udata.u_ptab) p->p_pptr = udata.u_ptab->p_pptr; /* Send SIGHUP to any pgrp members and remove them from our pgrp */ if (p->p_pgrp == udata.u_ptab->p_pid) { p->p_pgrp = 0; ssig(p, SIGHUP); } } tty_exit(); irqrestore(irq); #ifdef DEBUG kprintf ("udata.u_page %u, udata.u_ptab %x, udata.u_ptab->p_page %u\n", udata.u_page, udata.u_ptab, udata.u_ptab->p_page); #endif #ifdef CONFIG_ACCT acctexit(p); #endif udata.u_page = 0xFFFFU; udata.u_page2 = 0xFFFFU; /* FIXME: send SIGCLD here */ /* FIXME: POSIX.1 says that SIG_IGN for SIGCLD means don't go zombie, just clean up as we go */ /* Wake up a waiting parent, if any. */ wakeup((char *) udata.u_ptab->p_pptr); udata.u_ptab->p_status = P_ZOMBIE; nready--; nproc--; switchin(getproc()); panic("doexit: won't exit"); }
void doexit(uint16_t val) { int16_t j; ptptr p; irqflags_t irq; #ifdef DEBUG kprintf("process %d exiting\n", udata.u_ptab->p_pid); kprintf ("udata.u_page %u, udata.u_ptab %x, udata.u_ptab->p_page %u\n", udata.u_page, udata.u_ptab, udata.u_ptab->p_page); #endif if (udata.u_ptab->p_pid == 1) panic(PANIC_KILLED_INIT); sync(); /* Not necessary, but a good idea. */ irq = di(); /* Discard our memory before we blow away and reuse the memory */ pagemap_free(udata.u_ptab); for (j = 0; j < UFTSIZE; ++j) { if (udata.u_files[j] != NO_FILE) doclose(j); } udata.u_ptab->p_exitval = val; i_deref(udata.u_cwd); i_deref(udata.u_root); /* Stash away child's execution tick counts in process table, * overlaying some no longer necessary stuff. * * Pedantically POSIX says we should do this at the point of wait() */ udata.u_utime += udata.u_cutime; udata.u_stime += udata.u_cstime; memcpy(&(udata.u_ptab->p_priority), &udata.u_utime, 2 * sizeof(clock_t)); for (p = ptab; p < ptab_end; ++p) { if (p->p_status == P_EMPTY || p == udata.u_ptab) continue; /* Set any child's parents to our parent */ /* FIXME: do we need to wakeup the parent if we do this ? */ if (p->p_pptr == udata.u_ptab) p->p_pptr = udata.u_ptab->p_pptr; /* Send SIGHUP to any pgrp members and remove them from our pgrp */ if (p->p_pgrp == udata.u_ptab->p_pid) { p->p_pgrp = 0; ssig(p, SIGHUP); ssig(p, SIGCONT); } } tty_exit(); irqrestore(irq); #ifdef DEBUG kprintf ("udata.u_page %u, udata.u_ptab %x, udata.u_ptab->p_page %u\n", udata.u_page, udata.u_ptab, udata.u_ptab->p_page); #endif #ifdef CONFIG_ACCT acctexit(p); #endif udata.u_page = 0xFFFFU; udata.u_page2 = 0xFFFFU; signal_parent(udata.u_ptab->p_pptr); nready--; nproc--; switchin(getproc()); panic(PANIC_DOEXIT); }
inoptr kn_open(char *namep, inoptr *parent) { staticfast inoptr wd; /* the directory we are currently searching. */ staticfast inoptr ninode; inoptr temp; staticfast char *name; name = namep; #ifdef DEBUG kprintf("kn_open(\"%s\")\n", name); #endif if(*name == '/') wd = udata.u_root; else wd = udata.u_cwd; i_ref(ninode = wd); i_ref(ninode); for(;;) { if(ninode) magic(ninode); /* cheap way to spot rename inside yourself */ if (udata.u_rename == ninode) udata.u_rename = NULLINODE; /* See if we are at a mount point */ if(ninode) ninode = srch_mt(ninode); while(*name == '/') /* Skip(possibly repeated) slashes */ ++name; if(!*name) /* No more components of path? */ break; if(!ninode){ udata.u_error = ENOENT; goto nodir; } i_deref(wd); wd = ninode; if(getmode(wd) != F_DIR){ udata.u_error = ENOTDIR; goto nodir; } if(!(getperm(wd) & OTH_EX)){ udata.u_error = EPERM; goto nodir; } /* See if we are going up through a mount point */ if((wd == udata.u_root || (wd->c_num == ROOTINODE && wd->c_dev != root_dev)) && name[0] == '.' && name[1] == '.' && (name[2] == '/' || name[2] == '\0')){ if (wd == udata.u_root) { ninode = wd; name += 2; continue; } temp = fs_tab_get(wd->c_dev)->m_fs->s_mntpt; ++temp->c_refs; i_deref(wd); wd = temp; } ninode = srch_dir(wd, name); while(*name != '/' && *name) ++name; } if(parent) *parent = wd; else i_deref(wd); if(!(parent || ninode)) udata.u_error = ENOENT; return ninode; nodir: if(parent) *parent = NULLINODE; i_deref(wd); return NULLINODE; }
void doexit(uint16_t val) { int16_t j; ptptr p; irqflags_t irq; #ifdef DEBUG kprintf("process %d exiting %d\n", udata.u_ptab->p_pid, val); kprintf ("udata.u_page %u, udata.u_ptab %p, udata.u_ptab->p_page %u\n", udata.u_page, udata.u_ptab, udata.u_ptab->p_page); #endif if (udata.u_ptab->p_pid == 1) panic(PANIC_KILLED_INIT); sync(); /* Not necessary, but a good idea. */ irq = di(); /* We are exiting, hold all signals (they will never be delivered). If we don't do this we might take a signal while exiting which would be ... unfortunate */ udata.u_ptab->p_held = 0xFFFFFFFFUL; udata.u_cursig = 0; /* Discard our memory before we blow away and reuse the memory */ pagemap_free(udata.u_ptab); for (j = 0; j < UFTSIZE; ++j) { if (udata.u_files[j] != NO_FILE) doclose(j); } udata.u_ptab->p_exitval = val; i_deref(udata.u_cwd); i_deref(udata.u_root); /* Stash away child's execution tick counts in process table, * overlaying some no longer necessary stuff. * * Pedantically POSIX says we should do this at the point of wait() */ udata.u_utime += udata.u_cutime; udata.u_stime += udata.u_cstime; memcpy(&(udata.u_ptab->p_priority), &udata.u_utime, 2 * sizeof(clock_t)); for (p = ptab; p < ptab_end; ++p) { if (p->p_status == P_EMPTY || p == udata.u_ptab) continue; /* Set any child's parents to init */ if (p->p_pptr == udata.u_ptab) { p->p_pptr = ptab; /* ptab is always init */ /* Suppose our child is a zombie and init has SIGCLD blocked */ if (ptab[0].p_ignored & (1UL << SIGCHLD)) { p->p_status = P_EMPTY; } else { ssig(&ptab[0], SIGCHLD); wakeup(&ptab[0]); } } /* Send SIGHUP to any pgrp members and remove them from our pgrp */ if (p->p_pgrp == udata.u_ptab->p_pid) { p->p_pgrp = 0; ssig(p, SIGHUP); ssig(p, SIGCONT); } } tty_exit(); irqrestore(irq); #ifdef DEBUG kprintf ("udata.u_page %u, udata.u_ptab %p, udata.u_ptab->p_page %u\n", udata.u_page, udata.u_ptab, udata.u_ptab->p_page); #endif #ifdef CONFIG_ACCT acctexit(p); #endif udata.u_page = 0xFFFFU; udata.u_page2 = 0xFFFFU; signal_parent(udata.u_ptab->p_pptr); nready--; nproc--; switchin(getproc()); panic(PANIC_DOEXIT); }
arg_t _open(void) { int8_t uindex; int8_t oftindex; staticfast inoptr ino; int16_t perm; staticfast inoptr parent; char fname[FILENAME_LEN + 1]; int trunc; int r; int w; int j; parent = NULLINODE; trunc = flag & O_TRUNC; r = (flag + 1) & 1; w = (flag + 1) & 2; if (O_ACCMODE(flag) == 3 || (flag & O_BADBITS)) { udata.u_error = EINVAL; return (-1); } if ((uindex = uf_alloc()) == -1) return (-1); if ((oftindex = oft_alloc()) == -1) goto nooft; ino = n_open(name, &parent); if (ino) { i_deref(parent); /* O_EXCL test */ if ((flag & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL)) { udata.u_error = EEXIST; goto idrop; } } else { /* The n_open failed */ if (udata.u_error == EFAULT) goto cantopen; /* New file */ if (!(flag & O_CREAT)) { udata.u_error = ENOENT; goto cantopen; } filename(name, fname); /* newfile drops parent for us */ if (parent && (ino = newfile(parent, fname))) { ino->c_node.i_mode = (F_REG | (mode & MODE_MASK & ~udata.u_mask)); setftime(ino, A_TIME | M_TIME | C_TIME); wr_inode(ino); } else { udata.u_error = ENFILE; /* FIXME, should be set in newfile not bodged to a guessed code */ goto cantopen; } } /* Book our slot in case we block opening a device */ of_tab[oftindex].o_inode = ino; perm = getperm(ino); if ((r && !(perm & OTH_RD)) || (w && !(perm & OTH_WR))) { udata.u_error = EACCES; goto cantopen; } if (w) { if (getmode(ino) == F_DIR ) { udata.u_error = EISDIR; goto cantopen; } if (ino->c_flags & CRDONLY) { udata.u_error = EROFS; goto cantopen; } } if (isdevice(ino)) { inoptr *iptr = &of_tab[oftindex].o_inode; /* d_open may block and thus ino may become invalid as may parent (but we don't need it again). It may also be changed by the call to dev_openi */ if (dev_openi(iptr, flag) != 0) goto cantopen; /* May have changed */ /* get the static pointer back in case it changed via dev usage or just because we blocked */ ino = *iptr; } if (trunc && getmode(ino) == F_REG) { if (f_trunc(ino)) goto idrop; for (j = 0; j < OFTSIZE; ++j) /* Arguably should fix at read/write */ if (of_tab[j].o_inode == ino) of_tab[j].o_ptr = 0; } udata.u_files[uindex] = oftindex; of_tab[oftindex].o_ptr = 0; of_tab[oftindex].o_access = flag; /* Save the low bits only */ if (flag & O_CLOEXEC) udata.u_cloexec |= (1 << oftindex); /* FIXME: ATIME ? */ /* * Sleep process if no writer or reader */ if (getmode(ino) == F_PIPE && of_tab[oftindex].o_refs == 1 && !(flag & O_NDELAY)) psleep(ino); /* From the moment of the psleep ino is invalid */ return (uindex); idrop: i_deref(ino); cantopen: oft_deref(oftindex); /* This will call i_deref() */ nooft: udata.u_files[uindex] = NO_FILE; return (-1); }
arg_t _execve(void) { /* We aren't re-entrant where this matters */ uint8_t hdr[16]; staticfast inoptr ino; char **nargv; /* In user space */ char **nenvp; /* In user space */ struct s_argblk *abuf, *ebuf; int argc; uint16_t progptr; uint16_t progload; staticfast uint16_t top; uint16_t bin_size; /* Will need to be bigger on some cpus */ uint16_t bss; top = ramtop; if (!(ino = n_open_lock(name, NULLINOPTR))) return (-1); if (!((getperm(ino) & OTH_EX) && (ino->c_node.i_mode & F_REG) && (ino->c_node.i_mode & (OWN_EX | OTH_EX | GRP_EX)))) { udata.u_error = EACCES; goto nogood; } setftime(ino, A_TIME); udata.u_offset = 0; udata.u_count = 16; udata.u_base = hdr; udata.u_sysio = true; readi(ino, 0); if (udata.u_done != 16) { udata.u_error = ENOEXEC; goto nogood; } if (!header_ok(hdr)) { udata.u_error = ENOEXEC; goto nogood2; } progload = hdr[7] << 8; if (progload == 0) progload = PROGLOAD; top = *(uint16_t *)(hdr + 8); if (top == 0) /* Legacy 'all space' binary */ top = ramtop; else /* Requested an amount, so adjust for the base */ top += progload; bss = *(uint16_t *)(hdr + 14); /* Binary doesn't fit */ /* FIXME: review overflows */ bin_size = ino->c_node.i_size; progptr = bin_size + 1024 + bss; if (progload < PROGLOAD || top - progload < progptr || progptr < bin_size) { udata.u_error = ENOMEM; goto nogood2; } udata.u_ptab->p_status = P_NOSLEEP; /* If we made pagemap_realloc keep hold of some defined area we could in theory just move the arguments up or down as part of the process - that would save us all this hassle but replace it with new hassle */ /* Gather the arguments, and put them in temporary buffers. */ abuf = (struct s_argblk *) tmpbuf(); /* Put environment in another buffer. */ ebuf = (struct s_argblk *) tmpbuf(); /* Read args and environment from process memory */ if (rargs(argv, abuf) || rargs(envp, ebuf)) goto nogood3; /* SN */ /* This must be the last test as it makes changes if it works */ /* FIXME: once we sort out chmem we can make stack and data two elements. We never allocate 'code' as there is no split I/D */ /* This is only safe from deadlocks providing pagemap_realloc doesn't sleep */ if (pagemap_realloc(0, top - MAPBASE, 0)) goto nogood3; /* From this point on we are commmited to the exec() completing */ /* Core dump and ptrace permission logic */ #ifdef CONFIG_LEVEL_2 /* Q: should uid == 0 mean we always allow core */ if ((!(getperm(ino) & OTH_RD)) || (ino->c_node.i_mode & (SET_UID | SET_GID))) udata.u_flags |= U_FLAG_NOCORE; else udata.u_flags &= ~U_FLAG_NOCORE; #endif udata.u_top = top; udata.u_ptab->p_top = top; /* setuid, setgid if executable requires it */ if (ino->c_node.i_mode & SET_UID) udata.u_euid = ino->c_node.i_uid; if (ino->c_node.i_mode & SET_GID) udata.u_egid = ino->c_node.i_gid; /* FIXME: In the execve case we may on some platforms have space below PROGLOAD to clear... */ /* We are definitely going to succeed with the exec, * so we can start writing over the old program */ uput(hdr, (uint8_t *)progload, 16); /* At this point, we are committed to reading in and * executing the program. This call must not block. */ close_on_exec(); /* * Read in the rest of the program, block by block. We rely upon * the optimization path in readi to spot this is a big move to user * space and move it directly. */ progptr = progload + 16; if (bin_size > 16) { bin_size -= 16; udata.u_base = (uint8_t *)progptr; /* We copied the first block already */ udata.u_count = bin_size; udata.u_sysio = false; readi(ino, 0); if (udata.u_done != bin_size) goto nogood4; progptr += bin_size; } /* Wipe the memory in the BSS. We don't wipe the memory above that on 8bit boxes, but defer it to brk/sbrk() */ uzero((uint8_t *)progptr, bss); /* Set initial break for program */ udata.u_break = (int)ALIGNUP(progptr + bss); /* Turn off caught signals */ memset(udata.u_sigvec, 0, sizeof(udata.u_sigvec)); // place the arguments, environment and stack at the top of userspace memory, // Write back the arguments and the environment nargv = wargs(((char *) top - 2), abuf, &argc); nenvp = wargs((char *) (nargv), ebuf, NULL); // Fill in udata.u_name with program invocation name uget((void *) ugetw(nargv), udata.u_name, 8); memcpy(udata.u_ptab->p_name, udata.u_name, 8); tmpfree(abuf); tmpfree(ebuf); i_deref(ino); /* Shove argc and the address of argv just below envp FIXME: should flip them in crt0.S of app for R2L setups so we can get rid of the ifdefs */ #ifdef CONFIG_CALL_R2L /* Arguments are stacked the 'wrong' way around */ uputw((uint16_t) nargv, nenvp - 2); uputw((uint16_t) argc, nenvp - 1); #else uputw((uint16_t) nargv, nenvp - 1); uputw((uint16_t) argc, nenvp - 2); #endif /* Set stack pointer for the program */ udata.u_isp = nenvp - 2; /* Start execution (never returns) */ udata.u_ptab->p_status = P_RUNNING; doexec(progload); /* tidy up in various failure modes */ nogood4: /* Must not run userspace */ ssig(udata.u_ptab, SIGKILL); nogood3: udata.u_ptab->p_status = P_RUNNING; tmpfree(abuf); tmpfree(ebuf); nogood2: nogood: i_unlock_deref(ino); return (-1); }
arg_t _execve(void) { /* Not ideal on stack */ struct binfmt_flat binflat; inoptr ino; char **nargv; /* In user space */ char **nenvp; /* In user space */ struct s_argblk *abuf, *ebuf; int argc; uint32_t bin_size; /* Will need to be bigger on some cpus */ uaddr_t progbase, top; uaddr_t go; uint32_t true_brk; if (!(ino = n_open(name, NULLINOPTR))) return (-1); if (!((getperm(ino) & OTH_EX) && (ino->c_node.i_mode & F_REG) && (ino->c_node.i_mode & (OWN_EX | OTH_EX | GRP_EX)))) { udata.u_error = EACCES; goto nogood; } setftime(ino, A_TIME); udata.u_offset = 0; udata.u_count = sizeof(struct binfmt_flat); udata.u_base = (void *)&binflat; udata.u_sysio = true; readi(ino, 0); if (udata.u_count != sizeof(struct binfmt_flat)) { udata.u_error = ENOEXEC; goto nogood; } /* FIXME: ugly - save this as valid_hdr modifies it */ true_brk = binflat.bss_end; /* Hard coded for our 68K format. We don't quite use the ucLinux names, we don't want to load a ucLinux binary in error! */ if (memcmp(binflat.magic, "bFLT", 4) || !valid_hdr(ino, &binflat)) { udata.u_error = ENOEXEC; goto nogood2; } /* Memory needed */ bin_size = binflat.bss_end + binflat.stack_size; /* Overflow ? */ if (bin_size < binflat.bss_end) { udata.u_error = ENOEXEC; goto nogood2; } /* Gather the arguments, and put them in temporary buffers. */ abuf = (struct s_argblk *) tmpbuf(); /* Put environment in another buffer. */ ebuf = (struct s_argblk *) tmpbuf(); /* Read args and environment from process memory */ if (rargs(argv, abuf) || rargs(envp, ebuf)) goto nogood3; /* This must be the last test as it makes changes if it works */ /* FIXME: need to update this to support split code/data and to fix stack handling nicely */ if (pagemap_realloc(0, bin_size, 0)) goto nogood3; /* Core dump and ptrace permission logic */ #ifdef CONFIG_LEVEL_2 /* Q: should uid == 0 mean we always allow core */ if ((!(getperm(ino) & OTH_RD)) || (ino->c_node.i_mode & (SET_UID | SET_GID))) udata.u_flags |= U_FLAG_NOCORE; else udata.u_flags &= ~U_FLAG_NOCORE; #endif udata.u_codebase = progbase = pagemap_base(); /* From this point on we are commmited to the exec() completing so we can start writing over the old program */ uput(&binflat, (uint8_t *)progbase, sizeof(struct binfmt_flat)); /* setuid, setgid if executable requires it */ if (ino->c_node.i_mode & SET_UID) udata.u_euid = ino->c_node.i_uid; if (ino->c_node.i_mode & SET_GID) udata.u_egid = ino->c_node.i_gid; top = progbase + bin_size; // kprintf("user space at %p\n", progbase); // kprintf("top at %p\n", progbase + bin_size); bin_size = binflat.reloc_start + 4 * binflat.reloc_count; go = (uint32_t)progbase + binflat.entry; close_on_exec(); /* * Read in the rest of the program, block by block. We rely upon * the optimization path in readi to spot this is a big move to user * space and move it directly. */ if (bin_size > sizeof(struct binfmt_flat)) { /* We copied the header already */ bin_size -= sizeof(struct binfmt_flat); udata.u_base = (uint8_t *)progbase + sizeof(struct binfmt_flat); udata.u_count = bin_size; udata.u_sysio = false; readi(ino, 0); if (udata.u_count != bin_size) goto nogood4; } /* Header isn't counted in relocations */ relocate(&binflat, progbase, bin_size); /* This may wipe the relocations */ uzero((uint8_t *)progbase + binflat.data_end, binflat.bss_end - binflat.data_end + binflat.stack_size); /* Use of brk eats into the stack allocation */ /* Use the temporary we saved (hack) as we mangled bss_end */ udata.u_break = udata.u_codebase + true_brk; /* Turn off caught signals */ memset(udata.u_sigvec, 0, sizeof(udata.u_sigvec)); /* place the arguments, environment and stack at the top of userspace memory. */ /* Write back the arguments and the environment */ nargv = wargs(((char *) top - 4), abuf, &argc); nenvp = wargs((char *) (nargv), ebuf, NULL); /* Fill in udata.u_name with Program invocation name */ uget((void *) ugetl(nargv, NULL), udata.u_name, 8); memcpy(udata.u_ptab->p_name, udata.u_name, 8); tmpfree(abuf); tmpfree(ebuf); i_deref(ino); /* Shove argc and the address of argv just below envp */ uputl((uint32_t) nargv, nenvp - 1); uputl((uint32_t) argc, nenvp - 2); // Set stack pointer for the program udata.u_isp = nenvp - 2; /* * Sort of - it's a good way to deal with all the stupidity of * random 68K platforms we will have to handle, and a nice place * to stuff the signal trampoline 8) */ install_vdso(); // kprintf("Go = %p ISP = %p\n", go, udata.u_isp); doexec(go); nogood4: /* Must not run userspace */ ssig(udata.u_ptab, SIGKILL); nogood3: tmpfree(abuf); tmpfree(ebuf); nogood2: nogood: i_deref(ino); return (-1); }