Skip to content
This repository was archived by the owner on Nov 25, 2025. It is now read-only.
This repository was archived by the owner on Nov 25, 2025. It is now read-only.

Semantics of path_open #8

Closed
Closed

Description

@marmistrz

Recently there was some confusion about the semantics of path_open, for instance in bytecodealliance/wasmtime#570. I'd like to raise the following issues/doubts about the current API

Semantics of the rights

TL;DR: Can the implementation return more rights than specified in path_open and what are the exact semantics of the initial rights? What are actually inheriting rights meant to be?

The inheriting rights are defined by the spec as follows:

The inheriting rights are rights that will apply to file descriptors derived from the file descriptor itself.

This suggests that the inheriting rights are the rights a child file descriptor will possess after being opened through path_open.

On the other hand, path_open accepts two parameters, fs_rights_base and fs_rights_inheriting, which are defined as

The initial base [resp. inheriting] rights of the newly created file descriptor.

This would suggest that the rights defined by fs_rights_base and fs_rights_inheriting are going to be the rights possessed by the file descriptor until some of them are dropped using fd_fdstat_set_rights.

These two modes of behavior clearly contradict with each other. My interpretation is that

  1. the inheriting rights are maximal rights which can be possessed by any child descriptor
  2. the rights possessed by a file descriptor need to be a subset of both
    a. the explicitly requested rights
    b. the parent's inheriting rights

This would mean that the implementation is not allowed to grant more rights than requested. In particular, this would imply that after calling path_open will both fs_rights_base and fs_rights_inheriting set to 0, the resulting file descriptor should have no rights. Is this correct?

In particular, wasmtime, as it's currently implemented, will grant at least one of RIGHT_FD_READ or RIGHT_FD_WRITE, even if both fs_rights_base and fs_rights_inheriting set to 0. Is this a violation of the WASI spec? We assume no rights have been explicitly dropped, for now.

Declaration of the read/write intent

TL;DR: How should the read/write intent be expressed by the API users?

In POSIX, the read/write intent is explicit and expressed by the following access modes: O_RDONLY, O_WRONLY, or O_RDWR. In WASI, __wasi_oflags_t doesn't support declaring access modes. Instead, the way it's currently used by the Rust stdlib, the read/write intent is expressed by granting the permission to execute fd_read/fd_write, cf. the source code.

This sounds unfortunate, since rights only signify permissions, not the actual possibility of carrying out an action. In other words, it should be perfectly fine to open a directory will all possible rights, including the right to execute fd_write, even though actually trying to call fd_write on the descriptor would result in an EISDIR.

The problem with this approach is that, should we treat rights as permissions, we should always open the file for all possible modes of operation and only check for permissions on fd_read/fd_write. Still, it's impossible to know whether or not a valid path points to a file or a directory and implementation of such semantics would require two syscalls to open a directory unless O_DIRECTORY is explicitly used. Moreover, such implementation would deviate from what we expect from POSIX-compliant code that a file opened for reading may not be used for writing, as it wouldn't be possible to express such intent through the API.

Is the omission of open modes in __wasi_oflags_t an oversight or was it done on purpose?

cc @kubkon @sunfishcode @peterhuene

Activity

  1. sunfishcode commented on Jul 20, 2022

    @sunfishcode
    Member

    We ended up removing the rights flags altogether, and are now using a POSIX-like o-flags argument.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions