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

Use patches of the AndroidHardening project #226

Closed
ghost opened this issue Jan 16, 2019 · 27 comments
Closed

Use patches of the AndroidHardening project #226

ghost opened this issue Jan 16, 2019 · 27 comments
Labels
missing-issue-template This issue was not created with the issue template

Comments

@ghost
Copy link

ghost commented Jan 16, 2019

Is your feature request related to privacy?

It might be related to privacy, but I think it's more about security, which is also important

Is there a patch available for this feature somewhere?

https://github.com/AndroidHardening/chromium_patches

Describe the solution you'd like

Build and update Bromite with those patches that are not yet integrated.

Describe alternatives you've considered

Not building Bromite with those patches, what'd be a pity.

@csagan5
Copy link
Contributor

csagan5 commented Jan 16, 2019

I have checked those patches again, most of them are present in other patchsets in use by Bromite or covered with different patches; the 64bit patches (1st and 2nd) are not a good idea, and it is explained on the issue tracker why.

Generally what these patches lack is some rationale for the changes, as there is just a subject line.

I have selected 5 for possible inclusion in next release although the impact is minimal.

@csagan5
Copy link
Contributor

csagan5 commented Jan 18, 2019

Fixed in 71.0.3578.132 (not yet released).

@csagan5 csagan5 closed this as completed Jan 18, 2019
@thestinger
Copy link

The bulk of the changes are not currently included there, since they aren't updated for the latest releases. It doesn't currently include the past hardening, and a lot of that is also done outside of the repository via the hardened toolchain and base OS. It's only a placeholder with a minimum set of changes for the time being. Disabling field trials substantially reduces the invasiveness of the changes required for the basics, since setting default options actually works properly and a bunch of questionable things don't ever get enabled.

The reason for preferring 64-bit processes is providing substantially better exploit mitigations at the expense of slightly more memory usage. In addition to the standard mitigations, it also enables usage of https://github.com/AndroidHardening/hardened_malloc which is provided by the base OS.

It's obviously not the same thing without the hardened allocator, libc changes and toolchain changes.

@csagan5
Copy link
Contributor

csagan5 commented Mar 16, 2019

The bulk of the changes are not currently included there, since they aren't updated for the latest releases. It doesn't currently include the past hardening, and a lot of that is also done outside of the repository via the hardened toolchain and base OS. It's only a placeholder with a minimum set of changes for the time being.

Thanks for the explanation @thestinger; my only suggestion for improvement would be to expand the git commit message with rationale for the patch changes.

I do not currently have plans to switch to a hardened toolchain because of the extra work that would be involved; additionally, the default toolchain is currently tested (also for security issues, I hope) on the Android versions used by Chrome/Chromium and I deem that an advantage.

Is there a different location for latest Chromium patches one should look at? (Given that some/most of them might make sense only with a hardened kernel/toolchain).

The reason for preferring 64-bit processes is providing substantially better exploit mitigations at the expense of slightly more memory usage. In addition to the standard mitigations, it also enables usage of https://github.com/AndroidHardening/hardened_malloc which is provided by the base OS.

It's obviously not the same thing without the hardened allocator, libc changes and toolchain changes.

Do you think this patch could be of any benefit on non-hardened Android? e.g. if compiled with the default Chromium SDK and toolchain, would a 64-bit process benefit from better exploit mitigations on let's say ARM64?

@csagan5
Copy link
Contributor

csagan5 commented Mar 16, 2019

For the records, the patches included when this issue was closed are here: d5dede3

(Other patches were already present, others not applicable)

-fwrapv and -fstack-protector-strong already work with the default Chromium toolchain, so their TODOs are a bit lagging behind now (somebody could propose a patch upstream); back then I took some time to study the difference between --param=ssp-buffer-size=4, -fstack-protector-strong and -fstack-protector-all, interesting reads.

@thestinger
Copy link

thestinger commented Mar 17, 2019

I do not currently have plans to switch to a hardened toolchain because of the extra work that would be involved; additionally, the default toolchain is currently tested (also for security issues, I hope) on the Android versions used by Chrome/Chromium and I deem that an advantage.

I use the officially tested toolchains with hardening, so there's one for Android and one for Chromium. Some of that involves custom patches, while other parts can now be backported or simply enabled with custom compilation switches. They're close to enabling a subset of CFI on Android by default as they do on x86_64 Linux, but other than that it has to be enabled downstream.

Do you think this patch could be of any benefit on non-hardened Android? e.g. if compiled with the default Chromium SDK and toolchain, would a 64-bit process benefit from better exploit mitigations on let's say ARM64?

It will provide high entropy ASLR (24-bit to 32-bit depending on whether the kernel uses 3 or 4 level page tables rather than 16-bit for 32-bit processes), high entropy stack canaries (56/64-bit instead of 24/32-bit depending on whether a zero byte is used) and also features like pointer authentication and memory tagging when those are made available in the future.

The reason they started preferring 32-bit processes is to save memory, particularly since saving memory makes it feasible to use finer-grained sandboxing. Since I know the devices that I'm targeting have plenty of memory, it's not an issue to have 10% or so higher memory consumption for these processes.

Similarly, it's possible to enabling the 'Strict site isolation' feature for substantially better sandboxing isolating each site from each other, rather than just isolating content as a whole from the system. The cost is increased memory usage, and it can be substantial for some websites making very heavy usage of iframes. I'll probably be enabling that by default in the near future, just as I used to enable the WebView sandbox a couple years before they shipped it as standard.

-fwrapv and -fstack-protector-strong already work with the default Chromium toolchain, so their TODOs are a bit lagging behind now (somebody could propose a patch upstream); back then I took some time to study the difference between --param=ssp-buffer-size=4, -fstack-protector-strong and -fstack-protector-all, interesting reads.

They use -fstack-protector-strong on ChromeOS, but not yet on other platforms, because there's push back against enabling an option resulting in ~1-2% lower performance and ~2-3% larger binaries. The size increase on Android is something they care a lot about since some devices have very little storage space. That also means ever so slightly higher memory / cache usage but not by the full 2-3%.

Using -fwrapv (notably only when not using signed integer overflow checking - since it will override it and result in not performing checks) is just common sense since it eliminates the chance of security vulnerabilities being introduced by optimizations based on signed overflow being undefined. That has happened before, and those optimizations don't even add up to a 0.1% performance increase for this kind of software. It's not worth having. The Linux kernel passes -fwrapv and also -fno-strict-aliasing to disable those dangerous optimizations (since there's so much incorrect code they can break). In fact, it's easy to point to dozens of known examples of invalid code that could potentially be broken by those optimizations. I don't feel it's acceptable for projects to be using optimizations that are known to be broken with a bunch of code in their tree. They put barely any effort into even fixing the known cases. Chromium has blacklists for UBSan for 'false positives' (none of which are actually false positives, but rather "undefined, but not a bug beyond potentially being broken by optimizations or even code generation without them") and also for components too full of these bugs for them to currently want to bother with it. That includes a bunch of signed overflow issues (there's sadly no detection for aliasing violations, which are fairly common, but not that common).

@thestinger
Copy link

Also, using 64-bit means that a hardened allocator like https://github.com/AndroidHardening/hardened_malloc taking advantage of the 64-bit address space will be transparently used if it's present in the OS. So, right now, when running on the AndroidHardening releases.

There are other assorted hardening features that will be exclusive to 64-bit too, including the upcoming hardware-based pointer authentication (ARMv8.3), memory tagging (ARMv8.5) and branch target indicator features (ARMv8.5) features.

https://www.qualcomm.com/media/documents/files/whitepaper-pointer-authentication-on-armv8-3.pdf

Memory tagging primarily has to be implemented by memory allocators, including the system one in libc and the various ones in Chromium. There's a section on a great approach to using it in my allocator README:

https://github.com/AndroidHardening/hardened_malloc#memory-tagging

It adds tags to the upper bits of pointers and a pointer can only be used to access memory with the appropriate tag assigned, so it can guarantee that linear overflows on the heap are caught along with guaranteeing that use-after-free is caught within a certain number of allocation slot reuses (after 15-16 uses for different allocations the tag will wrap back to the same value). It also provides a decent chance of catching other arbitrary forms of heap corruption. Usage within a memory allocator will be nearly free in terms of overall performance. Maybe 1-2% performance cost for a major improvement. Compilers can also use it for protection on the stack, but that's substantially more expensive.

Branch target indicators will be nearly free (probably below 0.1% overall cost) and provide coarse-grained forward-edge (indirect calls) CFI as a baseline. Clang type-based CFI is a lot better, but it's nice to have something that can be applied universally without compatibility or performance issues. Enabling Clang CFI is a slow and painful process since all the bugs involving undefined code need to be fixed in the software.

Pointer authentication is a lot less compelling, since the primary use case is protecting return addresses and there are better approaches. It's a form of weak probabilistic backward-edge CFI. It would be nicer to have deterministic protections, and ideally fully precise ones, such as the protection provided by a hardware-based shadow stack.

@csagan5
Copy link
Contributor

csagan5 commented Mar 17, 2019

I use the officially tested toolchains with hardening, so there's one for Android and one for Chromium. Some of that involves custom patches, while other parts can now be backported or simply enabled with custom compilation switches.

@thestinger I could not find the Chromium toolchain in use for the AndroidHardening project; I am currently using Chromium's own suggested toolchain (https://chromium.googlesource.com/chromium/src/build/+/refs/heads/master/install-build-deps-android.sh), if you could share more details/patches about the hardened toolchain for Chromium I could consider integration.

They're close to enabling a subset of CFI on Android by default as they do on x86_64 Linux, but other than that it has to be enabled downstream.

https://bugs.chromium.org/p/chromium/issues/detail?id=469376

It seems to be blocked on a non-public bug.

Similarly, it's possible to enabling the 'Strict site isolation' feature for substantially better sandboxing isolating each site from each other, rather than just isolating content as a whole from the system. The cost is increased memory usage, and it can be substantial for some websites making very heavy usage of iframes. I'll probably be enabling that by default in the near future, just as I used to enable the WebView sandbox a couple years before they shipped it as standard.

It is now called --site-per-process (see https://bugs.chromium.org/p/chromium/issues/detail?id=497306); I have also just checked that there is an option to enable it only for devices with a certain amount of memory (kSitePerProcessOnlyForHighMemoryClients, with a default of 1024 MB), and although delivering less security to less performing devices is not a good practice I am considering enabling both of these features.

That includes a bunch of signed overflow issues (there's sadly no detection for aliasing violations, which are fairly common, but not that common).

As I understand your patch enables -fwrapv only for non-UBSan to make a sensible compromise on these "known issues" of the Chromium (and/or components) codebase?

By the way, thanks for the full explanation; I am going to add it to the fwrapv patch used in Bromite.

Also, using 64-bit means that a hardened allocator like https://github.com/AndroidHardening/hardened_malloc taking advantage of the 64-bit address space will be transparently used if it's present in the OS. So, right now, when running on the AndroidHardening releases.

There are other assorted hardening features that will be exclusive to 64-bit too, including the upcoming hardware-based pointer authentication (ARMv8.3), memory tagging (ARMv8.5) and branch target indicator features (ARMv8.5) features.

https://www.qualcomm.com/media/documents/files/whitepaper-pointer-authentication-on-armv8-3.pdf

Memory tagging primarily has to be implemented by memory allocators, including the system one in libc and the various ones in Chromium. There's a section on a great approach to using it in my allocator README:

https://github.com/AndroidHardening/hardened_malloc#memory-tagging

Thanks for these links, very interesting; I was kinda expecting this technology to come along as I have seen similar solutions pop up in the Intel world over the years.

In terms of changes to Bromite, the scope of switching from 32bit to 64bit is simply limited to the WebView since I have not been building a Monochrome release for some time now. I am aware of the popularity of the Bromite SystemWebview for embedding in other ROMs so I wonder whether this change would negatively impact the current user base (and I do not have figures aside from your input on this); since most users do not use a hardened ROM (as far as I know), they would benefit only from higher entropy in ASLR and stack canaries; even for this small improvement, I would be inclined to enable it.

Also, there is now a dedicated target for 64-bit Monochrome: chromium/chromium@9cd1720

But no such target for the webview alone?

https://github.com/AndroidHardening/hardened_malloc#memory-tagging

It adds tags to the upper bits of pointers and a pointer can only be used to access memory with the appropriate tag assigned, so it can guarantee that linear overflows on the heap are caught along with guaranteeing that use-after-free is caught within a certain number of allocation slot reuses (after 15-16 uses for different allocations the tag will wrap back to the same value). It also provides a decent chance of catching other arbitrary forms of heap corruption. Usage within a memory allocator will be nearly free in terms of overall performance. Maybe 1-2% performance cost for a major improvement. Compilers can also use it for protection on the stack, but that's substantially more expensive.

Branch target indicators will be nearly free (probably below 0.1% overall cost) and provide coarse-grained forward-edge (indirect calls) CFI as a baseline. Clang type-based CFI is a lot better, but it's nice to have something that can be applied universally without compatibility or performance issues. Enabling Clang CFI is a slow and painful process since all the bugs involving undefined code need to be fixed in the software.

@thestinger have you considered upstreaming some of this work? I can imagine you are or have been in contact with the guys at Project Zero?
I would imagine hardened memory allocators as a hot topic discussed/contended by core Android developers, the Android security team, the Fuchsia team(s) and the Project Zero people as well.

@thestinger
Copy link

thestinger commented Mar 17, 2019

@thestinger I could not find the Chromium toolchain in use for the AndroidHardening project; I am currently using Chromium's own suggested toolchain (https://chromium.googlesource.com/chromium/src/build/+/refs/heads/master/install-build-deps-android.sh), if you could share more details/patches about the hardened toolchain for Chromium I could consider integration.

The bulk of my work hasn't yet been restored for the current releases of Chromium and Android. I'm testing some of my past toolchain hardening locally but it's not yet used for my public releases. Most of my changes are still in old tags on https://github.com/AndroidHardeningArchive (only a subset was in the latest Oreo release of the old incarnation of my work) or in local branches / tags.

I'm not sure how aware you are about what happened with my business partner slowly corrupting the previous incarnation of the project and making it stray away from the open source roots before eventually deciding to completely screw me over. I'm now doing it on my own with the explicit decision to never have a business involved to the same extent. They'll be my projects without much trust or responsibility placed in other people. I'm working on getting funding for the projects and expanding the development team beyond myself, since it's a very broad project with a lot of areas requiring deep, complex work. It's going to be a lot different than before though, with everything permissively licensed (MIT) other than the kernel which has to be GPL2, along with keeping companies that are involved at a distance from the project and unable to significantly harm it in any way beyond no longer contributing resources or development time. However, this all means that the work has been set back many years, and it's taking me a lot of time to slowly piece together the same changes that I had from before.

The main features are a better implementation of a stack canaries and a feature for zero initializing all uninitialized local variables.

The improved stack canaries work by doing an XOR of the random value for the canary with the return address before writing out the canary value. Before checking the canary value and returning, it performs the XOR again, so the canary won't match if the return value was overwritten during the function call. On arm / arm64, return pointer protection also works better than x86 because they use a link register so the return address cannot be overwritten by another thread after this verification but before returning (a tiny window of opportunity, but it does exist on x86 and can be exploited via a race from other threads with a decent enough chance of success to make it work reliably as long as the attack can be repeatedly at a decent rate). I don't plan to upstream this because it would be difficult and there are better approaches like shadow stacks, ideally with hardware support to avoid bypasses. An early version of this was published at https://gist.github.com/thestinger/b8502a881d871fbc75d91bc00576157b but it was substantially improved since then, especially for arm64. I haven't yet ported it to the more recent LLVM releases used by the current versions of LLVM and Android though.

I helped push for the zero initialization feature being implemented upstream in LLVM and that was successful. In the future, it will be available in the standard Chromium toolchain and will just need to be enabled in their build configuration.

It seems to be blocked on a non-public bug.

The blockers are generally bugs it finds, so sometimes they're security issues which are always non-public until they get around to opening them up which they sometimes forget to do. They do sometimes have issues non-public for other reasons, especially those tied to new Android releases since in the past they've tried to keep them secret for a long time, but I don't think that's the case here.

It is now called --site-per-process (see https://bugs.chromium.org/p/chromium/issues/detail?id=497306); I have also just checked that there is an option to enable it only for devices with a certain amount of memory (kSitePerProcessOnlyForHighMemoryClients, with a default of 1024 MB), and although delivering less security to less performing devices is not a good practice I am considering enabling both of these features.

Yeah, the process model is called site-per-process, but the feature providing the security is still referred to as site isolation and Android still has 'Strict site isolation' as a chrome://flags entry.

As I understand your patch enables -fwrapv only for non-UBSan to make a sensible compromise on these "known issues" of the Chromium (and/or components) codebase?

By the way, thanks for the full explanation; I am going to add it to the fwrapv patch used in Bromite.

Ideally, -fwrapv could be always passed, but unfortunately the way it's implemented has silly interactions with other switches. The reason it would still make sense to pass it is because due to their UBSan blacklists, they get far from full coverage with it, so -fwrapv would still be better than nothing where it's not being used.

Here's an example of a program where the compiler will actively change the behavior due to optimizing based on the assumption that signed integer overflow is guaranteed to never occur:

#include <stdio.h>
#include <limits.h>

int x1(int x) { return (x + 1) > x; }

int x2(int x) { return (x - 1) > x; }

int x3(int x) { return (x + 1) < x; }

int x4(int x) { return (x - 1) < x; }

int main(void) {
  printf("%d %d %d %d\n", x1(INT_MAX), x2(INT_MAX), x3(INT_MAX), x4(INT_MAX));
  printf("%d %d %d %d\n", x1(INT_MIN), x2(INT_MIN), x3(INT_MIN), x4(INT_MIN));
  return 0;
}

clang -O0 p2.c && /a.out produces:

0 0 1 1
1 1 0 0

clang -O2 p2.c && /a.out produces a different result, since it optimized based the assumption that overflow could not occur in a way that changed program behavior:

1 0 0 1
1 0 0 1

This can introduce a vulnerability by removing incorrect but still important security checks such as checking for signed integer overflow after it has already occured which is very common.

Adding -fwrapv makes signed overflow defined, providing the -O0 result consistently regardless of the optimization level. Note that it is not at all guaranteed that -O0 will not break it either. It just doesn't in practice, for an example like this.

So, now, getting into why I don't pass -fwrapv when UBSan is used: since it makes signed integer overflow well-defined, Clang will disable the UBSan checks for signed integer overflow, including in the production-oriented trapping mode used for hardening.

Compile and run the same program like this: clang -fsanitize=undefined p2.c && ./a.out. It detects the problem and logs it since this is the UBSan debugging mode, with a debugging runtime. It can be set to abort via an environment variable. However, passing -fwrapv as an additional switch makes it well-defined and it isn't caught. That does make sense for -fsanitize=undefined. It doesn't make sense for -fsanitize=integer, which turns on both unsigned and signed integer overflow checking. Unsigned integer overflow checking is already well-defined to start with but yet it only performs unsigned overflow checks if -fwrapv is passed to make signed overflow similarly well-defined. That also applies to specifically asking for -fsanitize=signed-integer-overflow.

Production usage of the UBSan sanitizers is done like this: clang -fsanitize=signed-integer-overflow -fsanitize-trap=signed-integer-overflow p2.c && ./a.out. This makes it trap at runtime and avoids the debugging runtime, which adds a bunch of extra potentially exploitable attack surface, complexity and code bloat.

@thestinger have you considered upstreaming some of this work? I can imagine you are or have been in contact with the guys at Project Zero?
I would imagine hardened memory allocators as a hot topic discussed/contended by core Android developers, the Android security team, the Fuchsia team(s) and the Project Zero people as well.

I've upstreamed a significant amount in the past, but I last the time to keep doing it. My contact with various upstream projects, security researchers at Project Zero, etc. was drastically set back by what happened with my former business partner. He took over my Twitter account which was the primary way I interacted with the security community and I lost access to my work email. He even intentionally broke all of the redirects from the old repository locations to the new ones at https://github.com/AndroidHardening and https://github.com/AndroidHardeningArchive as soon as he had the opportunity. There was also an attack on my Reddit account making me lose access permanently. They spammed false reports from sockpuppet accounts and successfully got it banned for posting a public corporate email address, which they falsely portrayed as posting personal information. Reddit has yet to respond to any of my requests to review this, so I lost the ability to moderate the community there and properly migrate it to a new one with a sticky thread and locking the creation of new threads.

He also spent a lot of time spreading misinformation about what has happened and stopping people from easily contacting me, knowing what really occurred, or even realizing that anything had changed at all. He made it look as if the project stalled and died, rather than it continuing without the interference and involvement of the company, which had never owned or controlled it, due to it being set up as an independent open source project that the company was supposed to be supporting (when really it was the other way around).

Anyway, everything has been set back years, especially in terms of involvement with other projects and upstreaming the changes. Many of the changes need to be ported from Android 6 and Android 7 to Android 9 and soon 10, along with a similar situation for Chromium. I'm struggling to find enough time to keep everything going without any help and only a small amount of financial support. I'm making progress at restoring it though, as you can see.

The only parts of my work that survived the disaster and continued on immediately were the Auditor app for hardware-based attestation (https://github.com/AndroidHardening/Auditor) and the optional remote attestation service it can be used with (https://github.com/AndroidHardening/AttestationServer) which is now hosted at https://attestation.app/. There's an explanation of this at https://attestation.app/about and https://attestation.app/tutorial. Development of it was definitely slowed down and disrupted, but thanks to these being independent apps, I was able to continue development. The hardened Chromium work is closely tied to the hardened toolchain and OS work and I was unable to keep it going. It has also never had releases outside of the OS, especially since part of the hardening involved has to do with restricting system apps (including Chromium) from executing any code outside verified partitions via ART and SELinux changes.

@thestinger
Copy link

The toolchain hardening consists of those custom features (XOR canaries, zero initialization) along with enabling additional switches (zero initialization should soon be available like this) such as -fwrapv, -fstack-overflow-strong and also using some of the production-oriented sanitizers in the trapping mode. The baseline CFI feature should be finished up by Google soon, and their performance-based blacklists can be disabled to sacrifice some performance for better security. Ideally, the integer overflow checking (at least signed-integer-overflow), bounds checking (object-size, bounds) and other CFI sanitizers (including cast sanitizers) could be enabled too. It's difficult since it uncovers so many bugs, most of which are not actual security issues in practice, so there's a lot of busywork involved to fix these countless bugs or to blacklist them from checks (ideally at a fine-grained level, not the extremely coarse blacklisting they use in many cases right now). I was using the sanitizers in limited scopes before, but it's difficult to maintain. Google does test with UBSan, and in theory, it can be used, but there are a lot of subtle latent bugs and regular regressions.

@thestinger
Copy link

Also, -fno-strict-aliasing is a similar flag to -fwrapv disabling some optimizations that often break real world code in dangerous ways, but they actually already pass this on their own for the time being in build/config/compiler/BUILD.gn. It's important to keep an eye on that in case they fix the code that it very obviously breaks in practice and then remove disabling the optimization, because there is likely more code that it breaks in more subtle ways. It's far less likely to cause exploitable vulnerabilities than the optimizations based on assuming signed integer overflow doesn't happen though, which is disabled by -fwrapv (which makes it well-defined as wrapping).

@thestinger
Copy link

thestinger commented Mar 17, 2019

@csagan5 By the way, you may need https://github.com/AndroidHardening/chromium_patches/blob/pie/0005-disable-seed-based-field-trials.patch to disable the local field trials, which override some of the internal settings. Passing fieldtrial_testing_like_official_build = true is important and disables the testing configuration, which is for enabling the maximum set of experimental features for maximum test coverage, but disabling that results in using a random seed to pick a random set of field trials. You can check in chrome://version. If it shows "variations" at all, you still have the local field trials enabled. I expect it's why many of the Chromium forks hard-wired code to disable certain features, rather than using existing options after they found they didn't work, because those options really do work but get overridden by field trials.

@thestinger
Copy link

I've also confirmed that android_64bit_browser in Chromium 73.0.3683.75 (latest stable tag for Android) is a full replacement for my 64-bit Monochrome patch, so the build target in later releases should work properly too. As you mentioned though, my patch is still needed for the standalone WebView, although I only support that in case some organization wants custom builds without Chromium as the default browser. For example, some organizations want a locked down installation with only their chosen apps and where installing apps or even running any code from non-verified partitions is prevented in various ways (via SELinux policy and mount options for native code and also other mechanisms for interpreted code). In some of those cases, they don't want a browser, but the WebView is usually still needed for some local web content and perhaps some uses by their chosen apps so it can't generally be omitted.

@csagan5
Copy link
Contributor

csagan5 commented Mar 17, 2019

I'm not sure how aware you are about what happened with my business partner slowly corrupting the previous incarnation of the project and making it stray away from the open source roots before eventually deciding to completely screw me over. I'm now doing it on my own with the explicit decision to never have a business involved to the same extent. They'll be my projects without much trust or responsibility placed in other people.

Yes, I am aware - although I have not read too deep into it. I remember having a bitter feeling about the situation and I am first and foremost sorry for the human aspect of the situation.

I'm working on getting funding for the projects

You might already have done your homework on this, and aside from big public funding partners you could also consider Kickstarter/BountySource if you have not before. I do not use them myself but they seem viable.

and expanding the development team beyond myself, since it's a very broad project with a lot of areas requiring deep, complex work.

You might need some qualified open source project/community management help there, if the option of becoming one yourself is not viable (even if you were qualified, it would drain energies from hands-on development) perhaps you could check if any of such qualified help is available out there? I would expect professionals working with other medium/big open source projects to be the ideal candidates.

If you would like to talk about a possible collaboration, feel free to contact me via reddit or email; I might have the correct integrity requirements but might fall short on others, including competence and time.

It's going to be a lot different than before though, with everything permissively licensed (MIT) other than the kernel which has to be GPL2, along with keeping companies that are involved at a distance from the project and unable to significantly harm it in any way beyond no longer contributing resources or development time.

I am aware of your recent screw-over experience and I wish it to be an isolated special case; going forward, it is up to you to define collaboration methods which prevent harm. Personally for this project I have only received requests about rebranding/sponsorship/cloud integrations which I have politely declined.

However, this all means that the work has been set back many years, and it's taking me a lot of time to slowly piece together the same changes that I had from before.

The main features are a better implementation of a stack canaries and a feature for zero initializing all uninitialized local variables.

The improved stack canaries work by doing an XOR of the random value for the canary with the return address before writing out the canary value. Before checking the canary value and returning, it performs the XOR again, so the canary won't match if the return value was overwritten during the function call. On arm / arm64, return pointer protection also works better than x86 because they use a link register so the return address cannot be overwritten by another thread after this verification but before returning (a tiny window of opportunity, but it does exist on x86 and can be exploited via a race from other threads with a decent enough chance of success to make it work reliably as long as the attack can be repeatedly at a decent rate). I don't plan to upstream this because it would be difficult and there are better approaches like shadow stacks, ideally with hardware support to avoid bypasses. An early version of this was published at https://gist.github.com/thestinger/b8502a881d871fbc75d91bc00576157b but it was substantially improved since then, especially for arm64. I haven't yet ported it to the more recent LLVM releases used by the current versions of LLVM and Android though.

I helped push for the zero initialization feature being implemented upstream in LLVM and that was successful. In the future, it will be available in the standard Chromium toolchain and will just need to be enabled in their build configuration.

This looks like really cool stuff, but a notch or two above my level; I can understand what it does and how it is implemented but I would not be able to review it nor contribute to it.
If you work on it alone, another reason for upstreaming it would be that you possibly get the deserved review.

Yeah, the process model is called site-per-process, but the feature providing the security is still referred to as site isolation and Android still has 'Strict site isolation' as a chrome://flags entry.

Yes, the text says "Strict site isolation" and maps to enable-site-per-process:

    {"enable-site-per-process", flag_descriptions::kStrictSiteIsolationName,
     flag_descriptions::kStrictSiteIsolationDescription, kOsAndroid,
     SINGLE_VALUE_TYPE(switches::kSitePerProcess)},

I confirm that it's the same thing.

I've upstreamed a significant amount in the past, but I last the time to keep doing it. My contact with various upstream projects, security researchers at Project Zero, etc. was drastically set back by what happened with my former business partner. He took over my Twitter account which was the primary way I interacted with the security community and I lost access to my work email. He even intentionally broke all of the redirects from the old repository locations to the new ones at https://github.com/AndroidHardening and https://github.com/AndroidHardeningArchive as soon as he had the opportunity.

Was this due to a public image problem or to a mere confusion about the authenticity of your online identity and contributions? I would hope that security researchers and other projects would not judge the source of the work but the work itself, as much as possible.

There was also an attack on my Reddit account making me lose access permanently. They spammed false reports from sockpuppet accounts and successfully got it banned for posting a public corporate email address, which they falsely portrayed as posting personal information. Reddit has yet to respond to any of my requests to review this, so I lost the ability to moderate the community there and properly migrate it to a new one with a sticky thread and locking the creation of new threads.

The incentives at play (from Reddit perspective) will make it difficult for you to solve that in any way that resembles justice, so I would give up on that aspect, at least for now.

He also spent a lot of time spreading misinformation about what has happened and stopping people from easily contacting me, knowing what really occurred, or even realizing that anything had changed at all. He made it look as if the project stalled and died, rather than it continuing without the interference and involvement of the company, which had never owned or controlled it, due to it being set up as an independent open source project that the company was supposed to be supporting (when really it was the other way around).

Anyway, everything has been set back years, especially in terms of involvement with other projects and upstreaming the changes. Many of the changes need to be ported from Android 6 and Android 7 to Android 9 and soon 10, along with a similar situation for Chromium. I'm struggling to find enough time to keep everything going without any help and only a small amount of financial support. I'm making progress at restoring it though, as you can see.

I am still very sorry for the human aspect of the whole situation, and secondarily for the technical aspect; I would really hope you can cope and reduce the damage that this situation did to you and your trust, eventually.

I am very grateful that you decided to continue this work - also on behalf of other Android users; let me know if I can be of help somehow.

The only parts of my work that survived the disaster and continued on immediately were the Auditor app for hardware-based attestation (https://github.com/AndroidHardening/Auditor) and the optional remote attestation service it can be used with (https://github.com/AndroidHardening/AttestationServer) which is now hosted at https://attestation.app/. There's an explanation of this at https://attestation.app/about and https://attestation.app/tutorial. Development of it was definitely slowed down and disrupted, but thanks to these being independent apps, I was able to continue development. The hardened Chromium work is closely tied to the hardened toolchain and OS work and I was unable to keep it going. It has also never had releases outside of the OS, especially since part of the hardening involved has to do with restricting system apps (including Chromium) from executing any code outside verified partitions via ART and SELinux changes.

This is all very interesting and beautiful, but I can see how it goes beyond the browser to tie together security in depth.

The toolchain hardening consists of those custom features (XOR canaries, zero initialization) along with enabling additional switches (zero initialization should soon be available like this) such as -fwrapv, -fstack-overflow-strong and also using some of the production-oriented sanitizers in the trapping mode. The baseline CFI feature should be finished up by Google soon, and their performance-based blacklists can be disabled to sacrifice some performance for better security. Ideally, the integer overflow checking (at least signed-integer-overflow), bounds checking (object-size, bounds) and other CFI sanitizers (including cast sanitizers) could be enabled too. It's difficult since it uncovers so many bugs, most of which are not actual security issues in practice, so there's a lot of busywork involved to fix these countless bugs or to blacklist them from checks (ideally at a fine-grained level, not the extremely coarse blacklisting they use in many cases right now). I was using the sanitizers in limited scopes before, but it's difficult to maintain. Google does test with UBSan, and in theory, it can be used, but there are a lot of subtle latent bugs and regular regressions.

I expect the media libraries to be full of these.

@csagan5 By the way, you may need https://github.com/AndroidHardening/chromium_patches/blob/pie/0005-disable-seed-based-field-trials.patch to disable the local field trials, which override some of the internal settings. Passing fieldtrial_testing_like_official_build = true is important and disables the testing configuration, which is for enabling the maximum set of experimental features for maximum test coverage, but disabling that results in using a random seed to pick a random set of field trials.

Thanks for mentioning the difference between those two; I think all field trials are already blocked by this patch? https://github.com/bromite/bromite/blob/73.0.3683.61/build/patches/Disable-fetching-of-all-field-trials.patch

You can check in chrome://version. If it shows "variations" at all, you still have the local field trials enabled. I expect it's why many of the Chromium forks hard-wired code to disable certain features, rather than using existing options after they found they didn't work, because those options really do work but get overridden by field trials.

No variations displayed. Yes, I am familiar with the hard-wiring, I have done some myself before discovering how field trials work (but in my case I was simply missing fieldtrial_testing_like_official_build=true).
I had decided before to not include this patch since its effect was already otherwise achieved, but I can include it without any harm.

I've also confirmed that android_64bit_browser in Chromium 73.0.3683.75 (latest stable tag for Android) is a full replacement for my 64-bit Monochrome patch, so the build target in later releases should work properly too. As you mentioned though, my patch is still needed for the standalone WebView, although I only support that in case some organization wants custom builds without Chromium as the default browser. For example, some organizations want a locked down installation with only their chosen apps and where installing apps or even running any code from non-verified partitions is prevented in various ways (via SELinux policy and mount options for native code and also other mechanisms for interpreted code). In some of those cases, they don't want a browser, but the WebView is usually still needed for some local web content and perhaps some uses by their chosen apps so it can't generally be omitted.

I see; I will include this patch for future WebView builds. My only remaining concern would be about installation instructions, as there are some community-contributed instructions here on the wiki page (which I have not verified myself) and I wonder if the involved paths would need to be changed. It seems like not since /system/app/webview/lib/arm64/ is mentioned there.

Thanks for your extensive description for the patches and the AndroidHardening project; I was not aware you were continuing your work there (I assume most people are passively in the same shadow cone after the recent issues you mentioned).

I will mention the project and the URL on the official website and README of Bromite.

@thestinger
Copy link

thestinger commented Mar 18, 2019

I see; I will include this patch for future WebView builds. My only remaining concern would be about installation instructions, as there are some community-contributed instructions here on the wiki page (which I have not verified myself) and I wonder if the involved paths would need to be changed. It seems like not since /system/app/webview/lib/arm64/ is mentioned there.

The paths will be the same, since with or without the patch, it still provides complete 32-bit and 64-bit WebView implementations. It was only in Android Oreo that they enabled the WebView sandbox by default, so before then the entire thing always ran with the architecture of the app using it and that still has to be fully supported for compatibility at least outside builds for only modern releases. The patch only changes the preferred renderer architecture from 32-bit for 64-bit when the renderer is running as an isolated process (Oreo or later by default, but supported on Nougat or later via developer settings, and I used to enable it with some downstream fixes long before it was standard).

Their android_64bit_browser option makes the same change for the Monochrome version of the WebView in chrome/android/monochrome_android_manifest_jinja_variables.gni (by not setting it when that's used) but doesn't change the normal WebView architecture preference (which is hard-wired to 32-bit).

@thestinger
Copy link

Thanks for mentioning the difference between those two; I think all field trials are already blocked by this patch? https://github.com/bromite/bromite/blob/73.0.3683.61/build/patches/Disable-fetching-of-all-field-trials.patch

Ah, yeah, that seems to disable the effects fully at a different layer.

@csagan5
Copy link
Contributor

csagan5 commented Mar 19, 2019

@thestinger I have added your rationale to the patches: e7e7afd

@thestinger
Copy link

By the way, a minimal patch is required for preferring 64-bit as of Chromium v74 since android_64bit_browser was replaced with build targets for 64-bit browsers but they neglected to define them for the apk targets since they appear to use app bundles now.

@csagan5
Copy link
Contributor

csagan5 commented May 2, 2019

@thestinger I am still using this patch to enable 64-bit for the WebView, I cannot easily see how to enable preference of 64-bit for the main Chromium APK.

Do you have a reference patch or source line to look at?

@thestinger
Copy link

This is the patch for Monochrome: https://github.com/GrapheneOS/chromium_patches/blob/pie/0002-use-64-bit-Monochrome-processes.patch.

I haven't tried doing it for the standalone Chrome apks, but I'd expect it just needs:

if (android_64bit_target_cpu && enable_64_bit_browser) {
    is_64_bit_browser = true
}

i.e. the same as Monochrome but without needing to deal with choosing how the WebView is included.

@thestinger
Copy link

https://github.com/GrapheneOS/chromium_patches/blob/pie/0019-enable-strict-site-isolation-by-default-on-Android.patch is also important and site isolation is enabled everywhere other than Android. The reason it's not enabled by default on Android is the additional memory usage from guaranteeing that each site is isolated in dedicated processes rather than running iframes for other sites in-process. It doesn't impact memory usage for sites without things like iframes.

@thestinger
Copy link

Site isolation is the only real mitigation for Spectre v1. Nothing else fully works, so without it there's a known way to steal data from the browser (sessions and data for other sites).

https://v8.dev/blog/spectre

@csagan5
Copy link
Contributor

csagan5 commented May 4, 2019

@thestinger I am now using this patch to enable 64-bit also for ChromeModernPublic and Monochrome: it seems like builds for the browser APKs are already 64-bit by default.

For site isolation I use this compromise: https://github.com/bromite/bromite/blob/74.0.3729.122/build/patches/Enable-site-per-process-isolation-for-devices-with-enough-memory.patch

It would disable it with devices with enough memory; see https://bugs.chromium.org/p/chromium/issues/detail?id=844118

The comment in the code where the 1077MB limit is set:

  // Using 1077 rather than 1024 because 1) it helps ensure that devices with
  // exactly 1GB of RAM won't get included because of inaccuracies or off-by-one
  // errors and 2) this is the bucket boundary in Memory.Stats.Win.TotalPhys2.
  // See also https://crbug.com/844118.

Do we have POCs for older Android versions (which presumably run on devices with <1077 MB RAM) for Spectre v1? I would generally just enable the more secure approach, but I am afraid that upstream has verified that browser would simply not be usable on those low-end devices.

@csagan5 csagan5 reopened this May 4, 2019
@thestinger
Copy link

it seems like builds for the browser APKs are already 64-bit by default.

I don't think so, unless I'm missing something.

I would generally just enable the more secure approach, but I am afraid that upstream has verified that browser would simply not be usable on those low-end devices.

In general, it will be usable, but some sites with a huge number of iframes may not work well. For example, using GitHub is probably not going to use any extra memory, since I don't see anywhere that it uses iframes.

@csagan5
Copy link
Contributor

csagan5 commented May 6, 2019

@thestinger you're right, I was confused by reading through the branches in BUILD.gn.
I still have to figure out a way to enable 64-bit for the regular browser APK, and hopefully it will not cause side effects.

@csagan5
Copy link
Contributor

csagan5 commented May 12, 2019

I am closing this for now; @thestinger please let me know if you come up with new patches, I'll be watching the repo meanwhile.

@csagan5 csagan5 closed this as completed May 12, 2019
@kokukyocho
Copy link
Collaborator

Hello @Eddi2015!

I am a bot 🤖

Thanks for submitting this issue!
I noticed that it is missing the template, please edit the issue to match the template for either a bug or a feature request.

The issue will be automatically re-opened after that.

Tip: if you use GitHub in Desktop mode the template will be proposed to you when submitting issues.

@kokukyocho kokukyocho added the missing-issue-template This issue was not created with the issue template label Mar 25, 2021
@ghost ghost changed the title Use patches of the AndroidHardening project . Mar 25, 2021
@csagan5 csagan5 changed the title . Use patches of the AndroidHardening project Mar 25, 2021
calyxos-gerrit pushed a commit to CalyxOS/chromium that referenced this issue Mar 8, 2023
Using -fwrapv (notably only when not using signed integer overflow checking -
since it will override it and result in not performing checks) is just common
sense since it eliminates the chance of security vulnerabilities being
introduced by optimizations based on signed overflow being undefined.
That has happened before, and those optimizations don't even add up to a 0.1%
performance increase for this kind of software. It's not worth having.
The Linux kernel passes -fwrapv and also -fno-strict-aliasing to disable those
dangerous optimizations (since there is so much incorrect code they can break).
In fact, it is easy to point to dozens of known examples of invalid code that
could potentially be broken by those optimizations.

It is not acceptable for projects to be using optimizations that are known to
be broken with a bunch of code in their tree.
They put barely any effort into even fixing the known cases.
Chromium has blacklists for UBSan for 'false positives' (none of which are
actually false positives, but rather "undefined, but not a bug beyond
potentially being broken by optimizations or even code generation without
them") and also for components too full of these bugs for them to currently
want to bother with it. That includes a bunch of signed overflow issues
(there is sadly no detection for aliasing violations, which are fairly common,
but not that common).

Ideally, -fwrapv could be always passed, but unfortunately the way it is
implemented has silly interactions with other switches.
The reason it would still make sense to pass it is because due to their UBSan
blacklists, they get far from full coverage with it, so -fwrapv would still
be better than nothing where it's not being used.

Since -fwrapv makes signed integer overflow well-defined, Clang will disable
the UBSan checks for signed integer overflow, including in the
production-oriented trapping mode used for hardening.

Excerpt from bromite/bromite#226

Original License: MIT - https://spdx.org/licenses/MIT.html
License: GPL-3.0-only - https://spdx.org/licenses/GPL-3.0-only.html
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
missing-issue-template This issue was not created with the issue template
Projects
None yet
Development

No branches or pull requests

3 participants