Skip to content
This repository was archived by the owner on Jan 23, 2023. It is now read-only.

Remove FileSystemWatcher dependency from Unix X509Store#7655

Merged
bartonjs merged 2 commits intodotnet:masterfrom
bartonjs:unix_x509store_nofsw
Apr 13, 2016
Merged

Remove FileSystemWatcher dependency from Unix X509Store#7655
bartonjs merged 2 commits intodotnet:masterfrom
bartonjs:unix_x509store_nofsw

Conversation

@bartonjs
Copy link
Member

The original impetus for change was to remove the FileSystemWatcher dependency for the Unix implementation of X509Store. Since changes were being made, some tests were finally added to OuterLoop (since it involves making state changes on the filesystem). This uncovered an issue that creating new stores fails due to the directory permissions check being overly restrictive (in a way that we explicitly concluded it wasn't doing at the time of the change).

So, with the two commits:

  • Creating new stores works again
  • There are a lot of X509Store tests on Unix
  • The FSW dependency is removed, and all the associated caching and cache purge logic.

So, this reacts to #6797, fixes #6618, and fixes #3374.

cc: @stephentoub @weshaggard @atsushikan

@bartonjs
Copy link
Member Author

(@iamjasonp, you apparently just independently discovered the new store permissions problem, so... FYI, here's the fix PR)

@iamjasonp
Copy link
Member

FYI: to deal with cases where we only want tests to run sometimes, we've been using ConditionalFact. See: dotnet/wcf#978, dotnet/buildtools#619

Consider using [ConditionalFact] on the tests you know will modify the machine if you're concerned about modifying machine state

@bartonjs
Copy link
Member Author

@iamjasonp [ConditionalFact] is "in some detectable condition, do not run this test". The condition I want for non-ephemeral tests is "this isn't being called from build.cmd/build.sh", aka [OuterLoop].

@bartonjs bartonjs force-pushed the unix_x509store_nofsw branch from 5cee898 to 15c4a82 Compare April 11, 2016 19:47
@bartonjs
Copy link
Member Author

Test Outerloop Ubuntu14.04 Debug please

@stephentoub
Copy link
Member

@bartonjs, have you done any measurements to see how this impacts https performance with HttpClient when we're unable to use OpenSSL's cert verification, e.g. when the server cert callback is used?

@bartonjs
Copy link
Member Author

@stephentoub No, I haven't done any perf assessments. One call to Certificates per object is "less memory, and faster" (by a list and list copy). Multiple calls is "less memory, and filesystem v RAM slower".

Since CurlHandler doesn't open any X509Store objects itself (it uses X509Chain), it has one call per X509Store object, so it should be "less memory, and faster".

@stephentoub
Copy link
Member

Since CurlHandler doesn't open any X509Store objects itself (it uses X509Chain), it has one call per X509Store object, so it should be "less memory, and faster".

Maybe I'm just confused about the change? If we can't use the OpenSSL verification, we need to open and enumerate the root store, right? Which means whereas previously we would just access a collection in memory, now we need to enumerate the file system? So now we're enumerating the file system on every https connection, no?

@bartonjs
Copy link
Member Author

If we can't use the OpenSSL verification, we need to open and enumerate the root store, right?

Both root stores (user and machine), but yes.

Which means whereas previously we would just access a collection in memory, now we need to enumerate the file system?

X509Chain opens a new X509Store instance for each call to Build, so it was reading the filesystem into a List, registering a FSW, then copying the List out, then throwing it all away. Now it just reads the filesystem into an X509Certificate2Collection (aka List), without the other stuff.

The machine Root store is different, that one does get held as a static collection, so it's one filesystem read per process.

So now we're enumerating the file system on every https connection, no?

Yes, but we also were reading the filesystem on every https connection before this change.

@stephentoub
Copy link
Member

X509Chain opens a new X509Store instance for each call to Build, so it was reading the filesystem into a List, registering a FSW, then copying the List out, then throwing it all away. Now it just reads the filesystem into an X509Certificate2Collection (aka List), without the other stuff.

If the FSW was always getting thrown away, what was its purpose? I thought the purpose of it was to avoid needing to enumerate the file system for the machine store each time... was that not happening?

Yes, but we also were reading the filesystem on every https connection before this change.

Sure, for the user store, but now we're also always doing it for the machine store, no? Or are you saying the FSW mechanism was completely broken and we were always enumerating both the user and machine stores?

@bartonjs
Copy link
Member Author

LM\Root and LM\CA use CollectionBackedStoreProvider, which didn't change here.

The CU* stores used DirectoryBackedStoreProvider, which is changing. The cache+FSW allowed for a long-lived instance to do multiple reads of the Certificates property without having to go back to the filesystem, and that worked (to whatever extent of reliability FSW works). No part of that state was shared across instances representing the same store. So any X509Store in a using statement was paying costs with no dividends.

@stephentoub
Copy link
Member

Ah. Ok, I see now. Thanks for the explanation.

@bartonjs
Copy link
Member Author

Thanks for the explanation.

You're welcome. Thanks for caring enough to make the inquiries.

@bartonjs bartonjs force-pushed the unix_x509store_nofsw branch from 15c4a82 to a775727 Compare April 12, 2016 15:03
@bartonjs
Copy link
Member Author

Test Innerloop OSX Release Build and Test please

@bartonjs
Copy link
Member Author

(Previous run failed due to the machine going offline: http://dotnet-ci.cloudapp.net/job/dotnet_corefx/job/osx_release_prtest/3740/)

@weshaggard
Copy link
Member

I didn't dig into the code but the dependency removal looks good to me. Thanks for cleaning this up @bartonjs

@@ -84,11 +80,6 @@ internal DirectoryBasedStoreProvider(string storeName, OpenFlags openFlags)

public void Dispose()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does IStorePal still need to be IDisposable? I've not looked to see if other implementations have code in it.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The Windows version is holding native resources, yeah.

@stephentoub
Copy link
Member

LGTM

Users who create their first X509Store on build 23910 or later will get an exception that the directory has the wrong permissions. No test existed at the
time, and manual testing failed to identify the distinction between "continued
use" and "initial creation".

This changes the permissions check to ensure that the user permissions are
correct, and ignores the group and other permissions.  The files are explicitly
tested for rw?--?--?, and set to rw------- on mismatch, so there is no major
concern with the directory being overly readable.  It also adjusts the exception message to match the adjusted requirement, and adds a test.

This test will still suffer from the x509stores directory already existing on
established machines, since otherwise that runs the risk of breaking the
user's my and root stores if test cleanup goes awry.
With this change the Certificates collection will just read from the filesystem
on every call.  Since multiple calls are believed to be infrequent, this just
removes some memory and complexity trying to make the second call faster.

A large number of X509Store tests were also added to verify not just this
change's impact (namely, independant objects of the same store name should
see each other's changes immediately both before and after the code change)
but many of the machine-state impact altogether.  When directories get
created (first write), cleaned (never), files reused (when appropriate), etc.
@bartonjs bartonjs force-pushed the unix_x509store_nofsw branch from a775727 to 7d3bcf5 Compare April 13, 2016 00:31
@bartonjs
Copy link
Member Author

@mmitche hudson.remoting.ChannelClosedException: channel is already closed (http://dotnet-ci.cloudapp.net/job/dotnet_corefx/job/osx_release_prtest/3784/console)

@bartonjs
Copy link
Member Author

Since this passed other times, and passed on the Linux configurations, and the mac queue is still long, I'm just going to go ahead and merge.

@bartonjs bartonjs merged commit 9c0a7a9 into dotnet:master Apr 13, 2016
@bartonjs bartonjs deleted the unix_x509store_nofsw branch October 18, 2016 22:51
@karelz karelz modified the milestone: 1.0.0-rtm Dec 3, 2016
picenka21 pushed a commit to picenka21/runtime that referenced this pull request Feb 18, 2022
Remove FileSystemWatcher dependency from Unix X509Store

Commit migrated from dotnet/corefx@9c0a7a9
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Break X509Certificates dependency on FileSystemWatcher Add OuterLoop tests for X509Store

7 participants