eylenburg / eylenburg.github.io

https://eylenburg.github.io/
Creative Commons Attribution Share Alike 4.0 International
119 stars 12 forks source link

Android: "Sandboxed/unprivileged?" #74

Closed alohapersona closed 1 month ago

alohapersona commented 1 month ago

I think this row is really hard to understand correctly: All apps on Android are sandboxed, the question is only which privileges (can be based on permissions, but also beyond that) are granted. Privileged apps are not automatically super-high privileged. For example, it would be considered a bug in AOSP if a privileged app without contacts permission could access your contacts. While some privileges are granted merely from the fact that an app is installed as priv-app, most privileges rather stem from privileged permissions, that is permissions that can only be granted to priv-apps. A lot of apps in AOSP are in fact installed as priv-app, so privileged apps alone should not be considered an issue.

However, and this is why this still makes sense, one should not run untrusted code privileged, for the reason I mentioned that privileged apps do have some additional privileges that regular apps cannot get. For people caring about privacy, Play Services probably can't be trusted and thus should not run privileged and that's why GrapheneOS's solution to run Play Services unprivileged is a great idea. microG does run untrusted code as well when the "device attestation" (SafetyNet) functionality is enabled and DroidGuard is executed locally on the device - there is also a warning about this on the screen where you can enable it. So what matters mostly when using microG is if local DroidGuard execution is enabled when running as privileged app. DivestOS not only has microG running as unprivileged app, it also instructs microG to never attempt running DroidGuard locally (microG added a functionality for this on DivestOS request, see https://github.com/microg/GmsCore/issues/1971). For the other systems, I don't know what their default configuration is, which IMO would be relevant here.

In any case, the row should be renamed as "Unprivileged app?" or similar, as this is what it is about. A sandbox is used in all cases.

thestinger commented 1 month ago

This part of the table is already done well and should not be changed. The claims here are inaccurate and extremely biased towards microG with the aim of making the table inaccurate to promote it. The table is supposed to be objective and should not be deciding what is or isn't trustworthy based on subjective things. microG does not avoid using closed source Google Play code as part of each app using it which has access to what the apps can access. The claim that closed source code cannot be reviewed or that it inherently isn't trustworthy or as private is objectively wrong and probably so. You view open source as subjectively being trustworthy and closed source as not being trustworthy, but it is not inherently so and that's largely based on your misconception that open source means code gets reviewed/audited in a way that it doesn't and certainly hasn't for microG in particular. We have audited it, found privacy/security vulnerabilities and they are not fixed.

I think this row is really hard to understand correctly: All apps on Android are sandboxed, the question is only which privileges (can be based on permissions, but also beyond that) are granted.

Standard privileged Google Play services and standard microG integration do not run within the standard untrusted app sandbox. The standard untrusted app sandbox is what's being referred to as sandboxed apps. The table is defining this in a meaningful, sensible way which shows the difference between privileged vs. unprivileged Play services and microG. DivestOS integrates microG in a much different way than CalyxOS and /e/OS, which should be listed in the table. It running in the standard app sandbox does make a significant difference.

Privileged apps are not automatically super-high privileged.

Privileged apps do automatically get substantial privileges and run with significantly less isolation. This means they can do significantly more and they're also much less isolated from each other. They can access services they wouldn't be able to access without being a privileged app without receiving any privileged permissions. They don't get a per-app MLS policy so they aren't isolated from each other at a low-level in the way that regular sandboxed apps are isolated. A major part of the app sandbox (per-app MLS) is missing for them. That might change in the future, but for now that's how it works. Many checks in the high level parts of the OS also have a bypass for privileged apps without requiring any privileged permissions. It doesn't all have privileged permissions defined. Simply bundling an app with the OS isn't meant to bypass any of the permission model but making it a privileged app does.

A lot of apps in AOSP are in fact installed as priv-app, so privileged apps alone should not be considered an issue.

That's wrong. Normal bundled apps are not priv apps. Most priv apps don't have any user-facing activities and are not what users would consider apps. It's really an implementation detail that so much of the OS is implemented via the app runtime. It's unfortunate that so much unnecessary and misleading info is surfaced to users in Settings, but that's just how it is right now.

