Client: The systemd `keybase.mount` should not use the root directory

Created on 24 Dec 2017  Â·  17Comments  Â·  Source: keybase/client

I just installed the linux client and noticed that there is a fuse mount in /

$ ls -ld keybase
dr-x------ 1 root root 0 Dec 23 14:37 keybase/

$ mount | grep keybase
/dev/fuse on /keybase type fuse (rw,nosuid,nodev,relatime,user_id=1000,group_id=1000)

$ tree keybase/
keybase/
├── private
│   └── gdahlm
├── public
│   └── gdahlm
└── team

This behavior Violates the well established Filesystem Hierarchy Standard

The Root Filesystem
Applications must never create or require special files or subdirectories in the root directory. Other locations in the FHS hierarchy provide more than enough flexibility for any package.

It breaks if a host happens to have multiple authenticated users

jenkins@host:~$ ls /keybase 
ls: cannot access '/keybase': Permission denied

As this directory is in an improper location it may:

  • Be overly constrained by base apparmor profiles.
  • Run unconstrained, limiting the protections provided by these systems.
  • Potentially run in an un-encrypted root partition.
  • Fail to even run on systems where security is a concern which run a read-only root.
$ file `which run_keybase`
/usr/bin/run_keybase: Bourne-Again shell script, ASCII text executable

Note in the /usr/bin/run_keybase there is no option relocate this fuse mountpoint, yet it would be easy to leverage the XDG methods you are using to auto locate this fuse mount from application and your code.

start_background() {
  export KEYBASE_RUN_MODE="${KEYBASE_RUN_MODE:-prod}"
  export KEYBASE_DEBUG=1
  logdir="${XDG_CACHE_HOME:-$HOME/.cache}/keybase"
  mkdir -p "$logdir"

  echo Launching keybase service...
  # We set the --auto-forked flag here so that updated clients that try to
  # restart this service will know to re-fork it themselves. That's all it does.
  keybase -d --log-file="$logdir/keybase.service.log" service --auto-forked &>> "$logdir/keybase.start.log" &
  echo Mounting /keybase...
  kbfsfuse -debug -log-to-file /keybase &>> "$logdir/keybase.start.log" &
  echo Launching Keybase GUI...
  /opt/keybase/Keybase &>> "$logdir/Keybase.app.log" &
  write_startup_token "background"
}

Most likely this content _probably should_ be located under the $XDG_RUNTIME_DIR

$XDG_RUNTIME_DIR defines the base directory relative to which user-specific non-essential runtime >files and other file objects (such as sockets, named pipes, ...) should be stored. The directory MUST be >owned by the user, and he MUST be the only one having read and write access to it. Its Unix access >mode MUST be 0700.

Note: that there is a far more serious issue with this method and the systemd keybase.mount method that instantly caused me to remove this software, and avoid using it with a client.

$ systemctl stop keybase.moun
$ ls -ld /keybase/
drwxrwxrwx 2 root root 4096 Dec 23 14:37 /keybase/

When the service is stopped it leaves a directory, that will be referenced for security and encryption in a system level directory with a 0777 mode!!

By just following the long existing file system standards the risks of a huge security hole like this would be partially mitigated by other controls. But because best practices of the FHS and XDG standards are ignored the keybase team will take on all responsibilities for hardening and auditing.

Most helpful comment

What happens if keybase-mount-helper , the keybasehelper user, /keybase and /var/lib/keybase/ are not installed by the distro packaging? Does keybase simply create the hierarchy in $XDG_DATA_HOME/without these legacy symlinks, or does it error out due to missing assumptions?

Currently the keybase package in the official Arch Linux repos only installs the keybase binary (which is its own problem as the latest versions completely fail to function if the keybase service system-managed instance is not running), but I would like to look into updating it to provide kbfs etc. as well. I have no interest in installing a SUID binary running as yet-another-system-user just to create a deprecated one-user-only workaround for, as was stated above, a documentation issue.
(The GUI would be nice, if I could figure out how to build it without pulling in a prebuilt electron package.)

All 17 comments

Another report for this. It's about time to do something about it, isn't it?

As this appears to be a core design decision by keybase.io and seems unlikely to change; I have created an Apparmor profile gist which may help mitigate the issue. But it will place the burden of modifying the keybase code on the user if they want it to function.

My client lost confidence in Keybase.io due to this _mandatory_ application behavior, as they view it as circumventing operating system security measures. I was asked to write profiles which will _blacklist_ the application.

Due to contract restrictions I am unable assist in filing security vulnerabilities under bug bounty systems. If someone wants to file a full POC it wouldn't take much time and you may make some money.

_Hint: Dig around CVEs related to media mounting and note the resulting mitigation, especially those responsible for emitting devices automatically and the facilities that have been written to reduce the attack surface. Consider the context of a jump/bastion host with multiple users._

It is bizarre for a _security_ software company to make design choice to abandon OS vendor standards, protections, and controls by ignoring hierarchical namespace rules merely to....I don't know...simplify documentation?

Thank you for the detailed feedback. We are looking into it

Not sure if related, but, recently setup a Keybase account. While working on my local system, noticed that when performing actions via sudo su - that there was a /keybase directory at the root of my file system with the following ...

$> find / -name '*something*'
...
find: ‘/keybase’: Permission denied
...
$> ls -lah / | grep key
ls: cannot access '/keybase': Permission denied
d?????????   ? ?    ?       ?            ? keybase

Comparatively speaking, as the primary logged-in user _(who has sudo permissions)_ ...

$> ls -lah / | grep key
dr-x------   1 root root    0 Dec 26 02:11 keybase
$> ls -lah /keybase
dr-x------ 1 user root 0 Dec 26 02:11 private
dr-x------ 1 user root 0 Dec 26 02:11 public
dr-x------ 1 user root 0 Dec 26 02:11 team
$> _

I went through the motions of enabling and logging in as root, and got the same as sudo su - from a user account with sudo permissions. _(And then disabling root login, etc.)_

This is completely unacceptable. Not one of those: "_Oh, hey, feature, not bug, we'll get around to it when we decide not to_" type of situations.

You do not do this. I don't have the time or capacity to take @gdahlm up on fulfilling a bug-bounty or CVE — but more significantly, this should simply not be allowed except on LFS type systems _(where users haven't yet configured core security)_. It is not a rational decision to implement circumvention like this when you run an open-source repository and don't know what you're doing, or why you're doing it. Especially when that open source repository has anything to do with "social media" implications.

It would be really nice if various distros could get together and altogether BAN seemingly "trusted" keys from allowing 3rd party private repos that perform insecure actions. _(I haven't read any mailing lists related to this recently, but, probably the very reason why major distros distrust and won't allow Keybase as a distro-managed package.)_

To follow up on this: I understood you want to establish a globally unique filesystem tree where people can send pathnames to each other to reference files in /keybase and everyone can access those files by the same path name. So far so good.

Then I think the solution is quite easy: Think about the AFS filesystem or /media on Linux. In the first case, we have a globally distributed filesystem with a unique tree, too. Every site here is responsible for exactly one subtree inside /afs (or \\afs on Windows), namely /afs/some.domain.com. /media is smilar, in the sense that each user has their own subtree /media/someuser under which they mount their devices, but they do not manage /media themselves.

Now, the solution to the problem could simply be to provide a system-wide server process to manage /keybase instead of a per-user process. The individual users could then simply ask that service to mount their directories below /keybase (or /srv/keybase or /mnt/keybase). That would make Keybase truly multiuser and provide the globally unique tree. Guess this could even work on Windows...

yeah..... why not use /media/keybase or /mnt/keybase if you want people to be able to share file paths universally.

imo, if I send /keybase/public/dabura667/myfile.txt to a windows user they have to convert it to K:\keybase\public\dabura667\myfile.txt and there's a high chance their notepad or whatever will choke on my text file because Windows uses CRLF instead of LF linebreaks...

iow, universal compatibility is a pipe dream.

Linux and Mac should switch to /media/keybase/...

K: drive for Windows should be fine as is as I understand that adding drive letters is what they do with USB memory drives etc. so that's like Linux /media anyways.

As of yesterday's Linux releases (deb/rpm/AUR), the actual mountpoint for KBFS now resides at ~/.local/share/keybase/fs. This is primarily to fix the security issue of the world-writeable /keybase directory when nothing is mounted. But it also allows for multiple OS users to each have their own mount.

However, we still maintain a symlink at /keybase that points to the mountpoint of the first user to run run_keybase on the system. I understand this is controversial, but at this time we don't want to break compatibility with existing third-party applications that already depend on the /keybase path. This might be something we'll revisit in the future with a more careful plan for deprecating that old path, if we decide it's the best thing for our official packages.

