New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Sharp edges of the current capability system #16
Comments
WASI has fine grained sub-filedescriptor capabilities ("rights"). It does not perform DAC or MAC (though it may run on platforms which perform DAC or MAC beneath it). The "tcpdump" strategy with I agree, it'd be very useful to have more documentation on the capability model! Would you be interested in starting such a document? |
Can an application A which obtained capability set X (of type
I'm not feeling well versed in WASI yet (therefore my uneducated reactions and questions), so I'm afraid this wouldn't be a wise choice (also I'm UTC+1, which seems less than optimal for WASI 😉). |
Currently there is no way to copy a capability; it may be something we could add, though there are some subtle questions (does a copy of file capability share a file offset with the original? If so, that's maybe surprising and awkward; if not, we go against POSIX). Also there isn't an API for starting a new application yet. Other than those issues, yes, what you describe would work. Also, if there's anything that we can change to make participation easier for people in other timezones, please let us know. |
Actually, that's an interesting point, because it highlights some of the problems in POSIX's file abstraction, and subtle differences between its model and WASI's ocap model. In POSIX, the file descriptor returned by an C++ APIs tend to go around the duality by having two methods per I/O feature: one that takes a filename, and one that takes a std::istream object. However, you can't pass filenames around in wasi, by design. So the following code: void foobar(const std::string& filename) {
int lineCount = getLineCount(filename);
auto data = parseData(filename);
// ...
} might get replaced by: void foobar(File file) {
int lineCount = getLineCount(file);
auto data = parseData(file);
// ...
} except the code above doesn't work, because One solution is to place a A better solution would be to allow functions to take file descriptors without mutating their contents and offsets, ideally in a way guaranteed by the type system. Of course, that wouldn't be possible in many cases (eg pipes and sockets), but it would be useful when dealing with a filesystem. Another solution would be to differentiate a file capability from its contents: File myFile = open_at(myDir, "foobar");
Stream myFileStream = get_stream(myFile);
read(myFileStream, data); void foobar(File file) {
int lineCount = getLineCount(get_stream(file));
auto data = parseData(get_stream(file));
// ...
} |
@PoignardAzur Why can't |
Sure, that works, and it's basically equivalent to my use of get_stream above. The standard would have to define semantics for what happens when
The second one would allow a tightening of a file descriptor's capabilities, without impacting code using that file descriptor. |
Duplicating listening stream sockets and datagram sockets is immensely valuable. |
Also, expressed in libc terms, |
Ok, never mind the post above, then. This does bring back to the problem @sunfishcode pointed out, which is that, using POSIX |
So, after considering the problem, I think the use cases need to be hashed out. Basically, we're considering two types of duplications: one that makes a shallow copy of a file descriptor, and one that makes a deep copy of it (from the point of view of virtual tables; from the IO point of view, they're both shallow). Making a deep copy is useful for ocap purposes, but making a shallow copy is what POSIX does and has existing use cases (and is the only possible option for sockets and similar objects). @npmccallum: would you say there are common/important use cases, that require making a shallow copy of a file descriptor (eg both copies share a file offset), except for the "copy to stdin/stdout, then fork/execve" use case? Because if the only major use case is process forking, then I suggest the following implementation:
You'd also want the ability to borrow/move a non-copyable fd and constrain the rights given to it, in a way that doesn't affect the code passing that fd if it wants to do more with it when you're done. |
In follow-up to my noob question on wasmcap I'll drop in references here to other innovative work wrt capability systems (copying from the comment text):
|
So far it seems the most advanced practical capability system is Capsicum. I think it would be nice to correlate their API with WASI API just to avoid some potential mistakes (see e.g. fine grained sub-filedescriptor capabilities, rough comparison of cap systems in 2010, and an example of Capsicum in tcpdump).
Also other capability systems shall be compared in detail with WASI for the same reasons.
In the end an overview of currently existing practical capability systems made of some high-level points from the thorough detailed comparison could help WASI in adoption.
The text was updated successfully, but these errors were encountered: