adb: Preserve the original mount flags when remounting

This change preserves any additional flags mount flags (e.g. MS_NODEV)
that any of the mounts would have. This avoids unnecessarily opening up
permissions, and also allows kernels that have additional restrictions
about what mount flags can be used to be happy with the remounts.

Bug: 111618714
Test: `adb remount` works in Chrome OS
Test: `adb remount` works in sailfish_aosp

Change-Id: I20d9f2feaf3a47b93bfcdfb4164ee61546ec0b68
This commit is contained in:
Luis Hector Chavez 2018-07-18 17:43:28 -07:00
parent 54f40303d5
commit c20c85008d

View file

@ -26,6 +26,7 @@
#include <stdlib.h>
#include <string.h>
#include <sys/mount.h>
#include <sys/statvfs.h>
#include <sys/vfs.h>
#include <unistd.h>
@ -145,6 +146,17 @@ static bool can_unshare_blocks(int fd, const char* dev) {
return true;
}
static unsigned long get_mount_flags(int fd, const char* dir) {
struct statvfs st_vfs;
if (statvfs(dir, &st_vfs) == -1) {
// Even though we could not get the original mount flags, assume that
// the mount was originally read-only.
WriteFdFmt(fd, "statvfs of the %s mount failed: %s.\n", dir, strerror(errno));
return MS_RDONLY;
}
return st_vfs.f_flag;
}
static bool remount_partition(int fd, const char* dir) {
if (!directory_exists(dir)) {
return true;
@ -163,14 +175,23 @@ static bool remount_partition(int fd, const char* dir) {
dir, dev.c_str(), strerror(errno));
return false;
}
if (mount(dev.c_str(), dir, "none", MS_REMOUNT | MS_BIND, nullptr) == -1) {
unsigned long remount_flags = get_mount_flags(fd, dir);
if ((remount_flags & MS_RDONLY) == 0) {
// Mount is already writable.
return true;
}
remount_flags &= ~MS_RDONLY;
remount_flags |= MS_REMOUNT;
if (mount(dev.c_str(), dir, "none", remount_flags | MS_BIND, nullptr) == -1) {
// This is useful for cases where the superblock is already marked as
// read-write, but the mount itself is read-only, such as containers
// where the remount with just MS_REMOUNT is forbidden by the kernel.
WriteFdFmt(fd, "remount of the %s mount failed: %s.\n", dir, strerror(errno));
return false;
}
if (mount(dev.c_str(), dir, "none", MS_REMOUNT, nullptr) == -1) {
if (mount(dev.c_str(), dir, "none", remount_flags, nullptr) == -1) {
WriteFdFmt(fd, "remount of the %s superblock failed: %s\n", dir, strerror(errno));
return false;
}