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

x509_crt: handle properly broken links when looking for certificates #2602

Merged
merged 5 commits into from
Aug 3, 2022

Conversation

edsiper
Copy link

@edsiper edsiper commented Apr 25, 2019

Description

On non-windows environments, when loading certificates from a given
path through mbedtls_x509_crt_parse_path() function, if a symbolic
link is found and is broken (meaning the target file don't exists),
the function is returning MBEDTLS_ERR_X509_FILE_IO_ERROR which is
not honoring the default behavior of just skip the bad certificate file
and increase the counter of wrong files.

The problem have been raised many times in our open source project
called Fluent Bit which depends on MbedTLS:

fluent/fluent-bit#843 (comment)

The expected behavior is that if a simple certificate cannot be processed,
it should just be skipped.

This patch implements a workaround with lstat(2) and stat(2) to determinate
first, if the entry found in the directory is a symbolic link or not, if is
a symbolic link, do a proper stat(2) for the target file, otherwise process
normally. Upon finding a broken symbolic link it will increase the counter of
not processed certificates.

Status

READY

Backport in #6161

{
ret = MBEDTLS_ERR_X509_FILE_IO_ERROR;
goto cleanup;
/* determinate if the file entry could be a link, using lstat(2)

Choose a reason for hiding this comment

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

Minor: determine instead of determinate?

Or, alternatively, a suggestion for the entire comment: "Use lstat instead of stat to not fail in case of a broken link. In case of a valid link, another call to stat is needed below to query the properties of the file the link points to."

* information using stat(2). */
if( S_ISLNK( sb.st_mode ) )
{
/* if stat(2) fails it could be a broken link or a generic

Choose a reason for hiding this comment

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

Minor: Split the comment into multiple sentences. E.g. "If stat(2) fails, it could be a broken link or a generic error. If the link is broken, report is as a certificate that could not be processed; otherwise, return the generic MBEDTLS_ERR_X509_FILE_IO_ERROR."

library/x509_crt.c Outdated Show resolved Hide resolved
Copy link

@hanno-becker hanno-becker left a comment

Choose a reason for hiding this comment

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

@edsiper Thank you for your report and for providing the fix!

Overall, the PR looks good to me. I left some nitpicks, as well as a question in regards to the behavior in case of a broken link. Apart from that, I think the change merits an entry in the ChangeLog (probably in the Bugfix section), and we should have a test exercising mbedtls_x509_crt_parse_path() on a directory including a broken link (in the test suite tests/suites/test_suite_x509parse.datax). Could you take care of both?

Let us know if you need any support with it, and thanks again!

library/x509_crt.c Outdated Show resolved Hide resolved
@@ -1403,10 +1404,39 @@ int mbedtls_x509_crt_parse_path( mbedtls_x509_crt *chain, const char *path )
ret = MBEDTLS_ERR_X509_BUFFER_TOO_SMALL;
goto cleanup;
}
else if( stat( entry_name, &sb ) == -1 )
else
{
Copy link
Contributor

Choose a reason for hiding this comment

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

I'm a bit uncomfortable with the preexisting ask-for-permission (as opposed to ask-for-forgiveness) here, complete with race condition: stat then open. Granted, a directory containing certificates doesn't change often, and the use of opendir/readdir means that we don't get a consistent view of the directory if files are added, removed or renamed. But I'd still prefer to minimize such effects. In addition, the logic is getting more complex here.

If mbedtls_x509_crt_parse_file returns MBEDTLS_ERR_PK_FILE_IO_ERROR, it means that either fopen or fread failed in mbedtls_pk_load_file. In that case errno still contains the corresponding error code. Would it be possible to use this to switch to a beg-for-forgiveness approach? Always call mbedtls_x509_crt_parse_file, then if it returns MBEDTLS_ERR_PK_FILE_IO_ERROR, analyze errno to determine whether to count the file as silently skipped (ENOENT) or to error out (any other errno value).

This would change the behavior on non-regular, but fopen/fread-able files. For named pipes, that's rather an improvements. It would be a problem on systems where directories allow fopen and fread. What platforms allow that these days?

@daverodgman daverodgman added bug size-s Estimated task size: small (~2d) historical-reviewing Currently reviewing (for legacy PR/issues) priority-medium Medium priority - this can be reviewed as time permits and removed enhancement labels Jun 17, 2022
@daverodgman daverodgman self-assigned this Jul 8, 2022
Eduardo Silva and others added 4 commits July 20, 2022 14:36
On non-windows environments, when loading certificates from a given
path through mbedtls_x509_crt_parse_path() function, if a symbolic
link is found and is broken (meaning the target file don't exists),
the function is returning MBEDTLS_ERR_X509_FILE_IO_ERROR which is
not honoring the default behavior of just skip the bad certificate file
and increase the counter of wrong files.

The problem have been raised many times in our open source project
called Fluent Bit which depends on MbedTLS:

fluent/fluent-bit#843 (comment)

The expected behavior is that if a simple certificate cannot be processed,
it should just be skipped.

This patch implements a workaround with lstat(2) and stat(2) to determinate
first if the entry found in the directory is a symbolic link or not, if is
a simbolic link, do a proper stat(2) for the target file, otherwise process
normally. Upon find a broken symbolic link it will increase the counter of
not processed certificates.

Signed-off-by: Eduardo Silva <[email protected]>
Signed-off-by: Dave Rodgman <[email protected]>
@daverodgman
Copy link
Contributor

daverodgman commented Jul 20, 2022

Rebase and address feedback.

I haven't reworked to eliminate the stat-then-open issue @gilles-peskine-arm points out. It's a pre-existing issue, and it would be hard to fully eliminate this kind of race - the directory could be modified during iteration. It also sounds like the kind of thing where we might run into platform issues. So I think fixing the stat-then-open race is out-of-scope for this PR. I will open a separate issue (#6108)

@daverodgman daverodgman added needs-review Every commit must be reviewed by at least two team members, needs-ci Needs to pass CI tests and removed needs-work labels Jul 20, 2022
@daverodgman daverodgman added needs-reviewer This PR needs someone to pick it up for review and removed historical-reviewing Currently reviewing (for legacy PR/issues) labels Jul 20, 2022
@daverodgman daverodgman added the historical-reviewed Reviewed & agreed to keep legacy PR/issue label Jul 20, 2022
lstat is not available on some platforms (e.g. Ubuntu 16.04). In this
particular case stat is sufficient.

Signed-off-by: Dave Rodgman <[email protected]>
@daverodgman daverodgman removed the needs-ci Needs to pass CI tests label Jul 21, 2022
Copy link
Contributor

@tom-cosgrove-arm tom-cosgrove-arm left a comment

Choose a reason for hiding this comment

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

LGTM

@tom-daubney-arm tom-daubney-arm self-requested a review July 29, 2022 09:53
Copy link
Contributor

@tom-daubney-arm tom-daubney-arm left a comment

Choose a reason for hiding this comment

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

LGTM

@daverodgman daverodgman added approved Design and code approved - may be waiting for CI or backports needs-backports Backports are missing or are pending review and approval. and removed needs-review Every commit must be reviewed by at least two team members, needs-reviewer This PR needs someone to pick it up for review labels Jul 29, 2022
@gilles-peskine-arm gilles-peskine-arm dismissed hanno-becker’s stale review August 3, 2022 11:04

Hanno's changes have been addressed.

@gilles-peskine-arm gilles-peskine-arm removed the needs-backports Backports are missing or are pending review and approval. label Aug 3, 2022
@gilles-peskine-arm gilles-peskine-arm merged commit b3edc15 into Mbed-TLS:development Aug 3, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
approved Design and code approved - may be waiting for CI or backports bug component-x509 historical-reviewed Reviewed & agreed to keep legacy PR/issue priority-medium Medium priority - this can be reviewed as time permits size-s Estimated task size: small (~2d)
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants