static inline int init_tty_handle (struct shim_handle * hdl, bool write) { struct shim_dentry * dent = NULL; int ret; if ((ret = path_lookupat(NULL, "/dev/tty", LOOKUP_OPEN, &dent)) < 0) return ret; int flags = (write ? O_WRONLY : O_RDONLY)|O_APPEND; struct shim_mount * fs = dent->fs; ret = fs->d_ops->open(hdl, dent, flags); if (ret < 0) return ret; set_handle_fs(hdl, fs); hdl->dentry = dent; hdl->flags = O_RDWR|O_APPEND|0100000; int size; char * path = dentry_get_path(dent, true, &size); if (path) qstrsetstr(&hdl->path, path, size); else qstrsetstr(&hdl->path, "/dev/tty", 8); return 0; }
int shim_do_readlink (const char * file, char * buf, int bufsize) { if (!file) return -EFAULT; if (bufsize <= 0) return -EINVAL; /* The correct behavior is to return -EINVAL if file is not a symbolic link */ return -EINVAL; #if 0 int ret; struct shim_dentry * dent = NULL; if ((ret = path_lookupat(NULL, file, LOOKUP_ACCESS, &dent)) < 0) return ret; char * relpath; int len; relpath = dentry_get_path(dent, true, &len); if (len > bufsize) len = bufsize; memcpy(buf, relpath, len); put_dentry(dent); return len; #endif }
static int find_thread_link (const char * name, struct shim_qstr * link, struct shim_dentry ** dentptr, struct shim_thread ** threadptr) { const char * next, * nextnext; int next_len; int pid = parse_thread_name(name, &next, &next_len, &nextnext); if (pid < 0) return pid; struct shim_thread * thread = lookup_thread(pid); struct shim_dentry * dent = NULL; int ret = 0; if (!thread) return -ENOENT; if (!thread->in_vm) { ret = -ENOENT; goto out; } lock(&thread->lock); if (next_len == static_strlen("root") && !memcmp(next, "root", next_len)) { dent = thread->root; get_dentry(dent); } if (next_len == static_strlen("cwd") && !memcmp(next, "cwd", next_len)) { dent = thread->cwd; get_dentry(dent); } if (next_len == static_strlen("exe") && !memcmp(next, "exe", next_len)) { struct shim_handle * exec = thread->exec; if (!exec->dentry) { unlock(&thread->lock); ret = -EINVAL; goto out; } dent = exec->dentry; get_dentry(dent); } unlock(&thread->lock); if (nextnext) { struct shim_dentry * next_dent = NULL; ret = path_lookupat(dent, nextnext, 0, &next_dent, dent->fs); if (ret < 0) goto out; put_dentry(dent); dent = next_dent; } if (link) { int size; char * path = dentry_get_path(dent, true, &size); qstrsetstr(link, path, size); } if (dentptr) { get_dentry(dent); *dentptr = dent; } if (threadptr) { get_thread(thread); *threadptr = thread; } ret = 0; out: if (dent) put_dentry(dent); if (thread) put_thread(thread); return ret; }
static int isolate_fs (struct config_store * cfg, const char * path) { struct shim_dentry * dent = NULL; int ret = 0; if ((ret = path_lookupat(NULL, path, LOOKUP_OPEN, &dent)) < 0) return ret; if (!(dent->state & DENTRY_ISDIRECTORY)) { put_dentry(dent); return -ENOTDIR; } int dpath_len = 0; char * dpath = dentry_get_path(dent, true, &dpath_len); bool root_created = false; char t[CONFIG_MAX], u[CONFIG_MAX]; int nkeys, keybuf_size = CONFIG_MAX; char * keybuf = __alloca(keybuf_size); while ((nkeys = get_config_entries(cfg, "fs.mount.other", keybuf, keybuf_size)) == -ENAMETOOLONG) { keybuf_size *= 2; keybuf = __alloca(keybuf_size); } if (nkeys <= 0) goto root; char k[CONFIG_MAX], p[CONFIG_MAX]; memcpy(k, "fs.mount.other.", 15); const char * key = keybuf, * next = NULL; for (int n = 0 ; n < nkeys ; key = next, n++) { for (next = key ; *next ; next++); next++; int key_len = next - key - 1; memcpy(k + 15, key, key_len); char * kp = k + 15 + key_len; int ulen, plen; bool is_chroot = false; /* Skip FS that are not chroot */ memcpy(kp, ".type", 6); if ((ret = get_config(cfg, k, t, CONFIG_MAX)) <= 0) continue; if (ret == 6 || !memcmp(t, "chroot", 6)) is_chroot = true; memcpy(kp, ".uri", 5); if ((ulen = get_config(cfg, k, u, CONFIG_MAX)) <= 0) continue; memcpy(kp, ".path", 6); if ((plen = get_config(cfg, k, p, CONFIG_MAX)) <= 0) continue; if (plen >= dpath_len) { if (!memcmp(p, dpath, dpath_len)) { if (!p[dpath_len]) { root_created = true; debug("kept file rule: %s => %s\n", p, u); continue; } if (p[dpath_len] != '/') goto remove; /* keep this FS */ continue; } else { remove: if (!is_chroot) { debug("kept file rule: %s => %s\n", p, u); continue; } set_config(cfg, k, NULL); memcpy(kp, ".type", 6); set_config(cfg, k, NULL); memcpy(kp, ".uri", 5); set_config(cfg, k, NULL); debug("deleted file rule: %s => %s\n", p, u); } } else { if (memcmp(p, dpath, plen)) goto remove; assert(dpath[plen]); if (dpath[plen] != '/') goto remove; if (!is_chroot) { root_created = true; debug("kept file rule: %s => %s\n", p, u); continue; } append_uri(u, ulen, dpath + plen, dpath_len - plen); set_config(cfg, k, dpath); memcpy(kp, "uri", 5); set_config(cfg, k, u); root_created = true; debug("added file rule: %s => %s\n", dpath, u); } } root: if ((ret = get_config(cfg, "fs.mount.root.uri", u, CONFIG_MAX)) > 0) { int prefix_len = ret; if ((ret = get_config(cfg, "fs.mount.root.type", t, CONFIG_MAX)) > 0 && ret == 6 && !memcmp(t, "chroot", 6)) { /* remove the root FS */ set_config(cfg, "fs.mount.root.uri", NULL); set_config(cfg, "fs.mount.root.type", NULL); debug("deleted file rule: root\n"); /* add another FS as part of the original root FS */ if (!root_created) { append_uri(u, prefix_len, dpath, dpath_len); set_config(cfg, "fs.mount.other.root.path", dpath); set_config(cfg, "fs.mount.other.root.uri", u); set_config(cfg, "fs.mount.other.root.type", "chroot"); debug("added file rule: %s => %s\n", dpath, u); } } } return 0; }