android: Enforce read-only mapping of Ashmem regions.

This is a CL to solve the issue raised by 789959. The root of the
problem is that Android ashmem regions have a very different security
model than regular Posix shared memory regions:

- On Posix: the region doesn't have any associated read/write/exec
  protection mask, mmap() uses the file descriptor's access mode
  to determine if writable mappings are allowed. E.g. if the
  descriptor is opened with O_RDONLY, then an mmap() with PROT_WRITE
  will fail with an EACCES error.

- On Android: the Ashmem region has its own read/write/exec protection
  mask, and the file descriptor's access mode is ignored at mmap()
  time. Also, it is possible to change the region's protection mask
  through an ioctl(), that only allows dropping privileges. In other
  words, once a region has been turned read-only, it cannot be turned
  back to read-write, and any future mmap() attempts are affected
  (existing mappings that are read-write survive though).

- Also, there is no reliable way in Posix or Android to duplicate a
  file descriptor as read-only (even when /dev/fd/ or /proc/self/fd/
  are available), and no way to re-open an existing Ashmem region
  as read-only. This means that all Ashmem file descriptors have
  read-write access anyway.

Chromium code assumes that it is possible to create read-only
descriptors to shared memory region, then send them through IPC
to another process. On Android, this cannot work because all
descriptors are read-write anyway.

This CL works as follows to route around the issue, in the least
invasive possible way:

- On Android, add a "read_only_" flag to each SharedMemoryHandle
  instance, indicating that it is intended to only allow read-only
  mappings. This can be set with SetReadOnly() and tested with
  IsReadOnly(). Also ensure the flag is properly maintained
  when copying the handle instance, or sending it through IPC.

- Add a method called SetRegionReadOnly() to the
  Android version of the SharedMemoryHandle. This drops the write
  access bits from the _region_, making all future mappings _not_
  writable.

- Ensure that SetRegionReadOnly() is called at Map() time, when
  needed.

- Ensure that the region is sealed read-only when it is sent
  through IPC or Mojo through a read-only handle on Android.

- Modify the FieldTrial code to set the region read-only as soon
  as possible. This happens after the writable mapping has been
  created, and used by the PersistentMemoryAllocator, so it only
  affects processes that receive the region's file descriptor
  (i.e. sandboxed processes on Android).

  Also add a unit-test to verify that this works properly.

- Modify the user script loader to set the region read-only
  as soon as it has been populated. The code clearly throws
  away the original writable mapping before returning a read-only
  SharedMemory instance, so this should not create any problem.

  NOTE: This code is likely not used on Android yet, but better
  be safe than sorry.

- Fix content browser sensor-related tests, which used to map
  a shared memory region writable _after_ a read-only descriptor
  to it had been sent through Mojo to clients.

- Fix DeviceSensorHost implementation to ensure that its
  StartPolling() method always sends read-only file descriptors
  to the callback argument (crbug.com/793519, not Android-specific).

Also:

- Add ashmem_get_prot_region() to third_party/ashmem/ashmem.h,
  necessary to retrieve a region's current protection mask.
  This shall probably go into another CL.

- Fix a bug where Ashmem regions were blindy created with PROT_EXEC
  permission, even if the CreateOptions::executable bit was false.

- Add a unit-test to verify that anonymous region that are not
  created with CreateOptions::executable set to true cannot be
  mapped with PROT_EXEC. This test is Android-specific. It turns
  out that it fails on Linux (because /dev/shm is mounted on a
  tmpfs partition without the 'noexe' option, and there is no
  other way provided by the system to restrict PROT_EXEC-inducing
  mprotect() calls for these).

Bug: 789959,793519
Change-Id: Ibb02eddedd84f95462d7f8b94d3f2a100b983661
Reviewed-on: https://chromium-review.googlesource.com/805238
Commit-Queue: David Turner <digit@chromium.org>
Reviewed-by: Mark Pearson <mpearson@chromium.org>
Reviewed-by: Mark Mentovai <mark@chromium.org>
Reviewed-by: Tim Volodine <timvolodine@chromium.org>
Reviewed-by: agrieve <agrieve@chromium.org>
Reviewed-by: Robert Sesek <rsesek@chromium.org>
Reviewed-by: Ken Rockot <rockot@chromium.org>
Reviewed-by: Brandon Jones <bajones@chromium.org>
Reviewed-by: Camille Lamy <clamy@chromium.org>
Cr-Commit-Position: refs/heads/master@{#530553}
28 files changed