minijail: Copy the mount flags from source when bind-mounting

This change makes all bindmounts copy the mount flags from the source
path if a remount is issued. It also fixes a bug where ro mounts could
never become rw.

Bug: 111325710
Test: make tests
Test: Repro scenario in https://crbug.com/862171
Change-Id: Ia87ea2933f1ab1b8a9fd2efd6f832c51a5a8f7a2
diff --git a/system.c b/system.c
index 5e2a6f6..434980a 100644
--- a/system.c
+++ b/system.c
@@ -17,6 +17,7 @@
 #include <sys/prctl.h>
 #include <sys/socket.h>
 #include <sys/stat.h>
+#include <sys/statvfs.h>
 #include <unistd.h>
 
 #include "util.h"
@@ -268,7 +269,7 @@
  * Creates it if needed and possible.
  */
 int setup_mount_destination(const char *source, const char *dest, uid_t uid,
-			    uid_t gid, bool bind)
+			    uid_t gid, bool bind, unsigned long *mnt_flags)
 {
 	int rc;
 	struct stat st_buf;
@@ -309,6 +310,20 @@
 		domkdir = S_ISDIR(st_buf.st_mode) ||
 			  (!bind && (S_ISBLK(st_buf.st_mode) ||
 				     S_ISCHR(st_buf.st_mode)));
+
+		/* If bind mounting, also grab the mount flags of the source. */
+		if (bind && mnt_flags) {
+			struct statvfs stvfs_buf;
+			rc = statvfs(source, &stvfs_buf);
+			if (rc) {
+				rc = errno;
+				pwarn(
+				    "failed to look up mount flags: source=%s",
+				    source);
+				return -rc;
+			}
+			*mnt_flags = stvfs_buf.f_flag;
+		}
 	} else {
 		/* The source is a relative path -- assume it's a pseudo fs. */