However, and this is why this still makes sense, one should not run untrusted code privileged, for the reason I mentioned that privileged apps do have some additional privileges that regular apps cannot get. For people caring about privacy, Play Services probably can't be trusted and thus should not run privileged and that's why GrapheneOS's solution to run Play Services unprivileged is a great idea.

Play services is not inherently untrustworthy and microG is not inherently trustworthy. microG has had major privacy and security breaches such as leaking location data in multiple ways to apps which shouldn't have been able to get it. It still has issues with how they implement permission checks. It still has security issues with how they secure connections to services, resulting in data being more exposed. Simply tricking other apps into believing it's Play services is bypassing a security check and resulting in data being more exposed than it would be. Google is not the only threat to privacy.

microG doesn't change the fact that the client-side part of the Google Play SDK and libraries included in each app is still the closed source Google Play code or that the Google services are proprietary. Closed source does not make something untrustworthy or non-private. Privacy and security is orthogonal to whether something is open source or not. You're portraying it as if Google Play is malware when it certainly isn't. microG has significant privacy and security issues, and it has issues of trust too particularly with how some of the developers are behaving towards other open source projects.

microG does run untrusted code as well when the "device attestation" (SafetyNet) functionality is enabled and DroidGuard is executed locally on the device - there is also a warning about this on the screen where you can enable it. So what matters mostly when using microG is if local DroidGuard execution is enabled when running as privileged app. DivestOS not only has microG running as unprivileged app, it also instructs microG to never attempt running DroidGuard locally (microG added a functionality for this on DivestOS request, see https://github.com/microg/GmsCore/issues/1971). For the other systems, I don't know what their default configuration is, which IMO would be relevant here.

Your personal feeling that microG is trustworthy and Google Play is not trustworthy is simply your subjective opinion. microG uses a huge amount of code from Google, a lot of it open source and some of it not open source such as but not limited to what you mentioned yourself. You're conflating open source with private and trustworthy which is not at all the case. Many open source projects including microG have had major privacy violations.

microG has privacy and security flaws that are not present in the original implementation. The microG team is not inherently trustworthy and we can demonstrate that many of the major contributors are heavily involved in harassment and other very underhanded attacks on GrapheneOS. We can show that they are objectively doing a whole lot of things which a reasonable person would consider to make them untrustworthy. If you want to make this about whether software is subjectively trustworthy, that's all relevant.

This table is supposed to a objective comparison based on verifiable facts, not subjective opinions highly biased towards one thing or another. Google Play is largely closed source, including the client side SDK and library still used with microG and the services still used with microG. If you do not trust Google Play, why are you using apps which include the Google Play SDK and libraries inside them with access to everything they can do? The reality is that Google Play is extremely widely trusted code that's not widely viewed in the way you view it, and using microG is in fact still using and trusting that code. If you use the official builds of Signal, you trust closed source Google Play code with access to all your Signal keys, chats, etc. because it runs as part of the app. Is this a real problem? Closed source is also not a black box which can't be audited, contrary to common misconceptions about it. Both microG and sandboxed Google Play have heavily relied upon the fact that it's possible to review what closed source code does... so the whole basis for that claim is wrong.

A project being open source does not mean it is significantly reviewed and a project being closed source does not mean it isn't significantly reviewed. GrapheneOS has reviewed the microG code and found that it should not be trusted due to consistent privacy and security flaws. The developers of microG have consistently downplayed and covered up security flaws in their projects including microG, CalyxOS and /e/OS. They're consistently not honest with users about security. The claim that they're subjectively trustworthy is simply your opinion that's not shared by a huge portion of the open source and privacy communities. The GrapheneOS community certainly doesn't think people involved in attacks on our project and community are trustworthy. Google has behaved in a much more ethical way towards us...

alohapersona commented 1 month ago

In any case every app, including privileged apps, is sandboxed. Naming the row "sandboxed" thus is misleading, because it's sandboxed in all cases. That's why I suggested to rename it to something like "Privileged app?" or maybe "Running with higher privileges" or anything else (happy to hear your suggestions).

My suggestion was not to change any of the values, it remains the case that GrapheneOS and DivestOS run Play Services or microG unprivileged, while CalyxOS, /e/OS and iodeOS and Stock Android run microG or Play Services privileged (LineageOS can run Play Services privileged, microG privileged or microG unprivileged, depending on how the user installs it). I only think that Sandboxed is the wrong term here. Nothing of what you said changes anything about that.

Off-Topic on microG

> We have audited it, found privacy/security vulnerabilities and they are not fixed. And after auditing, you have reported the issues you found to their [issue tracker](https://github.com/microg/GmsCore/issues?q=author%3Athestinger) so they can be fixed? > some of it not open source such as but not limited to what you mentioned yourself Would be interested to hear about those, as I haven't read about such anywhere else.

matchboxbananasynergy commented 1 month ago

Of course some of my comments to microG are subjective and not objective. I don't think that matters for what I said though. In any case every app, including privileged apps, is sandboxed.

I think that the term sandboxed here doesn't sacrifice accuracy to the point where it can mislead, and I believe it helps every day people understand what is meant. The low-level nuances of how privileged vs regular untrusted apps work in Android are very interesting and there's a lot to unpack there, but I think that most people understand "not privileged" when they hear" sandboxed, no?

thestinger commented 1 month ago

In any case every app, including privileged apps, is sandboxed. Naming the row "sandboxed" thus is misleading, because it's sandboxed in all cases. That's why I suggested to rename it to something like "Privileged app?" or maybe "Running with higher privileges" or anything else (happy to hear your suggestions).

Privileged apps do not run in the untrusted app sandbox. They run in the privileged app SELinux domain which is not sandboxed in the same sense. It has much more access and doesn't isolate them from each other with MLS. Privileged apps inherently receive privileged access from being a privileged app and then more through privileged permissions. microG signature spoofing is itself a form of privileged access included even on DivestOS and therefore the answer to whether microG is specially privileged on DivestOS is yes but it does run in the standard app sandbox without standard privileged permissions. Defining a new kind of privileged access (signature spoofing of Google Play) and granting it to microG is still giving it privileged access. Therefore, microG always requires privileged access while sandboxed Google Play doesn't require it. Impersonating Google Play is relevant to privacy and security because microG does not uphold the same level of security and has missing security checks. That is very relevant to privacy and security, and signature spoofing is part of why it's an issue. The signature is being checked for a reason.

Sandboxed is referring to the standard app sandbox, not the priv app domain. It could be made more precise by stating standard app sandbox of untrusted app sandbox, sure. Sandboxed Google Play is called sandboxed Google Play because it uses the standard app sandbox, not the vastly more privileged gmscore SELinux domains with a huge number of privileged permissions and other whitelisted privileged access where it can hardly be called sandboxed. Play services and microG avoid MLS isolation through this privileged access. That means there isn't really isolation between profiles. Priv apps also lack standard isolation between each other. A priv app can access files of another priv app if it sets the permissions to allow it, and so on. A normal app can't access files of another app regardless of permissions. If a priv app accidentally sets their data directly to 755 permissions, only another priv app (such as microG) can access it. This is not irrelevant. Priv apps matter beyond privileged permissions.

And after auditing, you have reported the issues you found to their issue tracker so they can be fixed?

We don't report issues to groups involved in attacks on the GrapheneOS project including harassment.

Would be interested to hear about those, as I haven't read about such anywhere else.

Google is the primary developer of the open source AOSP, the Android SDK and AndroidX libraries, etc. That is largely Google code. Then there are the closed source Google Play services used by microG, the closed source libraries which call into it and the closed source code microG knows how to download (not only SafetyNet). Whether it's open or closed source doesn't determine what's trustworthy or not. We would certainly trust an app using the Google Play libraries over libraries developed by people involved in harassment targeting other open source developers. Calyx taking over the Seedvault project has led to us not trusting the code and being very careful about updating it particularly due to them frequently introducing security issues, downplaying them and even covering them up.

thestinger commented 1 month ago

Leaking location data to apps not supposed to be able to access it from the background is pretty bad, don't you think? microG knowingly had this leak for a long time. It was never really acknowledged to users. They eventually moved to using part of the API that's supposed to be used. It's still not fully resolved.

alohapersona commented 1 month ago

I think that the term sandboxed here doesn't sacrifice accuracy to the point where it can mislead, and I believe it helps every day people understand what is meant.

I disagree. We shouldn't conflate sandboxed with unprivileged. If something is not sandboxed, it is inherently neither privileged nor unprivileged, because a sandbox is strictly required to manage privileges. Sandboxed means we can manage privileges. If something is not in a sandbox, by definition it can do everything. If I hear the code runs outside the sandbox, it sounds like it is similar to root privileges, can access private files or memory of other apps and things like this. For example, Play Services cannot access the private messages in your Signal app even if it runs the way it works with OS other than GrapheneOS. I actually often heard the misconception that "Play Services runs as root" which is entirely untrue and is essentially the same.

Not wrongly claiming that something is not sandboxed is not helping everyday people understand anything, it misleds them. If we want to express that the sandbox is not as strict, which IMO is already a stretch, as it's just a different set of privileges granted and largely the same sandboxing technology (like UID, CGroup, SELinux), we could phrase it as "Runs in eased/privileged sandbox".

Off-Topic on microG

Sorry for derailing the thread by asking a question and getting mostly unrelated replies > and the closed source code microG knows how to download (not only SafetyNet) That was the question in first place what I wanted to hear about, you wrote a bunch of lines completely unrelated to my question and even that was already off-topic. At least be so kind to put your off-topic replies also in an off-topic collapse.

matchboxbananasynergy commented 1 month ago

If we want to express that the sandbox is not as strict, which IMO is already a stretch

I don't understand how you this claim can make sense given all the things a privileged app can do that regular sandboxed (untrusted_app context) cannot. It's in no way "a stretch" imo.

thestinger commented 1 month ago

I disagree. We shouldn't conflate sandboxed with unprivileged. If something is not sandboxed, it is inherently neither privileged nor unprivileged, because a sandbox is strictly required to manage privileges. Sandboxed means we can manage privileges. If something is not in a sandbox, by definition it can do everything. If I hear the code runs outside the sandbox, it sounds like it is similar to root privileges, can access private files or memory of other apps and things like this. For example, Play Services cannot access the private messages in your Signal app even if it runs the way it works with OS other than GrapheneOS. I actually often heard the misconception that "Play Services runs as root" which is entirely untrue and is essentially the same.

That would mean every single Linux process is "sandboxed" including init because it doesn't have control over the kernel and cannot escalate privileges to the kernel. It has limited privileges. That's really not what sandboxed means in any typical usage.

can access private files or memory of other apps and things like this

All privileged apps can do this in a way that regular apps in the standard app sandbox cannot do. It's an inherent part of being an privileged app that they do not have the same SELinux restrictions. Standard app sandbox outright prevents accessing files of other apps regardless of POSIX permissions, etc. Priv apps can do it.

Not wrongly claiming that something is not sandboxed is not helping everyday people understand anything, it misleds them. If we want to express that the sandbox is not as strict, which IMO is already a stretch, as it's just a different set of privileges granted and largely the same sandboxing technology (like UID, CGroup, SELinux), we could phrase it as "Runs in eased/privileged sandbox".

Priv apps do not use the same SELinux sandboxing technology as apps in the regular sandbox. They do not have the same MLS sandboxing at at all. They have different MAC policies too with much more access. That's without being granted privileged permissions.

user=_app isPrivApp=true domain=priv_app type=privapp_data_file levelFrom=user
user=_app minTargetSdkVersion=34 domain=untrusted_app type=app_data_file levelFrom=all

It is beyond one being in priv_app vs. one being in untrusted_app. priv_app doesn't have per-app MLS. There are some major exceptions from the regular sandboxing beyond this. Another MLS difference:

# For symlinks in app data files, require equivalence in order to manipulate or follow (read).
mlsconstrain { lnk_file } { open setattr unlink link rename read }
         ( (t2 != app_data_file_type or t2 == privapp_data_file) or l1 eq l2 or t1 == mlstrustedsubject);
# But for priv_app_data_file, continue to use dominance for symlinks because dynamite relies on this.
# TODO: Migrate to equivalence when it's no longer needed.
mlsconstrain { lnk_file } { open setattr unlink link rename read }
         ( (t2 != privapp_data_file and t2 != appdomain_tmpfs) or l1 dom l2 or t1 == mlstrustedsubject);

They want to eventually strengthen the priv app sandbox a bit but it is weaker in a bunch of ways right now. Components should be run as untrusted apps if at all possible. It would be good to phase out priv app and instead support whitelisting permissions for apps run in the untrusted app sandbox instead, which is not currently how it works. Regardless, microG would still be requesting privileged permissions and some of what it needs is what it gets from just being a privileged app.

alohapersona commented 1 month ago

I don't understand how you this claim can make sense given all the things a privileged app can do that regular sandboxed (untrusted_app context) cannot. It's in no way "a stretch" imo.

To explain my thinking with an example: If an app has Contacts permission, it can access the user's contacts. Would you say the sandbox of that app is less strict than the sandbox of an app without Contacts permission?

matchboxbananasynergy commented 1 month ago

I don't understand how you this claim can make sense given all the things a privileged app can do that regular sandboxed (untrusted_app context) cannot. It's in no way "a stretch" imo.

To explain my thinking with an example: If an app has Contacts permission, it can access the user's contacts. Would you say the sandbox of that app is less strict than the sandbox of an app without Contacts permission?

I realize that you almost certainly understand this, but I want to make sure that we're on the same page here. A regular sandboxed app defining the contacts permission in its manifest file doesn't mean it gets to access the device's contacts without the user granting it access to them. It only means it can ask, not that it gets it.

If you take two untrusted_app apps, one which defines the contacts permissions in its manifest, and one which doesn't, if the user doesn't grant the former access to the contacts, the apps have the same amount of access.

alohapersona commented 1 month ago

I realize that you almost certainly understand this, but I want to make sure that we're on the same page here. A regular sandboxed app defining the contacts permission in its manifest file doesn't mean it gets to access the device's contacts without the user granting it access to them. It only means it can ask, not that it gets it.

Yes, certainly I am aware, I was explicitly talking about the case where the Contacts permission is granted (to me that's "has Contacts permission"). So in other words: Would you say that toggling the switch of the Contacts permission on an app moves it into a less strict sandbox? Or does the sandbox remain the same and it "just" gives additional privileges?

thestinger commented 1 month ago

To explain my thinking with an example: If an app has Contacts permission, it can access the user's contacts. Would you say the sandbox of that app is less strict than the sandbox of an app without Contacts permission?

Granting the Contacts permission to an app exposes more attack surface and therefore weakens the sandbox. It both grants it access to more data and more attack surface. Wouldn't you agree that an app granted access to specific contacts via Contacts Scopes on GrapheneOS is more strictly sandboxed than an app which gets access to not only all the contacts but also the other things that the Contacts permission gives access to beyond contacts themselves? Contact Scopes is also read access only so it can't be used to stick an image in there to attack Signal or another app using contacts. Contact Scopes is an app sandboxing improvement since it provides a way to avoid giving as much access and attack surface as you would need to without it.

thestinger commented 1 month ago

@alohapersona Privileged apps do not run in the same app sandbox. They do not only get additional access through specific privileged permissions. Your claim is broad enough to claim that the init process is sandboxed because it has limited access, cannot access everything and does not control the higher privileged kernel, etc. particularly on GrapheneOS where we reinforce that boundary (not for this near irrelevant case, but other more relevant ones).

thestinger commented 1 month ago

You're claiming that every process on Android is sandboxed because they all have limited access and cannot mess with the kernel. The definition you want to use is contrived and not useful. We're referring to the standard app sandbox which on GrapheneOS also has much less attack surface, improved protection against escaping it with exploits and a better permission model via features like Storage and Contact Scopes which are needed to avoid it being much worse than iOS among other improvements. This should not say privileged when it's referring to whether an app runs in the standard app sandbox, not whether specific privileged access is granted. DivestOS will have to marked as having privileged access for microG if it's changed away from the current definition because signature spoofing is privileged access, but it does run in the standard app sandbox.

alohapersona commented 1 month ago

Yes, I would argue that the init process and every other process runs in some kind of sandbox, but you seem to have a different understanding of the term sandbox than I do.

To come back to the initial purpose of this issue, I already suggested to call it "Runs in eased/privileged sandbox", which you haven't disagreed with. I would deem this way more accurate than the previous wording.

thestinger commented 1 month ago

@alohapersona It's not how almost anyone else uses the term sandbox. No one who works in this space would refer to stuff like system_server as being sandboxed. Many experts view the standard Android app sandbox as barely qualifying as a sandbox at all but it's improved quite a lot on GrapheneOS and we're continuing to do more. The privileged app domain is much less restricted including not having per-app-instance MLS and having a partial bypass for MLS among other things.

To come back to the initial purpose of this issue, I already suggested to call it "Runs in eased/privileged sandbox", which you haven't disagreed with. I would deem this way more accurate than the previous wording.

It's not the same app sandbox, so it's wrong and I disagree with it. The table should not inaccurately imply that privileged microG runs in the same sandbox with eased restrictions or specific privileged permissions when there is more to it than that. It is not the same low-level SELinux sandbox... It is not only privileged permissions or similar things as you keep claiming.

My suggestion is to change the row to say "Standard app sandbox" and simply say Yes for GrapheneOS / DivestOS and elaborating for the others by saying "No (privileged permissions and SELinux domain)". Do you agree that is correct?

Priv apps have the old style sandboxing approach from before Android 9 without per-app MLS in addition to having privileged SELinux MAC and MLS access, privileged status elsewhere in the OS and specific privileged permissions. You're ignoring that it is actually a different sandbox: levelFrom=user instead of levelFrom=all and priv_app domain instead of untrusted_app. You can compare the differences between priv_app and untrusted_app.

Here's an example of one way the SELinux policy has a major difference impacting which APIs it can use:

allow priv_app system_api_service:service_manager find;

This allows it to use @System APIs, which do not all have privileged permission checks. In many cases, stuff is limited to priv apps. Over time, it's split into permissions to avoid all priv apps having access.

Additionally:

music_recognition_service:service_manager find;
network_watchlist_service:service_manager find;
oem_lock_service:service_manager find;
persistent_data_block_service:service_manager find;
recovery_service:service_manager find;
stats_service:service_manager find;

Moving on from which system_server services are available, there are many other differences in the SELinux MAC policy. The MLS containment is entirely lacking within the same user for priv apps and the part they still have is only relevant when using multiple users. Simply have to look at the SELinux policy to see that it is not actually the same app sandbox. There are multiple versions of the untrusted app sandbox too which is major part of why target API level matters in addition to higher level behavior differences that are better documented.

matchboxbananasynergy commented 1 month ago

Yes, I would argue that the init process and every other process runs in some kind of sandbox, but you seem to have a different understanding of the term sandbox than I do.

This comes back to my initial point. This is not a reasonable distinction that people looking at the table would understand. If you explain to people that you consider init to be sandboxed and also consider regular installed apps sandboxed too, they'll just be more confused. Hell, I'm fairly familiar with this stuff and understanding the point you're trying to make has taken me multiple long posts.

To come back to the initial purpose of this issue, I already suggested to call it "Runs in eased/privileged sandbox", which you haven't disagreed with. I would deem this way more accurate than the previous wording.

I still think doesn't do a good job of explaining the difference to people viewing the table.

matchboxbananasynergy commented 1 month ago

My suggestion is to change the row to say "Standard app sandbox" and simply say Yes for GrapheneOS / DivestOS and elaborating for the others by saying "No (privileged permissions and SELinux domain)". Do you agree that is correct?

Could be full green for GrapheneOS and light green for DivestOS with a hover tooltip explaining the signature spoofing.

thestinger commented 1 month ago

That also applies to the others too.