← Back to team overview

checkbox-dev team mailing list archive

Execution as another user - requirements

 

This is a follow-up to the 'execution as another user' email.

TL;DR; This is a summary of our requirements for running stuff as another user.

== R1 ==
We need to be able to switch to another user ID.

This is pretty easy but it has some non-obvious complexities. Remember
that we are talking about a *framework*. We may be used multiple
different contexts 1) in a command line program 2) in a graphical
application on classic desktop 3) in a touch application in a
sandboxed/constrained environment 4) in a headless application running
remotely (no tty) somewhere.

Having said that we have the following options:

1) We can write a non-interpreted (e.g. compiled) setuid executable
2) We can write a system-wide DBus service
3) We can use pkexec to start a non-setuid program
4) We can use sudo to start a non-setuid program

I will discuss each option later on. For now just keep in mind that
they have different failure and interaction modes. We need to know if
something works, didn't work or is still waiting for user input.
Ideally we should also be able to know if it can be used in the first
place (without asking).

== R2 ==
We need to stay secure.

This basically means that we cannot lessen the security of a system
that has our tools installed. Neither sudo nor pkexec lessen system
security because they don't grant, automatically, any permissions out
of the box. They are also well-known and easy to administer (local
system configuration can enforce any extra constraints and
privileges).

For us security can be defined, I think, by the following two rules:

I) The part of PlainBox that runs as root will never run arbitrary
shell commands without tracing their root of trust first.
II) The part of PlainBox that runs as root will carefully sanitize the
execution environment not to allow exploiting trusted commands by
passing malicious environment variables.

Rule I is currently implemented by disallowing the user to specify the
command to execute. Instead, the trusted component picks the command
based on the checksum of the job that the user has requested. This
prevents several kinds of forgery that are traditionally possible.
Since the checksum is cryptographically secure it can be used as a
form of content signature, the user cannot perform any race attacks by
requesting a shell command from a particular job while rewriting the
definition of the job.

Rule II is currently *not* implemented because the default settings
will prevent running any commands as root without first asking for the
password of an administrative user account. It is listed here in case
we want to change that and allow password-less security elevation to
be allowed. In practice this most likely affects things like: PATH and
all the environment variables starting with the string LD_ (see
ld.so(8) for details). It can also affect any additional environment
variable that may be consumed by any command used in all the jobs that
need to run as root. I suspect it requires additional research though,
and that we should not enable this without labelling it "insecure".

== R3 ==
We need to be able to run all the jobs that can be started as a non-root user.

This means that the mechanism should allow us to see generated jobs
(local and template jobs). This may also mean that some of the jobs
are loaded from insecure locations (writeable by untrusted user
accounts). The last requirement is clearly evident when testing
development code or working on providers (when PROVIDERPATH is set to
something in $HOME, $TMP or elsewhere) and the user is working on a
job definition that requires root. Note that this cannot compromise
the security specification of R2. This is currently unspecified (how
it should work) but the requirement is worth mentioning since the only
reason we have the sudo execution controller (aka run jobs via sudo)
is for handling cases where the trusted launcher cannot be used
(because it doesn't read jobs from insecure locations).

== R4 ==
We need to be able to terminate processes that were started this way.

This is currently *not* implemented but we've learned the hard way
that we need to have this feature. The part that runs as another user
needs to stick around long enough to allow us to tell it to stop the
processes it has started. Alternatively we need a helper that we can
ask to kill any process that we've started ourselves (securely, so
that we can't use it to DOS the system by killing init, for example).
It is closely tied to the implementation of R1 but it is a separate
requirement IMHO.

I think rules R1-R4 accurately capture everything that we need to do,
that we know of. If you know about something else please reply and
comment.

That's it. I will summarize what we can do in the next email.

Thanks
ZK