Example #1
0
void put_handle (struct shim_handle * hdl)
{
    int ref_count = REF_DEC(hdl->ref_count);

#ifdef DEBUG_REF
    debug("put handle %p(%s) (ref_count = %d)\n", hdl, __handle_name(hdl),
          ref_count);
#endif

    if (!ref_count) {
        if (hdl->fs && hdl->fs->fs_ops &&
            hdl->fs->fs_ops->hput)
            hdl->fs->fs_ops->hput(hdl);

        qstrfree(&hdl->path);
        qstrfree(&hdl->uri);

        if (hdl->pal_handle)
            DkObjectClose(hdl->pal_handle);

        if (hdl->dentry)
            put_dentry(hdl->dentry);

        if (hdl->fs)
            put_mount(hdl->fs);

        destroy_handle(hdl);
    }
}
Example #2
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
}
Example #3
0
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;
}
Example #4
0
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);
}
Example #5
0
static int proc_thread_link_stat (const char * name, struct stat * buf)
{
    struct shim_dentry * dent;

    int ret = find_thread_link(name, NULL, &dent, NULL);
    if (ret < 0)
        return ret;

    if (!dent->fs || !dent->fs->d_ops || !dent->fs->d_ops->stat) {
        ret = -EACCES;
        goto out;
    }

    ret = dent->fs->d_ops->stat(dent, buf);
out:
    put_dentry(dent);
    return ret;
}
Example #6
0
static int proc_thread_link_mode (const char * name, mode_t * mode)
{
    struct shim_dentry * dent;

    int ret = find_thread_link(name, NULL, &dent, NULL);
    if (ret < 0)
        return ret;

    if (!dent->fs || !dent->fs->d_ops || !dent->fs->d_ops->mode) {
        ret = -EACCES;
        goto out;
    }

    ret = dent->fs->d_ops->mode(dent, mode, true);
out:
    put_dentry(dent);
    return ret;
}
Example #7
0
static int proc_thread_link_open (struct shim_handle * hdl,
                                  const char * name, int flags)
{
    struct shim_dentry * dent;

    int ret = find_thread_link(name, NULL, &dent, NULL);
    if (ret < 0)
        return ret;

    if (!dent->fs || !dent->fs->d_ops || !dent->fs->d_ops->open) {
        ret = -EACCES;
        goto out;
    }

    ret = dent->fs->d_ops->open(hdl, dent, flags);
out:
    put_dentry(dent);
    return 0;
}
Example #8
0
int shim_do_lstat (const char * file, struct stat * stat)
{
    if (!file)
        return -EFAULT;

    int ret;
    struct shim_dentry * dent = NULL;

    if ((ret = path_lookupat(NULL, file, LOOKUP_ACCESS, &dent)) < 0)
        goto out;

    struct shim_mount * fs = dent->fs;

    if (!fs->d_ops || !fs->d_ops->stat) {
        ret = -EACCES;
        goto out_dentry;
    }

    ret = fs->d_ops->stat(dent, stat);
out_dentry:
    put_dentry(dent);
out:
    return ret;
}
Example #9
0
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;
}
Example #10
0
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;
}
Example #11
0
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;
}
Example #12
0
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;
}