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