From d35d676bbcc5124fc01b7d6d9d2d9c5b497fba4b Mon Sep 17 00:00:00 2001 From: Dan Gohman Date: Wed, 4 Dec 2019 05:32:17 -0800 Subject: [PATCH 1/7] Add functions for working with file permissions. Add functions and types to query and set the filesystem permissions of a file: read, write, execute (for files), and search (for directories). These permissions aren't the only thing which determines whether a given file or directory can be accessed; hosts may impose additional arbitrary security restrictions not reflected here. WASI itself does not currently have the ability to execute files, so the meaning of "execute" here is entirely up to the host filesystem. These are similar to fchmod/fchmodat/fstat/fstatat in POSIX, though there are some differences: - This doesn't surface POSIX's setuid, setgid, or sticky bits. These can be added in the future if needed, though they'll require additional security and portability considerations. - This uses separate flags for "execute" on files vs "search" on directories. WASI libc can provide a POSIX-compatible C API. - This doesn't expose POSIX's user/group/other concepts. These can be added in the future if needed, though they'll require additional security and portability considerations. Implementations in POSIX environments should follow the umask when setting permissions flags. --- phases/ephemeral/witx/typenames.witx | 33 ++++++++++++- phases/ephemeral/witx/wasi_ephemeral_fd.witx | 35 ++++++++++++++ .../ephemeral/witx/wasi_ephemeral_path.witx | 46 ++++++++++++++++++- 3 files changed, 111 insertions(+), 3 deletions(-) diff --git a/phases/ephemeral/witx/typenames.witx b/phases/ephemeral/witx/typenames.witx index 904aa1ca..171fc7f9 100644 --- a/phases/ephemeral/witx/typenames.witx +++ b/phases/ephemeral/witx/typenames.witx @@ -246,19 +246,23 @@ $path_rename_source ;;; The right to invoke `path_rename` with the file descriptor as the target directory. $path_rename_target - ;;; The right to invoke `path_filestat_get`. + ;;; The right to invoke `path_filestat_get` or `path_permissions_get`. $path_filestat_get ;;; The right to change a file's size (there is no `path_filestat_set_size`). ;;; If `path_open` is set, includes the right to invoke `path_open` with `oflags::trunc`. $path_filestat_set_size ;;; The right to invoke `path_filestat_set_times`. $path_filestat_set_times - ;;; The right to invoke `fd_filestat_get`. + ;;; The right to invoke `path_filestat_set_permissions`. + $path_permissions_set + ;;; The right to invoke `fd_filestat_get` or `fd_permissions_get`. $fd_filestat_get ;;; The right to invoke `fd_filestat_set_size`. $fd_filestat_set_size ;;; The right to invoke `fd_filestat_set_times`. $fd_filestat_set_times + ;;; The right to invoke `fd_filestat_set_permissions`. + $fd_permissions_set ;;; The right to invoke `path_symlink`. $path_symlink ;;; The right to invoke `path_remove_directory`. @@ -477,6 +481,31 @@ ) ) +;;; File permissions. This represents the permissions associated with a +;;; file in a filesystem, and don't fully reflect all the conditions +;;; which determine whether a given WASI program can access the file. +(typename $permissions + (enum u8 + ;;; For files, permission to read the file. + ;;; For directories, permission to do `readdir` within the directory. + $read + + ;;; For files, permission to mutate the file. + ;;; For directories, permission to create, remove, and rename items + ;;; within the directory. + $write + + ;;; For files, permission to "execute" the file, using whatever + ;;; concept of "executing" the host filesystem has. + ;;; This flag is not valid for directories. + $execute + + ;;; For directories, permission to access files within the directory. + ;;; This flag is not valid for files. + $search + ) +) + ;;; User-provided value that may be attached to objects that is retained when ;;; extracted from the implementation. (typename $userdata u64) diff --git a/phases/ephemeral/witx/wasi_ephemeral_fd.witx b/phases/ephemeral/witx/wasi_ephemeral_fd.witx index 9fbad9ab..4cc3d02a 100644 --- a/phases/ephemeral/witx/wasi_ephemeral_fd.witx +++ b/phases/ephemeral/witx/wasi_ephemeral_fd.witx @@ -107,6 +107,41 @@ (result $error $errno) ) + ;;; Return the permissions of a file or directory. + ;;; + ;;; This returns the permissions associated with a file or directory in + ;;; a filesystem at the time it is called. The ability to actually access + ;;; a file or directory may depend on additional permissions not reflected + ;;; here. + ;;; + ;;; Note: This is similar to reading the `st_mode` flag after a + ;;; `fstat` call in POSIX. + (@interface func (export "permissions_get") + (param $fd $fd) + (result $error $errno) + ;;; The permissions to associate with the file. + (result $permissions $permissions) + ) + + ;;; Set the permissions of a file or directory. + ;;; + ;;; This sets the permissions associated with a file or directory in + ;;; a filesystem at the time it is called. The ability to actually access + ;;; a file or directory may depend on additional permissions not reflected + ;;; here. + ;;; + ;;; Note: This is similar `fchmod` in POSIX. + ;;; + ;;; Unlike POSIX, this doesn't expose a user/group/other distinction; + ;;; implementations in POSIX environments are suggested to consult the + ;;; umask to determine which of the user/group/other flags to modify. + (@interface func (export "permissions_set") + (param $fd $fd) + ;;; The permissions associated with the file. + (result $permissions $permissions) + (result $error $errno) + ) + ;;; Read from a file descriptor, without using and updating the file descriptor's offset. ;;; Note: This is similar to `preadv` in POSIX. (@interface func (export "pread") diff --git a/phases/ephemeral/witx/wasi_ephemeral_path.witx b/phases/ephemeral/witx/wasi_ephemeral_path.witx index 16c97469..b709c10f 100644 --- a/phases/ephemeral/witx/wasi_ephemeral_path.witx +++ b/phases/ephemeral/witx/wasi_ephemeral_path.witx @@ -50,6 +50,49 @@ (result $error $errno) ) + ;;; Return the permissions of a file or directory. + ;;; + ;;; This returns the permissions associated with a file or directory in + ;;; a filesystem at the time it is called. The ability to actually access + ;;; a file or directory may depend on additional permissions not reflected + ;;; here. + ;;; + ;;; Note: This is similar to reading the `st_mode` flag after a + ;;; `fstatat` call in POSIX. + (@interface func (export "permissions_get") + (param $fd $fd) + ;;; Flags determining the method of how the path is resolved. + (param $flags $lookupflags) + ;;; The path to a file to query. + (param $path string) + (result $error $errno) + ;;; The permissions associated with the file. + (result $permissions $permissions) + ) + + ;;; Set the permissions of a file or directory. + ;;; + ;;; This sets the permissions associated with a file or directory in + ;;; a filesystem at the time it is called. The ability to actually access + ;;; a file or directory may depend on additional permissions not reflected + ;;; here. + ;;; + ;;; Note: This is similar to `fchmodat` in POSIX. + ;;; + ;;; Unlike POSIX, this doesn't expose a user/group/other distinction; + ;;; implementations in POSIX environments are suggested to consult the + ;;; umask to determine which of the user/group/other flags to modify. + (@interface func (export "permissions_set") + (param $fd $fd) + ;;; Flags determining the method of how the path is resolved. + (param $flags $lookupflags) + ;;; The path to a file to query. + (param $path string) + ;;; The permissions to associate with the file. + (param $permissions $permissions) + (result $error $errno) + ) + ;;; Create a hard link. ;;; Note: This is similar to `linkat` in POSIX. (@interface func (export "link") @@ -94,6 +137,8 @@ (param $fs_rights_base $rights) (param $fs_rights_inherting $rights) (param $fdflags $fdflags) + ;;; If a file is created, the filesystem permissions to associate with it. + (param $permissions $permissions) (result $error $errno) ;;; The file descriptor of the file that has been opened. (result $opened_fd $fd) @@ -147,7 +192,6 @@ (result $error $errno) ) - ;;; Unlink a file. ;;; Return `EISDIR` if the path refers to a directory. ;;; Note: This is similar to `unlinkat(fd, path, 0)` in POSIX. From 70edef867cae87e815d9159526e054f39f979978 Mon Sep 17 00:00:00 2001 From: Dan Gohman Date: Wed, 4 Dec 2019 08:32:56 -0800 Subject: [PATCH 2/7] Make $permissions a flags. --- phases/ephemeral/witx/typenames.witx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/phases/ephemeral/witx/typenames.witx b/phases/ephemeral/witx/typenames.witx index 171fc7f9..9a179c4c 100644 --- a/phases/ephemeral/witx/typenames.witx +++ b/phases/ephemeral/witx/typenames.witx @@ -485,7 +485,7 @@ ;;; file in a filesystem, and don't fully reflect all the conditions ;;; which determine whether a given WASI program can access the file. (typename $permissions - (enum u8 + (flags u8 ;;; For files, permission to read the file. ;;; For directories, permission to do `readdir` within the directory. $read From 49cfce3e483cd22827e74bb19c935fdb169a4a51 Mon Sep 17 00:00:00 2001 From: Dan Gohman Date: Wed, 4 Dec 2019 09:21:50 -0800 Subject: [PATCH 3/7] Put a permissions field in `filestat`. This is instead of dedicated `permissions_get` functions. --- phases/ephemeral/witx/typenames.witx | 6 ++++-- phases/ephemeral/witx/wasi_ephemeral_fd.witx | 16 --------------- .../ephemeral/witx/wasi_ephemeral_path.witx | 20 ------------------- 3 files changed, 4 insertions(+), 38 deletions(-) diff --git a/phases/ephemeral/witx/typenames.witx b/phases/ephemeral/witx/typenames.witx index 9a179c4c..d9ac27e8 100644 --- a/phases/ephemeral/witx/typenames.witx +++ b/phases/ephemeral/witx/typenames.witx @@ -246,7 +246,7 @@ $path_rename_source ;;; The right to invoke `path_rename` with the file descriptor as the target directory. $path_rename_target - ;;; The right to invoke `path_filestat_get` or `path_permissions_get`. + ;;; The right to invoke `path_filestat_get`. $path_filestat_get ;;; The right to change a file's size (there is no `path_filestat_set_size`). ;;; If `path_open` is set, includes the right to invoke `path_open` with `oflags::trunc`. @@ -255,7 +255,7 @@ $path_filestat_set_times ;;; The right to invoke `path_filestat_set_permissions`. $path_permissions_set - ;;; The right to invoke `fd_filestat_get` or `fd_permissions_get`. + ;;; The right to invoke `fd_filestat_get`. $fd_filestat_get ;;; The right to invoke `fd_filestat_set_size`. $fd_filestat_set_size @@ -468,6 +468,8 @@ (field $ino $inode) ;;; File type. (field $filetype $filetype) + ;;; File permissions. + (field $permissions $permissions) ;;; Number of hard links to the file. (field $nlink $linkcount) ;;; For regular files, the file size in bytes. For symbolic links, the length in bytes of the pathname contained in the symbolic link. diff --git a/phases/ephemeral/witx/wasi_ephemeral_fd.witx b/phases/ephemeral/witx/wasi_ephemeral_fd.witx index 4cc3d02a..89d86e1b 100644 --- a/phases/ephemeral/witx/wasi_ephemeral_fd.witx +++ b/phases/ephemeral/witx/wasi_ephemeral_fd.witx @@ -107,22 +107,6 @@ (result $error $errno) ) - ;;; Return the permissions of a file or directory. - ;;; - ;;; This returns the permissions associated with a file or directory in - ;;; a filesystem at the time it is called. The ability to actually access - ;;; a file or directory may depend on additional permissions not reflected - ;;; here. - ;;; - ;;; Note: This is similar to reading the `st_mode` flag after a - ;;; `fstat` call in POSIX. - (@interface func (export "permissions_get") - (param $fd $fd) - (result $error $errno) - ;;; The permissions to associate with the file. - (result $permissions $permissions) - ) - ;;; Set the permissions of a file or directory. ;;; ;;; This sets the permissions associated with a file or directory in diff --git a/phases/ephemeral/witx/wasi_ephemeral_path.witx b/phases/ephemeral/witx/wasi_ephemeral_path.witx index b709c10f..97d8cfb5 100644 --- a/phases/ephemeral/witx/wasi_ephemeral_path.witx +++ b/phases/ephemeral/witx/wasi_ephemeral_path.witx @@ -50,26 +50,6 @@ (result $error $errno) ) - ;;; Return the permissions of a file or directory. - ;;; - ;;; This returns the permissions associated with a file or directory in - ;;; a filesystem at the time it is called. The ability to actually access - ;;; a file or directory may depend on additional permissions not reflected - ;;; here. - ;;; - ;;; Note: This is similar to reading the `st_mode` flag after a - ;;; `fstatat` call in POSIX. - (@interface func (export "permissions_get") - (param $fd $fd) - ;;; Flags determining the method of how the path is resolved. - (param $flags $lookupflags) - ;;; The path to a file to query. - (param $path string) - (result $error $errno) - ;;; The permissions associated with the file. - (result $permissions $permissions) - ) - ;;; Set the permissions of a file or directory. ;;; ;;; This sets the permissions associated with a file or directory in From 637bcfc9ff7d6e3895604e88e463636137962bc0 Mon Sep 17 00:00:00 2001 From: Dan Gohman Date: Wed, 4 Dec 2019 09:28:50 -0800 Subject: [PATCH 4/7] Fold the $search permission for directories into the $read permission. --- phases/ephemeral/witx/typenames.witx | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/phases/ephemeral/witx/typenames.witx b/phases/ephemeral/witx/typenames.witx index d9ac27e8..43cb61ff 100644 --- a/phases/ephemeral/witx/typenames.witx +++ b/phases/ephemeral/witx/typenames.witx @@ -489,7 +489,11 @@ (typename $permissions (flags u8 ;;; For files, permission to read the file. - ;;; For directories, permission to do `readdir` within the directory. + ;;; For directories, permission to do `readdir` and access files + ;;; within the directory. + ;;; + ;;; Note: This is similar to the read bit being set on files, and the + ;;; read *and* execute bits being set on directories. $read ;;; For files, permission to mutate the file. @@ -501,10 +505,6 @@ ;;; concept of "executing" the host filesystem has. ;;; This flag is not valid for directories. $execute - - ;;; For directories, permission to access files within the directory. - ;;; This flag is not valid for files. - $search ) ) From 2a0c047dce4570fb5e10afd39c03fc40db157eae Mon Sep 17 00:00:00 2001 From: Dan Gohman Date: Wed, 4 Dec 2019 09:31:47 -0800 Subject: [PATCH 5/7] Add a $private permission flag. --- phases/ephemeral/witx/typenames.witx | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/phases/ephemeral/witx/typenames.witx b/phases/ephemeral/witx/typenames.witx index 43cb61ff..1ce283dd 100644 --- a/phases/ephemeral/witx/typenames.witx +++ b/phases/ephemeral/witx/typenames.witx @@ -505,6 +505,12 @@ ;;; concept of "executing" the host filesystem has. ;;; This flag is not valid for directories. $execute + + ;;; For filesystems which have a concept of multiple "users", this flag + ;;; indicates that the file is only accessible by the effective "user" + ;;; that the WASI store uses to access the filesystem, and inaccessible + ;;; to other "users". + $private ) ) From 8eb491172135f516c149adf07dc46ece373f4978 Mon Sep 17 00:00:00 2001 From: Dan Gohman Date: Fri, 13 Dec 2019 06:36:02 -0800 Subject: [PATCH 6/7] Ensure that $permissions is declared before it's used. --- phases/ephemeral/witx/typenames.witx | 48 ++++++++++++++-------------- 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/phases/ephemeral/witx/typenames.witx b/phases/ephemeral/witx/typenames.witx index 1ce283dd..d30ca8f3 100644 --- a/phases/ephemeral/witx/typenames.witx +++ b/phases/ephemeral/witx/typenames.witx @@ -459,30 +459,6 @@ ;;; Number of hard links to an inode. (typename $linkcount u64) -;;; File attributes. -(typename $filestat - (struct - ;;; Device ID of device containing the file. - (field $dev $device) - ;;; File serial number. - (field $ino $inode) - ;;; File type. - (field $filetype $filetype) - ;;; File permissions. - (field $permissions $permissions) - ;;; Number of hard links to the file. - (field $nlink $linkcount) - ;;; For regular files, the file size in bytes. For symbolic links, the length in bytes of the pathname contained in the symbolic link. - (field $size $filesize) - ;;; Last data access timestamp. - (field $atim $timestamp) - ;;; Last data modification timestamp. - (field $mtim $timestamp) - ;;; Last file status change timestamp. - (field $ctim $timestamp) - ) -) - ;;; File permissions. This represents the permissions associated with a ;;; file in a filesystem, and don't fully reflect all the conditions ;;; which determine whether a given WASI program can access the file. @@ -514,6 +490,30 @@ ) ) +;;; File attributes. +(typename $filestat + (struct + ;;; Device ID of device containing the file. + (field $dev $device) + ;;; File serial number. + (field $ino $inode) + ;;; File type. + (field $filetype $filetype) + ;;; File permissions. + (field $permissions $permissions) + ;;; Number of hard links to the file. + (field $nlink $linkcount) + ;;; For regular files, the file size in bytes. For symbolic links, the length in bytes of the pathname contained in the symbolic link. + (field $size $filesize) + ;;; Last data access timestamp. + (field $atim $timestamp) + ;;; Last data modification timestamp. + (field $mtim $timestamp) + ;;; Last file status change timestamp. + (field $ctim $timestamp) + ) +) + ;;; User-provided value that may be attached to objects that is retained when ;;; extracted from the implementation. (typename $userdata u64) From da7fef3a1012227457b1f4ccad8ed38ee42c3462 Mon Sep 17 00:00:00 2001 From: Dan Gohman Date: Mon, 16 Dec 2019 06:36:25 -0800 Subject: [PATCH 7/7] Clarify a Note about a relationship to POSIX. --- phases/ephemeral/witx/typenames.witx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/phases/ephemeral/witx/typenames.witx b/phases/ephemeral/witx/typenames.witx index d30ca8f3..aac53061 100644 --- a/phases/ephemeral/witx/typenames.witx +++ b/phases/ephemeral/witx/typenames.witx @@ -469,7 +469,7 @@ ;;; within the directory. ;;; ;;; Note: This is similar to the read bit being set on files, and the - ;;; read *and* execute bits being set on directories. + ;;; read *and* execute bits being set on directories, in POSIX. $read ;;; For files, permission to mutate the file.