Skip to content

Commit

Permalink
[LibOS] Add O_PATH support to open syscall
Browse files Browse the repository at this point in the history
Signed-off-by: Borys Popławski <[email protected]>
  • Loading branch information
boryspoplawski committed Jun 20, 2022
1 parent 97d3f69 commit 19f8e65
Show file tree
Hide file tree
Showing 19 changed files with 213 additions and 77 deletions.
13 changes: 1 addition & 12 deletions LibOS/shim/include/shim_fs.h
Original file line number Diff line number Diff line change
Expand Up @@ -152,10 +152,6 @@ struct shim_fs_ops {
/* seek: the content from the file opened as handle */
file_off_t (*seek)(struct shim_handle* hdl, file_off_t offset, int whence);

/* move, copy: rename or duplicate the file */
int (*move)(const char* trim_old_name, const char* trim_new_name);
int (*copy)(const char* trim_old_name, const char* trim_new_name);

/* Returns 0 on success, -errno on error */
int (*truncate)(struct shim_handle* hdl, file_off_t len);

Expand All @@ -165,14 +161,6 @@ struct shim_fs_ops {
/* setflags: set flags of the file */
int (*setflags)(struct shim_handle* hdl, int flags);

/*
* \brief Deallocate handle data.
*
* Deallocates any filesystem-specific resources associated with the handle. Called just before
* destroying the handle.
*/
void (*hdrop)(struct shim_handle* hdl);

/* lock and unlock the file */
int (*lock)(const char* trim_name);
int (*unlock)(const char* trim_name);
Expand Down Expand Up @@ -925,6 +913,7 @@ extern struct shim_fs socket_builtin_fs;
extern struct shim_fs epoll_builtin_fs;
extern struct shim_fs eventfd_builtin_fs;
extern struct shim_fs synthetic_builtin_fs;
extern struct shim_fs path_builtin_fs;

struct shim_fs* find_fs(const char* name);

Expand Down
1 change: 1 addition & 0 deletions LibOS/shim/include/shim_handle.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ enum shim_handle_type {
TYPE_PSEUDO, /* pseudo nodes (currently directories), handled by `pseudo_*` functions */
TYPE_TMPFS, /* string-based files (with data inside dentry), used by `tmpfs` filesystem */
TYPE_SYNTHETIC, /* synthetic files, used by `synthetic` filesystem */
TYPE_PATH, /* path to a file (the file is not actually opened) */

/* Pipes and sockets: */
TYPE_PIPE, /* pipes, used by `pipe` filesystem */
Expand Down
3 changes: 0 additions & 3 deletions LibOS/shim/src/bookkeep/shim_handle.c
Original file line number Diff line number Diff line change
Expand Up @@ -498,9 +498,6 @@ void put_handle(struct shim_handle* hdl) {
if (hdl->fs && hdl->fs->fs_ops && hdl->fs->fs_ops->close)
hdl->fs->fs_ops->close(hdl);

if (hdl->fs && hdl->fs->fs_ops && hdl->fs->fs_ops->hdrop)
hdl->fs->fs_ops->hdrop(hdl);

free(hdl->uri);

if (hdl->pal_handle) {
Expand Down
8 changes: 5 additions & 3 deletions LibOS/shim/src/fs/chroot/encrypted.c
Original file line number Diff line number Diff line change
Expand Up @@ -384,16 +384,18 @@ static int chroot_encrypted_flush(struct shim_handle* hdl) {
return ret;
}

static void chroot_encrypted_hdrop(struct shim_handle* hdl) {
static int chroot_encrypted_close(struct shim_handle* hdl) {
assert(hdl->type == TYPE_CHROOT_ENCRYPTED);
if (hdl->inode->type != S_IFREG)
return;
return 0;

struct shim_encrypted_file* enc = hdl->inode->data;

lock(&hdl->inode->lock);
encrypted_file_put(enc);
unlock(&hdl->inode->lock);

return 0;
}

static ssize_t chroot_encrypted_read(struct shim_handle* hdl, void* buf, size_t count,
Expand Down Expand Up @@ -473,7 +475,7 @@ struct shim_fs_ops chroot_encrypted_fs_ops = {
.hstat = &generic_inode_hstat,
.truncate = &chroot_encrypted_truncate,
.poll = &generic_inode_poll,
.hdrop = &chroot_encrypted_hdrop,
.close = &chroot_encrypted_close,
.checkpoint = &chroot_encrypted_checkpoint,
.migrate = &chroot_encrypted_migrate,
.mmap = &generic_emulated_mmap,
Expand Down
1 change: 1 addition & 0 deletions LibOS/shim/src/fs/shim_fs.c
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ struct shim_fs* builtin_fs[] = {
&eventfd_builtin_fs,
&pseudo_builtin_fs,
&synthetic_builtin_fs,
&path_builtin_fs,
};

static struct shim_lock mount_mgr_lock;
Expand Down
25 changes: 25 additions & 0 deletions LibOS/shim/src/fs/shim_fs_path.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
/* SPDX-License-Identifier: LGPL-3.0-or-later */
/* Copyright (C) 2022 Intel Corporation
* Borys Popławski <[email protected]>
*/

#include "shim_fs.h"

static int hstat(struct shim_handle* handle, struct stat* buf) {
if (!handle->inode) {
return -EINVAL;
}
return generic_inode_hstat(handle, buf);
}

static struct shim_fs_ops path_fs_ops = {
.hstat = hstat,
};

static struct shim_d_ops path_d_ops = {};

struct shim_fs path_builtin_fs = {
.name = "path",
.fs_ops = &path_fs_ops,
.d_ops = &path_d_ops,
};
63 changes: 40 additions & 23 deletions LibOS/shim/src/fs/shim_namei.c
Original file line number Diff line number Diff line change
Expand Up @@ -445,40 +445,56 @@ int open_namei(struct shim_handle* hdl, struct shim_dentry* start, const char* p

ret = path_lookupat(start, path, lookup_flags, &dent);
if (ret < 0)
goto err;
goto out;

if (flags & O_PATH) {
if (!dent->inode) {
ret = -ENOENT;
goto out;
}

assoc_handle_with_dentry(hdl, dent, flags);
if (dent->inode->type == S_IFDIR) {
hdl->is_dir = true;
hdl->dir_info.dents = NULL;
}

hdl->type = TYPE_PATH;
hdl->fs = &path_builtin_fs;
ret = 0;
goto out;
}

if (dent->inode && dent->inode->type == S_IFDIR) {
if (flags & O_WRONLY || flags & O_RDWR ||
((flags & O_CREAT) && !(flags & O_DIRECTORY) && !(flags & O_EXCL))) {
ret = -EISDIR;
goto err;
goto out;
}
}

if (dent->inode && dent->inode->type == S_IFLNK) {
/*
* Can happen if user specified O_NOFOLLOW, or O_TRUNC | O_EXCL. Posix requires us to fail
* with -ELOOP when trying to open a symlink.
*
* (Linux allows opening a symlink with O_PATH, but Gramine does not support it yet).
*/
ret = -ELOOP;
goto err;
goto out;
}

bool need_open = true;
if (!dent->inode) {
if (!(flags & O_CREAT)) {
ret = -ENOENT;
goto err;
goto out;
}

/* Check the parent permission first */
struct shim_dentry* dir = dentry_up(dent);
if (dir) {
ret = check_permissions(dir, MAY_WRITE | MAY_EXEC);
if (ret < 0)
goto err;
goto out;
}

struct shim_fs* fs = dent->mount->fs;
Expand All @@ -487,57 +503,58 @@ int open_namei(struct shim_handle* hdl, struct shim_dentry* start, const char* p
if (flags & O_DIRECTORY) {
if (!fs->d_ops->mkdir) {
ret = -EINVAL;
goto err;
goto out;
}
ret = fs->d_ops->mkdir(dent, mode & ~S_IFMT);
if (ret < 0)
goto err;
goto out;
} else {
if (!fs->d_ops->creat) {
ret = -EINVAL;
goto err;
goto out;
}
ret = fs->d_ops->creat(hdl, dent, flags, mode & ~S_IFMT);
if (ret < 0)
goto err;
goto out;
assoc_handle_with_dentry(hdl, dent, flags);
need_open = false;
}
} else {
/* The file exists. This is not permitted if both O_CREAT and O_EXCL are set. */
if ((flags & O_CREAT) && (flags & O_EXCL)) {
ret = -EEXIST;
goto err;
goto out;
}

/* Check permissions. Note that we do it only if the file already exists: a newly created
* file is allowed to have a mode that's incompatible with `acc_mode`. */
ret = check_permissions(dent, acc_mode);
if (ret < 0)
goto err;
goto out;
}

if (hdl && need_open) {
ret = dentry_open(hdl, dent, flags);
if (ret < 0)
goto err;
goto out;
}

ret = 0;

out:
if (found) {
*found = dent;
} else {
put_dentry(dent);
if (ret == 0) {
assert(dent);
get_dentry(dent);
*found = dent;
} else {
*found = NULL;
}
}
unlock(&g_dcache_lock);
return 0;

err:
if (dent)
put_dentry(dent);

if (found)
*found = NULL;

unlock(&g_dcache_lock);
return ret;
}
Expand Down
1 change: 1 addition & 0 deletions LibOS/shim/src/meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ libos_sources = files(
'fs/shim_fs_hash.c',
'fs/shim_fs_lock.c',
'fs/shim_fs_mem.c',
'fs/shim_fs_path.c',
'fs/shim_fs_pseudo.c',
'fs/shim_fs_synthetic.c',
'fs/shim_fs_util.c',
Expand Down
9 changes: 8 additions & 1 deletion LibOS/shim/src/sys/shim_open.c
Original file line number Diff line number Diff line change
Expand Up @@ -100,8 +100,15 @@ long shim_do_creat(const char* path, mode_t mode) {
}

long shim_do_openat(int dfd, const char* filename, int flags, int mode) {
/* Clear invalid flags. */
flags &= O_ACCMODE | O_APPEND | O_CLOEXEC | O_CREAT | O_DIRECT | O_DIRECTORY | O_DSYNC | O_EXCL
| O_LARGEFILE | O_NOATIME | O_NOCTTY | O_NOFOLLOW | O_NONBLOCK | O_PATH | O_SYNC
| O_TMPFILE | O_TRUNC;

/* TODO: fail explicitly on valid but unsupported flags. */

if (flags & O_PATH) {
return -EINVAL;
flags &= O_PATH | O_CLOEXEC | O_DIRECTORY | O_NOFOLLOW;
}

if (!is_user_string_readable(filename))
Expand Down
8 changes: 4 additions & 4 deletions LibOS/shim/test/ltp/ltp.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -276,15 +276,15 @@ skip = yes
[execve05]
skip = yes

# copy child
# execveat not implemented
[execveat01]
skip = yes

# copy child
# execveat not implemented
[execveat02]
skip = yes

# copy child
# execveat not implemented
[execveat03]
skip = yes

Expand Down Expand Up @@ -1294,7 +1294,7 @@ skip = yes
[open12]
skip = yes

# Requires touch() support
# Requires `utime*` syscall support
[open13]
skip = yes

Expand Down
22 changes: 21 additions & 1 deletion LibOS/shim/test/regression/common.h
Original file line number Diff line number Diff line change
@@ -1,15 +1,35 @@
/* SPDX-License-Identifier: LGPL-3.0-or-later */
/* Copyright (C) 2021 Intel Corporation
/* Copyright (C) 2022 Intel Corporation
* Paweł Marczewski <[email protected]>
* Borys Popławski <[email protected]>
*/

#ifndef COMMON_H_
#define COMMON_H_

#include <assert.h>
#include <err.h>

#define OVERFLOWS(type, val) \
({ \
type __dummy; \
__builtin_add_overflow((val), 0, &__dummy); \
})

#define CHECK(x) ({ \
__typeof__(x) _x = (x); \
if (_x == -1) { \
err(1, "error at %s (line %d)", #x, __LINE__); \
} \
_x; \
})

#define SAME_TYPE(a, b) __builtin_types_compatible_p(__typeof__(a), __typeof__(b))
#define IS_STATIC_ARRAY(a) (!SAME_TYPE(a, &*(a)))

#define ARRAY_LEN(arr) ({ \
static_assert(IS_STATIC_ARRAY(arr), "not a static array"); \
sizeof(arr) / sizeof(arr[0]); \
})

#endif /* COMMON_H_ */
10 changes: 1 addition & 9 deletions LibOS/shim/test/regression/epoll_test.c
Original file line number Diff line number Diff line change
Expand Up @@ -7,19 +7,11 @@
#include <sys/wait.h>
#include <unistd.h>

#define CHECK(x) ({ \
__typeof__(x) _x = (x); \
if (_x == -1) { \
err(1, "error at line %d", __LINE__); \
} \
_x; \
})
#include "common.h"

#define ERR(msg, args...) \
errx(1, "%d: " msg, __LINE__, ##args)

#define ARRAY_LEN(arr) (sizeof(arr) / sizeof(arr[0]))

static uint64_t wait_event(int epfd, struct epoll_event* possible_events,
size_t possible_events_len) {
struct epoll_event event = { 0 };
Expand Down
4 changes: 2 additions & 2 deletions LibOS/shim/test/regression/groups.c
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
#include <sys/wait.h>
#include <unistd.h>

#define ARRAY_LEN(x) (sizeof(x) / sizeof(x[0]))
#include "common.h"

static gid_t test_groups[] = { 0, 1337, 1337, 0 };

Expand Down Expand Up @@ -46,7 +46,7 @@ int main(void) {
x = getgroups(ARRAY_LEN(groups), groups);
if (x < 0) {
err(1, "getgroups");
} else if (x != ARRAY_LEN(groups)) {
} else if ((size_t)x != ARRAY_LEN(groups)) {
errx(1, "getgroups returned invalid length: %d (expected: %zu)", x, ARRAY_LEN(groups));
}

Expand Down
1 change: 1 addition & 0 deletions LibOS/shim/test/regression/meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ tests = {
'mprotect_file_fork': {},
'mprotect_prot_growsdown': {},
'multi_pthread': {},
'open_opath': {},
'openmp': {
# NOTE: This will use `libgomp` in GCC and `libomp` in Clang.
'c_args': '-fopenmp',
Expand Down
Loading

0 comments on commit 19f8e65

Please sign in to comment.