-
-
Notifications
You must be signed in to change notification settings - Fork 10.1k
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
Make calls to getenv(3) safer when setuid. #7047
Conversation
I left the |
I'd say bad idea in the suggested form. For two reasons. 1. Does it actually have to be non-discriminating? I mean would it actually be appropriate to ignore all environment variables? Well, it's not like I have ready answer to the question, but at least I think that it should be posed, and I don't see that it was. I mean it pretty much looks like "replace everything just because". 2. What about other systems? Why does it have to be not only Linux-specific, but even glibc-version-specific? I mean if we consider this a security issue, then there should be fall-back code that provide corresponding functionality on other systems. In other words even from this angle it looks pretty much like "just because"... |
It isn't Linux specific although it is Unix specific. With Unprivileged execution is unchanged -- this change only impacts programs that are setuid or have otherwise raised capabilities. Applications that are run either as a user or as root have unchanged access to their environment. I'm having difficulty thinking of a situation where a setuid program would rely on unfettered access the environment unless I'm trying to hack the system. |
I apparently missed extra if in non-glibc case. I suppose I was tipped off by subject, which is actually misleading. As this is not about using secure_getenv when available, but changing getenv's behaviour completely. So what's with that? I mean totally misleading subject. [BTW, is this a feature? This is reference to assertion made elsewhere that current definition of "feature" is too imprecise to be useful.] But back on topic...
Yet it's not about reading variable per se but what effect do they have, is it? Consider locale for example, would you deny setuid program to read LANG? One can ask if all variables interpreted by OpenSSL lib are equally sensitive, but you just can't make such general assertion about all environment variables, and base merge request [with misleading subject] on it. I probably should clarify that I'm not saying that I know the answer to the implied question, only that it's not given that such generalization is warranted. |
Yeah, bad subject choice. For that I apologise. I'm way too good at picking bad names and titles. I too am not sure if all of the |
What at least needs to use this is everything related to filenames and paths.
|
crypto/conf/conf_mod.c
Outdated
@@ -481,7 +481,7 @@ char *CONF_get1_default_config_file(void) | |||
int len; | |||
|
|||
if (!OPENSSL_issetugid()) { | |||
file = getenv("OPENSSL_CONF"); | |||
file = ossl_safe_getenv("OPENSSL_CONF"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
See the dissonance? One line up? Now jumping to conf_api. If config file. i.e. one that is not appointed by OPENSSL_CONF, is considered trusted, would it be appropriate to deny environment references?
crypto/engine/eng_list.c
Outdated
@@ -318,7 +318,7 @@ ENGINE *ENGINE_by_id(const char *id) | |||
*/ | |||
if (strcmp(id, "dynamic")) { | |||
if (OPENSSL_issetugid() | |||
|| (load_dir = getenv("OPENSSL_ENGINES")) == NULL) | |||
|| (load_dir = ossl_safe_getenv("OPENSSL_ENGINES")) == NULL) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
See the dissonance? One line up?
I'd gone back to I'm unsure about the LEGACY_GOST_PKCS12 environment variable in |
crypto/rand/randfile.c
Outdated
@@ -264,9 +264,9 @@ const char *RAND_file_name(char *buf, size_t size) | |||
#else | |||
if (OPENSSL_issetugid() != 0) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
should this be removed ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, it is removable. I've done so.
The slight difference on the else branch (the extra getenv) phased me.
@@ -82,7 +83,7 @@ char *_CONF_get_string(const CONF *conf, const char *section, | |||
if (v != NULL) | |||
return v->value; | |||
if (strcmp(section, "ENV") == 0) { | |||
p = getenv(name); | |||
p = ossl_safe_getenv(name); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As already said, at this point config file is supposed to be "trusted". I.e. in setuid case it won't be one appointed by OPENSSL_CONF environment variable. Would it be appropriate to suppress this? Or in other words wouldn't it be appropriate to say that if system owner says "read environment variable" is trusted config, then it should be done unconditionally?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Even if the configuration file is trusted, the environment can't be.
@@ -262,11 +262,9 @@ const char *RAND_file_name(char *buf, size_t size) | |||
} | |||
} | |||
#else | |||
if (OPENSSL_issetugid() != 0) { | |||
if ((s = ossl_safe_getenv("RANDFILE")) == NULL || *s == '\0') { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Problem here is that suggested ossl_safe_getenv is "tri-state", denied, no-variable, value, and it's impossible to tell first two apart. As result of suggested change no-RANDFILE-variable is rendered to be equivalent of "denied". No good...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't see what's the problem here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, "no good" was too strong. Formally speaking the flow is different because of "tri-state" thing, but it's true that overall outcome is the same in this case. Modulo redundant call to set[gu]id in case ossl_safe_getenv('RANDFILE") returns NULL...
crypto/sm2/sm2_crypt.c
Outdated
sz = 2 * ASN1_object_size(0, field_size + 1, V_ASN1_OCTET_STRING) | ||
+ ASN1_object_size(0, md_size, V_ASN1_INTEGER) | ||
+ ASN1_object_size(0, msg_len, V_ASN1_INTEGER); | ||
*ct_size = ASN1_object_size(0, sz, V_ASN1_SEQUENCE); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unrelated modification.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oops, I was testing the code I pasted into another PR. I'll remove.
Overall I'd argue against using safe_getenv. Less Linux dependencies is better. Because our goal is wider than Linux. Trouble is that Linux is the only one that gets real and thorough exercise. And in such case it would be only appropriate that non-Linux-specific code paths are exercised on Linux. As for ossl_safe_getenv, I'm a bit torn. But I'm inclined to say that if there is need to secure more environment variable references, explicit OPENSSL_issetugid tests around the problematic references might be more appropriate. Because ossl_safe_getenv is "tri-state", which might be wrong in some circumstances. Which means that there would be calls to ossl_safe_getenv, but there also would be calls to OPENSSL_issetugid. In which case a unified approach would be more readable, because reader and developer would be excused from struggling with question which one to use when. |
Andy Polyakov wrote:
dot-asm commented on this pull request.
> @@ -82,7 +83,7 @@ char *_CONF_get_string(const CONF *conf, const char *section,
if (v != NULL)
return v->value;
if (strcmp(section, "ENV") == 0) {
- p = getenv(name);
+ p = ossl_safe_getenv(name);
As already said, at this point config file is supposed to be "trusted". I.e. in setuid case it won't be one appointed by OPENSSL_CONF environment variable. Would it be appropriate to suppress this? Or in other words wouldn't it be appropriate to say that if system owner says "read environment variable" is trusted config, then it should be done unconditionally?
I cannot see how is such case someone would could use environment
variables. If configuration (even trusted) has at least one environment
it has to be ignored at all.
Otherwise code will produce unexpected failures.
As result in setuid programs we cannot have "trusted" config - only
default with documentation that environment variables are risky.
Abnormal failures is reason to vote against whole idea for "safe" use of
environment variables.
|
The problem with OPENSSL_issetugid is that there can be other ways how to elevate privileges than just setuid/setgid - particularly there are the capabilities which can be elevated on file with similar mechanism as setuid/setgid. Glibc secure_getenv handles that. |
An attempt is made to use capabilities in |
Travis failures are not relevant. |
Change all calls to getenv() inside libcrypto to use a new wrapper function that use secure_getenv() if available and an issetugid then getenv if not. CPU processor override flags are unchanged. Extra checks for OPENSSL_issetugid() have been removed in favour of the safe getenv.
to be squashed
Does this need more discussion or can it be merged now that 1.1.1 is live? |
I think this is ready to get merged? |
Change all calls to getenv() inside libcrypto to use a new wrapper function that use secure_getenv() if available and an issetugid then getenv if not. CPU processor override flags are unchanged. Extra checks for OPENSSL_issetugid() have been removed in favour of the safe getenv. Reviewed-by: Bernd Edlinger <bernd.edlinger@hotmail.de> (Merged from #7047)
Change all calls to getenv() inside libcrypto to use a new wrapper function that use secure_getenv() if available and an issetugid then getenv if not. CPU processor override flags are unchanged. Extra checks for OPENSSL_issetugid() have been removed in favour of the safe getenv. Reviewed-by: Bernd Edlinger <bernd.edlinger@hotmail.de> (Merged from #7047) (cherry picked from commit 5c39a55)
Change all calls to getenv() inside libcrypto to use a new wrapper function that use secure_getenv() if available and an issetugid then getenv if not. CPU processor override flags are unchanged. Extra checks for OPENSSL_issetugid() have been removed in favour of the safe getenv. Reviewed-by: Bernd Edlinger <bernd.edlinger@hotmail.de> (Merged from #7047) (cherry picked from commit 5c39a55)
Merged to master, 1.1.1 and 1.1.0. 1.0.2 will be a separate PR. Thanks. |
Manual merge of openssl#7047 to 1.0.2-stable.
Manual merge of openssl#7047 to 1.0.2-stable.
Change all calls to
getenv()
inside libcrypto to use a new wrapper function that usesecure_getenv()
if available and anOPENSSL_issetugid()
thengetenv()
if not.