Dropbox and filesystem compatibility §
On the 10th of August, Dropbox announced that their Linux client will "soon" stop working on any filesystem that's not ext4. Their argument for this new limitation (thereby excluding XFS, Btrfs, etc.) was:
One of our requirements is that the Dropbox folder must be located on a filesystem that supports extended attributes.
A supported file system is required as Dropbox relies on extended attributes (X-attrs) to identify files in the Dropbox folder and keep them in sync. We will keep supporting only the most common file systems that support X-attrs, so we can ensure stability and a consistent experience.
This, of course, is pure bullshit for several reasons. These days nearly all popular Linux filesystems support xattrs and so far Dropbox has worked without any problems on them, littering its
com.dropbox.attributes everywhere. (And—as far as I know—Linux xattrs as a feature came along with XFS in the first place, which makes this argument doubly ridiculous.)
Instead, I have reasons to believe that the cause of this new policy was other filesystems' incompatibility with the way Dropbox attempts to encrypt (obfuscate) its on-disk configuration, including the network credentials.
Dropbox started doing so in 2011, after one Derek Newton posted an article on his blog complaining about how someone could, having gained access to your computer, simply make a copy of your config.db and forever have access to your Dropbox that way.
[…] Here’s the problem: the config.db file is completely portable and is *not* tied to the system in any way.
The blog post was rather alarmist, having no concrete suggestions other than
Don’t use Dropbox and/or allow your users to use Dropbox, and somewhat implying that other products weren't vulnerable to this and it was all Dropbox's fault. In other words, it had all the right properties to cause public outrage. (Perhaps unusually, HN did not take the bait.)
Soon after that happened, Dropbox pushed out a new version which encrypted the configuration file with a host-specific identifier. This was easy on Windows, as DPAPI already had a function called CryptProtectData() just for this purpose. However, the available methods on Linux were far more limited – no decent account-specific credential storage (libsecret wasn't around until next year, and is of very limited use outside GNOME even today); no decent host identifier (/etc/machine-id didn't exist, and they probably didn't want to depend on dbus-daemon being present). Fortunately they didn't do something quite as stupid as binding to the MAC address, but the method they ended up choosing turned out to be almost as bad.
The (possible) actual reason
The Dropbox client uses two filesystem properties to generate a per-host encryption key: the inode number of
~/.dropbox/instance1/ and the fsid of the filesystem that the directory resides on. The first part is not too bad (nearly all Linux filesystems have permanent inode numbers) and probably would have been sufficient on its own to avoid simple copy&pasting. The second part is where the trouble lies.
statvfs() on a path will give you
struct statvfs with various filesystem parameters, mainly disk space currently used and available (this is used by
df). One of the remaining fields is
f_fsid, described vaguely as "Filesystem ID". As seen in the documentation of statfs(2) (which is the underlying Linux syscall):
The general idea is that f_fsid contains some random stuff such that the pair (f_fsid,ino) uniquely determines a file. Some operating systems use (a variation on) the device number, or the device number combined with the filesystem type. Several operating systems restrict giving out the f_fsid field to the superuser only (and zero it for unprivileged users), because this field is used in the filehandle of the filesystem when NFS-exported, and giving it out is a security concern.
The problem is, nowhere is it specified that this filesystem ID will remain static through the lifetime of that filesystem. An encryption key has to remain fixed, otherwise of course it will fail to decrypt the data – so if the fsid ever changes on its own, all Dropbox configuration suddenly becomes inaccessible and you get prompted to reauthenticate, re-link the computer, reindex and so on.
And that's exactly what happens with, say, XFS. If you check the fsid of an XFS filesystem, you'll notice that it's not a random code as with ext4; instead it's only based on the underlying device node's "major/minor" numbers:
$ stat -f ~/.dropbox/instance1 File: "/home/grawity/.dropbox/instance1" ID: 80300000000 Namelen: 255 Type: xfs Block size: 4096 Fundamental block size: 4096 Blocks: Total: 242021853 Free: 132274009 Available: 132274009 Inodes: Total: 484083200 Free: 481465381
Aside from the obvious problem of not actually being different between hosts, it simultaneously has the opposite problem of (not necessarily, but often) changing across reboots on the exact same host. For example, when my laptop had its Linux root disk in the CD-tray slot (with the old HDD being internal) the ID was
80400000000. As soon as I switched the disks around, the filesystem ID changed and I had to reconfigure Dropbox anew and wait for it to reindex tons of files.
(At first I thought it was the database that got corrupted, but no matter what backups I'd restore the client would just quietly delete all configuration upon starting it. Since I really wanted to avoid the long reindex, that's what prompted me to dig deeper into this. However, I'm certainly not the first to discover the mechanism – indeed, I simply got all information from a few GitHub repositories aimed at "Dropbox forensics", one of which even had the actual Dropbox Python code implementing the 'hostkey' storage.)
The fun part
What happened somewhere around June: While waiting for Dropbox to reindex my 80 GB of files, I was browsing the net looking to see whether anyone else had the same problem, and found a Dropbox Forum thread with someone's very similar complaint: every few reboots, all Dropbox settings would simply disappear. When I asked to compare
stat -f -c %i outputs across several reboots, the original poster soon confirmed that it was the exact same problem, and went to directly contact the Dropbox support team. Unfortunately, they got a discouraging reply:
I have received a reply from our specialized team,
Unfortunately, this does not meet the minimum requirements for the Dropbox application. OpenSUSE along with the file system is not supported.
Please review our recommended minimum requirements on the following page:
We are of course always looking for user input when creating the next version of the Dropbox app. I will make sure your comments are passed along to our development team.
— Dropbox support quoted in a forum post
And pass to their development team they did. Come 9th of August, Dropbox staff announced this:
Hi everyone, on Nov. 7, 2018, we’re ending support for Dropbox syncing to drives with certain uncommon file systems. […]
— official post in Dropbox forums
So instead of looking into other ways to protect the credentials, Dropbox chose to just continue relying on undocumented, ext4-specific behavior and hope that if users go away, the problem also goes away. Dickbags.
It would be unfair to just rant about what was done without trying to come up with good alternatives for the future. (On the off chance that Dropbox developers are looking into alternative methods for protecting the hostkeys, perhaps they would welcome suggestions.)
- Instead of using the fsid + inode combination, maybe just the inode number would have been enough. It is just as difficult to reproduce as the fsid. (Which, I should note, is not very difficult with LD_PRELOAD – but it would still be at the same security level that the current method is.)
- Another form of machine identifier might be available. Nowadays most Linux systems have an UUID in
/etc/machine-id, using this would be quite portable. (FreeBSD has
/etc/hostidfor the same purpose, and other BSDs could just manually create such a file as a workaround.)
- A standard API for credential storage, such as freedesktop.org's "Secret Service" (via libsecret), might work for desktop users – at least those who aren't too unhappy with having to install GNOME Keyring, for there still aren't any alternative libsecret backends. (KDE had plans to implement this in KWallet but still haven't.) And it would be more difficult to pull off if running Dropbox on a headless system (which is officially supported and shouldn't be forgotten). Side note: I do have a libsecret backend of my own, written in Python for use on headless systems, but it's still mostly a toy project.
- A privileged daemon which holds secrets for all users (essentially like 'ssh-agent' or 'gpg-agent') would be possible, although it would need root access for everyone who wants to install Dropbox (no more installing to your homedir). But it works for KWallet.
- MAC addresses are not a good idea; they're likely change too often. (Indeed as a recent privacy-enhancing feature they often change every time you connect to a Wi-Fi network.)
- (Ironically, they could have avoided this by storing the key in – wait for it – an xattr. But perhaps this is not sufficiently secure – copying a file will often automatically include its user xattrs, in the same way that modification time is almost always preserved.)
Personally, if I was pressed to implement per-host obfuscation somehow, I would combine the inode number and /etc/machine-id. There just isn't much else to go with.
I have heard "just use rsync" and "just use nextcloud" a hundred times. Keyboard cowboys who want to tell me that again are recommended to just go away.