Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Filter environment variables when creating child processes #5984

Conversation

oheger-bosch
Copy link
Member

This PR addresses #5973. Refer to the single commits for further details.

@codecov
Copy link

codecov bot commented Oct 21, 2022

Codecov Report

Base: 57.79% // Head: 57.83% // Increases project coverage by +0.04% 🎉

Coverage data is based on head (23d5657) compared to base (5788347).
Patch coverage: 100.00% of modified lines in pull request are covered.

Additional details and impacted files
@@             Coverage Diff              @@
##               main    #5984      +/-   ##
============================================
+ Coverage     57.79%   57.83%   +0.04%     
- Complexity     2013     2019       +6     
============================================
  Files           324      324              
  Lines         18761    18761              
  Branches       3876     3881       +5     
============================================
+ Hits          10842    10850       +8     
+ Misses         6862     6852      -10     
- Partials       1057     1059       +2     
Flag Coverage Δ
funTest-non-analyzer 51.01% <0.00%> (+0.06%) ⬆️
test 27.53% <100.00%> (+0.01%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

Impacted Files Coverage Δ
model/src/main/kotlin/config/OrtConfiguration.kt 97.43% <100.00%> (+0.13%) ⬆️
.../src/main/kotlin/config/LicenseFilenamePatterns.kt
...odel/src/main/kotlin/config/LicenseFilePatterns.kt 86.95% <0.00%> (ø)
analyzer/src/main/kotlin/managers/Bundler.kt 48.07% <0.00%> (+0.19%) ⬆️
cli/src/main/kotlin/commands/AnalyzerCommand.kt 87.19% <0.00%> (+0.60%) ⬆️
cli/src/main/kotlin/commands/ConfigCommand.kt 59.37% <0.00%> (+3.12%) ⬆️
downloader/src/main/kotlin/vcs/Git.kt 74.33% <0.00%> (+5.16%) ⬆️

Help us with your feedback. Take ten seconds to tell us how you rate us. Have a feature suggestion? Share it here.

☔ View full report at Codecov.
📢 Do you have feedback about the report comment? Let us know in this issue.

model/src/main/kotlin/config/OrtConfiguration.kt Outdated Show resolved Hide resolved
model/src/main/kotlin/config/OrtConfiguration.kt Outdated Show resolved Hide resolved
# A file with default configuration options used by ORT. These options can be overridden in custom configuration files.

ort:
variablesToPropagate:
Copy link
Member

Choose a reason for hiding this comment

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

Phew. Looking at the length of this, I really wonder whether the "allow"-approach is the right one.

In either case we should probably consider to support wildcards or regexes, so one could allow / deny e.g. CARGO_*.

Copy link
Member Author

Choose a reason for hiding this comment

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

Yes, I was already sceptical when the decision was taken. It will be very difficult to come up with an exhaustive list. In addition, this list will have to be maintained when there are new versions of tools.

Using of wildcards will simplify the configuration, but again increase the risk that an unwanted variable is passed through.

Copy link
Member

Choose a reason for hiding this comment

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

I wonder whether we should come up with something completely different... a "crazy" approach could be to look at the entropy of the value of an environment variable to "guess" whether it's likely a password or so, and only then do not pass it on to the spawned process.

Or, instead of a global list, create tool-specific lists that are used in CommandLineTool objects. I.e. we should wrap each tool we call in an object instead of implementing the interface in the main class itself (see MercurialCommand for an example), and each of these objects gets its own (hard-coded) list of allowed environment variables. That should at least ease maintainability a bit.

Copy link
Member Author

Choose a reason for hiding this comment

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

I fear the entropy approach is too clever to work in practice.

If the allowed variables were configured at the command line tools, this could indeed make the maintenance a bit easier. But how could these configurations then be extended? For our use case, we will need to pass additional variables with credentials to package managers.

model/src/main/kotlin/config/OrtConfiguration.kt Outdated Show resolved Hide resolved
utils/common/src/main/kotlin/ProcessCapture.kt Outdated Show resolved Hide resolved
@@ -70,12 +79,21 @@ class ProcessCapture(
* Filter out the variables that are not white-listed to be propagated from [environment].
*/
private fun filterEnvironmentVariables(environment: MutableMap<String, String>): MutableMap<String, String> {
val keysToRemove = environment.keys.filterNot { it in variablesToPropagate }
val keys = environment.keys.handleCase()
Copy link
Member

Choose a reason for hiding this comment

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

Alternatively to this, apply .toSortedMap(String.CASE_INSENSITIVE_ORDER) to environment on Windows before looking up the keys.

- NODE_PATH
- NODE_EXTRA_CA_CERTS
- PREFIX
- TERM
Copy link
Member

Choose a reason for hiding this comment

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

We should also propagate PATH and PWD.

Copy link
Member Author

Choose a reason for hiding this comment

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

PATH really seems to be required. Lots of tests were failing because tools could not be found.

@oheger-bosch oheger-bosch force-pushed the oheger-bosch/utils/filter_env_variables branch from 5487735 to fbde14e Compare October 26, 2022 13:13
@oheger-bosch
Copy link
Member Author

I have implemented an alternative approach as described in my last comment on #5973. This seems to be significantly easier by (hopefully) offering a comparable level of security.

@oheger-bosch oheger-bosch marked this pull request as ready for review October 27, 2022 06:23
@oheger-bosch oheger-bosch requested a review from a team as a code owner October 27, 2022 06:23
@oheger-bosch oheger-bosch force-pushed the oheger-bosch/utils/filter_env_variables branch from fbde14e to d95f17c Compare November 2, 2022 09:02
utils/common/src/main/kotlin/EnvironmentVariableFilter.kt Outdated Show resolved Hide resolved
utils/common/src/main/kotlin/EnvironmentVariableFilter.kt Outdated Show resolved Hide resolved
utils/common/src/main/kotlin/EnvironmentVariableFilter.kt Outdated Show resolved Hide resolved
utils/common/src/main/kotlin/EnvironmentVariableFilter.kt Outdated Show resolved Hide resolved
utils/common/src/main/kotlin/EnvironmentVariableFilter.kt Outdated Show resolved Hide resolved
utils/common/src/main/kotlin/EnvironmentVariableFilter.kt Outdated Show resolved Hide resolved
utils/common/src/main/kotlin/EnvironmentVariableFilter.kt Outdated Show resolved Hide resolved
model/src/main/kotlin/config/OrtConfiguration.kt Outdated Show resolved Hide resolved
utils/common/src/main/kotlin/ProcessCapture.kt Outdated Show resolved Hide resolved
utils/common/src/main/kotlin/EnvironmentVariableFilter.kt Outdated Show resolved Hide resolved
@oheger-bosch oheger-bosch force-pushed the oheger-bosch/utils/filter_env_variables branch 2 times, most recently from 65e5231 to 8703f03 Compare November 4, 2022 11:11
@oheger-bosch oheger-bosch force-pushed the oheger-bosch/utils/filter_env_variables branch from 8703f03 to da9c584 Compare November 4, 2022 12:18
utils/common/src/main/kotlin/EnvironmentVariableFilter.kt Outdated Show resolved Hide resolved
* A set with patterns for variable names that are denied by default. All variables containing one of these
* strings (ignoring case) are not propagated to child processes.
*/
val DEFAULT_DENY_PATTERNS = setOf(
Copy link
Member

Choose a reason for hiding this comment

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

Thinking about it, the term "pattern" in the variable name (and also in the docs above) probably is a bit too auspicious as these neither are glob nor regex patterns (I was looking for docs by which principle patterns are matched). So, as this simply is a case-insensitive sub-string search, maybe just use "term"?

Copy link
Member

Choose a reason for hiding this comment

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

Or "substrings", also see my comment about not using a regexes below.

Copy link
Member Author

Choose a reason for hiding this comment

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

Now using the term "substrings" (hopefully) everywhere.

)

/** Stores the current deny patterns used by this filter. */
private var denyPatterns = DEFAULT_DENY_PATTERNS.toPatterns()
Copy link
Member

Choose a reason for hiding this comment

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

BTW, this line confirms me that "patters" is the wrong word for the variable, because if they already were patters, there would be no point in converting them toPatterns().

utils/common/src/main/kotlin/EnvironmentVariableFilter.kt Outdated Show resolved Hide resolved
utils/common/src/main/kotlin/EnvironmentVariableFilter.kt Outdated Show resolved Hide resolved
model/src/main/kotlin/config/OrtConfiguration.kt Outdated Show resolved Hide resolved
@sschuberth
Copy link
Member

BTW @oheger-bosch, did you forget to push?

@oheger-bosch oheger-bosch force-pushed the oheger-bosch/utils/filter_env_variables branch from da9c584 to 6e712ec Compare November 8, 2022 06:17
@oheger-bosch
Copy link
Member Author

BTW @oheger-bosch, did you forget to push?

I did not manage to finish this yesterday. Sorry for the confusion. Now all changes should be available.

Copy link
Member

@sschuberth sschuberth left a comment

Choose a reason for hiding this comment

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

Just some (hopefully) final nits.

utils/common/src/main/kotlin/EnvironmentVariableFilter.kt Outdated Show resolved Hide resolved

withEnvironment(env) {
val proc = if (Os.isWindows) {
ProcessCapture("cmd.exe", "/c", "echo %DB_USER%:%DB_PASSWORD%.%DB_CONN%")
Copy link
Member

Choose a reason for hiding this comment

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

Just wondering, why are you using . as a separator before the DB_CONN? For a more realistic example, shouldn't it be @?

Copy link
Member Author

Choose a reason for hiding this comment

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

Yes, but the "@" character could be problematic when it is interpreted by the shell. I did not want to mess around with escaping syntax, since for the test it is only relevant that some of the values are replaced while others are not.

@oheger-bosch oheger-bosch force-pushed the oheger-bosch/utils/filter_env_variables branch from 6e712ec to 78058c0 Compare November 8, 2022 08:34
@sschuberth sschuberth requested a review from a team November 8, 2022 09:27
sschuberth
sschuberth previously approved these changes Nov 8, 2022
/**
* Remove all keys from [environment] that do not pass this filter.
*/
fun filter(environment: MutableMap<String, String>): MutableMap<String, String> {
Copy link
Member

Choose a reason for hiding this comment

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

Having a function that modifies it parameters AND returns the modified version is a bit of codesmell.

I would rather have either an extension function MutableMap<String, String>.filter or no return value.

Copy link
Member

@sschuberth sschuberth Nov 8, 2022

Choose a reason for hiding this comment

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

I like the idea of an extension function that only filters in-place.

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 parameter is returned to have a single expression in ProcessCapture where the filter is applied. I am not sure whether I understand the proposal for an extension function. How would the signature of such an extension function look like and how would it help in this context?

Copy link
Member

Choose a reason for hiding this comment

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

As written MutableMap<String, String>.filter() and applied like that:

with(EnvironmentVariableFilter) {
    environment().filter().putAll(environment)
}

but it is more verbose.

Copy link
Member

Choose a reason for hiding this comment

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

Or remove the return value, you don't use it in ProcessCapture.

Copy link
Member Author

Choose a reason for hiding this comment

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

Hm, the extension function would suffer from the same codesmell problem, wouldn't it? If it returns a value (this in this case), it is not obvious that filtering was done in-place.

I am fine with removing the return value. It is used in ProcessCapture for the method chaining, but if this becomes more verbose, this should not be a big issue.

Copy link
Member

Choose a reason for hiding this comment

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

You're right: since environment() is a MutableMap and there is no 'cleaner' way of changing it, I am find to leave the code as it is.

cli/src/funTest/kotlin/OrtMainFunTest.kt Show resolved Hide resolved
nnobelis
nnobelis previously approved these changes Nov 8, 2022
This object contains functionality to filter out specific variables
from the environment when creating child processes. It is going to be
used by ProcessCapture to prevent that sensitive information is
accidentally passed to external programs called by ORT.

Signed-off-by: Oliver Heger <oliver.heger@bosch.io>
These properties allow the configuration of the
EnvironmentVariableFilter class introduced in the previous commit.

Signed-off-by: Oliver Heger <oliver.heger@bosch.io>
Before spawning a new process, apply EnvironmentVariableFilter to the
environment map to make sure that only uncritical variables are
passed.

Signed-off-by: Oliver Heger <oliver.heger@bosch.io>
After loading the configuration, pass the properties related to
filtering environment variables to EnvironmentVariableFilter, so that
they are taken into account when creating new child processes.

Signed-off-by: Oliver Heger <oliver.heger@bosch.io>
@oheger-bosch oheger-bosch merged commit 3d009a0 into oss-review-toolkit:main Nov 8, 2022
@oheger-bosch oheger-bosch deleted the oheger-bosch/utils/filter_env_variables branch November 8, 2022 14:21
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants