SecurityEngineering/NSS Startup and Shutdown in Gecko: Difference between revisions
(Created page with "----- <center><big>'''Draft'''</big></center> ----- This is an informational document outlining the modernization and simplification of NSS startup and shutdown in Gecko. It...") |
(more details on the current setup, the desired setup, and how to get there) |
||
Line 8: | Line 8: | ||
Classes in PSM implement a number of interfaces that require NSS functionality. Instantiating any of these classes causes the PSM component to be initialized. This initialization starts a few services needed by (for instance) certificate verification. It also performs the initialization of NSS. This involves calling the overall NSS_Initialize function as well as some configuration options like only enabling specific ciphersuites and loading the trust anchors for certificate verification. | Classes in PSM implement a number of interfaces that require NSS functionality. Instantiating any of these classes causes the PSM component to be initialized. This initialization starts a few services needed by (for instance) certificate verification. It also performs the initialization of NSS. This involves calling the overall NSS_Initialize function as well as some configuration options like only enabling specific ciphersuites and loading the trust anchors for certificate verification. | ||
The PSM component observes a number of events, including XPCOM shutdown. | The PSM component observes a number of events, including notification of profile changes, preference changes, and XPCOM shutdown. Upon receiving the "profile-before-change" notification, the PSM component releases all NSS resources held by PSM objects and calls NSS_Shutdown. Consequently, whenever a PSM object attempts to use an NSS resource or call an NSS function, it first must check if NSS has been shut down. This is coordinated by having such classes inherit from nsNSSShutDownObject. At each point NSS resources are used, these classes first acquire an nsNSSShutDownPreventionLock and check isAlreadyShutDown() (see nsNSSShutDown.h). | ||
On the topic of profile changes, the current implementation implies that profile switching is supported. That is, the implementation expects that Gecko may initialize NSS in one profile, shut it down, change profiles, and re-initialize NSS (all in the same process). This functionality has not been supported for a long time. | |||
As a consequence of this design, when implementing new functionality that uses NSS, it is easy to do the wrong thing. For instance, code that merely calls NSS functions but do not hold NSS resources may forget to check and prevent NSS from shutting down during the use of that function. Another common mistake is to acquire the nsNSSShutDownPreventionLock but not actually check if NSS has been shut down. These have often led to shutdown crashes (see for example [https://bugzilla.mozilla.org/show_bug.cgi?id=1114741 bug 1114741], [https://bugzilla.mozilla.org/show_bug.cgi?id=1046221 bug 1046221], [https://bugzilla.mozilla.org/show_bug.cgi?id=1029173 bug 1029173], and [https://bugzilla.mozilla.org/show_bug.cgi?id=911336 bug 911336]). | |||
=== The Desired Setup === | |||
NSS should be initialized exactly once and shut down exactly once. Code that uses it should only be able to run after NSS is guaranteed to be initialized. While such code is running, it should prevent NSS from being shut down out from under it. Once NSS has been shut down (upon notification that the entire process is shutting down), all methods that would use NSS should check for this and return an error. | |||
It should be easy to write new code that correctly deals with these restrictions. | |||
=== How to Get There === | |||
* Remove unused and/or unnecessary cruft from PSM/NSS initialization | |||
** For instance, nsPSMUITracker has already been removed: [https://bugzilla.mozilla.org/show_bug.cgi?id=1215690 bug 1215690]) | |||
** This can include the misleading profile change event handling | |||
* Begin to separate NSS-only initialization from PSM component initialization | |||
* Ensure NSS is initialized before execution reaches any code that requires it | |||
* |
Revision as of 21:23, 23 October 2015
This is an informational document outlining the modernization and simplification of NSS startup and shutdown in Gecko. It is organized in three parts: the current setup, the desired setup, and a roadmap for achieving the desired setup. If the current date is later than 1 November 2016, this document is likely out of date.
The Current Setup
Classes in PSM implement a number of interfaces that require NSS functionality. Instantiating any of these classes causes the PSM component to be initialized. This initialization starts a few services needed by (for instance) certificate verification. It also performs the initialization of NSS. This involves calling the overall NSS_Initialize function as well as some configuration options like only enabling specific ciphersuites and loading the trust anchors for certificate verification.
The PSM component observes a number of events, including notification of profile changes, preference changes, and XPCOM shutdown. Upon receiving the "profile-before-change" notification, the PSM component releases all NSS resources held by PSM objects and calls NSS_Shutdown. Consequently, whenever a PSM object attempts to use an NSS resource or call an NSS function, it first must check if NSS has been shut down. This is coordinated by having such classes inherit from nsNSSShutDownObject. At each point NSS resources are used, these classes first acquire an nsNSSShutDownPreventionLock and check isAlreadyShutDown() (see nsNSSShutDown.h).
On the topic of profile changes, the current implementation implies that profile switching is supported. That is, the implementation expects that Gecko may initialize NSS in one profile, shut it down, change profiles, and re-initialize NSS (all in the same process). This functionality has not been supported for a long time.
As a consequence of this design, when implementing new functionality that uses NSS, it is easy to do the wrong thing. For instance, code that merely calls NSS functions but do not hold NSS resources may forget to check and prevent NSS from shutting down during the use of that function. Another common mistake is to acquire the nsNSSShutDownPreventionLock but not actually check if NSS has been shut down. These have often led to shutdown crashes (see for example bug 1114741, bug 1046221, bug 1029173, and bug 911336).
The Desired Setup
NSS should be initialized exactly once and shut down exactly once. Code that uses it should only be able to run after NSS is guaranteed to be initialized. While such code is running, it should prevent NSS from being shut down out from under it. Once NSS has been shut down (upon notification that the entire process is shutting down), all methods that would use NSS should check for this and return an error.
It should be easy to write new code that correctly deals with these restrictions.
How to Get There
- Remove unused and/or unnecessary cruft from PSM/NSS initialization
- For instance, nsPSMUITracker has already been removed: bug 1215690)
- This can include the misleading profile change event handling
- Begin to separate NSS-only initialization from PSM component initialization
- Ensure NSS is initialized before execution reaches any code that requires it