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

[file_selector_android] Refactor interactions with ContentProvider provided filenames #8184

Merged
merged 27 commits into from
Nov 27, 2024

Conversation

gmackall
Copy link
Member

@gmackall gmackall commented Nov 26, 2024

https://developer.android.com/privacy-and-security/risks/untrustworthy-contentprovider-provided-filename#don%27t-trust-user-input

Adapted from this option
https://developer.android.com/privacy-and-security/risks/untrustworthy-contentprovider-provided-filename#sanitize-provided-filenames

Pre-launch Checklist

If you need help, consider asking for advice on the #hackers-new channel on Discord.

@gmackall
Copy link
Member Author

gmackall commented Nov 26, 2024

cc @reidbaker @stuartmorgan

Still need to write tests but any thoughts re: this specific implementation or using sanitation in general are welcome. The sanitization function is directly lifted from the android docs, applied it to both the file name and file extension.

We could alternatively regress to not using a filename that is a function of the original file name, which is option one here (and what android recommends)
https://developer.android.com/privacy-and-security/risks/untrustworthy-contentprovider-provided-filename#don't-trust-user-input

@stuartmorgan
Copy link
Contributor

We could alternatively regress to not using a filename that is a function of the original file name

flutter/flutter#64685 had a fair number of votes; I would strongly prefer not to regress it. If we want to go back to generated filenames, I think we would need to do that as a second, longer-term step with a new API that returns a data structure that contains the file as well as other metadata like the original name.

@reidbaker reidbaker self-requested a review November 26, 2024 19:58
@gmackall gmackall changed the title [file_selector_android][wip] Refactor interactions with ContentProvider provided filenames [file_selector_android] Refactor interactions with ContentProvider provided filenames Nov 26, 2024
@gmackall gmackall marked this pull request as ready for review November 26, 2024 21:18
// Mocks a malicious content provider attempting to use path indirection to modify files outside
// of the intended directory.
// See https://developer.android.com/privacy-and-security/risks/untrustworthy-contentprovider-provided-filename#don%27t-trust-user-input.
private static class MockMaliciousContentProvider extends ContentProvider {
Copy link
Member Author

@gmackall gmackall Nov 26, 2024

Choose a reason for hiding this comment

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

I believe I could have set up mocks to get the new test to work with the existing MockContentProvider, but this felt closer to testing the actual attack to me, so I made it its own content provider.

Open to changing if it is too verbose to have this in addition to the existing MockContentProvider

Copy link
Contributor

Choose a reason for hiding this comment

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

I like this and I don't think it is too verbose given the value. If someone did then I would still prefer this pattern but with the content providers moved to another file.

@gmackall
Copy link
Member Author

image_picker pr is also up at #8188, but I'll wait to request review till this lands (the pr is extremely similar).

Copy link
Contributor

@reidbaker reidbaker left a comment

Choose a reason for hiding this comment

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

approve % comments

// Mocks a malicious content provider attempting to use path indirection to modify files outside
// of the intended directory.
// See https://developer.android.com/privacy-and-security/risks/untrustworthy-contentprovider-provided-filename#don%27t-trust-user-input.
private static class MockMaliciousContentProvider extends ContentProvider {
Copy link
Contributor

Choose a reason for hiding this comment

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

I like this and I don't think it is too verbose given the value. If someone did then I would still prefer this pattern but with the content providers moved to another file.

protected static @NonNull File saferOpenFile(@NonNull String path, @NonNull String expectedDir) throws IllegalArgumentException, IOException {
File f = new File(path);
String canonicalPath = f.getCanonicalPath();
if (!canonicalPath.startsWith(expectedDir)) {

Choose a reason for hiding this comment

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

In theory, this check would allow a path traversal into a directory that has expectedDir as a prefix.

String expectedDir = "/data/data/com.app/cache/123";
String path = "/data/data/com.app/cache/123/../12345/traversal.png";
String canonicalPath = "/data/data/com.app/cache/12345/traversal.png";
canonicalPath.startsWith(expectedDir); // true

However, because of the filename sanitization earlier, path traversal sequences are already prevented and this cannot occur. Additionally, the expected directory is an unknown UUID. So, this is not an issue here; I just wanted to mention it for next time. :)

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 think this would be an interesting comment to convey to the authors of that method/maintainers of the page, I can try to bring it to their attention. Presumably this would be fixed by making the check instead be

canonicalPath.startsWith(expectedDir + "/")

(after optionally stripping a / char at the very end so that we don't end up expecting "some/path/" + "/")

Choose a reason for hiding this comment

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

I found a specific GitHub CodeQL docs page about the Partial Path Traversal issue that explains a better mitigation using Path objects
https://codeql.github.com/codeql-query-help/java/java-partial-path-traversal-from-remote/

@gmackall gmackall added the autosubmit Merge PR when tree becomes green via auto submit App label Nov 27, 2024
@auto-submit auto-submit bot merged commit f7667a6 into flutter:main Nov 27, 2024
77 checks passed
engine-flutter-autoroll added a commit to engine-flutter-autoroll/flutter that referenced this pull request Nov 28, 2024
github-merge-queue bot pushed a commit to flutter/flutter that referenced this pull request Nov 28, 2024
flutter/packages@e6932b7...bc0c22d

2024-11-27 [email protected]
[image_picker_android] Refactor interactions with ContentProvider
provided filenames (flutter/packages#8188)
2024-11-27 [email protected]
[file_selector_android] Refactor interactions with `ContentProvider`
provided filenames (flutter/packages#8184)

If this roll has caused a breakage, revert this CL and stop the roller
using the controls here:
https://autoroll.skia.org/r/flutter-packages-flutter-autoroll
Please CC [email protected] on the revert to ensure that a
human
is aware of the problem.

To file a bug in Flutter:
https://github.com/flutter/flutter/issues/new/choose

To report a problem with the AutoRoller itself, please file a bug:
https://issues.skia.org/issues/new?component=1389291&template=1850622

Documentation for the AutoRoller is here:
https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
autosubmit Merge PR when tree becomes green via auto submit App p: file_selector platform-android
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants