static int __del_msg_handle (struct shim_msg_handle * msgq) { if (msgq->deleted) return -EIDRM; msgq->deleted = true; free(msgq->queue); msgq->queuesize = 0; msgq->queueused = 0; free(msgq->types); msgq->ntypes = 0; struct shim_handle * hdl = MSG_TO_HANDLE(msgq); lock(msgq_list_lock); list_del_init(&msgq->list); put_handle(hdl); if (!hlist_unhashed(&msgq->key_hlist)) { hlist_del_init(&msgq->key_hlist); put_handle(hdl); } if (!hlist_unhashed(&msgq->qid_hlist)) { hlist_del_init(&msgq->qid_hlist); put_handle(hdl); } unlock(msgq_list_lock); return 0; }
int shim_do_pipe2 (int * filedes, int flags) { if (!filedes) return -EINVAL; int ret = 0; struct shim_handle * hdl1 = get_new_handle(); struct shim_handle * hdl2 = get_new_handle(); if (!hdl1 || !hdl2) { ret = -ENOMEM; goto out; } hdl1->type = TYPE_PIPE; set_handle_fs(hdl1, &pipe_builtin_fs); hdl1->flags = O_RDONLY; hdl1->acc_mode = MAY_READ; hdl2->type = TYPE_PIPE; set_handle_fs(hdl2, &pipe_builtin_fs); hdl2->flags = O_WRONLY; hdl2->acc_mode = MAY_WRITE; if ((ret = create_pipes(&hdl1->info.pipe.pipeid, &hdl1->pal_handle, &hdl2->pal_handle, &hdl1->uri, flags)) < 0) goto out; qstrcopy(&hdl2->uri, &hdl2->uri); flags = flags & O_CLOEXEC ? FD_CLOEXEC : 0; int vfd1 = set_new_fd_handle(hdl1, flags, NULL); int vfd2 = set_new_fd_handle(hdl2, flags, NULL); if (vfd1 < 0 || vfd2 < 0) { if (vfd1 >= 0) { struct shim_handle * tmp = detach_fd_handle(vfd1, NULL, NULL); if (tmp) close_handle(tmp); } if (vfd2 >= 0) { struct shim_handle * tmp = detach_fd_handle(vfd2, NULL, NULL); if (tmp) close_handle(tmp); } goto out; } filedes[0] = vfd1; filedes[1] = vfd2; out: if (hdl1) put_handle(hdl1); if (hdl2) put_handle(hdl2); return ret; }
int shim_do_ftruncate (int fd, loff_t length) { struct shim_handle * hdl = get_fd_handle(fd, NULL, NULL); if (!hdl) return -EBADF; struct shim_mount * fs = hdl->fs; int ret = -EACCES; if (!fs || !fs->fs_ops) goto out; if (hdl->type == TYPE_DIR) goto out; if (!fs->fs_ops->truncate) { ret = -EROFS; goto out; } ret = fs->fs_ops->truncate(hdl, length); out: put_handle(hdl); return ret; }
/* lseek is simply doing arithmetic on the offset, no PAL call here */ off_t shim_do_lseek (int fd, off_t offset, int origin) { if (origin != SEEK_SET && origin != SEEK_CUR && origin != SEEK_END) return -EINVAL; struct shim_handle * hdl = get_fd_handle(fd, NULL, NULL); if (!hdl) return -EBADF; int ret = 0; struct shim_mount * fs = hdl->fs; assert(fs && fs->fs_ops); if (!fs->fs_ops->seek) { ret = -ESPIPE; goto out; } if (hdl->type == TYPE_DIR) { /* TODO: handle lseek'ing of directories */ ret = -ENOSYS; goto out; } ret = fs->fs_ops->seek(hdl, offset, origin); out: put_handle(hdl); return ret; }
int shim_do_fsync (int fd) { struct shim_handle * hdl = get_fd_handle(fd, NULL, NULL); if (!hdl) return -EBADF; int ret = -EACCES; struct shim_mount * fs = hdl->fs; if (!fs || !fs->fs_ops) goto out; if (hdl->type == TYPE_DIR) goto out; if (!fs->fs_ops->flush) { ret = -EROFS; goto out; } ret = fs->fs_ops->flush(hdl); out: put_handle(hdl); return ret; }
int shim_do_openat (int dfd, const char * filename, int flags, int mode) { if (!filename || test_user_string(filename)) return -EFAULT; if (*filename == '/') return shim_do_open(filename, flags, mode); struct shim_dentry * dir = NULL; int ret = 0; if ((ret = path_startat(dfd, &dir)) < 0) return ret; struct shim_handle * hdl = get_new_handle(); if (!hdl) { ret = -ENOMEM; goto out; } ret = open_namei(hdl, dir, filename, flags, mode, NULL); if (ret < 0) goto out_hdl; ret = set_new_fd_handle(hdl, flags & O_CLOEXEC ? FD_CLOEXEC : 0, NULL); out_hdl: put_handle(hdl); out: put_dentry(dir); return ret; }
size_t shim_do_read (int fd, void * buf, size_t count) { struct shim_handle * hdl = get_fd_handle(fd, NULL, NULL); if (!hdl) return -EBADF; int ret = do_handle_read(hdl, buf, count); put_handle(hdl); return ret; }
size_t shim_do_read (int fd, void * buf, size_t count) { if (!buf || test_user_memory(buf, count, true)) return -EFAULT; struct shim_handle * hdl = get_fd_handle(fd, NULL, NULL); if (!hdl) return -EBADF; int ret = do_handle_read(hdl, buf, count); put_handle(hdl); return ret; }
size_t shim_do_write (int fd, const void * buf, size_t count) { if (!buf || test_user_memory((void *) buf, count, false)) return -EFAULT; struct shim_handle * hdl = get_fd_handle(fd, NULL, NULL); if (!hdl) return -EBADF; int ret = do_handle_write(hdl, buf, count); put_handle(hdl); return ret; }
ssize_t shim_do_pwrite64 (int fd, char * buf, size_t count, loff_t pos) { if (!buf || test_user_memory(buf, count, false)) return -EFAULT; if (pos < 0) return -EINVAL; struct shim_handle * hdl = get_fd_handle(fd, NULL, NULL); if (!hdl) return -EBADF; struct shim_mount * fs = hdl->fs; ssize_t ret = -EACCES; if (!fs || !fs->fs_ops) goto out; if (!fs->fs_ops->seek) { ret = -ESPIPE; goto out; } if (!fs->fs_ops->write) goto out; if (hdl->type == TYPE_DIR) goto out; int offset = fs->fs_ops->seek(hdl, 0, SEEK_CUR); if (offset < 0) { ret = offset; goto out; } ret = fs->fs_ops->seek(hdl, pos, SEEK_SET); if (ret < 0) goto out; int bytes = fs->fs_ops->write(hdl, buf, count); ret = fs->fs_ops->seek(hdl, offset, SEEK_SET); if (ret < 0) goto out; ret = bytes; out: put_handle(hdl); return ret; }
PyObject * py_guestfs_create (PyObject *self, PyObject *args) { guestfs_h *g; g = guestfs_create (); if (g == NULL) { PyErr_SetString (PyExc_RuntimeError, "guestfs.create: failed to allocate handle"); return NULL; } guestfs_set_error_handler (g, NULL, NULL); /* This can return NULL, but in that case put_handle will have * set the Python error string. */ return put_handle (g); }
size_t shim_do_pread64 (int fd, char * buf, size_t count, loff_t pos) { struct shim_handle * hdl = get_fd_handle(fd, NULL, NULL); if (!hdl) return -EBADF; struct shim_mount * fs = hdl->fs; size_t ret = -EACCES; if (!fs || !fs->fs_ops) goto out; if (!fs->fs_ops->seek) { ret = -ESPIPE; goto out; } if (!fs->fs_ops->read) goto out; if (hdl->type == TYPE_DIR) goto out; int offset = fs->fs_ops->seek(hdl, 0, SEEK_CUR); if (offset < 0) { ret = offset; goto out; } ret = fs->fs_ops->seek(hdl, pos, SEEK_SET); if (ret < 0) goto out; int bytes = fs->fs_ops->read(hdl, buf, count); ret = fs->fs_ops->seek(hdl, offset, SEEK_SET); if (ret < 0) goto out; ret = bytes; out: put_handle(hdl); return ret; }
int shim_do_open (const char * file, int flags, mode_t mode) { if (!file || !(*file)) return -EINVAL; struct shim_handle * hdl = get_new_handle(); if (!hdl) return -ENOMEM; int ret = 0; ret = open_namei(hdl, NULL, file, flags, mode, NULL); if (ret < 0) goto out; ret = set_new_fd_handle(hdl, flags & O_CLOEXEC ? FD_CLOEXEC : 0, NULL); out: put_handle(hdl); return ret; }
int shim_do_truncate (const char * path, loff_t length) { struct shim_dentry * dent = NULL; int ret = 0; if (!path || test_user_string(path)) return -EFAULT; if ((ret = path_lookupat(NULL, path, 0, &dent, NULL)) < 0) return ret; struct shim_mount * fs = dent->fs; if (!fs || !fs->d_ops || !fs->d_ops->open) { ret = -EBADF; goto out; } if (!fs->fs_ops->truncate) { ret = -EROFS; goto out; } struct shim_handle * hdl = get_new_handle(); if (!hdl) { ret = -ENOMEM; goto out; } hdl->fs = fs; if ((ret = fs->d_ops->open(hdl, dent, O_WRONLY)) < 0) goto out_handle; ret = fs->fs_ops->truncate(hdl, length); flush_handle(hdl); out_handle: put_handle(hdl); out: return ret; }
static PyObject * py_hivex_open (PyObject *self, PyObject *args) { PyObject *py_r; hive_h *r; char *filename; int flags; if (!PyArg_ParseTuple (args, (char *) "si:hivex_open", &filename, &flags)) return NULL; r = hivex_open (filename, flags); if (r == NULL) { PyErr_SetString (PyExc_RuntimeError, strerror (errno)); return NULL; } py_r = put_handle (r); return py_r; }
int shim_do_fstat (int fd, struct stat * stat) { struct shim_handle * hdl = get_fd_handle(fd, NULL, NULL); if (!hdl) return -EBADF; int ret = -EACCES; struct shim_mount * fs = hdl->fs; if (!fs || !fs->fs_ops) goto out; if (!fs->fs_ops->hstat) goto out; ret = fs->fs_ops->hstat(hdl, stat); out: put_handle(hdl); return ret; }
void close_handle (struct shim_handle * hdl) { int opened = REF_DEC(hdl->opened); #ifdef DEBUG_REF debug("close handle %p(%s) (opened = %d)\n", hdl, __handle_name(hdl), opened); #endif if (!opened) { if (hdl->type == TYPE_DIR) { struct shim_dir_handle * dir = &hdl->info.dir; if (dir->dot) { put_dentry(dir->dot); dir->dot = NULL; } if (dir->dotdot) { put_dentry(dir->dotdot); dir->dotdot = NULL; } while (*dir->ptr) { struct shim_dentry * dent = *dir->ptr; put_dentry(dent); *(dir->ptr++) = NULL; } } else { if (hdl->fs && hdl->fs->fs_ops && hdl->fs->fs_ops->close) hdl->fs->fs_ops->close(hdl); } } put_handle(hdl); }
int shim_do_execve_rtld (struct shim_handle * hdl, const char ** argv, const char ** envp) { BEGIN_PROFILE_INTERVAL(); struct shim_thread * cur_thread = get_cur_thread(); int ret; if ((ret = close_cloexec_handle(cur_thread->handle_map)) < 0) return ret; SAVE_PROFILE_INTERVAL(close_CLOEXEC_files_for_exec); void * tcb = malloc(sizeof(__libc_tcb_t)); if (!tcb) return -ENOMEM; populate_tls(tcb, false); __disable_preempt(&((__libc_tcb_t *) tcb)->shim_tcb); // Temporarily disable preemption // during execve(). debug("set tcb to %p\n", tcb); put_handle(cur_thread->exec); get_handle(hdl); cur_thread->exec = hdl; old_stack_top = cur_thread->stack_top; old_stack = cur_thread->stack; old_stack_red = cur_thread->stack_red; cur_thread->stack_top = NULL; cur_thread->stack = NULL; cur_thread->stack_red = NULL; initial_envp = NULL; new_argc = 0; for (const char ** a = argv ; *a ; a++, new_argc++); new_argcp = &new_argc; if ((ret = init_stack(argv, envp, &new_argcp, &new_argp, REQUIRED_ELF_AUXV, &new_auxp)) < 0) return ret; SAVE_PROFILE_INTERVAL(alloc_new_stack_for_exec); SWITCH_STACK(new_argp); cur_thread = get_cur_thread(); UPDATE_PROFILE_INTERVAL(); DkVirtualMemoryFree(old_stack, old_stack_top - old_stack); DkVirtualMemoryFree(old_stack_red, old_stack - old_stack_red); if (bkeep_munmap(old_stack, old_stack_top - old_stack, 0) < 0 || bkeep_munmap(old_stack_red, old_stack - old_stack_red, 0) < 0) BUG(); remove_loaded_libraries(); clean_link_map_list(); SAVE_PROFILE_INTERVAL(unmap_loaded_binaries_for_exec); reset_brk(); size_t count = DEFAULT_VMA_COUNT; struct shim_vma_val * vmas = malloc(sizeof(struct shim_vma_val) * count); if (!vmas) return -ENOMEM; retry_dump_vmas: ret = dump_all_vmas(vmas, count); if (ret == -EOVERFLOW) { struct shim_vma_val * new_vmas = malloc(sizeof(struct shim_vma_val) * count * 2); if (!new_vmas) { free(vmas); return -ENOMEM; } free(vmas); vmas = new_vmas; count *= 2; goto retry_dump_vmas; } if (ret < 0) { free(vmas); return ret; } count = ret; for (struct shim_vma_val * vma = vmas ; vma < vmas + count ; vma++) { /* Don't free the current stack */ if (vma->addr == cur_thread->stack) continue; /* Free all the mapped VMAs */ if (!(vma->flags & VMA_UNMAPPED)) DkVirtualMemoryFree(vma->addr, vma->length); /* Remove the VMAs */ bkeep_munmap(vma->addr, vma->length, vma->flags); } free_vma_val_array(vmas, count); SAVE_PROFILE_INTERVAL(unmap_all_vmas_for_exec); if ((ret = load_elf_object(cur_thread->exec, NULL, 0)) < 0) shim_terminate(ret); init_brk_from_executable(cur_thread->exec); load_elf_interp(cur_thread->exec); SAVE_PROFILE_INTERVAL(load_new_executable_for_exec); cur_thread->robust_list = NULL; #ifdef PROFILE if (ENTER_TIME) SAVE_PROFILE_INTERVAL_SINCE(syscall_execve, ENTER_TIME); #endif debug("execve: start execution\n"); execute_elf_object(cur_thread->exec, new_argcp, new_argp, REQUIRED_ELF_AUXV, new_auxp); return 0; }
int shim_do_ioctl (int fd, int cmd, unsigned long arg) { struct shim_handle * hdl = get_fd_handle(fd, NULL, NULL); if (!hdl) return -EBADF; int ret = -EAGAIN; switch(cmd) { /* <include/asm/termios.h> */ case TCGETS: case TCSETS: case TCSETSW: case TCSETSF: case TCGETA: case TCSETA: case TCSETAW: case TCSETAF: case TCSBRK: case TCXONC: case TCFLSH: case TIOCEXCL: case TIOCNXCL: case TIOCSCTTY: case TIOCGPGRP: case TIOCSPGRP: case TIOCOUTQ: case TIOCSTI: case TIOCGWINSZ: case TIOCMGET: case TIOCMBIS: case TIOCMBIC: case TIOCMSET: case TIOCGSOFTCAR: case TIOCSSOFTCAR: /* case TIOCINQ = FIONREAD */ case TIOCLINUX: case TIOCCONS: case TIOCGSERIAL: case TIOCSSERIAL: case TIOCPKT: case TIOCNOTTY: case TIOCSETD: case TIOCGETD: case TCSBRKP: ret = ioctl_termios(hdl, cmd, arg); break; case FIONBIO: if (hdl->fs && hdl->fs->fs_ops && hdl->fs->fs_ops->setflags) hdl->fs->fs_ops->setflags(hdl, hdl->flags | O_NONBLOCK); hdl->flags |= O_NONBLOCK; ret = 0; break; case FIONCLEX: hdl->flags &= ~FD_CLOEXEC; ret = 0; break; case FIOCLEX: hdl->flags |= FD_CLOEXEC; ret = 0; break; case FIOASYNC: ret = install_async_event(hdl->pal_handle, 0, &signal_io, NULL); break; case TIOCSERCONFIG: case TIOCSERGWILD: case TIOCSERSWILD: case TIOCGLCKTRMIOS: case TIOCSLCKTRMIOS: case TIOCSERGSTRUCT: case TIOCSERGETLSR: case TIOCSERGETMULTI: case TIOCSERSETMULTI: ret = ioctl_termios(hdl, cmd, arg); break; case FDCLRPRM: case FDSETPRM: case FDDEFPRM: case FDGETPRM: case FDMSGON: case FDMSGOFF: case FDFMTBEG: case FDFMTTRK: case FDFMTEND: case FDSETEMSGTRESH: case FDFLUSH: case FDSETMAXERRS: case FDGETMAXERRS: case FDGETDRVTYP: case FDSETDRVPRM: case FDGETDRVPRM: case FDGETDRVSTAT: case FDPOLLDRVSTAT: case FDRESET: case FDGETFDCSTAT: case FDWERRORCLR: case FDWERRORGET: case FDRAWCMD: case FDTWADDLE: ret = ioctl_fd(hdl, cmd, arg); break; case FIONREAD: { struct shim_mount * fs = hdl->fs; int size = 0; int offset = 0; if (!fs || !fs->fs_ops) { ret = -EACCES; break; } if (fs->fs_ops->hstat) { struct stat stat; ret = fs->fs_ops->hstat(hdl, &stat); if (ret < 0) break; size = stat.st_size; goto done_fioread; } if (hdl->pal_handle) { PAL_STREAM_ATTR attr; if (!DkStreamAttributesQueryByHandle(hdl->pal_handle, &attr)) { ret = -PAL_ERRNO; break; } size = attr.pending_size; goto done_fioread; } done_fioread: if (fs->fs_ops->seek) { ret = fs->fs_ops->seek(hdl, 0, SEEK_CUR); if (ret < 0) break; offset = ret; } *(int *) arg = size - offset; ret = 0; break; } /* Socket configuration controls. */ case SIOCGIFNAME: /* 0x8910 get iface name */ case SIOCSIFLINK: /* 0x8911 set iface channel */ case SIOCGIFCONF: /* 0x8912 get iface list */ case SIOCGIFFLAGS: /* 0x8913 get flags */ case SIOCSIFFLAGS: /* 0x8914 set flags */ case SIOCGIFADDR: /* 0x8915 get PA address */ case SIOCSIFADDR: /* 0x8916 set PA address */ case SIOCGIFDSTADDR: /* 0x8917 get remote PA address */ case SIOCSIFDSTADDR: /* 0x8918 set remote PA address */ case SIOCGIFBRDADDR: /* 0x8919 get broadcast PA address */ case SIOCSIFBRDADDR: /* 0x891a set broadcast PA address */ case SIOCGIFNETMASK: /* 0x891b get network PA mask */ case SIOCSIFNETMASK: /* 0x891c set network PA mask */ case SIOCGIFMETRIC: /* 0x891d get metric */ case SIOCSIFMETRIC: /* 0x891e set metric */ case SIOCGIFMEM: /* 0x891f get memory address (BSD) */ case SIOCSIFMEM: /* 0x8920 set memory address (BSD) */ case SIOCGIFMTU: /* 0x8921 get MTU size */ case SIOCSIFMTU: /* 0x8922 set MTU size */ case SIOCSIFNAME: /* 0x8923 set interface name */ case SIOCSIFHWADDR: /* 0x8924 set hardware address */ case SIOCGIFENCAP: /* 0x8925 get/set encapsulations */ case SIOCSIFENCAP: /* 0x8926 */ case SIOCGIFHWADDR: /* 0x8927 Get hardware address */ case SIOCGIFSLAVE: /* 0x8929 Driver slaving support */ case SIOCSIFSLAVE: /* 0x8930 */ case SIOCADDMULTI: /* 0x8931 Multicast address lists */ case SIOCDELMULTI: /* 0x8932 */ case SIOCGIFINDEX: /* 0x8933 name -> if_index mapping */ /* SIOGIFINDEX = SIOCGIFINDEX misprint compatibility :-) */ case SIOCSIFPFLAGS: /* 0x8934 set/get extended flags set */ case SIOCGIFPFLAGS: /* 0x8935 */ case SIOCDIFADDR: /* 0x8936 delete PA address */ case SIOCSIFHWBROADCAST: /* 0x8937 set hardware broadcast addr */ case SIOCGIFCOUNT: /* 0x8938 get number of devices */ case SIOCGIFBR: /* 0x8940 Bridging support */ case SIOCSIFBR: /* 0x8941 Set bridging options */ case SIOCGIFTXQLEN: /* 0x8942 Get the tx queue length */ case SIOCSIFTXQLEN: /* 0x8943 Set the tx queue length */ ret = ioctl_netdevice(hdl, cmd, arg); break; default: ret = -ENOSYS; break; } put_handle(hdl); return ret; }
/*===========================================================================* * do_getdents * *===========================================================================*/ ssize_t do_getdents(ino_t ino_nr, struct fsdriver_data *data, size_t bytes, off_t *posp) { /* Retrieve directory entries. */ struct fsdriver_dentry fsdentry; char name[NAME_MAX+1]; struct inode *ino, *child; struct sffs_attr attr; off_t pos; int r; /* must be at least sizeof(struct dirent) + NAME_MAX */ static char buf[BLOCK_SIZE]; if ((ino = find_inode(ino_nr)) == NULL) return EINVAL; if (!IS_DIR(ino)) return ENOTDIR; if (*posp < 0 || *posp >= ULONG_MAX) return EINVAL; /* We are going to need at least one free inode to store children in. */ if (!have_free_inode()) return ENFILE; /* If we don't have a directory handle yet, get one now. */ if ((r = get_handle(ino)) != OK) return r; fsdriver_dentry_init(&fsdentry, data, bytes, buf, sizeof(buf)); /* We use the seek position as file index number. The first position is for * the "." entry, the second position is for the ".." entry, and the next * position numbers each represent a file in the directory. */ do { /* Determine which inode and name to use for this entry. * We have no idea whether the host will give us "." and/or "..", * so generate our own and skip those from the host. */ pos = (*posp)++; if (pos == 0) { /* Entry for ".". */ child = ino; strcpy(name, "."); get_inode(child); } else if (pos == 1) { /* Entry for "..", but only when there is a parent. */ if (ino->i_parent == NULL) continue; child = ino->i_parent; strcpy(name, ".."); get_inode(child); } else { /* Any other entry, not being "." or "..". */ attr.a_mask = SFFS_ATTR_MODE; r = sffs_table->t_readdir(ino->i_dir, pos - 2, name, sizeof(name), &attr); if (r != OK) { /* No more entries? Then close the handle and stop. */ if (r == ENOENT) { put_handle(ino); break; } /* FIXME: what if the error is ENAMETOOLONG? */ return r; } if (!strcmp(name, ".") || !strcmp(name, "..")) continue; if ((child = lookup_dentry(ino, name)) == NULL) { child = get_free_inode(); /* We were promised a free inode! */ assert(child != NULL); child->i_flags = MODE_TO_DIRFLAG(attr.a_mode); add_dentry(ino, name, child); } } r = fsdriver_dentry_add(&fsdentry, INODE_NR(child), name, strlen(name), IS_DIR(child) ? DT_DIR : DT_REG); put_inode(child); if (r < 0) return r; } while (r > 0); return fsdriver_dentry_finish(&fsdentry); }
size_t shim_do_getdents64 (int fd, struct linux_dirent64 * buf, size_t count) { if (!buf || test_user_memory(buf, count, true)) return -EFAULT; struct shim_handle * hdl = get_fd_handle(fd, NULL, NULL); if (!hdl) return -EBADF; int ret = -EACCES; if (hdl->type != TYPE_DIR) { ret = -ENOTDIR; goto out; } /* DEP 3/3/17: Properly handle an unlinked directory */ if (hdl->dentry->state & DENTRY_NEGATIVE) { ret = -ENOENT; goto out; } lock(&hdl->lock); struct shim_dir_handle * dirhdl = &hdl->info.dir; struct shim_dentry * dent = hdl->dentry; struct linux_dirent64 * b = buf; int bytes = 0; /* If we haven't listed the directory, do this first */ if (!(dent->state & DENTRY_LISTED)) { ret = list_directory_dentry(dent); if (ret) goto out; } #define DIRENT_SIZE(len) (sizeof(struct linux_dirent64) + (len) + 1) #define ASSIGN_DIRENT(dent, name, type) \ do { \ int len = strlen(name); \ if (bytes + DIRENT_SIZE(len) > count) \ goto done; \ \ b->d_ino = (dent)->ino; \ b->d_off = ++dirhdl->offset; \ b->d_reclen = DIRENT_SIZE(len); \ b->d_type = (type); \ \ memcpy(b->d_name, name, len + 1); \ \ b = (void *) b + DIRENT_SIZE(len); \ bytes += DIRENT_SIZE(len); \ } while(0) if (dirhdl->dot) { ASSIGN_DIRENT(dirhdl->dot, ".", LINUX_DT_DIR); put_dentry(dirhdl->dot); dirhdl->dot = NULL; } if (dirhdl->dotdot) { ASSIGN_DIRENT(dirhdl->dotdot, "..", LINUX_DT_DIR); put_dentry(dirhdl->dotdot); dirhdl->dotdot = NULL; } if (dirhdl->ptr == (void *) -1) { ret = list_directory_handle(dent, hdl); if (ret) goto out; } while (dirhdl->ptr && *dirhdl->ptr) { dent = *dirhdl->ptr; /* DEP 3/3/17: We need to filter negative dentries */ if (!(dent->state & DENTRY_NEGATIVE)) ASSIGN_DIRENT(dent, dentry_get_name(dent), get_dirent_type(dent->type)); put_dentry(dent); *(dirhdl->ptr++) = NULL; } #undef DIRENT_SIZE #undef ASSIGN_DIRENT done: ret = bytes; /* DEP 3/3/17: Properly detect EINVAL case, where buffer is too small to * hold anything */ if (bytes == 0 && (dirhdl->dot || dirhdl->dotdot || (dirhdl->ptr && *dirhdl->ptr))) ret = -EINVAL; unlock(&hdl->lock); out: put_handle(hdl); return ret; }
size_t shim_do_getdents64 (int fd, struct linux_dirent64 * buf, size_t count) { struct shim_handle * hdl = get_fd_handle(fd, NULL, NULL); if (!hdl) return -EBADF; int ret = -EACCES; if (hdl->type != TYPE_DIR) { ret = -ENOTDIR; goto out; } lock(hdl->lock); struct shim_dir_handle * dirhdl = &hdl->info.dir; struct shim_dentry * dent = hdl->dentry; struct linux_dirent64 * b = buf; int bytes = 0; #define DIRENT_SIZE(len) (sizeof(struct linux_dirent64) + (len) + 1) #define ASSIGN_DIRENT(dent, name, type) \ do { \ int len = strlen(name); \ if (bytes + DIRENT_SIZE(len) > count) \ goto done; \ \ b->d_ino = dent->ino; \ b->d_off = ++dirhdl->offset; \ b->d_reclen = DIRENT_SIZE(len); \ b->d_type = type ? : get_dirent_type(dent->mode); \ \ memcpy(b->d_name, name, len + 1); \ \ b = (void *) b + DIRENT_SIZE(len); \ bytes += DIRENT_SIZE(len); \ } while(0) if (dirhdl->dot) { ASSIGN_DIRENT(dirhdl->dot, ".", LINUX_DT_DIR); put_dentry(dirhdl->dot); dirhdl->dot = NULL; } if (dirhdl->dotdot) { ASSIGN_DIRENT(dirhdl->dotdot, "..", LINUX_DT_DIR); put_dentry(dirhdl->dotdot); dirhdl->dotdot = NULL; } while (*dirhdl->ptr) { dent = *dirhdl->ptr; ASSIGN_DIRENT(dent, dentry_get_name(dent), 0); put_dentry(dent); *(dirhdl->ptr++) = NULL; } #undef DIRENT_SIZE #undef ASSIGN_DIRENT done: ret = bytes; unlock(hdl->lock); out: put_handle(hdl); return ret; }
int shim_do_execve_rtld (struct shim_handle * hdl, const char ** argv, const char ** envp) { BEGIN_PROFILE_INTERVAL(); struct shim_thread * cur_thread = get_cur_thread(); int ret; if ((ret = close_cloexec_handle(cur_thread->handle_map)) < 0) return ret; SAVE_PROFILE_INTERVAL(close_CLOEXEC_files_for_exec); void * tcb = malloc(sizeof(__libc_tcb_t)); if (!tcb) return -ENOMEM; populate_tls(tcb); put_handle(cur_thread->exec); get_handle(hdl); cur_thread->exec = hdl; old_stack_top = cur_thread->stack_top; old_stack = cur_thread->stack; old_stack_red = cur_thread->stack_red; cur_thread->stack_top = NULL; cur_thread->stack = NULL; cur_thread->stack_red = NULL; initial_envp = NULL; new_argc = 0; for (const char ** a = argv ; *a ; a++, new_argc++); if ((ret = init_stack(argv, envp, &new_argp, REQUIRED_ELF_AUXV, &new_auxp)) < 0) return ret; SAVE_PROFILE_INTERVAL(alloc_new_stack_for_exec); switch_stack(new_argp); cur_thread = get_cur_thread(); UPDATE_PROFILE_INTERVAL(); DkVirtualMemoryFree(old_stack, old_stack_top - old_stack); DkVirtualMemoryFree(old_stack_red, old_stack - old_stack_red); int flags = VMA_INTERNAL; bkeep_munmap(old_stack, old_stack_top - old_stack, &flags); bkeep_munmap(old_stack_red, old_stack - old_stack_red, &flags); remove_loaded_libraries(); clean_link_map_list(); SAVE_PROFILE_INTERVAL(unmap_loaded_binaries_for_exec); init_brk(); unmap_all_vmas(); SAVE_PROFILE_INTERVAL(unmap_all_vmas_for_exec); if ((ret = load_elf_object(cur_thread->exec, NULL, 0)) < 0) shim_terminate(); load_elf_interp(cur_thread->exec); SAVE_PROFILE_INTERVAL(load_new_executable_for_exec); debug("execve: start execution\n"); execute_elf_object(cur_thread->exec, new_argc, new_argp, REQUIRED_ELF_AUXV, new_auxp); return 0; }
/*===========================================================================* * do_getdents * *===========================================================================*/ int do_getdents() { /* Retrieve directory entries. */ char name[NAME_MAX+1]; struct inode *ino, *child; struct dirent *dent; struct sffs_attr attr; size_t len, off, user_off, user_left; off_t pos; int r; /* must be at least sizeof(struct dirent) + NAME_MAX */ static char buf[BLOCK_SIZE]; attr.a_mask = SFFS_ATTR_MODE; if ((ino = find_inode(m_in.REQ_INODE_NR)) == NULL) return EINVAL; if (m_in.REQ_SEEK_POS_HI != 0) return EINVAL; if (!IS_DIR(ino)) return ENOTDIR; /* We are going to need at least one free inode to store children in. */ if (!have_free_inode()) return ENFILE; /* If we don't have a directory handle yet, get one now. */ if ((r = get_handle(ino)) != OK) return r; off = 0; user_off = 0; user_left = m_in.REQ_MEM_SIZE; /* We use the seek position as file index number. The first position is for * the "." entry, the second position is for the ".." entry, and the next * position numbers each represent a file in the directory. */ for (pos = m_in.REQ_SEEK_POS_LO; ; pos++) { /* Determine which inode and name to use for this entry. * We have no idea whether the host will give us "." and/or "..", * so generate our own and skip those from the host. */ if (pos == 0) { /* Entry for ".". */ child = ino; strcpy(name, "."); get_inode(child); } else if (pos == 1) { /* Entry for "..", but only when there is a parent. */ if (ino->i_parent == NULL) continue; child = ino->i_parent; strcpy(name, ".."); get_inode(child); } else { /* Any other entry, not being "." or "..". */ r = sffs_table->t_readdir(ino->i_dir, pos - 2, name, sizeof(name), &attr); if (r != OK) { /* No more entries? Then close the handle and stop. */ if (r == ENOENT) { put_handle(ino); break; } /* FIXME: what if the error is ENAMETOOLONG? */ return r; } if (!strcmp(name, ".") || !strcmp(name, "..")) continue; if ((child = lookup_dentry(ino, name)) == NULL) { child = get_free_inode(); /* We were promised a free inode! */ assert(child != NULL); child->i_flags = MODE_TO_DIRFLAG(attr.a_mode); add_dentry(ino, name, child); } } len = DWORD_ALIGN(sizeof(struct dirent) + strlen(name)); /* Is the user buffer too small to store another record? * Note that we will be rerequesting the same dentry upon a subsequent * getdents call this way, but we really need the name length for this. */ if (user_off + off + len > user_left) { put_inode(child); /* Is the user buffer too small for even a single record? */ if (user_off == 0 && off == 0) return EINVAL; break; } /* If our own buffer cannot contain the new record, copy out first. */ if (off + len > sizeof(buf)) { r = sys_safecopyto(m_in.m_source, m_in.REQ_GRANT, user_off, (vir_bytes) buf, off, D); if (r != OK) { put_inode(child); return r; } user_off += off; user_left -= off; off = 0; } /* Fill in the actual directory entry. */ dent = (struct dirent *) &buf[off]; dent->d_ino = INODE_NR(child); dent->d_off = pos; dent->d_reclen = len; strcpy(dent->d_name, name); off += len; put_inode(child); } /* If there is anything left in our own buffer, copy that out now. */ if (off > 0) { r = sys_safecopyto(m_in.m_source, m_in.REQ_GRANT, user_off, (vir_bytes) buf, off, D); if (r != OK) return r; user_off += off; } m_out.RES_SEEK_POS_HI = 0; m_out.RES_SEEK_POS_LO = pos; m_out.RES_NBYTES = user_off; return OK; }
int shim_do_socketpair (int domain, int type, int protocol, int * sv) { if (domain != AF_UNIX) return -EAFNOSUPPORT; if (type != SOCK_STREAM) return -EPROTONOSUPPORT; if (!sv) return -EINVAL; int ret = 0; struct shim_handle * hdl1 = get_new_handle(); struct shim_handle * hdl2 = get_new_handle(); if (!hdl1 || !hdl2) { ret = -ENOMEM; goto out; } struct shim_sock_handle * sock1 = &hdl1->info.sock; struct shim_sock_handle * sock2 = &hdl2->info.sock; hdl1->type = TYPE_SOCK; set_handle_fs(hdl1, &socket_builtin_fs); hdl1->flags = O_RDONLY; hdl1->acc_mode = MAY_READ|MAY_WRITE; sock1->domain = domain; sock1->sock_type = type & ~(SOCK_NONBLOCK|SOCK_CLOEXEC); sock1->protocol = protocol; sock1->sock_state = SOCK_ACCEPTED; hdl2->type = TYPE_SOCK; set_handle_fs(hdl2, &socket_builtin_fs); hdl1->flags = O_WRONLY; hdl2->acc_mode = MAY_READ|MAY_WRITE; sock2->domain = domain; sock2->sock_type = type & ~(SOCK_NONBLOCK|SOCK_CLOEXEC); sock2->protocol = protocol; sock2->sock_state = SOCK_CONNECTED; if ((ret = create_pipes(&sock1->addr.un.pipeid, &hdl1->pal_handle, &hdl2->pal_handle, &hdl1->uri, type & SOCK_NONBLOCK ? O_NONBLOCK : 0)) < 0) goto out; sock2->addr.un.pipeid = sock1->addr.un.pipeid; qstrcopy(&hdl2->uri, &hdl1->uri); int flags = type & SOCK_CLOEXEC ? FD_CLOEXEC : 0; int vfd1 = set_new_fd_handle(hdl1, flags, NULL); int vfd2 = set_new_fd_handle(hdl2, flags, NULL); if (vfd1 < 0 || vfd2 < 0) { if (vfd1 >= 0) { struct shim_handle * tmp = detach_fd_handle(vfd1, NULL, NULL); if (tmp) close_handle(tmp); } if (vfd2 >= 0) { struct shim_handle * tmp = detach_fd_handle(vfd2, NULL, NULL); if (tmp) close_handle(tmp); } goto out; } sv[0] = vfd1; sv[1] = vfd2; out: if (hdl1) put_handle(hdl1); if (hdl2) put_handle(hdl2); return ret; }
int init_important_handles (void) { struct shim_thread * thread = get_cur_thread(); if (thread->handle_map) goto done; struct shim_handle_map * handle_map = get_cur_handle_map(thread); if (!handle_map) { handle_map = get_new_handle_map(INIT_HANDLE_MAP_SIZE); if (!handle_map) return -ENOMEM; set_handle_map(thread, handle_map); } lock(handle_map->lock); if (handle_map->fd_size < 3) { if (!__enlarge_handle_map(handle_map, INIT_HANDLE_MAP_SIZE)) { unlock(handle_map->lock); return -ENOMEM; } } struct shim_handle * hdl = NULL; int ret; for (int fd = 0 ; fd < 3 ; fd++) if (!HANDLE_ALLOCATED(handle_map->map[fd])) { if (!hdl) { hdl = get_new_handle(); if (!hdl) return -ENOMEM; if ((ret = init_tty_handle(hdl, fd)) < 0) { put_handle(hdl); return ret; } } else { get_handle(hdl); } __set_new_fd_handle(&handle_map->map[fd], fd, hdl, 0); put_handle(hdl); if (fd != 1) hdl = NULL; } else { if (fd == 1) hdl = handle_map->map[fd]->handle; } if (handle_map->fd_top == FD_NULL || handle_map->fd_top < 2) handle_map->fd_top = 2; unlock(handle_map->lock); done: init_exec_handle(thread); return 0; }
void put_msg_handle (struct shim_msg_handle * msgq) { put_handle(MSG_TO_HANDLE(msgq)); }
static int __add_msg_handle (unsigned long key, IDTYPE msqid, bool owned, struct shim_msg_handle ** msghdl) { struct hlist_head * key_head = (key != IPC_PRIVATE) ? &msgq_key_hlist[MSGQ_HASH(key)] : NULL; struct hlist_head * qid_head = msqid ? &msgq_qid_hlist[MSGQ_HASH(msqid)] : NULL; struct shim_msg_handle * tmp; struct hlist_node * pos; if (key_head) hlist_for_each_entry(tmp, pos, key_head, key_hlist) if (tmp->msqkey == key) { if (tmp->msqid == msqid) { if (msghdl) *msghdl = tmp; return 0; } return -EEXIST; } if (qid_head) hlist_for_each_entry(tmp, pos, qid_head, qid_hlist) if (tmp->msqid == msqid) { if (key) tmp->msqkey = key; if (msghdl) *msghdl = tmp; return 0; } struct shim_handle * hdl = get_new_handle(); if (!hdl) return -ENOMEM; struct shim_msg_handle * msgq = &hdl->info.msg; hdl->type = TYPE_MSG; msgq->msqkey = key; msgq->msqid = msqid; msgq->owned = owned; msgq->deleted = false; msgq->currentsize = 0; msgq->event = DkSynchronizationEventCreate(0); msgq->queue = malloc(MSG_QOBJ_SIZE * DEFAULT_MSG_QUEUE_SIZE); msgq->queuesize = DEFAULT_MSG_QUEUE_SIZE; msgq->queueused = 0; msgq->freed = NULL; msgq->ntypes = 0; msgq->maxtypes = INIT_MSG_TYPE_SIZE; msgq->types = malloc(sizeof(struct msg_type) * INIT_MSG_TYPE_SIZE); INIT_LIST_HEAD(&msgq->list); get_handle(hdl); list_add_tail(&msgq->list, &msgq_list); INIT_HLIST_NODE(&msgq->key_hlist); if (key_head) { get_handle(hdl); hlist_add_head(&msgq->key_hlist, key_head); } INIT_HLIST_NODE(&msgq->qid_hlist); if (qid_head) { get_handle(hdl); hlist_add_head(&msgq->qid_hlist, qid_head); } if (!msghdl) { put_handle(hdl); return 0; } *msghdl = msgq; return 0; }
int thread_exit(struct shim_thread * self, bool send_ipc) { /* Chia-Che: Broadcast exit message as early as possible, so other process can start early on responding. */ if (self->in_vm && send_ipc) ipc_cld_exit_send(self->ppid, self->tid, self->exit_code, self->term_signal); lock(&self->lock); if (!self->is_alive) { debug("thread %d is dead\n", self->tid); out: unlock(&self->lock); return 0; } #ifdef PROFILE self->exit_time = GET_PROFILE_INTERVAL(); #endif int exit_code = self->exit_code; self->is_alive = false; if (is_internal(self)) goto out; struct shim_handle_map * handle_map = self->handle_map; struct shim_handle * exec = self->exec; struct shim_thread * parent = self->parent; self->handle_map = NULL; self->exec = NULL; if (parent) { assert(parent != self); assert(parent->child_exit_event); debug("thread exits, notifying thread %d\n", parent->tid); lock(&parent->lock); LISTP_DEL_INIT(self, &parent->children, siblings); LISTP_ADD_TAIL(self, &parent->exited_children, siblings); if (!self->in_vm) { debug("deliver SIGCHLD (thread = %d, exitval = %d)\n", self->tid, exit_code); siginfo_t info; memset(&info, 0, sizeof(siginfo_t)); info.si_signo = SIGCHLD; info.si_pid = self->tid; info.si_uid = self->uid; info.si_status = (exit_code & 0xff) << 8; append_signal(parent, SIGCHLD, &info, true); } unlock(&parent->lock); DkEventSet(parent->child_exit_event); } else { debug("parent not here, need to tell another process\n"); ipc_cld_exit_send(self->ppid, self->tid, self->exit_code, self->term_signal); } struct robust_list_head * robust_list = (void *) self->robust_list; self->robust_list = NULL; unlock(&self->lock); if (handle_map) put_handle_map(handle_map); if (exec) put_handle(exec); if (robust_list) release_robust_list(robust_list); if (self->clear_child_tid) release_clear_child_id (self->clear_child_tid); DkEventSet(self->exit_event); return 0; }