Open Bug 1823139 Opened 2 years ago Updated 4 months ago

When using "always ask me where to save files", the background download uses the default downloads folder, which can undermine use of encrypted storage - should encrypt the temporary data

Categories

(Toolkit :: Downloads API, enhancement, P5)

Firefox 110
enhancement

Tracking

()

People

(Reporter: mail, Unassigned)

References

Details

(Keywords: dupeme)

Steps to reproduce:

  1. Download a file to an encrypted disk or USB drive

I'm filing this issue for Firefox, but possibly any Mozilla product that uses the same download logic suffers from this.

Actual results:

The file gets stored unencrypted in "Downloads" and only afterwards is copied to the encrypted drive that the user specified.

On Linux, this is easily observable with strace:

openat(AT_FDCWD</home/niklas>, "/encrypted/mfyile.txt", O_WRONLY|O_CREAT|O_EXCL|O_TRUNC, 0644) = 55</encrypted/mfyile.txt>
rename("/home/niklas/Downloads/2P-d2Pv6.txt.part", "/encrypted/mfyile.txt") = -1 EXDEV (Invalid cross-device link)
openat(AT_FDCWD</home/niklas>, "/encrypted/mfyile.txt", O_WRONLY|O_CREAT|O_TRUNC, 0600) = 56</encrypted/mfyile.txt>

Expected results:

Firefox should follow the standard security practice of saving temporary files in the target folder.

Chrome does this correctly:

