Closed Bug 1973462 Opened 1 year ago Closed 4 months ago

Private browsing data in parent process not released quickly under some circumstances

Categories

(Firefox :: Private Browsing, defect, P3)

Firefox 140
defect

Tracking

()

RESOLVED INCOMPLETE

People

(Reporter: jenwolf, Unassigned)

Details

User Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:140.0) Gecko/20100101 Firefox/140.0

Steps to reproduce:

The Firefox main process exhibits significant memory usage compared to the Edge browser. Upon initial launch, Firefox consumes approximately 500MB of RAM, while Edge starts with around 50MB. Over time, especially when opening and closing multiple private windows, the RAM usage of the Firefox main process continues to increase, reaching about 2GB within a day of usage and continues to increase. In contrast, Edge's main process releases RAM back to its initial state of 50MB when windows are closed. Additionally, when closing Firefox, all processes terminate immediately except for the main process, which takes an extended period to close and exhibits high CPU usage while attempting to release the accumulated memory.

Steps to reproduce:

1- Launch Firefox and observe the initial RAM usage (approximately 500MB in my case).
2- Open multiple private windows in Firefox.
3- Close the private windows one by one and monitor the RAM usage of the Firefox main process.
4- Continue this process for an extended period (e.g., one day).
5- Close Firefox completely and observe the behavior of the main process.

Actual results:

The Firefox main process's RAM usage increases significantly over time, reaching about 2GB and continues to increase, without effectively releasing memory when private windows are closed. The main process takes a long time to close, with high CPU usage, indicating a memory leak.

Expected results:

The Firefox main process should maintain a stable memory usage similar to Edge, releasing RAM back to its initial state when private windows are closed, and terminating promptly without high CPU usage.

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

Component: Untriaged → Performance: Memory
Product: Firefox → Core

I wanted to provide some additional details based on my observations.

The Firefox main process is currently using approximately 2 GB of RAM. Here’s a breakdown of the explicit memory usage for the main process:

1,382.02 MB (100.0%) -- explicit
├────517.51 MB (37.45%) ── heap-unclassified
├────425.27 MB (30.77%) ++ window-objects
├────234.20 MB (16.95%) ++ js-non-window
├─────42.14 MB (03.05%) ++ startup-cache
├─────41.31 MB (02.99%) ++ (24 tiny)
├─────29.44 MB (02.13%) ++ storage
├─────28.78 MB (02.08%) ++ images
├─────18.29 MB (01.32%) ++ workers/workers(chrome)
├─────15.48 MB (01.12%) ── cert-storage/storage
├─────15.05 MB (01.09%) ++ xpconnect
└─────14.55 MB (01.05%) ++ script-preloader

The significant amount of memory classified as "heap-unclassified" (37.45%) is particularly concerning, as it may indicate objects that are not being properly released.

I hope this information helps in diagnosing the memory leak issue.

I can confirm that the memory issue is related to the "heap-unclassified" category, as its usage continues to increase. Currently, the main process is utilizing approximately 2.1 GB of memory, and the explicit memory usage reflects a corresponding rise in RAM consumption.

Here’s a breakdown of the explicit memory usage:

1,530.33 MB (100.0%) -- explicit
├────624.97 MB (40.84%) ── heap-unclassified
├────456.33 MB (29.82%) ++ window-objects
├────244.20 MB (15.96%) ++ js-non-window
├─────52.96 MB (03.46%) ++ (25 tiny)
├─────42.15 MB (02.75%) ++ startup-cache
├─────31.41 MB (02.05%) ++ storage
├─────28.47 MB (01.86%) ++ images
├─────18.29 MB (01.19%) ++ workers/workers(chrome)
├─────15.91 MB (01.04%) ++ xpconnect
└─────15.65 MB (01.02%) ── cert-storage/storage

the main process is now 2.7GB:
1,851.41 MB (100.0%) -- explicit
├────786.25 MB (42.47%) ── heap-unclassified
├────558.16 MB (30.15%) ++ window-objects
├────288.74 MB (15.60%) ++ js-non-window
├─────88.25 MB (04.77%) ++ (28 tiny)
├─────42.94 MB (02.32%) ++ startup-cache
├─────33.22 MB (01.79%) ++ images
├─────30.36 MB (01.64%) ++ storage
└─────23.50 MB (01.27%) ++ xpconnect