More details:

  • Package installation now creates a keybasehelper system user.
  • A new binary, with SUID to keybasehelper, is installed at /usr/bin/keybase-mount-helper.
  • Package installation changes /keybase to be a symlink to /var/lib/keybase/mount1, which is owned by keybasehelper.
  • The first user to run run_keybase launches keybase-mount-helper, which turns /var/lib/keybase/mount1 into a symlink to ~/.local/share/keybase/fs (or $XDG_DATA_HOME/keybase/fs, if that is set).
  • Note you can also change the location of this mountpoint with keybase config set mountdir <abs_path_to_mountdir>.
  • Other users who run run_keybase will get their own ~/.local/share/keybase/fs mountpoint, and will see a message encouraging them to link it to ~/keybase if they so desire.

Please let me know if you see any security issues with this scheme.

A similar plan is coming to macOS soon as well, though that platform doesn't have the same security issue as far as I know, as it doesn't rely on a world-writeable /keybase.

That is an acceptable solution.

I'm not interested in re-installing or willing to test, but, all of the steps outlined make sense.

Of course, I would encourage an earlier removal of clutter — earlier depreciation of /keybase — rather than later. _(So that 3rd party apps are not further built on it or come to rely upon it.)_ Simply put: The longer cluttering-up the root file system remains, the more issues can be built upon it later.

Thanks for all your input!

What happens if keybase-mount-helper , the keybasehelper user, /keybase and /var/lib/keybase/ are not installed by the distro packaging? Does keybase simply create the hierarchy in $XDG_DATA_HOME/without these legacy symlinks, or does it error out due to missing assumptions?

Currently the keybase package in the official Arch Linux repos only installs the keybase binary (which is its own problem as the latest versions completely fail to function if the keybase service system-managed instance is not running), but I would like to look into updating it to provide kbfs etc. as well. I have no interest in installing a SUID binary running as yet-another-system-user just to create a deprecated one-user-only workaround for, as was stated above, a documentation issue.
(The GUI would be nice, if I could figure out how to build it without pulling in a prebuilt electron package.)

What happens if keybase-mount-helper , the keybasehelper user, /keybase and /var/lib/keybase/ are not installed by the distro packaging? Does keybase simply create the hierarchy in $XDG_DATA_HOME/without these legacy symlinks, or does it error out due to missing assumptions?

KBFS itself does not depend on the distro packaging. Keybase provides its own scripts for the official packages, post_install.sh and run_keybase, that manage the dir layout. I _believe_ those scripts would show warning messages but not fail outright if the keybasehelper stuff wasn't available, but I haven't tested it. In any case, a distro can always replace those scripts with custom ones if they don't do the right thing. We'd also probably accept patches to them.

Thanks, so does that mean that kbfsfuse just uses ~/.local/share/keybase/fs as the default on firstrun, or would that actually have to be reimplemented in some wrapper script?

The run_keybase script is definitely something I'd like to avoid anyway, as it seems to do too much and contains hardcoded assumptions about how the keybase gui is started which would not play nicely with using a system electron...

Thanks, so does that mean that kbfsfuse just uses ~/.local/share/keybase/fs as the default on firstrun, or would that actually have to be reimplemented in some wrapper script?

Yes, if no mountpoint is passed in on the command line and $XDG_DATA_HOME isn't set, KBFS uses ~/.local/share/keybase/fs as the mountpoint.

Is there a reason kbfs has its own repo and its own release tagging schedule, but the systemd unit kbfs.service is contained in the client repo?

Sorry, historical reasons only. I'll try to keep the kbfs tags updated as we do releases, but it's not automated so it'll rely on me remembering to push a tag.

I see. I wasn't sure whether it made sense to download the kbfs and client archives, using different versions, just to grab the service file. But it might make sense to move kbfs-specific packaging resources into the kbfs repo anyway.

As of today's Linux release, we've adopted a new strategy for dealing with /keybase: by default we now mount a "root redirector" process there, run with a suid-root binary, that sends users to their own private mounts. The redirector binary is very limited in what it can do, and of course is open source.

There is also a way of turning off the root redirector if you don't like it, so that Keybase won't touch the root of your local FS. See the "Mountpoints" section here: https://keybase.io/docs/kbfs/understanding_kbfs

Was this page helpful?
0 / 5 - 0 ratings