Added a casper execution service. Provides an interface for user to:
- define a set of allowed executables.
- execute command if allowed, returns a file descriptor back to user.
The test file attached has an example of how to use cap_exec.
Differential D24327
Add new casper execution service yzhong_freebsdfoundation.org on Apr 7 2020, 5:32 PM. Authored by Tags Referenced Files
Details
Added a casper execution service. Provides an interface for user to:
The test file attached has an example of how to use cap_exec. Run the tests in the tests directory.
Diff Detail
Event TimelineComment Actions In the process of Capsicumizing sort(1), I found that I couldn't properly close the file descriptors that came from this service. It used to return the file descriptor of a FILE* opened via popen(3). This meant that the user can't use pclose to close the file descriptor they receive; pclose expects the same FILE * that popen returned, which the user can't recover. Pclose is responsible for waiting until the opened process ends, and if it isn't called, the user will get concurrency issues (like writing to a file, "closing" it, and then trying to read from it before the write actually finishes). Now, cap_exec comes with matching open and close functions. cap_exec_open() (previously just cap_exec) now uses pdfork(2) and pipe(2) instead of popen to run the command - the process descriptor from pdfork and the file descriptor from pipe are stored together in an internal list structure. cap_exec_close() needs the process descriptor so that it can use kqueue(2) to wait for the process to finish executing. (We can't use wait() here because this solution is implemented in the sandboxed part of the program.) I also changed the service to return FILE*s instead of file descriptors. I suspect that a common use case for this service is to replace popen, and this change makes doing that straightforward. Comment Actions I wonder we can't just use fileargs and fexecve? Do you plan to add some test cases?
Comment Actions Thinking about it more, the change to FILE* makes it somewhat unintuitive (or impossible?) to execute commands that you neither read from nor write to. Initially, I made the change because I was doing: I would appreciate any input on this issue. Comment Actions Please don't take this an a criticisms I just would like to know the advantages of this approach. In pseudo code something like: const char *filenames[] = { '/bin/cat' }; fa = fileargs_init(filenames, 1, O_EXEC, 0, ...) fd = fileargs_open(fa, '/bin/cat'); fork(); fexecve(fd, ...); Comment Actions Would such an approach work if I don't have the full path of the program to be executed? And also, do you mean that fileargs and fexecve can replace the internals of cap_exec, or that cap_exec can be discarded entirely in favour of them? I was recommended to look at cap_exec when I was working on sort, and I made fixes to it due to that - if a workable solution already exists I would not mind using that instead. One advantage of cap_exec as it is is that it can be a drop-in replacement for popen, whereas using fileargs looks like it takes more rewriting work, so its usefulness really depends on how often popen is used, I suppose. Comment Actions Note that in Casper service user interface and Casper backend are separate processes. Casper does all the work and the user interface simply passes and receives parameters.
Comment Actions Doing the work on the user interface side was a conscious decision on my part. What are the disadvantages of doing it this way? And yes, I do plan to write tests.
Comment Actions I was mistaken we need service like this, we just need to work a little bit more on it.
Comment Actions From my understanding, doing work in the user interface functions is the same as doing work in user program, as they are the same process. It won't be allowed if program is in cap mode. Comment Actions
Thats right, cap_exec_init, cap_exec_open, cap_exec_close are done potentialy in the sandboxed process.
That's right. Casper is outside the sandbox so we can do fancy things under exec_command. Comment Actions I understand what you mean. That's why I used pdfork - having the process descriptor lets me wait for the program even in Capability mode. All the current functionality works, so I'd prefer to keep things as it is unless we want the service to do more.
Comment Actions
Comment Actions It's quite interesting that even though a sandbox process is not allowed to open a file, it is allowed to close one.
Comment Actions Added some simple tests, and made changes according to feedback. The biggest change is the addition of cap_exec_t structures, which behave very similarly to fileargs_t structures in cap_fileargs. Now there is no global state on the user's side, and you can now open multiple cap_exec services without issue. |