Skip to content
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

File Descriptor Interface #170

Open
joshuakarp opened this issue May 28, 2021 · 0 comments
Open

File Descriptor Interface #170

joshuakarp opened this issue May 28, 2021 · 0 comments

Comments

@joshuakarp
Copy link
Contributor

joshuakarp commented May 28, 2021

Created by robbie-cronin

File Descriptor

This is a theoretically elegant way of passing capabilities around. Because of its advanced nature, it will probably only be used by advanced users like Matrix AI, or other people who really care about security.

A file descriptor is a kernel object representing/and acting like a file. But it doesn't exist on the filesystem. It's not a "named" file.

myprogramthatneedssecret --password-file /path/to/the/secret/file # we saw this with step-ca
# now with process substitution/redirection, we get a magical file descriptor
myprogramthatneedssecret --password-file <(pk secrets get blah)

Now technically this just really makes use of the shell. There's no magic supplied by polykey.

So this is elegant because it really is a principle of least privilege.

There's no secret floating around in the environment variables, nor in the filesystem, nor in the clipboard. The file descriptor is created and ONLY accessible by the program in which it was passed to. There's no way for any other program to read that file descriptor (unless they are able to break the kernel).

If another program wanted to read it, it could not. Firstly because there's no "name" for this file descriptor. The name that myprogramthatneedssecret knows is not a universal name. It's a name only local to that specific process.

Now this also allows myprogramthatneedssecret to pass that file descriptor. It is possible to use UDS to pass file descriptors between processes.

One thing though, this makes the fd read-once. It's a "single-use" place. That's good and bad. What if you wanted to be able to read multiple times? It is not possible unless you are using ZSH:

myprogramthatneedssecret --password-file =(pk secrets get blah)

However this is not as secure as before, because ZSH creates a file at /tmp, and uses that as the real file, to allow random access and repeated reads.

Also the other thing is, the file descriptor is readable as long as the myprogramthatneedssecret keeps the file descriptor open. As soon as the program closes, or explicitly closes the file descriptor, the file is not readable.

Now because we are using the shell, the idea that the descriptor is only readable by myprogramthatneedssecret is not entirely true.

Because you can do this:

#!/usr/bin/env bash

echo $$

exec 3< <(echo abc)

sleep 10000

cat <&3

And in a separate program to output cat /proc/PID/fd/3 where PID is what is echoed from the above script.

The fd however is limited to r-x------ and so it is only readable any program acting under the same user authority.

lr-x------ 1 cmcdragonkai operators 64 Jul 15 20:44 3 -> 'pipe:[10749868]'

But this is all because it is the shell that is doing the magic.

What if Polykey was doing the magic?

Then it would be possible to ensure absolute security of the file descriptor.

How would this work? 2 ways:

  1. Passing directly from parent to child
  2. Via UDS

For parent to child, this is actually similar to the environment variable situation. So you would "run" the process, while having opened an anonymous pipe, and subsequently piping the secret into the pipe and assigning to a file descriptor. However this requires passing some address in the same process space to the child process so it knows what number is the file descriptor relating to the secret. This is explained here: https://stackoverflow.com/a/21512395

This won't work for alot of programs. Because they were not designed to receive parameters referring a file descriptor number.

For UDS, this could work as well, but again relies on the idea that the receiving program knows how to use the socket. Furthermore the socket has to exist on the filesystem.

Which is why this is theoretically elegant, but practically difficult to do. Unless we are the ones writing the target program as well. So in the case of Matrix OS, this is the case where we could potentially use UDS or other stuff.

For normal use cases, it appears the process substitution/redirection is the best way to do it if you want to use file descriptors. The important idea is to realize that the secret is still readable on the filesystem if the other process knew the PID of the shell managing it, and if the fd hasn't been fully read yet, because it's a read-once fd. And also it needs to be running under the authority of the same user that is running the shell.

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

No branches or pull requests

1 participant