I started Firefox June 21, now the main process is 4.3GB:

3,138.99 MB (100.0%) -- explicit
├──1,230.24 MB (39.19%) ── heap-unclassified
├──1,186.84 MB (37.81%) ++ window-objects
├────443.07 MB (14.12%) ++ js-non-window
├────117.32 MB (03.74%) ++ (28 tiny)
├─────54.10 MB (01.72%) ++ images
├─────43.29 MB (01.38%) ++ startup-cache
├─────32.42 MB (01.03%) ++ storage
└─────31.71 MB (01.01%) ++ xpconnect

Why do you keep posting partial snippets from about:memory?
Please attach a memory report, if you want anybody to take a proper look at your problem.

Also, possible dupe of bug 1655255.

This is not my problem; it is a bug that affects all users and can be easily reproduced by anyone. It is **clear **that I am not attaching a memory report because the heap-unclassified is consuming a significant amount of memory, making the report unnecessary. The main process is currently using 4 GB of memory, broken down as follows:

2,827.13 MB (100.0%) -- explicit
├──1,253.59 MB (44.34%) ── heap-unclassified
├────911.47 MB (32.24%) ++ window-objects
├────384.35 MB (13.60%) ++ js-non-window
├────112.49 MB (03.98%) ++ (28 tiny)
├─────56.14 MB (01.99%) ++ images
├─────43.29 MB (01.53%) ++ startup-cache
├─────34.21 MB (01.21%) ++ storage
└─────31.60 MB (01.12%) ++ xpconnect

This indicates that the window-objects consumed some RAM temporarily and were evicted once they were no longer needed/

I reviewed the bug you referenced, and it is not a duplicate. This issue is related to memory leaks in the main process, which can accumulate to several gigabytes over the course of a day due to private browsing, where private windows can be opened and closed multiple times, and this will continue to increase. In contrast, the bug you mentioned results in only a few hundred megabytes of memory usage from opening a few tabs (assuming normal browsing), which is relatively minor.

Flags: needinfo?(mozilla)
Summary: Memory Leak in Firefox Main Process → Memory Leak in Firefox Main Process: Repeated Opening and Closing of Private Browsing Windows Over Extended Periods

I have been testing version 141.0.0.299 (RC2) for the past two days and have noticed some improvements:

  1. Memory Usage: The main process now starts at 300 MB, down from the usual 500 MB, even with 8 windows open.

  2. RAM Consumption: After opening and closing multiple private windows, the main process only consumes 1 GB of RAM, whereas it typically reaches 2GB at this stage.

  3. Heap Unclassified Memory: The heap-unclassified memory for the main process has decreased to 25.50% of the total usage, compared to the previous 45%.

However, there are still issues that need to be addressed, as the memory leak is still present. I will continue to monitor the performance and will report back if I notice any further differences.

Flags: needinfo?(mozilla)

I believe this extreme memory leak may be due to local storage and data retained in RAM for private browsing windows, which are not being fully released upon closing these windows. A potential workaround could involve starting a new process to serve as a memory holder for private browsing. This process could then be closed when the private windows are closed, which would help manage memory more effectively.

Flags: needinfo?(jlink)

If my previous analysis is accurate (comment 10), this presents a potential security risk. Data from private browsing sessions may still remain in RAM after closure, allowing anyone with elevated permissions to dump the memory of the main process and access sensitive information from previous private browsing activities.

Firefox does launch new content processes for sites in private browsing mode. You can watch your process list output when you browse to the same site in a regular window and a private window. Each will generate a content process.

(In reply to Eddie Carswell from comment #12)

While Firefox does initiate a new process for private browsing, similar to normal browsing, it does not create a new process for each private window or tab. This behavior is governed by the dom.ipc.processCount.webIsolated setting.

As I mentioned in my previous comment, local storage and cookies are not stored on disk but rather in RAM. Typically, these data are saved in 'C:\Users\<your Windows login username>\AppData\Roaming\Mozilla\Firefox\Profiles\<profile_folder>\storage\default'. However, I haven't analyzed the RAM dump of the main process, but I've observed that the memory usage of the main process increases each time a private session is opened and closed. This suggests that the data, which are not saved to disk, are likely retained in the main process. It appears that Firefox does not release this data upon closing a private session.

To test this yourself, you can open two private windows. In the first window, navigate to a site and change a setting to save cookies. After closing the first window, open the same site in the second private window. You will notice that your settings are still retained in the second window, indicating that this data is indeed being stored in the main process.

Flags: needinfo?(eddiecarswell13)

After analyzing the memory dump for the main Firefox process, I have identified a critical issue: the main process retains memory associated with private browsing sessions even after these sessions are closed. This behavior poses a significant security risk, as sensitive data from private browsing activities may remain in RAM. Consequently, individuals with elevated permissions could potentially access this information by dumping the memory of the main process.

To mitigate this risk, I recommend implementing a workaround that involves creating a separate process dedicated to handling private browsing sessions. This process would manage the memory associated with private browsing and could be terminated when the private windows are closed. This approach would enhance memory management and help ensure that sensitive information is not inadvertently retained.

I will mark this bug as a security risk due to the potential exposure of sensitive data.

Summary: Memory Leak in Firefox Main Process: Repeated Opening and Closing of Private Browsing Windows Over Extended Periods → Extreme Memory Leak: Private Browsing Data Retained in Firefox Main Process, Exposing Sensitive Information

Each origin still spawns a content process (in my configuration with fission and isolation enabled), and a separate process will be spawned if it's opened in private browsing mode too. I see this in about:processes where I have two DuckDuckGo PIDs - one normal and one private. Multiple tabs for the same origin would usually be grouped in the same content process.

As for persisting data between private sessions, I haven't seen that happen in my recent experiences. Maybe the private window was closed but then a new one opened before the content processes exited. Perhaps the data would persist in that case? It seems odd that site storage for private sessions would even be in the main process and not in the private processes that were spawned.

To test this yourself, you can open two private windows. In the first window, navigate to a site and change a setting to save cookies. After closing the first window, open the same site in the second private window. You will notice that your settings are still retained in the second window, indicating that this data is indeed being stored in the main process.

Rereading this I see what you are referring to. There is only one private session active at a time. If you have two private windows open, they are in the same private session and that would be expected behavior. The changes will persist until all private windows are closed and the content processes for that session exit. After closing all private windows and checking that no private content processes remain in about:processes, you can open a new private window and see that those settings should no longer persist.

Flags: needinfo?(eddiecarswell13)

Although, if content processes are sandboxed from reading the local disk, then the main process would be the one responsible for reading and writing to local storage. That would mean that it could be caching data for private sessions as well, unless that was redirected elsewhere for private sessions.

I wonder if the main process is actually handling the local storage for private sites, and isn't garbage collecting the data after a private session closes (and all related processes exit). If so, that would be something in need of fixing, both for the memory leak and for privacy concerns.

(In reply to Eddie Carswell from comment #16)

Rereading this I see what you are referring to. There is only one private session active at a time. If you have two private windows open, they are in the same private session and that would be expected behavior. The changes will persist until all private windows are closed and the content processes for that session exit. After closing all private windows and checking that no private content processes remain in about:processes, you can open a new private window and see that those settings should no longer persist.

I want to clarify that I'm not referring to private sessions; I'm discussing the underlying process. You mentioned that data from private browsing is saved in a web-isolated process. However, this doesn't seem accurate. When you close the first window, the web-isolated process should terminate, which would imply that the data is erased, as per your claim. Yet, if you open the same site in a second window (within the same private session), the data remains accessible, which contradicts your assertion. This indicates that the data was not stored in the web-isolated process but rather in the main process. I have confirmed this by analyzing the dump file for the main process.

I would like to express my concern regarding the lack of attention this bug has received from the trigger owner. I have flagged the issue, and I believe it warrants classification as a CVE with a severity score of 9.5 or higher. This vulnerability clearly exposes private data during private browsing, even after closing the private session. It can be easily accessed by anyone through a memory dump of the main process.

I am marking this as a security bug for the moment for further discussion/investigation.

I have been following the discussion here but will need to pull in some other domain experts to help validate/evaluate the potential for a security issue.

Group: core-security
Flags: needinfo?(jlink)

Private browsing is only supposed to prevent private data from being written to disk. Somebody with root access who can read arbitrary memory of the Firefox process is not part of the threat model. If you want to protect against somebody who has access to Firefox's memory after your private browsing session but not during the session, you should restart Firefox.

Group: core-security

(In reply to Andrew McCreight [:mccr8] from comment #21)

Private browsing is only supposed to prevent private data from being written to disk. Somebody with root access who can read arbitrary memory of the Firefox process is not part of the threat model. If you want to protect against somebody who has access to Firefox's memory after your private browsing session but not during the session, you should restart Firefox.

I believe there is a fundamental issue with the logic presented. It assumes that users are aware they should close Firefox after exiting private browsing, which is not a widely known fact. In fact, there is no documentation indicating that users must close Firefox to ensure their privacy.

If this is to be treated as a normal bug, it would be essential to inform users about the need to close Firefox after private browsing sessions. Failing to do so exposes users to potential privacy risks, which contradicts the purpose of private browsing.

This would be akin to Firefox needing to warn the user not to have any malware and not to grant local attackers access to their computer to ensure the safety of their data.

While Firefox takes some steps to protect against some classes of local attackers, as well as defend against some types of processes running on the user's computer - these protections are best-effort, do not represent a defensible security boundary, and when bypassed - are not be considered a security vulnerability.

That said I agree that we definitely should not be persisting data relating to closed Private Browsing sessions in the main process - it does represent a practice that needlessly retains private data we don't need to, and uses excessive memory. Because of the way PBM is architected, as long as one window remains open, I think we need retain things; but when the last one is closed, we shouldn't? Emma has be thinking about PBM design in this area, adding her - I wonder if the incrementing of mPrivateBrowsingId could be accompanied by a wipe of data associated with lower ids?

Component: Performance: Memory → Private Browsing
Product: Core → Firefox
Summary: Extreme Memory Leak: Private Browsing Data Retained in Firefox Main Process, Exposing Sensitive Information → Private browsing data in parent process not released quickly under some circumstances

I've moved this to the private browsing component, where it is more likely to get attention, and removed the editorializing from the summary. It does sound like there is some potential for improving the privacy and memory usage for users who are using a number of private browsing sessions over a long period of time.

(In reply to Tom Ritter [:tjr] from comment #23)

This would be akin to Firefox needing to warn the user not to have any malware and not to grant local attackers access to their computer to ensure the safety of their data.

While Firefox takes some steps to protect against some classes of local attackers, as well as defend against some types of processes running on the user's computer - these protections are best-effort, do not represent a defensible security boundary, and when bypassed - are not be considered a security vulnerability.

That said I agree that we definitely should not be persisting data relating to closed Private Browsing sessions in the main process - it does represent a practice that needlessly retains private data we don't need to, and uses excessive memory. Because of the way PBM is architected, as long as one window remains open, I think we need retain things; but when the last one is closed, we shouldn't? Emma has be thinking about PBM design in this area, adding her - I wonder if the incrementing of mPrivateBrowsingId could be accompanied by a wipe of data associated with lower ids?

I'd expect that if we switch to a model with incrementing private browsing ids, the moment one is no longer in use we'd purge data for it. However having multiple private browsing ids shouldn't really change anything here. We already purge data as soon as the session ends (=the last private browsing window closes). This happens via the last-pb-context-exited message: https://searchfox.org/mozilla-central/search?q=last-pb-context-exited
Every component that holds PBM data is responsible for listening to this message and cleaning up data on private browsing session end.

I'm curious which data is actually leftover? If we can identify data persisting in memory across PBM sessions we can work on those bugs / components specifically.

My primary concern is not malware, but rather the potential for unauthorized access to sensitive data in a networked workplace. Given that anyone with admin permissions can easily access data from previous private sessions, I find it surprising that this exposure has not been classified as a CVE with a score of 10.

I have previously proposed a workaround in comments #11 and #14.

  • In comment #11, I suggested: "A potential workaround could involve starting a new process to serve as a memory holder for private browsing. This process could then be closed when the private windows are closed, which would help manage memory more effectively."

  • In comment #14, I elaborated: "To mitigate this risk, I recommend implementing a workaround that involves creating a separate process dedicated to handling private browsing sessions. This process would manage the memory associated with private browsing and could be terminated when the private windows are closed. This approach would enhance memory management and help ensure that sensitive information is not inadvertently retained."

I believe this solution could significantly improve the security of private browsing sessions and enhance memory management. I look forward to further discussions on how we can address this issue effectively.

(In reply to Jen1 from comment #26)

My primary concern is not malware, but rather the potential for unauthorized access to sensitive data in a networked workplace. Given that anyone with admin permissions can easily access data from previous private sessions,

As already explained in comment #23, actors with local access (especially admin access!) are not in the threat model. Irrespective of what remediations we might add for the issue at hand, a local admin could just replace your Firefox binaries with a malware-modified copy, install third-party software that keylogs, or any number of other things that would compromise your security/privacy without touching Firefox's memory at all.

I have previously proposed a workaround in comments #11 and #14.

You've both dumped the main process memory and complained about how much memory use there is in that process, and yet are still talking about using a different process. If you are genuinely interested in Firefox architecture, please see https://firefox-source-docs.mozilla.org/dom/ipc/process_model.html and other reading there. But TL;DR: the bug is about private data in the parent process, and switching Firefox to use multiple parent processes would be a multi-year effort for many engineers (because different browser windows talk to each other and the DOM is not threadsafe, and therefore also cannot easily be split across processes).

A much more pertinent and feasible fix here would be making sure that we expeditiously release/free/delete data relating to private browsing that is held in the parent process when the last private browsing window closes. You say that this does not happen. However, there is no detail in the bug about what data we're talking about. Put differently:

(In reply to Emma Zühlcke [:emz] from comment #25)

I'm curious which data is actually leftover? If we can identify data persisting in memory across PBM sessions we can work on those bugs / components specifically.

Given how important you believe this bug to be, please help answer this question.

Flags: needinfo?(jenwolf)

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

As already explained in comment #23, actors with local access (especially admin access!) are not in the threat model. Irrespective of what remediations we might add for the issue at hand, a local admin could just replace your Firefox binaries with a malware-modified copy, install third-party software that keylogs, or any number of other things that would compromise your security/privacy without touching Firefox's memory at all.

Actors with local access cannot replace binaries or install third-party software undetected, but they can read the RAM without detection, which is a significant concern.

You've both dumped the main process memory and complained about how much memory use there is in that process, and yet are still talking about using a different process. If you are genuinely interested in Firefox architecture, please see https://firefox-source-docs.mozilla.org/dom/ipc/process_model.html and other reading there. But TL;DR: the bug is about private data in the parent process, and switching Firefox to use multiple parent processes would be a multi-year effort for many engineers (because different browser windows talk to each other and the DOM is not threadsafe, and therefore also cannot easily be split across processes).

As JFK once said, "We choose to go to the moon in this decade and do the other things, not because they are easy, but because they are hard."

A much more pertinent and feasible fix here would be making sure that we expeditiously release/free/delete data relating to private browsing that is held in the parent process when the last private browsing window closes. You say that this does not happen. However, there is no detail in the bug about what data we're talking about. Put differently:

(In reply to Emma Zühlcke [:emz] from comment #25)

I'm curious which data is actually leftover? If we can identify data persisting in memory across PBM sessions we can work on those bugs / components specifically.

Given how important you believe this bug to be, please help answer this question.

Regarding your last question, if you’re asking me, I can confirm that plaintext for sites visited in private sessions may still be visible after those sessions are closed.

Flags: needinfo?(jenwolf)

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

For more information, please visit BugBot documentation.

Flags: needinfo?(tihuang)

(In reply to Jen1 from comment #28)

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

(In reply to Emma Zühlcke [:emz] from comment #25)

I'm curious which data is actually leftover? If we can identify data persisting in memory across PBM sessions we can work on those bugs / components specifically.

Given how important you believe this bug to be, please help answer this question.

Regarding your last question, if you’re asking me, I can confirm that plaintext for sites visited in private sessions may still be visible after those sessions are closed.

Can you provide a more detailed, specific example? What site are you using to test, and what kind of text remains? HTML markup? User input in a text field? Something else?

Flags: needinfo?(jenwolf)
Severity: -- → S3
Flags: needinfo?(tihuang)
Priority: -- → P3

A needinfo is requested from the reporter, however, the reporter is inactive on Bugzilla. Given that the bug is still UNCONFIRMED, closing the bug as incomplete.

For more information, please visit BugBot documentation.

Status: UNCONFIRMED → RESOLVED
Closed: 4 months ago
Flags: needinfo?(jenwolf)
Resolution: --- → INCOMPLETE
You need to log in before you can comment on or make changes to this bug.