xref: /openbmc/linux/drivers/android/binderfs.c (revision 3ad20fe3)
13ad20fe3SChristian Brauner /* SPDX-License-Identifier: GPL-2.0 */
23ad20fe3SChristian Brauner 
33ad20fe3SChristian Brauner #include <linux/compiler_types.h>
43ad20fe3SChristian Brauner #include <linux/errno.h>
53ad20fe3SChristian Brauner #include <linux/fs.h>
63ad20fe3SChristian Brauner #include <linux/fsnotify.h>
73ad20fe3SChristian Brauner #include <linux/gfp.h>
83ad20fe3SChristian Brauner #include <linux/idr.h>
93ad20fe3SChristian Brauner #include <linux/init.h>
103ad20fe3SChristian Brauner #include <linux/ipc_namespace.h>
113ad20fe3SChristian Brauner #include <linux/kdev_t.h>
123ad20fe3SChristian Brauner #include <linux/kernel.h>
133ad20fe3SChristian Brauner #include <linux/list.h>
143ad20fe3SChristian Brauner #include <linux/magic.h>
153ad20fe3SChristian Brauner #include <linux/major.h>
163ad20fe3SChristian Brauner #include <linux/miscdevice.h>
173ad20fe3SChristian Brauner #include <linux/module.h>
183ad20fe3SChristian Brauner #include <linux/mutex.h>
193ad20fe3SChristian Brauner #include <linux/mount.h>
203ad20fe3SChristian Brauner #include <linux/parser.h>
213ad20fe3SChristian Brauner #include <linux/radix-tree.h>
223ad20fe3SChristian Brauner #include <linux/sched.h>
233ad20fe3SChristian Brauner #include <linux/slab.h>
243ad20fe3SChristian Brauner #include <linux/spinlock_types.h>
253ad20fe3SChristian Brauner #include <linux/stddef.h>
263ad20fe3SChristian Brauner #include <linux/string.h>
273ad20fe3SChristian Brauner #include <linux/types.h>
283ad20fe3SChristian Brauner #include <linux/uaccess.h>
293ad20fe3SChristian Brauner #include <linux/user_namespace.h>
303ad20fe3SChristian Brauner #include <linux/xarray.h>
313ad20fe3SChristian Brauner #include <uapi/asm-generic/errno-base.h>
323ad20fe3SChristian Brauner #include <uapi/linux/android/binder.h>
333ad20fe3SChristian Brauner #include <uapi/linux/android/binder_ctl.h>
343ad20fe3SChristian Brauner 
353ad20fe3SChristian Brauner #include "binder_internal.h"
363ad20fe3SChristian Brauner 
373ad20fe3SChristian Brauner #define FIRST_INODE 1
383ad20fe3SChristian Brauner #define SECOND_INODE 2
393ad20fe3SChristian Brauner #define INODE_OFFSET 3
403ad20fe3SChristian Brauner #define INTSTRLEN 21
413ad20fe3SChristian Brauner #define BINDERFS_MAX_MINOR (1U << MINORBITS)
423ad20fe3SChristian Brauner 
433ad20fe3SChristian Brauner static struct vfsmount *binderfs_mnt;
443ad20fe3SChristian Brauner 
453ad20fe3SChristian Brauner static dev_t binderfs_dev;
463ad20fe3SChristian Brauner static DEFINE_MUTEX(binderfs_minors_mutex);
473ad20fe3SChristian Brauner static DEFINE_IDA(binderfs_minors);
483ad20fe3SChristian Brauner 
493ad20fe3SChristian Brauner /**
503ad20fe3SChristian Brauner  * binderfs_info - information about a binderfs mount
513ad20fe3SChristian Brauner  * @ipc_ns:         The ipc namespace the binderfs mount belongs to.
523ad20fe3SChristian Brauner  * @control_dentry: This records the dentry of this binderfs mount
533ad20fe3SChristian Brauner  *                  binder-control device.
543ad20fe3SChristian Brauner  * @root_uid:       uid that needs to be used when a new binder device is
553ad20fe3SChristian Brauner  *                  created.
563ad20fe3SChristian Brauner  * @root_gid:       gid that needs to be used when a new binder device is
573ad20fe3SChristian Brauner  *                  created.
583ad20fe3SChristian Brauner  */
593ad20fe3SChristian Brauner struct binderfs_info {
603ad20fe3SChristian Brauner 	struct ipc_namespace *ipc_ns;
613ad20fe3SChristian Brauner 	struct dentry *control_dentry;
623ad20fe3SChristian Brauner 	kuid_t root_uid;
633ad20fe3SChristian Brauner 	kgid_t root_gid;
643ad20fe3SChristian Brauner 
653ad20fe3SChristian Brauner };
663ad20fe3SChristian Brauner 
673ad20fe3SChristian Brauner static inline struct binderfs_info *BINDERFS_I(const struct inode *inode)
683ad20fe3SChristian Brauner {
693ad20fe3SChristian Brauner 	return inode->i_sb->s_fs_info;
703ad20fe3SChristian Brauner }
713ad20fe3SChristian Brauner 
723ad20fe3SChristian Brauner bool is_binderfs_device(const struct inode *inode)
733ad20fe3SChristian Brauner {
743ad20fe3SChristian Brauner 	if (inode->i_sb->s_magic == BINDERFS_SUPER_MAGIC)
753ad20fe3SChristian Brauner 		return true;
763ad20fe3SChristian Brauner 
773ad20fe3SChristian Brauner 	return false;
783ad20fe3SChristian Brauner }
793ad20fe3SChristian Brauner 
803ad20fe3SChristian Brauner /**
813ad20fe3SChristian Brauner  * binderfs_binder_device_create - allocate inode from super block of a
823ad20fe3SChristian Brauner  *                                 binderfs mount
833ad20fe3SChristian Brauner  * @ref_inode: inode from wich the super block will be taken
843ad20fe3SChristian Brauner  * @userp:     buffer to copy information about new device for userspace to
853ad20fe3SChristian Brauner  * @req:       struct binderfs_device as copied from userspace
863ad20fe3SChristian Brauner  *
873ad20fe3SChristian Brauner  * This function allocated a new binder_device and reserves a new minor
883ad20fe3SChristian Brauner  * number for it.
893ad20fe3SChristian Brauner  * Minor numbers are limited and tracked globally in binderfs_minors. The
903ad20fe3SChristian Brauner  * function will stash a struct binder_device for the specific binder
913ad20fe3SChristian Brauner  * device in i_private of the inode.
923ad20fe3SChristian Brauner  * It will go on to allocate a new inode from the super block of the
933ad20fe3SChristian Brauner  * filesystem mount, stash a struct binder_device in its i_private field
943ad20fe3SChristian Brauner  * and attach a dentry to that inode.
953ad20fe3SChristian Brauner  *
963ad20fe3SChristian Brauner  * Return: 0 on success, negative errno on failure
973ad20fe3SChristian Brauner  */
983ad20fe3SChristian Brauner static int binderfs_binder_device_create(struct inode *ref_inode,
993ad20fe3SChristian Brauner 					 struct binderfs_device __user *userp,
1003ad20fe3SChristian Brauner 					 struct binderfs_device *req)
1013ad20fe3SChristian Brauner {
1023ad20fe3SChristian Brauner 	int minor, ret;
1033ad20fe3SChristian Brauner 	struct dentry *dentry, *dup, *root;
1043ad20fe3SChristian Brauner 	struct binder_device *device;
1053ad20fe3SChristian Brauner 	size_t name_len = BINDERFS_MAX_NAME + 1;
1063ad20fe3SChristian Brauner 	char *name = NULL;
1073ad20fe3SChristian Brauner 	struct inode *inode = NULL;
1083ad20fe3SChristian Brauner 	struct super_block *sb = ref_inode->i_sb;
1093ad20fe3SChristian Brauner 	struct binderfs_info *info = sb->s_fs_info;
1103ad20fe3SChristian Brauner 
1113ad20fe3SChristian Brauner 	/* Reserve new minor number for the new device. */
1123ad20fe3SChristian Brauner 	mutex_lock(&binderfs_minors_mutex);
1133ad20fe3SChristian Brauner 	minor = ida_alloc_max(&binderfs_minors, BINDERFS_MAX_MINOR, GFP_KERNEL);
1143ad20fe3SChristian Brauner 	mutex_unlock(&binderfs_minors_mutex);
1153ad20fe3SChristian Brauner 	if (minor < 0)
1163ad20fe3SChristian Brauner 		return minor;
1173ad20fe3SChristian Brauner 
1183ad20fe3SChristian Brauner 	ret = -ENOMEM;
1193ad20fe3SChristian Brauner 	device = kzalloc(sizeof(*device), GFP_KERNEL);
1203ad20fe3SChristian Brauner 	if (!device)
1213ad20fe3SChristian Brauner 		goto err;
1223ad20fe3SChristian Brauner 
1233ad20fe3SChristian Brauner 	inode = new_inode(sb);
1243ad20fe3SChristian Brauner 	if (!inode)
1253ad20fe3SChristian Brauner 		goto err;
1263ad20fe3SChristian Brauner 
1273ad20fe3SChristian Brauner 	inode->i_ino = minor + INODE_OFFSET;
1283ad20fe3SChristian Brauner 	inode->i_mtime = inode->i_atime = inode->i_ctime = current_time(inode);
1293ad20fe3SChristian Brauner 	init_special_inode(inode, S_IFCHR | 0600,
1303ad20fe3SChristian Brauner 			   MKDEV(MAJOR(binderfs_dev), minor));
1313ad20fe3SChristian Brauner 	inode->i_fop = &binder_fops;
1323ad20fe3SChristian Brauner 	inode->i_uid = info->root_uid;
1333ad20fe3SChristian Brauner 	inode->i_gid = info->root_gid;
1343ad20fe3SChristian Brauner 
1353ad20fe3SChristian Brauner 	name = kmalloc(name_len, GFP_KERNEL);
1363ad20fe3SChristian Brauner 	if (!name)
1373ad20fe3SChristian Brauner 		goto err;
1383ad20fe3SChristian Brauner 
1393ad20fe3SChristian Brauner 	strscpy(name, req->name, name_len);
1403ad20fe3SChristian Brauner 
1413ad20fe3SChristian Brauner 	device->binderfs_inode = inode;
1423ad20fe3SChristian Brauner 	device->context.binder_context_mgr_uid = INVALID_UID;
1433ad20fe3SChristian Brauner 	device->context.name = name;
1443ad20fe3SChristian Brauner 	device->miscdev.name = name;
1453ad20fe3SChristian Brauner 	device->miscdev.minor = minor;
1463ad20fe3SChristian Brauner 	mutex_init(&device->context.context_mgr_node_lock);
1473ad20fe3SChristian Brauner 
1483ad20fe3SChristian Brauner 	req->major = MAJOR(binderfs_dev);
1493ad20fe3SChristian Brauner 	req->minor = minor;
1503ad20fe3SChristian Brauner 
1513ad20fe3SChristian Brauner 	ret = copy_to_user(userp, req, sizeof(*req));
1523ad20fe3SChristian Brauner 	if (ret) {
1533ad20fe3SChristian Brauner 		ret = -EFAULT;
1543ad20fe3SChristian Brauner 		goto err;
1553ad20fe3SChristian Brauner 	}
1563ad20fe3SChristian Brauner 
1573ad20fe3SChristian Brauner 	root = sb->s_root;
1583ad20fe3SChristian Brauner 	inode_lock(d_inode(root));
1593ad20fe3SChristian Brauner 	dentry = d_alloc_name(root, name);
1603ad20fe3SChristian Brauner 	if (!dentry) {
1613ad20fe3SChristian Brauner 		inode_unlock(d_inode(root));
1623ad20fe3SChristian Brauner 		ret = -ENOMEM;
1633ad20fe3SChristian Brauner 		goto err;
1643ad20fe3SChristian Brauner 	}
1653ad20fe3SChristian Brauner 
1663ad20fe3SChristian Brauner 	/* Verify that the name userspace gave us is not already in use. */
1673ad20fe3SChristian Brauner 	dup = d_lookup(root, &dentry->d_name);
1683ad20fe3SChristian Brauner 	if (dup) {
1693ad20fe3SChristian Brauner 		if (d_really_is_positive(dup)) {
1703ad20fe3SChristian Brauner 			dput(dup);
1713ad20fe3SChristian Brauner 			dput(dentry);
1723ad20fe3SChristian Brauner 			inode_unlock(d_inode(root));
1733ad20fe3SChristian Brauner 			ret = -EEXIST;
1743ad20fe3SChristian Brauner 			goto err;
1753ad20fe3SChristian Brauner 		}
1763ad20fe3SChristian Brauner 		dput(dup);
1773ad20fe3SChristian Brauner 	}
1783ad20fe3SChristian Brauner 
1793ad20fe3SChristian Brauner 	inode->i_private = device;
1803ad20fe3SChristian Brauner 	d_add(dentry, inode);
1813ad20fe3SChristian Brauner 	fsnotify_create(root->d_inode, dentry);
1823ad20fe3SChristian Brauner 	inode_unlock(d_inode(root));
1833ad20fe3SChristian Brauner 
1843ad20fe3SChristian Brauner 	return 0;
1853ad20fe3SChristian Brauner 
1863ad20fe3SChristian Brauner err:
1873ad20fe3SChristian Brauner 	kfree(name);
1883ad20fe3SChristian Brauner 	kfree(device);
1893ad20fe3SChristian Brauner 	mutex_lock(&binderfs_minors_mutex);
1903ad20fe3SChristian Brauner 	ida_free(&binderfs_minors, minor);
1913ad20fe3SChristian Brauner 	mutex_unlock(&binderfs_minors_mutex);
1923ad20fe3SChristian Brauner 	iput(inode);
1933ad20fe3SChristian Brauner 
1943ad20fe3SChristian Brauner 	return ret;
1953ad20fe3SChristian Brauner }
1963ad20fe3SChristian Brauner 
1973ad20fe3SChristian Brauner /**
1983ad20fe3SChristian Brauner  * binderfs_ctl_ioctl - handle binder device node allocation requests
1993ad20fe3SChristian Brauner  *
2003ad20fe3SChristian Brauner  * The request handler for the binder-control device. All requests operate on
2013ad20fe3SChristian Brauner  * the binderfs mount the binder-control device resides in:
2023ad20fe3SChristian Brauner  * - BINDER_CTL_ADD
2033ad20fe3SChristian Brauner  *   Allocate a new binder device.
2043ad20fe3SChristian Brauner  *
2053ad20fe3SChristian Brauner  * Return: 0 on success, negative errno on failure
2063ad20fe3SChristian Brauner  */
2073ad20fe3SChristian Brauner static long binder_ctl_ioctl(struct file *file, unsigned int cmd,
2083ad20fe3SChristian Brauner 			     unsigned long arg)
2093ad20fe3SChristian Brauner {
2103ad20fe3SChristian Brauner 	int ret = -EINVAL;
2113ad20fe3SChristian Brauner 	struct inode *inode = file_inode(file);
2123ad20fe3SChristian Brauner 	struct binderfs_device __user *device = (struct binderfs_device __user *)arg;
2133ad20fe3SChristian Brauner 	struct binderfs_device device_req;
2143ad20fe3SChristian Brauner 
2153ad20fe3SChristian Brauner 	switch (cmd) {
2163ad20fe3SChristian Brauner 	case BINDER_CTL_ADD:
2173ad20fe3SChristian Brauner 		ret = copy_from_user(&device_req, device, sizeof(device_req));
2183ad20fe3SChristian Brauner 		if (ret) {
2193ad20fe3SChristian Brauner 			ret = -EFAULT;
2203ad20fe3SChristian Brauner 			break;
2213ad20fe3SChristian Brauner 		}
2223ad20fe3SChristian Brauner 
2233ad20fe3SChristian Brauner 		ret = binderfs_binder_device_create(inode, device, &device_req);
2243ad20fe3SChristian Brauner 		break;
2253ad20fe3SChristian Brauner 	default:
2263ad20fe3SChristian Brauner 		break;
2273ad20fe3SChristian Brauner 	}
2283ad20fe3SChristian Brauner 
2293ad20fe3SChristian Brauner 	return ret;
2303ad20fe3SChristian Brauner }
2313ad20fe3SChristian Brauner 
2323ad20fe3SChristian Brauner static void binderfs_evict_inode(struct inode *inode)
2333ad20fe3SChristian Brauner {
2343ad20fe3SChristian Brauner 	struct binder_device *device = inode->i_private;
2353ad20fe3SChristian Brauner 
2363ad20fe3SChristian Brauner 	clear_inode(inode);
2373ad20fe3SChristian Brauner 
2383ad20fe3SChristian Brauner 	if (!device)
2393ad20fe3SChristian Brauner 		return;
2403ad20fe3SChristian Brauner 
2413ad20fe3SChristian Brauner 	mutex_lock(&binderfs_minors_mutex);
2423ad20fe3SChristian Brauner 	ida_free(&binderfs_minors, device->miscdev.minor);
2433ad20fe3SChristian Brauner 	mutex_unlock(&binderfs_minors_mutex);
2443ad20fe3SChristian Brauner 
2453ad20fe3SChristian Brauner 	kfree(device->context.name);
2463ad20fe3SChristian Brauner 	kfree(device);
2473ad20fe3SChristian Brauner }
2483ad20fe3SChristian Brauner 
2493ad20fe3SChristian Brauner static const struct super_operations binderfs_super_ops = {
2503ad20fe3SChristian Brauner 	.statfs = simple_statfs,
2513ad20fe3SChristian Brauner 	.evict_inode = binderfs_evict_inode,
2523ad20fe3SChristian Brauner };
2533ad20fe3SChristian Brauner 
2543ad20fe3SChristian Brauner static int binderfs_rename(struct inode *old_dir, struct dentry *old_dentry,
2553ad20fe3SChristian Brauner 			   struct inode *new_dir, struct dentry *new_dentry,
2563ad20fe3SChristian Brauner 			   unsigned int flags)
2573ad20fe3SChristian Brauner {
2583ad20fe3SChristian Brauner 	struct inode *inode = d_inode(old_dentry);
2593ad20fe3SChristian Brauner 
2603ad20fe3SChristian Brauner 	/* binderfs doesn't support directories. */
2613ad20fe3SChristian Brauner 	if (d_is_dir(old_dentry))
2623ad20fe3SChristian Brauner 		return -EPERM;
2633ad20fe3SChristian Brauner 
2643ad20fe3SChristian Brauner 	if (flags & ~RENAME_NOREPLACE)
2653ad20fe3SChristian Brauner 		return -EINVAL;
2663ad20fe3SChristian Brauner 
2673ad20fe3SChristian Brauner 	if (!simple_empty(new_dentry))
2683ad20fe3SChristian Brauner 		return -ENOTEMPTY;
2693ad20fe3SChristian Brauner 
2703ad20fe3SChristian Brauner 	if (d_really_is_positive(new_dentry))
2713ad20fe3SChristian Brauner 		simple_unlink(new_dir, new_dentry);
2723ad20fe3SChristian Brauner 
2733ad20fe3SChristian Brauner 	old_dir->i_ctime = old_dir->i_mtime = new_dir->i_ctime =
2743ad20fe3SChristian Brauner 		new_dir->i_mtime = inode->i_ctime = current_time(old_dir);
2753ad20fe3SChristian Brauner 
2763ad20fe3SChristian Brauner 	return 0;
2773ad20fe3SChristian Brauner }
2783ad20fe3SChristian Brauner 
2793ad20fe3SChristian Brauner static int binderfs_unlink(struct inode *dir, struct dentry *dentry)
2803ad20fe3SChristian Brauner {
2813ad20fe3SChristian Brauner 	/*
2823ad20fe3SChristian Brauner 	 * The control dentry is only ever touched during mount so checking it
2833ad20fe3SChristian Brauner 	 * here should not require us to take lock.
2843ad20fe3SChristian Brauner 	 */
2853ad20fe3SChristian Brauner 	if (BINDERFS_I(dir)->control_dentry == dentry)
2863ad20fe3SChristian Brauner 		return -EPERM;
2873ad20fe3SChristian Brauner 
2883ad20fe3SChristian Brauner 	return simple_unlink(dir, dentry);
2893ad20fe3SChristian Brauner }
2903ad20fe3SChristian Brauner 
2913ad20fe3SChristian Brauner static const struct file_operations binder_ctl_fops = {
2923ad20fe3SChristian Brauner 	.owner		= THIS_MODULE,
2933ad20fe3SChristian Brauner 	.open		= nonseekable_open,
2943ad20fe3SChristian Brauner 	.unlocked_ioctl	= binder_ctl_ioctl,
2953ad20fe3SChristian Brauner 	.compat_ioctl	= binder_ctl_ioctl,
2963ad20fe3SChristian Brauner 	.llseek		= noop_llseek,
2973ad20fe3SChristian Brauner };
2983ad20fe3SChristian Brauner 
2993ad20fe3SChristian Brauner /**
3003ad20fe3SChristian Brauner  * binderfs_binder_ctl_create - create a new binder-control device
3013ad20fe3SChristian Brauner  * @sb: super block of the binderfs mount
3023ad20fe3SChristian Brauner  *
3033ad20fe3SChristian Brauner  * This function creates a new binder-control device node in the binderfs mount
3043ad20fe3SChristian Brauner  * referred to by @sb.
3053ad20fe3SChristian Brauner  *
3063ad20fe3SChristian Brauner  * Return: 0 on success, negative errno on failure
3073ad20fe3SChristian Brauner  */
3083ad20fe3SChristian Brauner static int binderfs_binder_ctl_create(struct super_block *sb)
3093ad20fe3SChristian Brauner {
3103ad20fe3SChristian Brauner 	int minor, ret;
3113ad20fe3SChristian Brauner 	struct dentry *dentry;
3123ad20fe3SChristian Brauner 	struct binder_device *device;
3133ad20fe3SChristian Brauner 	struct inode *inode = NULL;
3143ad20fe3SChristian Brauner 	struct dentry *root = sb->s_root;
3153ad20fe3SChristian Brauner 	struct binderfs_info *info = sb->s_fs_info;
3163ad20fe3SChristian Brauner 
3173ad20fe3SChristian Brauner 	device = kzalloc(sizeof(*device), GFP_KERNEL);
3183ad20fe3SChristian Brauner 	if (!device)
3193ad20fe3SChristian Brauner 		return -ENOMEM;
3203ad20fe3SChristian Brauner 
3213ad20fe3SChristian Brauner 	inode_lock(d_inode(root));
3223ad20fe3SChristian Brauner 
3233ad20fe3SChristian Brauner 	/* If we have already created a binder-control node, return. */
3243ad20fe3SChristian Brauner 	if (info->control_dentry) {
3253ad20fe3SChristian Brauner 		ret = 0;
3263ad20fe3SChristian Brauner 		goto out;
3273ad20fe3SChristian Brauner 	}
3283ad20fe3SChristian Brauner 
3293ad20fe3SChristian Brauner 	ret = -ENOMEM;
3303ad20fe3SChristian Brauner 	inode = new_inode(sb);
3313ad20fe3SChristian Brauner 	if (!inode)
3323ad20fe3SChristian Brauner 		goto out;
3333ad20fe3SChristian Brauner 
3343ad20fe3SChristian Brauner 	/* Reserve a new minor number for the new device. */
3353ad20fe3SChristian Brauner 	mutex_lock(&binderfs_minors_mutex);
3363ad20fe3SChristian Brauner 	minor = ida_alloc_max(&binderfs_minors, BINDERFS_MAX_MINOR, GFP_KERNEL);
3373ad20fe3SChristian Brauner 	mutex_unlock(&binderfs_minors_mutex);
3383ad20fe3SChristian Brauner 	if (minor < 0) {
3393ad20fe3SChristian Brauner 		ret = minor;
3403ad20fe3SChristian Brauner 		goto out;
3413ad20fe3SChristian Brauner 	}
3423ad20fe3SChristian Brauner 
3433ad20fe3SChristian Brauner 	inode->i_ino = SECOND_INODE;
3443ad20fe3SChristian Brauner 	inode->i_mtime = inode->i_atime = inode->i_ctime = current_time(inode);
3453ad20fe3SChristian Brauner 	init_special_inode(inode, S_IFCHR | 0600,
3463ad20fe3SChristian Brauner 			   MKDEV(MAJOR(binderfs_dev), minor));
3473ad20fe3SChristian Brauner 	inode->i_fop = &binder_ctl_fops;
3483ad20fe3SChristian Brauner 	inode->i_uid = info->root_uid;
3493ad20fe3SChristian Brauner 	inode->i_gid = info->root_gid;
3503ad20fe3SChristian Brauner 
3513ad20fe3SChristian Brauner 	device->binderfs_inode = inode;
3523ad20fe3SChristian Brauner 	device->miscdev.minor = minor;
3533ad20fe3SChristian Brauner 
3543ad20fe3SChristian Brauner 	dentry = d_alloc_name(root, "binder-control");
3553ad20fe3SChristian Brauner 	if (!dentry)
3563ad20fe3SChristian Brauner 		goto out;
3573ad20fe3SChristian Brauner 
3583ad20fe3SChristian Brauner 	inode->i_private = device;
3593ad20fe3SChristian Brauner 	info->control_dentry = dentry;
3603ad20fe3SChristian Brauner 	d_add(dentry, inode);
3613ad20fe3SChristian Brauner 	inode_unlock(d_inode(root));
3623ad20fe3SChristian Brauner 
3633ad20fe3SChristian Brauner 	return 0;
3643ad20fe3SChristian Brauner 
3653ad20fe3SChristian Brauner out:
3663ad20fe3SChristian Brauner 	inode_unlock(d_inode(root));
3673ad20fe3SChristian Brauner 	kfree(device);
3683ad20fe3SChristian Brauner 	iput(inode);
3693ad20fe3SChristian Brauner 
3703ad20fe3SChristian Brauner 	return ret;
3713ad20fe3SChristian Brauner }
3723ad20fe3SChristian Brauner 
3733ad20fe3SChristian Brauner static const struct inode_operations binderfs_dir_inode_operations = {
3743ad20fe3SChristian Brauner 	.lookup = simple_lookup,
3753ad20fe3SChristian Brauner 	.rename = binderfs_rename,
3763ad20fe3SChristian Brauner 	.unlink = binderfs_unlink,
3773ad20fe3SChristian Brauner };
3783ad20fe3SChristian Brauner 
3793ad20fe3SChristian Brauner static int binderfs_fill_super(struct super_block *sb, void *data, int silent)
3803ad20fe3SChristian Brauner {
3813ad20fe3SChristian Brauner 	struct binderfs_info *info;
3823ad20fe3SChristian Brauner 	int ret = -ENOMEM;
3833ad20fe3SChristian Brauner 	struct inode *inode = NULL;
3843ad20fe3SChristian Brauner 	struct ipc_namespace *ipc_ns = sb->s_fs_info;
3853ad20fe3SChristian Brauner 
3863ad20fe3SChristian Brauner 	get_ipc_ns(ipc_ns);
3873ad20fe3SChristian Brauner 
3883ad20fe3SChristian Brauner 	sb->s_blocksize = PAGE_SIZE;
3893ad20fe3SChristian Brauner 	sb->s_blocksize_bits = PAGE_SHIFT;
3903ad20fe3SChristian Brauner 
3913ad20fe3SChristian Brauner 	/*
3923ad20fe3SChristian Brauner 	 * The binderfs filesystem can be mounted by userns root in a
3933ad20fe3SChristian Brauner 	 * non-initial userns. By default such mounts have the SB_I_NODEV flag
3943ad20fe3SChristian Brauner 	 * set in s_iflags to prevent security issues where userns root can
3953ad20fe3SChristian Brauner 	 * just create random device nodes via mknod() since it owns the
3963ad20fe3SChristian Brauner 	 * filesystem mount. But binderfs does not allow to create any files
3973ad20fe3SChristian Brauner 	 * including devices nodes. The only way to create binder devices nodes
3983ad20fe3SChristian Brauner 	 * is through the binder-control device which userns root is explicitly
3993ad20fe3SChristian Brauner 	 * allowed to do. So removing the SB_I_NODEV flag from s_iflags is both
4003ad20fe3SChristian Brauner 	 * necessary and safe.
4013ad20fe3SChristian Brauner 	 */
4023ad20fe3SChristian Brauner 	sb->s_iflags &= ~SB_I_NODEV;
4033ad20fe3SChristian Brauner 	sb->s_iflags |= SB_I_NOEXEC;
4043ad20fe3SChristian Brauner 	sb->s_magic = BINDERFS_SUPER_MAGIC;
4053ad20fe3SChristian Brauner 	sb->s_op = &binderfs_super_ops;
4063ad20fe3SChristian Brauner 	sb->s_time_gran = 1;
4073ad20fe3SChristian Brauner 
4083ad20fe3SChristian Brauner 	info = kzalloc(sizeof(struct binderfs_info), GFP_KERNEL);
4093ad20fe3SChristian Brauner 	if (!info)
4103ad20fe3SChristian Brauner 		goto err_without_dentry;
4113ad20fe3SChristian Brauner 
4123ad20fe3SChristian Brauner 	info->ipc_ns = ipc_ns;
4133ad20fe3SChristian Brauner 	info->root_gid = make_kgid(sb->s_user_ns, 0);
4143ad20fe3SChristian Brauner 	if (!gid_valid(info->root_gid))
4153ad20fe3SChristian Brauner 		info->root_gid = GLOBAL_ROOT_GID;
4163ad20fe3SChristian Brauner 	info->root_uid = make_kuid(sb->s_user_ns, 0);
4173ad20fe3SChristian Brauner 	if (!uid_valid(info->root_uid))
4183ad20fe3SChristian Brauner 		info->root_uid = GLOBAL_ROOT_UID;
4193ad20fe3SChristian Brauner 
4203ad20fe3SChristian Brauner 	sb->s_fs_info = info;
4213ad20fe3SChristian Brauner 
4223ad20fe3SChristian Brauner 	inode = new_inode(sb);
4233ad20fe3SChristian Brauner 	if (!inode)
4243ad20fe3SChristian Brauner 		goto err_without_dentry;
4253ad20fe3SChristian Brauner 
4263ad20fe3SChristian Brauner 	inode->i_ino = FIRST_INODE;
4273ad20fe3SChristian Brauner 	inode->i_fop = &simple_dir_operations;
4283ad20fe3SChristian Brauner 	inode->i_mode = S_IFDIR | 0755;
4293ad20fe3SChristian Brauner 	inode->i_mtime = inode->i_atime = inode->i_ctime = current_time(inode);
4303ad20fe3SChristian Brauner 	inode->i_op = &binderfs_dir_inode_operations;
4313ad20fe3SChristian Brauner 	set_nlink(inode, 2);
4323ad20fe3SChristian Brauner 
4333ad20fe3SChristian Brauner 	sb->s_root = d_make_root(inode);
4343ad20fe3SChristian Brauner 	if (!sb->s_root)
4353ad20fe3SChristian Brauner 		goto err_without_dentry;
4363ad20fe3SChristian Brauner 
4373ad20fe3SChristian Brauner 	ret = binderfs_binder_ctl_create(sb);
4383ad20fe3SChristian Brauner 	if (ret)
4393ad20fe3SChristian Brauner 		goto err_with_dentry;
4403ad20fe3SChristian Brauner 
4413ad20fe3SChristian Brauner 	return 0;
4423ad20fe3SChristian Brauner 
4433ad20fe3SChristian Brauner err_with_dentry:
4443ad20fe3SChristian Brauner 	dput(sb->s_root);
4453ad20fe3SChristian Brauner 	sb->s_root = NULL;
4463ad20fe3SChristian Brauner 
4473ad20fe3SChristian Brauner err_without_dentry:
4483ad20fe3SChristian Brauner 	put_ipc_ns(ipc_ns);
4493ad20fe3SChristian Brauner 	iput(inode);
4503ad20fe3SChristian Brauner 	kfree(info);
4513ad20fe3SChristian Brauner 
4523ad20fe3SChristian Brauner 	return ret;
4533ad20fe3SChristian Brauner }
4543ad20fe3SChristian Brauner 
4553ad20fe3SChristian Brauner static int binderfs_test_super(struct super_block *sb, void *data)
4563ad20fe3SChristian Brauner {
4573ad20fe3SChristian Brauner 	struct binderfs_info *info = sb->s_fs_info;
4583ad20fe3SChristian Brauner 
4593ad20fe3SChristian Brauner 	if (info)
4603ad20fe3SChristian Brauner 		return info->ipc_ns == data;
4613ad20fe3SChristian Brauner 
4623ad20fe3SChristian Brauner 	return 0;
4633ad20fe3SChristian Brauner }
4643ad20fe3SChristian Brauner 
4653ad20fe3SChristian Brauner static int binderfs_set_super(struct super_block *sb, void *data)
4663ad20fe3SChristian Brauner {
4673ad20fe3SChristian Brauner 	sb->s_fs_info = data;
4683ad20fe3SChristian Brauner 	return set_anon_super(sb, NULL);
4693ad20fe3SChristian Brauner }
4703ad20fe3SChristian Brauner 
4713ad20fe3SChristian Brauner static struct dentry *binderfs_mount(struct file_system_type *fs_type,
4723ad20fe3SChristian Brauner 				     int flags, const char *dev_name,
4733ad20fe3SChristian Brauner 				     void *data)
4743ad20fe3SChristian Brauner {
4753ad20fe3SChristian Brauner 	struct super_block *sb;
4763ad20fe3SChristian Brauner 	struct ipc_namespace *ipc_ns = current->nsproxy->ipc_ns;
4773ad20fe3SChristian Brauner 
4783ad20fe3SChristian Brauner 	if (!ns_capable(ipc_ns->user_ns, CAP_SYS_ADMIN))
4793ad20fe3SChristian Brauner 		return ERR_PTR(-EPERM);
4803ad20fe3SChristian Brauner 
4813ad20fe3SChristian Brauner 	sb = sget_userns(fs_type, binderfs_test_super, binderfs_set_super,
4823ad20fe3SChristian Brauner 			 flags, ipc_ns->user_ns, ipc_ns);
4833ad20fe3SChristian Brauner 	if (IS_ERR(sb))
4843ad20fe3SChristian Brauner 		return ERR_CAST(sb);
4853ad20fe3SChristian Brauner 
4863ad20fe3SChristian Brauner 	if (!sb->s_root) {
4873ad20fe3SChristian Brauner 		int ret = binderfs_fill_super(sb, data, flags & SB_SILENT ? 1 : 0);
4883ad20fe3SChristian Brauner 		if (ret) {
4893ad20fe3SChristian Brauner 			deactivate_locked_super(sb);
4903ad20fe3SChristian Brauner 			return ERR_PTR(ret);
4913ad20fe3SChristian Brauner 		}
4923ad20fe3SChristian Brauner 
4933ad20fe3SChristian Brauner 		sb->s_flags |= SB_ACTIVE;
4943ad20fe3SChristian Brauner 	}
4953ad20fe3SChristian Brauner 
4963ad20fe3SChristian Brauner 	return dget(sb->s_root);
4973ad20fe3SChristian Brauner }
4983ad20fe3SChristian Brauner 
4993ad20fe3SChristian Brauner static void binderfs_kill_super(struct super_block *sb)
5003ad20fe3SChristian Brauner {
5013ad20fe3SChristian Brauner 	struct binderfs_info *info = sb->s_fs_info;
5023ad20fe3SChristian Brauner 
5033ad20fe3SChristian Brauner 	if (info && info->ipc_ns)
5043ad20fe3SChristian Brauner 		put_ipc_ns(info->ipc_ns);
5053ad20fe3SChristian Brauner 
5063ad20fe3SChristian Brauner 	kfree(info);
5073ad20fe3SChristian Brauner 	kill_litter_super(sb);
5083ad20fe3SChristian Brauner }
5093ad20fe3SChristian Brauner 
5103ad20fe3SChristian Brauner static struct file_system_type binder_fs_type = {
5113ad20fe3SChristian Brauner 	.name		= "binder",
5123ad20fe3SChristian Brauner 	.mount		= binderfs_mount,
5133ad20fe3SChristian Brauner 	.kill_sb	= binderfs_kill_super,
5143ad20fe3SChristian Brauner 	.fs_flags	= FS_USERNS_MOUNT,
5153ad20fe3SChristian Brauner };
5163ad20fe3SChristian Brauner 
5173ad20fe3SChristian Brauner static int __init init_binderfs(void)
5183ad20fe3SChristian Brauner {
5193ad20fe3SChristian Brauner 	int ret;
5203ad20fe3SChristian Brauner 
5213ad20fe3SChristian Brauner 	/* Allocate new major number for binderfs. */
5223ad20fe3SChristian Brauner 	ret = alloc_chrdev_region(&binderfs_dev, 0, BINDERFS_MAX_MINOR,
5233ad20fe3SChristian Brauner 				  "binder");
5243ad20fe3SChristian Brauner 	if (ret)
5253ad20fe3SChristian Brauner 		return ret;
5263ad20fe3SChristian Brauner 
5273ad20fe3SChristian Brauner 	ret = register_filesystem(&binder_fs_type);
5283ad20fe3SChristian Brauner 	if (ret) {
5293ad20fe3SChristian Brauner 		unregister_chrdev_region(binderfs_dev, BINDERFS_MAX_MINOR);
5303ad20fe3SChristian Brauner 		return ret;
5313ad20fe3SChristian Brauner 	}
5323ad20fe3SChristian Brauner 
5333ad20fe3SChristian Brauner 	binderfs_mnt = kern_mount(&binder_fs_type);
5343ad20fe3SChristian Brauner 	if (IS_ERR(binderfs_mnt)) {
5353ad20fe3SChristian Brauner 		ret = PTR_ERR(binderfs_mnt);
5363ad20fe3SChristian Brauner 		binderfs_mnt = NULL;
5373ad20fe3SChristian Brauner 		unregister_filesystem(&binder_fs_type);
5383ad20fe3SChristian Brauner 		unregister_chrdev_region(binderfs_dev, BINDERFS_MAX_MINOR);
5393ad20fe3SChristian Brauner 	}
5403ad20fe3SChristian Brauner 
5413ad20fe3SChristian Brauner 	return ret;
5423ad20fe3SChristian Brauner }
5433ad20fe3SChristian Brauner 
5443ad20fe3SChristian Brauner device_initcall(init_binderfs);
545