arg_t _sendto(void) { struct socket *s = sock_get(fd, NULL); struct sockaddr_in sin; uint16_t flags; uint16_t alen; uint16_t err; if (s == NULL) return -1; if (s->s_state == SS_UNCONNECTED) { err = sock_autobind(s); if (err) return err; } if (s->s_state < SS_BOUND) { udata.u_error = EINVAL; return -1; } if (s->s_state != SS_BOUND && s->s_state < SS_CONNECTED) { udata.u_error = ENOTCONN; return -1; } flags = ugetw(&uaddr->sio_flags); if (flags) { udata.u_error = EINVAL; return -1; } alen = ugetw(&uaddr->sio_flags); /* Save the address and then just do a 'write' */ if (s->s_type != SOCKTYPE_TCP && alen) { if (s->s_state >= SS_CONNECTING) { udata.u_error = EISCONN; return -1; } /* Use the address in atmp */ s->s_flag |= SFLAG_ATMP; if (sa_getremote(&uaddr->sio_addr, &sin) == -1) return -1; s->s_addr[SADDR_TMP].addr = sin.sin_addr.s_addr; s->s_addr[SADDR_TMP].port = sin.sin_port; } else { s->s_flag &= ~SFLAG_ATMP; if (s->s_state < SS_CONNECTED) { udata.u_error = EDESTADDRREQ; return -1; } } return _write(); }
int gfx_draw_op(uarg_t arg, char *ptr) { int err=0; int l; int c = 8; /* 4 x uint16_t */ uint16_t *p = (uint16_t *)(char *)0x5e00; map_for_video(); l = ugetw(ptr); if (l < 6 || l > 512){ err = EINVAL; goto ret; } if (arg != GFXIOC_READ) c = l; if (uget(ptr + 2, (char *)0x5e00, c)){ err = EFAULT; goto ret; } switch(arg) { case GFXIOC_DRAW: /* TODO if (draw_validate(ptr, l, 256, 192)) - or 128! return EINVAL */ video_cmd( ( char *)0x5e00 ); break; case GFXIOC_WRITE: case GFXIOC_READ: if (l < 8){ err= EINVAL; break; } l -= 8; if (p[0] > 191 || p[1] > 31 || p[2] > 191 || p[3] > 31 || p[0] + p[2] > 192 || p[1] + p[3] > 32 || (p[2] * p[3]) > l) { err = -EFAULT; break; } if (arg == GFXIOC_READ) { video_read( (char *)0x5e00 ); if (uput( (char *)0x5e00 + 8, ptr+10, l-2)) err = EFAULT; break; } video_write( (char *)0x5e00 ); } ret: map_for_kernel(); return err; }
arg_t _recvfrom(void) { struct socket *s = sock_get(fd, NULL); int ret; uint16_t flags; /* FIXME: will need _read redone for banked syscalls */ if (s == NULL) return -1; flags = ugetw(&uaddr->sio_flags); if (flags) { udata.u_error = EINVAL; return -1; } ret = _read(); if (ret < 0) return ret; if (sa_put(s, SADDR_TMP, &uaddr->sio_addr)) return -1; return ret; }
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); }