site  contact  subhomenews

Infrastructure in place to run each app as a separate user

September 14, 2021 — BarryK

The 'spot' user was broken in EasyOS, for the situation in which a password is entered at bootup and folders in the working-partition are encrypted. After some experimenting and lucky guesses, this problem was solved, see previous blog post:

https://bkhome.org/news/202109/fscrypt-now-works-in-user-spot.html

I have now embarked on a significant change in how EasyOS works: run any app that accesses the Internet as a non-root user. Not 'spot', but each app will run as its own user.

I got this idea a couple of years ago, when reading how Android works. This is how Android works, each app runs as a separate user. This then can be the basic mechanism for access permissions. For example, if file /etc/group has a group for "camera", like this:

camera::118:root,spot

...on the end is a comma-delimited list of users allowed to access the "camera" group.

Running an app as a non-root user also means that it can't write just anywhere in the filesystem, can be constrained to only write in its own home folder. And if required, can be prevented from reading critical files.

Of course Easy already has "crippled root" in containers, so running, say, SeaMonkey, on the main desktop as a non-root user would have to be seen as an alternative security strategy. SeaMonkey will run a little bit faster, and won't have the issues that some people have reported with running SM in a container, such as problem with network connectivity.

If each app is run as its own user, this means that EasyOS can implement a permissions management GUI like in Android. Like, do you want this app to be able to access the camera, network, audio, folders outside the "home" folder? ...etc.

So, have started to setup the infrastructure to support this. The idea is that top-level /clients folder will have these non-root users, though I would like to refer to them as "clients".

WoofQ is now defaulting to run SeaMonkey as a client. That is, it will run as user "seamonkey" and group "seamonkey". So, in woofQ, have built EasyOS, and running it, this is what is seen under /clients folder:

img1

...'rover' and 'zeus' were experiments, they may get removed. 'spot' is deprecated, may also get removed.

The idea is that each client app will have a folder under /clients, which is actually the home-folder for that app. Clicking on 'seamonkey' will show what that client has to "offer":

img2

The 'Downloads' folder is SeaMonkey's default file download and open location. Clicking on the 'seamonkey' icon will run SeaMonkey. I don't know what 'Desktop' folder is for, SeaMonkey created that automatically.

Of course, SM can still be launched in the usual way, from the "www" icon on the desktop, or via the menu. And it will run as a client, that is, as user 'seamonkey'.

As before, SeaMonkey can be changed to run either as a root user, or client 'seamonkey', via the menu "System -> Login & Security Manager". Just like before, with 'spot'.

There is a file that shows what apps are running as a client, it is file /root/.clients-status. Here it what it has on my currenly running EasyOS:

seamonkey=true

Which means that SM will run as a client. If it had "seamonkey=false", or seamonkey completely missing from the file, then SM will run as root. The "Login & Security Manager" writes to this file.

Scripts for client management are now grouped under /usr/local/clients. WoofQ runs one of these, 'setup-client', when building EasyOS, if it is chosen to run SM as a client. The main thing that the script does is create a special script for running SM, /usr/bin/seamonkey (and the original is renamed to seamonkey.bin). Here is the script:

#!/bin/sh
APPbin='/usr/bin/seamonkey.bin'
APPname='seamonkey'
DISPLAY=:0
[ -f /clients/seamonkey/.mozilla/seamonkey/a2bvafqx.default/places.sqlite ] && ln -snf /usr/lib/seamonkey/seamonkey /usr/bin/seamonkey.bin
#script to run $APPbin as a client...
ARGS=""
if [ $1 ];then
while [ "$1" ]
do
#do not put quotes around if a single word. example is "-edit" for seamonkey, the quotes stuff it up entirely...
if [ "${1/ /}" == "${1}" ];then
ARGS="${ARGS} ${1}"
else
ARGS="${ARGS} \"${1}\""
fi
shift
done
fi

if [ $(id -u) -ne 0 ]; then
exec "$APPbin" $ARGS
fi
#if inside a container, do not run as client...
if [ -f /INSIDE_* ];then
exec "$APPbin" ${ROOTOPTS} ${ARGS}
fi

#this is a method to authorize x server to run by user. works when server running.
#note: this setting does not seem to be stored in a file. it affects the currently
# running x server and will be lost when x quits.
ALLOWflg="$(xhost | grep -o ":${APPname}$")"
if [ ! "$ALLOWflg" ];then
xhost +SI:localuser:${APPname}
fi

[ $XAUTHORITY ] && cp $XAUTHORITY -f /clients/${APPname}/.Xauthority 2>/dev/null
touch /clients/${APPname}/.Xauthority
#following line is mostly there to catch any root:root files that may have got copied in...
chown -R ${APPname}:${APPname} /clients/${APPname} &
sleep 0.1
export XAUTHORITY=/clients/${APPname}/.Xauthority
export XDG_CONFIG_HOME=/clients/${APPname}/.config
export XDG_CACHE_HOME=/clients/${APPname}/.cache
export XDG_DATA_HOME=/clients/${APPname}/.local/share

#20210912 need to allow write inside encrypted fs...
which keyctl >/dev/null
if [ $? -eq 0 ];then
IDflg="$(grep -o " logon " /proc/keys)"
else
IDflg=""
fi
if [ "$IDflg" ];then
exec su -l ${APPname} -s /bin/sh -c "DISPLAY=${DISPLAY} /usr/local/clients/run-client-indirect \"$APPbin\" $ARGS"
else
exec su -l ${APPname} -s /bin/sh -c "DISPLAY=${DISPLAY} \"$APPbin\" $ARGS"
fi

This is the content of /usr/local/clients/run-client-indirect:

#!/bin/sh
#when running in fscrypt encrypted folder, need to run this so as
#to enable write-permission when logged into a non-root client.

APP="$1"; shift
ARGS=""
#[ $1 ] && while [ "$1" ]; do ARGS="$ARGS \"$1\""; shift; done
if [ $1 ];then
while [ "$1" ]
do
#do not put quotes around if a single word. example is "-edit" for seamonkey, the quotes stuff it up entirely...
if [ "${1/ /}" == "${1}" ];then
ARGS="${ARGS} ${1}"
else
ARGS="${ARGS} \"${1}\""
fi
shift
done
fi

ID="$(grep " logon " /proc/keys | head -n 1 | cut -f 1 -d " ")"
if [ "$ID" ];then
keyctl link 0x${ID} @us #link fscrypt key to user-session.
fi

exec ${APP} ${ARGS}
###end###

Have posted these technical details for whoever is interested, but from the user perspective, you just want it to work, and be easy to use.

Well, it should be easy. SeaMonkey works as normal, except that cannot save files outside its home, /clients/seamonkey. Not by default anyway.

By means of the "Login & Security Manager", you should be able to select any app to run as a client.

Testing with SeaMonkey, all is good, except for the Composer module. I use this regularly, and want to be able to edit html files anywhere. Not quite sure how to handle this -- might setup SeaMonkey-Composer to run as root only.

There are some issues to resolve, so it will be awhile before the next release. It is likely that the next release of EasyOS will have a version bump to 3.0.

I have got Chromium SFS running as a non-root user. This was a problem, see earlier posts. Will probably have it default to run as a client, so there will be a folder /clients/chromium, just like have for SM.

So, what to choose? Do you run SM as a client on the main desktop, or as "crippled root" in a container. Or... this is a possibility, run SM as a non-root client inside a container -- I don't yet know if that will work, but it sure would be the ultimate in security.  

Tags: easy