rename("/encrypted/Unconfirmed 942995.crdownload", "/encrypted/mfyile.txt" <unfinished ...>

This issue was already pointed out 4 years ago in https://bugzilla.mozilla.org/show_bug.cgi?id=1521041#c5:

But why is Firefox using the /tmp folder in the first place, would it not be better to do a tmp file in the same folder

This would probably be better, yes. Both for privacy (if you're downloading to an encrypted folder, there is probably a good reason) and for performance (renaming across file systems is slow)

The Bugbug bot thinks this bug should belong to the 'Firefox::Downloads Panel' component, and is moving the bug to that component. Please correct in case you think the bot is wrong.

Component: Untriaged → Downloads Panel

I have checked Thunderbird 102.7.2, specifically right-click -> "Save as..." on an email attachment.
Unlike Firefox, t writes the byes directly to the target file, without atomic rename.
This means it does not suffer from this break of confidentiality (leaking data onto unencrypted storage despite the user explicitly saving them somewhere else).

But the lack of atomic rename means that Thunderbird's download feature is not as robust against power loss or the disk getting full as Firefox is, so Thunderbird will save corrupt (truncated) data in such situations.

(In reply to Niklas Hambüchen from comment #0)

Steps to reproduce:

  1. Download a file to an encrypted disk or USB drive

Download how, exactly? And where/when is Firefox set up to use the encrypted disk or USB drive?

Starting from the default configuration, if you set the encrypted volume as the default downloads directory using Firefox's settings, I would expect the file to not be saved anywhere else.

So presumably either you are doing something else (e.g. picking a location for each download or similar?), or there's a bug somewhere. But either way without more details about what exactly you mean by "download a file" (given there are about 42 different ways of doing that in Firefox), it's hard to be sure what is happening.

Flags: needinfo?(mail)

Yes, picking the location for the download using the location picker (setting "[x] Always ask you where to save files", as otherwise the user can't choose the download location) - sorry for being vague, I considered that the main way to download a file "to" a user-chosen location.

I'm not setting the encrypted volume as the default downloads directory, since such USB drive is not always attached.

Flags: needinfo?(mail)

Thanks for the added detail.

Honestly, it's not clear to me what Chrome does here. Because for both Firefox and Chrome, the download starts while the "choose where you want to save the file" dialog is shown, and the bytes need to go somewhere, so "just" creating the temp file in the destination is not actually possible until the user tells the browser what the destination folder is, and so the question is about what happens before that. Once you accept the dialog, the file is moved to the destination directory (even if not yet complete), IIRC.

At least on my quick tests on a Linux VM I don't see chromium either writing to disk or increasing resident memory. Yet if I leave the dialog up long enough, once I accept it, the entirety of e.g. a 512mb file is right there in the destination. Computers are great but they're not magic - the bytes need to be somewhere, before the download completes. So presumably I'm not looking in the right places to see what chromium is doing here (and unfortunately I have limited time to dig into this issue). Storing the entire download in memory (when the user may not be at the computer and the file may be quite large) has obvious downsides. If chromium uses a disk-backed (swap) mechanism, that presumably has similar downsides to the ones complained about in comment 0?

Speaking of which, it'd still be useful to understand those downsides a bit better, to evaluate if/how to address this. What is the threat model you're using here, exactly? Unless the default download directory you've set is world-readable, given the file is moved as soon as you pick a target location, under what circumstances is the fact that it is saved elsewhere initially a problem?

Flags: needinfo?(mail)
Keywords: dupeme
Summary: Firefox buffers downloads outside selected folder, subverting encrypted storage → When using "always ask me where to save files", the background download uses the default downloads folder, which can undermine use of encrypted storage

what Chrome does here

I think I figured that out now.
Indeed I was wrong, Chrome does the same thing as Firefox:

[pid 977709] openat(AT_FDCWD</home/niklas>, "/tmp/.org.chromium.Chromium.NcdyxO", O_RDWR|O_CREAT|O_EXCL, 0600 <unfinished ...>
[pid 977709] close(183</tmp/.org.chromium.Chromium.NcdyxO> <unfinished ...>
[pid 977709] <... openat resumed>)      = 183</tmp/.org.chromium.Chromium.NcdyxO
[pid 977709] openat(AT_FDCWD</home/niklas>, "/tmp/.org.chromium.Chromium.NcdyxO", O_RDWR <unfinished ...>
[pid 977709] <... openat resumed>)      = 183</tmp/.org.chromium.Chromium.NcdyxO>
[pid 977709] pwrite64(183</tmp/.org.chromium.Chromium.NcdyxO>, "PK\3\4\n\0\0\0...

So I can see the writes to disk on Linux (pwrite64 syscall).

The first temp file "/tmp/.org.chromium.Chromium.NcdyxO" is not to me even as root via plain ls, but it is also not showing as (deleted) in lsof or ls -l /proc/977709/fd. I suspect that Chromium's sandbox (or on this machine, Ubuntu Snap's sandbox) uses Linux User Namespaces to create a filesystem namespace, which is why root user cannot trivially see it.

Once the user chooses the target location, it copies the bytes over to the new temporary location, then suffixed .crdownload.

Looks like I should file a Chromium issue as well :)

You're of course correct that for the "buffer downloads until the user has chosen a location" feature, either RAM or some temporary disk needs to be chosen.

What is the threat model

User downloads sensitive data onto encrypted removable media (USB drive, network mount), on a machine that does not have full disk encryption set up for the home/root partition (e.g. C:\ on Windows or /home on Unixes).
Then the laptop gets lost or stolen.
The attacker reads the sensitive unencrypted data off the laptop partition.

In this case, the user thought they were using an encryption-at-rest workflow that would usually prevent the sensitive information being recoverable, and they weren't aware that buffering to (effectively) permanent storage is done in between.

I see a couple of solutions:

  1. Disable the "buffer downloads until the user has chosen a location" feature as a sacrifice to protecting agains the above threat model by default. Drawback: Might make Firefox feel slightly less snappy because the download is started only after the user is done with the file save picker.
  2. Do the buffering into memory, bound that memory to some maximum amount. Benefit: Would address the above drawback for small files. For large files, the overall download probably takes much longer than the file picker workflow anyway.
  3. Encrypt the temporary file that's put in the default location with an in-memory symmetric encryption key. As soon as the user chooses the the location, decrypt what was downloaded so far into the .part file in the target directory.

(3) seems to address all concerns. Symmetric encryption is extremely fast compared to file and network IO.

(For example 1.9 GB/s for openssl speed -evp chacha20-poly1305 or 2.7 GB/s for `openssl speed -evp aes-256-gcm, for a single core on my older i5-4590 from 9 years ago.)

Flags: needinfo?(mail)

(In reply to Niklas Hambüchen from comment #6)

Thanks for the quick response!

what Chrome does here

I think I figured that out now.
Indeed I was wrong, Chrome does the same thing as Firefox:

Ah, ok. That's somewhat reassuring for me, at least, that there isn't some "obvious" fix for this that I was missing.

Looks like I should file a Chromium issue as well :)

If/when you do so, can you add a link into the "see also" field here (or comment)? This helps us keep track.

What is the threat model

User downloads sensitive data onto encrypted removable media (USB drive, network mount), on a machine that does not have full disk encryption set up for the home/root partition (e.g. C:\ on Windows or /home on Unixes).
Then the laptop gets lost or stolen.
The attacker reads the sensitive unencrypted data off the laptop partition.

So I'm a bit confused still. In the steps in comment 0 (I don't have a Linux device with an encrypted volume I can use to test myself), I would expect the file to not be in the unencrypted drive anymore after the user selects a destination and the download completes. Is this not the case? Because that sounds like a much more straightforward issue to address... If the rename fails with EXDEV and then we copy the file instead, I would expect it to be deleted after the copy. So it shouldn't be on the unencrypted laptop partition anymore...

Or is that working as I expect, but are you talking specifically about the use of data recovery tools on that volume, where even if the file has been deleted, some data may be recoverable? It's not entirely clear from the description.

I see a couple of solutions:

  1. Disable the "buffer downloads until the user has chosen a location" feature as a sacrifice to protecting agains the above threat model by default. Drawback: Might make Firefox feel slightly less snappy because the download is started only after the user is done with the file save picker.
  2. Do the buffering into memory, bound that memory to some maximum amount. Benefit: Would address the above drawback for small files. For large files, the overall download probably takes much longer than the file picker workflow anyway.
  3. Encrypt the temporary file that's put in the default location with an in-memory symmetric encryption key. As soon as the user chooses the the location, decrypt what was downloaded so far into the .part file in the target directory.

Thanks. These are reasonable, if non-trivial to implement, suggestions. The issues I see are that for (1) and (2), the speed with which folks can download files is gradually increasing, as fibre-to-the-premises and so on becomes more common. Even on my not particularly fast connection, the file can easily be 100s of MB before I pick a destination, possibly "worse" if there is effective transport-level gzip compression. The speed with which the user selects a destination probably depends on whether there is significant folder nesting, they want to copy a filename from somewhere else, or similar. There's no guarantee that that "pick a destination" process takes only seconds.

The encryption solution doesn't have this issue, though it adds CPU use and breaks some user flows if the browser quits or crashes before the download finishes - at that point the key would be lost and so it would not be possible to resume the download. We could potentially work around that by using a secure storage facility for the key, but of course that adds further complexity.

I would probably prefer to make that kind of thing opt-in, given the performance impact - especially because the default on Windows and macOS systems these days is that the entire main drive is encrypted anyway, so the user doesn't gain anything from double-encrypting. I expect the situation on Linux depends on the distro and various other factors.

Flags: needinfo?(mail)

(In reply to :Gijs (he/him) from comment #7)

(In reply to Niklas Hambüchen from comment #6)

  1. Disable the "buffer downloads until the user has chosen a location" feature as a sacrifice to protecting agains the above threat model by default. Drawback: Might make Firefox feel slightly less snappy because the download is started only after the user is done with the file save picker.

Bah, I misread, sorry. But this is quite difficult, actually - we often (exception is <a href="..." download=myfile.txt>) don't know it's a download until there's a full http/https connection to the target file, and we start getting data from the server. At that point, (I think) we cannot keep the connection alive indefinitely without getting the data, and aborting and restarting the request isn't necessarily going to work and/or produce the same file (or even a download at all!). That is also why it works the way it currently does, AIUI.

I would expect it to be deleted after the copy. So it shouldn't be on the unencrypted laptop partition anymore

Or [...] are you talking specifically about the use of data recovery tools on that volume, where even if the file has been deleted, some data may be recoverable? It's not entirely clear from the description.

Yes. That expectation that deleting a file resulting in the data being physically deleted from the unencrypted partition is not right.

You probably know what I mean, but for full clarity:

On both Linux and Windows, if you delete a file, the OS only deletes its entry "pointer" in the file system tree / lookup table. All the Bytes are still on disk. You can trivially recover them using standard tools such as cat or dd on the device file (these are not even sophisticated data "recovery tools", they just print the contents of a file or disk to screen). Not doing the physical erasure of the contents is what makes deletions of large files so fast.

The actual physical Bytes will only be deleted when they are re-used, e.g. when the disk fills up.

In the old days, you could re-open the file to had written, and override its contents with e.g. 0-Bytes. That's what e.g. the Unix shred tool does. Old hard drives, with simple file systems on top, would override exactly the same locations. But modern hardware and software use various approaches that can make overrides just write to other locations (e.g. wear leveling on SSDs, copy-on-write on newer file systems), so that the supposed-to-be-deleted Bytes are still there even after overrides.

That's why people use encrypted partitions: Then it doesn't matter that OSs don't actually physically delete Bytes on deletion, as everything is inaccessible to whomever steals the laptop.

because the default on Windows and macOS systems these days is that the entire main drive is encrypted anyway

This is not the case according to my research, e.g. https://www.zdnet.com/article/does-disk-encryption-slow-down-your-pc/

the system disk is encrypted by default, but that encryption uses a clear key. The encryption doesn't protect your data unless you sign in with a Microsoft account

Further, whether that feature is enabled at all also depends on the hardware you install Windows on.

I know less about macOS, but it's apparently similar: https://www.lifewire.com/encrypt-any-mac-5196664

Automatic T2 chip encryption does not require a password to decrypt by default. You’ll need to enable FileVault to require a password for decryption.

On the performance point:

opt-in, given the performance impact

My argument above is that the performance impact of encryption is negligible. Even 10-year old CPUs can perform it at > 2GB/s per core (see my numbers above); this is much faster than the speed of any download (and again, per core).

(And it cannot practically be slower than the download in most cases, as most downloads today use HTTPS so there's already decryption involved anyway.)

Also, you don't need to encrypt the entire file, only the buffered part during the display of the file picker.

gzip

Your point about gzip, perhaps surprisingly, strengthens the argument for encryption: Due to how it works, gzip decompression is much slower than encryption. For example on my machine with the 2 GB/s encryption, gzip -d's speed tops out at 200 MB/s -- 10x slower. So if gzip is involved, it is a 10x tighter bottleneck than encryption can be.

if the browser quits or crashes before the download finishes - at that point the key would be lost and so it would not be possible to resume the download

Again here, this risk only exists during the time period where the file picker popup is open. So the amount of data the user would use is only of the last few seconds.

Beyond that, Firefox today already loses this data anyway: If you kill Firefox while the download file picker is open (with the buffering going on in the background), Firefox cannot resume that aborted download, because it does not even appear in the Downloads list before the user has finished the file picker.

So this would not be a feature regression.

So in summary, for suggestion (3):

  • Encryption is very unlikely to be a bottleneck.
  • Even if it were, it is only required for a fraction of the file (during the picker dialogue).
  • The only real drawback I see is increased implementation complexity. (Though performing a streaming encryption while doing simple linear writes/reads is not super complicated.)
  • The benefit would be that Firefox can be trusted much more when downloading important files.

Let me know what you think about these points!

Flags: needinfo?(mail)

The severity field is not set for this bug.
:mak, could you have a look please?

For more information, please visit auto_nag documentation.

Flags: needinfo?(mak)

(In reply to Niklas Hambüchen from comment #9)

because the default on Windows and macOS systems these days is that the entire main drive is encrypted anyway

This is not the case according to my research <snip>
The encryption doesn't protect your data unless you sign in with a Microsoft account

Microsoft is making it harder and harder not to do this, so I still expect this to cover a growing portion of Windows users.

opt-in, given the performance impact

My argument above is that the performance impact of encryption is negligible. Even 10-year old CPUs can perform it at > 2GB/s per core (see my numbers above); this is much faster than the speed of any download (and again, per core).

Your use of "performance" is about the ultimate speed of the download; mine was about the CPU use, which is non-negligible for decent encryption (that is sort of the point).

Anyway, I think the cost/benefit here is not great. In particular:

(Though performing a streaming encryption while doing simple linear writes/reads is not super complicated.)

I don't think adding this encryption, ensuring it is strong enough (what does that mean), failsafe, and transparent to the user, and the CPU load is acceptable, is "not super complicated". And it adds benefits for people who... sometimes (but not always) use strongly encrypted data storage for some files, but don't use full disk encryption for any drive they use as the default downloads location. That's a pretty small set of people.

Anyway, we can keep the bug open, and I would consider an appropriate patch, but I don't expect people inside Mozilla are likely to have time to work on it / fix it.

Type: defect → enhancement
Summary: When using "always ask me where to save files", the background download uses the default downloads folder, which can undermine use of encrypted storage → When using "always ask me where to save files", the background download uses the default downloads folder, which can undermine use of encrypted storage - should encrypt the temporary data
Status: UNCONFIRMED → NEW
Component: Downloads Panel → Downloads API
Ever confirmed: true
Flags: needinfo?(mak)
OS: Unspecified → All
Product: Firefox → Toolkit
Hardware: Unspecified → All
Priority: -- → P5
Severity: -- → N/A

There are also UX problems caused by this.

For example, when the user is on a Linux live CD, and wants to download an Ubuntu ISO, there is not enough space in the live system for the download.

However, even if the user uses the file save dialog to store it on a separate disk with enough space, Firefox will silently fail the download, because it tries to store it on the too-small user live directory.

A 0-byte file is created. The user remains puzzled why it didn't work.

(In reply to Niklas Hambüchen from comment #12)

There are also UX problems caused by this.

For example, when the user is on a Linux live CD, and wants to download an Ubuntu ISO, there is not enough space in the live system for the download.

However, even if the user uses the file save dialog to store it on a separate disk with enough space, Firefox will silently fail the download, because it tries to store it on the too-small user live directory.

A 0-byte file is created. The user remains puzzled why it didn't work.

Please file a separate bug about this with more detailed steps to reproduce, as it is an orthogonal problem. Encrypting the data would not solve this scenario. Conversely, fixing the "the temporary destination does not have space for this download" case would not fix the encryption issue. And anyway I would have expected both an actual error message (even if not very user friendly) to be shown, and for a retry to work correctly (because at that point the download destination is set). All of this is best discussed in a separate bug with more details about the exact steps you're taking and what happens.

Flags: needinfo?(mail)

.(In reply to :Gijs (he/him) from comment #13)

it is an orthogonal problem

Partially.

The fundamental problem is exactly what the issue title says:

When using "always ask me where to save files", the background download uses the default downloads folder

If Firefox started writing bytes only to the folder the user chose as per suggested solutions (1) or (2) above, both problems would be solved.

I agree on the UX problem of lack of error messages; I filed it now as Bug 1925371.

Flags: needinfo?(mail)
See Also: → 1925371
You need to log in before you can comment on or make changes to this bug.