Skip to content

New lib for optionally preloading crypto functions#1853

Merged
robgjansen merged 12 commits intoshadow:mainfrom
robgjansen:crypto-preload
Feb 12, 2022
Merged

New lib for optionally preloading crypto functions#1853
robgjansen merged 12 commits intoshadow:mainfrom
robgjansen:crypto-preload

Conversation

@robgjansen
Copy link
Copy Markdown
Member

Adds a new lib that preloads some AES functions so we can optionally skip some CPU crypto operations for faster simulation on older hardware (e.g. CPUs that do not support AES-NI).

When enabled (it's off by default), the preload lib will be injected into the LD_PRELOAD environment for all nodes, and we skip some AES symmetric encryption and decryption operations, including the ones used by Tor. (Disabling encryption is safe in private, synthetic Shadow nets.)

refs #1370

@robgjansen robgjansen added Type: Enhancement New functionality or improved design Component: Libraries Support functions like LD_PRELOAD and logging Component: Main Composing the core Shadow executable Tag: Performance Related to improving shadow's run-time labels Jan 14, 2022
@robgjansen robgjansen self-assigned this Jan 14, 2022
@github-actions github-actions bot added the Component: Build Build/install tools and dependencies label Jan 14, 2022
@stevenengler
Copy link
Copy Markdown
Contributor

Adding benchmark runtime graph:

run_time

@robgjansen
Copy link
Copy Markdown
Member Author

I verified that the crypto preload lib is correctly appearing in the nodes' LD_PRELOAD env variable, but the AES crypto functions are not getting intercepted properly:

Counters: {'AES_encrypt':0, 'AES_decrypt':0, 'AES_ctr128_encrypt':0, 'CRYPTO_ctr128_encrypt':0, 'CRYPTO_ctr128_encrypt_ctr32':0, 'EVP_Cipher':0}

Which is why we see no significant change in performance. A grab from perf top shows us that indeed we are spending a lot of time in AES_encrypt:

perf_top

@robgjansen
Copy link
Copy Markdown
Member Author

It appears that tor is being linked against libcrypto.so, which I thought would be enough to make AES_encrypt preloadable via the LD_PRELOAD method. This case does appear to be working in my dev VM, but not on the gh runner. Note that the libshadow_openssl_rng.so preload works the same way too, and is on by default.

I don't think we should have to build openssl manually like we used to do (and then link tor to it using its --with-openssl-dir build option). But clearly something is not quite right here...

@stevenengler
Copy link
Copy Markdown
Contributor

stevenengler commented Jan 18, 2022

It looks like I can reproduce this in an ubuntu 20.04 container on an ubuntu 20.04 host. I see the "Loading the preloaded crypto interception lib" in the plugin's stderr, but no counters (I removed the (cnt % 1000) == 0 condition). I see this behaviour with tor 0.4.5.9, 0.4.6.9, and 0.3.5.17.

@stevenengler
Copy link
Copy Markdown
Contributor

stevenengler commented Jan 25, 2022

The openssl crypto functions are not intercepted in an ubuntu 20.04 container, but they are intercepted in a debian 11 container. The openssl rand functions are intercepted in both the ubuntu 20.04 and debian 11 containers.

@robgjansen robgjansen force-pushed the crypto-preload branch 2 times, most recently from e4c5916 to df13476 Compare January 28, 2022 00:16
@robgjansen
Copy link
Copy Markdown
Member Author

The openssl crypto functions are not intercepted in an ubuntu 20.04 container, but they are intercepted in a debian 11 container. The openssl rand functions are intercepted in both the ubuntu 20.04 and debian 11 containers.

Explanation of the problem is at #1370 (comment), work-around is to conditionally intercept EVP_EncryptUpdate.

Now waiting on a performance benchmark test to see if it works.

@robgjansen
Copy link
Copy Markdown
Member Author

robgjansen commented Feb 1, 2022

Latest findings: doesn't seem to work on Ubuntu 20.04 because there is a fair amount of AES triggered internally in openssl. It does seem to work as expected in Debian 11 though:

run_time

@robgjansen robgjansen marked this pull request as ready for review February 1, 2022 18:58
@robgjansen robgjansen requested a review from sporksmith February 1, 2022 19:17
@github-actions github-actions bot added the Component: Testing Unit and integration tests and frameworks label Feb 3, 2022
@robgjansen
Copy link
Copy Markdown
Member Author

@sporksmith What do you think about just removing the whole cache and EVP_EncryptUpdate code? I don't think we need it on Debian 11 anyway (or when using an openssl whose functions go through the PLT), and it would be much simpler.

@sporksmith
Copy link
Copy Markdown
Contributor

@sporksmith What do you think about just removing the whole cache and EVP_EncryptUpdate code? I don't think we need it on Debian 11 anyway (or when using an openssl whose functions go through the PLT), and it would be much simpler.

The current approach might be nice to keep around if we ever want to pursue it further - e.g. we care about getting it to work on other platforms, or it stops working on Debian. I could go either way though.

@github-actions github-actions bot removed the Component: Testing Unit and integration tests and frameworks label Feb 3, 2022
@robgjansen robgjansen force-pushed the crypto-preload branch 2 times, most recently from 4fb7810 to 3202172 Compare February 11, 2022 01:54
@robgjansen
Copy link
Copy Markdown
Member Author

Latest results using benchmark runner in Debian 11 container running on machine without AES-NI, and after setting things up for consistent simulation stop times. The PR (with --use-preload-openssl-crypto true) seems to reduce total run time as expected:

run_time

The option is false by default. If set to true, we will add the
openssl crypto preload lib to the LD_PRELOAD path for all nodes
running in Shadow to skip some encrypt and decrypt operations.
This may speed up simulations, particularly on older CPUs that
do not support AES-NI optimizations.

Turning on crypto preloading should be done with care, since it
may have unintended side effects for the applications running in
Shadow.
Giving them a common prefix ensures that they appear together in
the Shadow options list, making it easier to find them and to see
that there are multiple related options available.
We keep a small cache of callers into EVP_EncryptUpdate so we don't
have to perform expensive string operations on every call. For now
we just use a small cache of pointers and a dead simple caching
policy; this works fine in Tor, where testing reveals that there is
a small number of callers of EVP_EncryptUpdate from tor/libssl.so.
@robgjansen
Copy link
Copy Markdown
Member Author

@github-actions github-actions bot added the Component: Documentation In-repository documentation, under docs/ label Feb 12, 2022
@robgjansen robgjansen merged commit 280ba08 into shadow:main Feb 12, 2022
@robgjansen robgjansen deleted the crypto-preload branch February 12, 2022 20:50
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Component: Build Build/install tools and dependencies Component: Documentation In-repository documentation, under docs/ Component: Libraries Support functions like LD_PRELOAD and logging Component: Main Composing the core Shadow executable Tag: Performance Related to improving shadow's run-time Type: Enhancement New functionality or improved design

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants