sdcardfs: Bring up to date with Android M permissions:

In M, the workings of sdcardfs were changed significantly.
This brings sdcardfs into line with the changes.

Change-Id: I10e91a84a884c838feef7aa26c0a2b21f02e052e
diff --git a/fs/sdcardfs/sdcardfs.h b/fs/sdcardfs/sdcardfs.h
index f666eff..ba1c7d9 100644
--- a/fs/sdcardfs/sdcardfs.h
+++ b/fs/sdcardfs/sdcardfs.h
@@ -42,6 +42,7 @@
 #include <linux/types.h>
 #include <linux/security.h>
 #include <linux/string.h>
+#include <linux/list.h>
 #include "multiuser.h"
 
 /* the file system name */
@@ -70,8 +71,8 @@
 #define fix_derived_permission(x)	\
 	do {						\
 		(x)->i_uid = SDCARDFS_I(x)->d_uid;	\
-		(x)->i_gid = SDCARDFS_I(x)->d_gid;	\
-		(x)->i_mode = ((x)->i_mode & S_IFMT) | SDCARDFS_I(x)->d_mode;\
+		(x)->i_gid = get_gid(SDCARDFS_I(x));	\
+		(x)->i_mode = ((x)->i_mode & S_IFMT) | get_mode(SDCARDFS_I(x));\
 	} while (0)
 
 /* OVERRIDE_CRED() and REVERT_CRED()
@@ -99,35 +100,28 @@
 		(int)current->cred->fsuid, 		\
 		(int)current->cred->fsgid);
 
-/* Android 4.4 support */
+/* Android 5.0 support */
 
 /* Permission mode for a specific node. Controls how file permissions
  * are derived for children nodes. */
 typedef enum {
-	/* Nothing special; this node should just inherit from its parent. */
-	PERM_INHERIT,
-	/* This node is one level above a normal root; used for legacy layouts
-	 * which use the first level to represent user_id. */
-	PERM_LEGACY_PRE_ROOT,
-	/* This node is "/" */
-	PERM_ROOT,
-	/* This node is "/Android" */
-	PERM_ANDROID,
-	/* This node is "/Android/data" */
-	PERM_ANDROID_DATA,
-	/* This node is "/Android/obb" */
-	PERM_ANDROID_OBB,
-	/* This node is "/Android/user" */
-	PERM_ANDROID_USER,
+    /* Nothing special; this node should just inherit from its parent. */
+    PERM_INHERIT,
+    /* This node is one level above a normal root; used for legacy layouts
+     * which use the first level to represent user_id. */
+    PERM_PRE_ROOT,
+    /* This node is "/" */
+    PERM_ROOT,
+    /* This node is "/Android" */
+    PERM_ANDROID,
+    /* This node is "/Android/data" */
+    PERM_ANDROID_DATA,
+    /* This node is "/Android/obb" */
+    PERM_ANDROID_OBB,
+    /* This node is "/Android/media" */
+    PERM_ANDROID_MEDIA,
 } perm_t;
 
