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

Expand fix for potential Privilege Escalation via Content Provider (CVE-2018-9492) #2482

Merged
merged 4 commits into from
Jan 23, 2023

Conversation

vestrel00
Copy link
Contributor

@vestrel00 vestrel00 commented Jan 18, 2023

❗ Problem

The changes contained in #2466 that were merged and released in 6.12.0 were not enough to pass Data/Secure theorem security scans.

This is either due to...

  • The security scans expecting exact copy-paste of their suggested code
  • OR it expects the security checks to also be applied to insert, update, and delete ContentProvider functions
    • The security check was, and is currently, only applied to the query function.

💡 Solution

In order to completely fix the potential security vulnerability described in #2460, we should also apply the security checks to the insert, update, and delete functions of SentryInitProvider and SentryPerformanceProvider.

This may not result in passing Data/Secure theorem security scans in case it is expecting copy-paste code of the suggest code. However, we will be 100% sure that we are protected no matter what scanners say 😎

Thanks to my colleague @artour-bakiev for being diligent in making sure that I do the right thing for everyone ❤️

💚 How did you test it?

I smoke tested the Android sample to make sure that it still works and is not just crashing (lol).

I do not actually know how to perform the attack, so I'm not able to verify that this works against attackers. However, it is safe to assume that it will work given that the attacker will have a different package than the app package.

📝 Checklist

  • I reviewed the submitted code
  • I added tests to verify the changes
  • I updated the docs if needed
  • No breaking changes

🔮 Next steps

There are no next steps after this. If the next Sentry version that contains these changes still do no pass the Data/Secure theorem security scans, then we know that they are expecting copy-paste of their suggested code, which we are just not going to do 😁

Note that there is no urgency in getting this change out in a new Sentry version. We can wait a whole month. No rush. Whenever the next Sentry version is released is kewl!

* of the {@link ContentProvider}. Additionally, those functions are secure.
*/
@ApiStatus.Internal
abstract class EmptySecureContentProvider extends ContentProvider {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

This PR comes with this additional benefit of making it clear to contributors and consumers that Sentry does not actually have any "real" ContentProviders =)

@Nullable String s,
@Nullable String[] strings1,
@Nullable String s1) {
securityChecker.checkPrivilegeEscalation(this);
Copy link
Contributor Author

@vestrel00 vestrel00 Jan 18, 2023

Choose a reason for hiding this comment

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

Note that there is no need to add this check to other overridable query functions because they all ultimately use this function.

See my comment in my previous PR; #2466 (comment)

new ContentProviderSecurityChecker();

@Override
public final @Nullable Cursor query(
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Added the final modifier here to make sure that this cannot be overridden further by subclasses. This ensures that the contract described in the class name and class doc is upheld at the compiler level!


@Override
public final @Nullable Uri insert(@NotNull Uri uri, @Nullable ContentValues contentValues) {
securityChecker.checkPrivilegeEscalation(this);
Copy link
Contributor Author

@vestrel00 vestrel00 Jan 18, 2023

Choose a reason for hiding this comment

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

Note that there is no need to add this check to other overridable insert functions because they all ultimately use this function.

See my similar comment in my previous PR; #2466 (comment)


@Override
public final int delete(@NotNull Uri uri, @Nullable String s, @Nullable String[] strings) {
securityChecker.checkPrivilegeEscalation(this);
Copy link
Contributor Author

@vestrel00 vestrel00 Jan 18, 2023

Choose a reason for hiding this comment

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

Note that there is no need to add this check to other overridable delete functions because they all ultimately use this function.

See my similar comment in my previous PR; #2466 (comment)

@Nullable ContentValues contentValues,
@Nullable String s,
@Nullable String[] strings) {
securityChecker.checkPrivilegeEscalation(this);
Copy link
Contributor Author

@vestrel00 vestrel00 Jan 18, 2023

Choose a reason for hiding this comment

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

Note that there is no need to add this check to other overridable update functions because they all ultimately use this function.

See my similar comment in my previous PR; #2466 (comment)

abstract class EmptySecureContentProvider extends ContentProvider {

private final ContentProviderSecurityChecker securityChecker =
new ContentProviderSecurityChecker();
Copy link
Contributor Author

Choose a reason for hiding this comment

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

You will notice that I am not initializing this with a reference to this ContentProvider. If I did, the code would be a tiny bit shorter at function call-sites;

securityChecker.checkPrivilegeEscalation();

It looks nice and is okay because there is no harm in saving a hard reference to the ContentProvider as long as we don't leak it. However, this would come at the price of having to assign the value of this in onCreate, which would require it being annotated with @CallSuper, and this not being final...

EmptySecureContentProvider {

  private ContentProviderSecurityChecker securityChecker;

  @CallSuper
  @Override
  public boolean onCreate() {
    securityChecker = new ContentProviderSecurityChecker(this);
    return false;
  }
}

So.. I think that we don't need to go through all that trouble just so that we don't have to pas in a reference to the ContentProvider when calling securityChecker.checkPrivilegeEscalation.

* <p>Call this function in the {@link ContentProvider#query(Uri, String[], String, String[],
* String)} function.
* <p>Call this function in the {@link ContentProvider}'s implementations of the abstract
* functions; query, insert, update, and delete.
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Updated documentation.

@codecov
Copy link

codecov bot commented Jan 18, 2023

Codecov Report

Base: 80.08% // Head: 80.08% // No change to project coverage 👍

Coverage data is based on head (61baa44) compared to base (ffa66c8).
Patch has no changes to coverable lines.

Additional details and impacted files
@@            Coverage Diff            @@
##               main    #2482   +/-   ##
=========================================
  Coverage     80.08%   80.08%           
  Complexity     3904     3904           
=========================================
  Files           320      320           
  Lines         14751    14751           
  Branches       1950     1950           
=========================================
  Hits          11813    11813           
  Misses         2168     2168           
  Partials        770      770           

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.

Copy link
Member

@markushi markushi left a comment

Choose a reason for hiding this comment

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

LGTM!

@vestrel00
Copy link
Contributor Author

vestrel00 commented Jan 20, 2023

I will fix the merge conflicts tomorrow. Or feel free to do it if you plan to merge this now.

new ContentProviderSecurityChecker().checkPrivilegeEscalation(this);
return null;
}

@Override
public @Nullable String getType(@NotNull Uri uri) {
return null;

Choose a reason for hiding this comment

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

Does it make sense to validate the getType as well?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

No. According to the ContentProvider.getType, documentation...

Note that there are no permissions needed for an application to access this information; if your content provider requires read and/or write permissions, or is not exported, all applications can still call this method regardless of their access permissions. This allows them to retrieve the MIME type for a URI when dispatching intents.

There is no "privilege escalation" exploit here because there is no privilege required to use this function at all. This is public function that is able to be used without any permissions even if not exported.

I would really like to keep my code changes minimal so as to minimize the risk of regression 🙏

@vestrel00
Copy link
Contributor Author

vestrel00 commented Jan 20, 2023

I fixed the merge conflicts. Feel free to merge whenever 🙏

Thanks in advance!

@markushi markushi merged commit 897ad85 into getsentry:main Jan 23, 2023
@markushi
Copy link
Member

FYI: This fix will be part of the 6.13.0 release, which should be available within the next hours.

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