-/* Permissions structure to derive */
-typedef enum {
-	DERIVE_NONE,
-	DERIVE_LEGACY,
-	DERIVE_UNIFIED,
-} derive_t;
-
 typedef enum {
 	LOWER_FS_EXT4,
 	LOWER_FS_FAT,
@@ -161,9 +155,9 @@
 extern struct dentry *sdcardfs_lookup(struct inode *dir, struct dentry *dentry,
 				    struct nameidata *nd);
 extern struct inode *sdcardfs_iget(struct super_block *sb,
-				 struct inode *lower_inode);
+				 struct inode *lower_inode, userid_t id);
 extern int sdcardfs_interpose(struct dentry *dentry, struct super_block *sb,
-			    struct path *lower_path);
+			    struct path *lower_path, userid_t id);
 
 /* file private data */
 struct sdcardfs_file_info {
@@ -174,18 +168,16 @@
 /* sdcardfs inode data in memory */
 struct sdcardfs_inode_info {
 	struct inode *lower_inode;
-	/* state derived based on current position in hierachy
-	 * caution: d_mode does not include file types
-	 */
+	/* state derived based on current position in hierachy */
 	perm_t perm;
 	userid_t userid;
 	uid_t d_uid;
-	gid_t d_gid;
-	mode_t d_mode;
+	bool under_android;
 
 	struct inode vfs_inode;
 };
 
+
 /* sdcardfs dentry data in memory */
 struct sdcardfs_dentry_info {
 	spinlock_t lock;	/* protects lower_path */
@@ -196,15 +188,17 @@
 struct sdcardfs_mount_options {
 	uid_t fs_low_uid;
 	gid_t fs_low_gid;
-	gid_t write_gid;
-	int split_perms;
-	derive_t derive;
+	userid_t fs_user_id;
+	gid_t gid;
 	lower_fs_t lower_fs;
+	mode_t mask;
+	bool multiuser;
 	unsigned int reserved_mb;
 };
 
 /* sdcardfs super-block data in memory */
 struct sdcardfs_sb_info {
+	struct super_block *sb;
 	struct super_block *lower_sb;
 	/* derived perm policy : some of options have been added
 	 * to sdcardfs_mount_options (Android 4.4 support) */
@@ -213,6 +207,7 @@
 	char *obbpath_s;
 	struct path obbpath;
 	void *pkgl_id;
+	struct list_head list;
 };
 
 /*
@@ -331,6 +326,44 @@
 SDCARDFS_DENT_FUNC(lower_path)
 SDCARDFS_DENT_FUNC(orig_path)
 
+static inline int get_gid(struct sdcardfs_inode_info *info) {
+	struct sdcardfs_sb_info *sb_info = SDCARDFS_SB(info->vfs_inode.i_sb);
+	if (sb_info->options.gid == AID_SDCARD_RW) {
+		/* As an optimization, certain trusted system components only run
+		 * as owner but operate across all users. Since we're now handing
+		 * out the sdcard_rw GID only to trusted apps, we're okay relaxing
+		 * the user boundary enforcement for the default view. The UIDs
+		 * assigned to app directories are still multiuser aware. */
+		return AID_SDCARD_RW;
+	} else {
+		return multiuser_get_uid(info->userid, sb_info->options.gid);
+	}
+}
+static inline int get_mode(struct sdcardfs_inode_info *info) {
+	int owner_mode;
+	int filtered_mode;
+	struct sdcardfs_sb_info *sb_info = SDCARDFS_SB(info->vfs_inode.i_sb);
+	int visible_mode = 0775 & ~sb_info->options.mask;
+
+	if (info->perm == PERM_PRE_ROOT) {
+		/* Top of multi-user view should always be visible to ensure
+		* secondary users can traverse inside. */
+		visible_mode = 0711;
+	} else if (info->under_android) {
+		/* Block "other" access to Android directories, since only apps
+		* belonging to a specific user should be in there; we still
+		* leave +x open for the default view. */
+		if (sb_info->options.gid == AID_SDCARD_RW) {
+			visible_mode = visible_mode & ~0006;
+		} else {
+			visible_mode = visible_mode & ~0007;
+		}
+	}
+	owner_mode = info->lower_inode->i_mode & 0700;
+	filtered_mode = visible_mode & (owner_mode | (owner_mode >> 3) | (owner_mode >> 6));
+	return filtered_mode;
+}
+
 static inline int has_graft_path(const struct dentry *dent)
 {
 	int ret = 0;
@@ -364,22 +397,24 @@
 		sdcardfs_put_lower_path(dent, real_lower);
 }
 
+extern struct mutex sdcardfs_super_list_lock;
+extern struct list_head sdcardfs_super_list;
+
 /* for packagelist.c */
-extern int get_caller_has_rw_locked(void *pkgl_id, derive_t derive);
 extern appid_t get_appid(void *pkgl_id, const char *app_name);
-extern int check_caller_access_to_name(struct inode *parent_node, const char* name,
-                                        derive_t derive, int w_ok, int has_rw);
+extern int check_caller_access_to_name(struct inode *parent_node, const char* name);
 extern int open_flags_to_access_mode(int open_flags);
-extern void * packagelist_create(gid_t write_gid);
-extern void packagelist_destroy(void *pkgl_id);
 extern int packagelist_init(void);
 extern void packagelist_exit(void);
 
 /* for derived_perm.c */
 extern void setup_derived_state(struct inode *inode, perm_t perm,
-			userid_t userid, uid_t uid, gid_t gid, mode_t mode);
+			userid_t userid, uid_t uid, bool under_android);
 extern void get_derived_permission(struct dentry *parent, struct dentry *dentry);
-extern void update_derived_permission(struct dentry *dentry);
+extern void get_derived_permission_new(struct dentry *parent, struct dentry *dentry, struct dentry *newdentry);
+extern void get_derive_permissions_recursive(struct dentry *parent);
+
+extern void update_derived_permission_lock(struct dentry *dentry);
 extern int need_graft_path(struct dentry *dentry);
 extern int is_base_obbpath(struct dentry *dentry);
 extern int is_obbpath_invalid(struct dentry *dentry);
@@ -484,4 +519,18 @@
 		return 1;
 }
 
+/* Copies attrs and maintains sdcardfs managed attrs */
+static inline void sdcardfs_copy_and_fix_attrs(struct inode *dest, const struct inode *src)
+{
+	dest->i_mode = (src->i_mode  & S_IFMT) | get_mode(SDCARDFS_I(dest));
+	dest->i_uid = SDCARDFS_I(dest)->d_uid;
+	dest->i_gid = get_gid(SDCARDFS_I(dest));
+	dest->i_rdev = src->i_rdev;
+	dest->i_atime = src->i_atime;
+	dest->i_mtime = src->i_mtime;
+	dest->i_ctime = src->i_ctime;
+	dest->i_blkbits = src->i_blkbits;
+	dest->i_flags = src->i_flags;
+	set_nlink(dest, src->i_nlink);
+}
 #endif	/* not _SDCARDFS_H_ */