17e84522cSMrinal Pandey // 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> 1401b3f1fcSChristian Brauner #include <linux/namei.h> 153ad20fe3SChristian Brauner #include <linux/magic.h> 163ad20fe3SChristian Brauner #include <linux/major.h> 173ad20fe3SChristian Brauner #include <linux/miscdevice.h> 183ad20fe3SChristian Brauner #include <linux/module.h> 193ad20fe3SChristian Brauner #include <linux/mutex.h> 203ad20fe3SChristian Brauner #include <linux/mount.h> 21095cf502SChristian Brauner #include <linux/fs_parser.h> 223ad20fe3SChristian Brauner #include <linux/radix-tree.h> 233ad20fe3SChristian Brauner #include <linux/sched.h> 24849d540dSChristian Brauner #include <linux/seq_file.h> 253ad20fe3SChristian Brauner #include <linux/slab.h> 263ad20fe3SChristian Brauner #include <linux/spinlock_types.h> 273ad20fe3SChristian Brauner #include <linux/stddef.h> 283ad20fe3SChristian Brauner #include <linux/string.h> 293ad20fe3SChristian Brauner #include <linux/types.h> 303ad20fe3SChristian Brauner #include <linux/uaccess.h> 313ad20fe3SChristian Brauner #include <linux/user_namespace.h> 323ad20fe3SChristian Brauner #include <linux/xarray.h> 333ad20fe3SChristian Brauner #include <uapi/asm-generic/errno-base.h> 343ad20fe3SChristian Brauner #include <uapi/linux/android/binder.h> 35c13295adSChristian Brauner #include <uapi/linux/android/binderfs.h> 363ad20fe3SChristian Brauner 373ad20fe3SChristian Brauner #include "binder_internal.h" 383ad20fe3SChristian Brauner 393ad20fe3SChristian Brauner #define FIRST_INODE 1 403ad20fe3SChristian Brauner #define SECOND_INODE 2 413ad20fe3SChristian Brauner #define INODE_OFFSET 3 423ad20fe3SChristian Brauner #define INTSTRLEN 21 433ad20fe3SChristian Brauner #define BINDERFS_MAX_MINOR (1U << MINORBITS) 4436bdf3caSChristian Brauner /* Ensure that the initial ipc namespace always has devices available. */ 4536bdf3caSChristian Brauner #define BINDERFS_MAX_MINOR_CAPPED (BINDERFS_MAX_MINOR - 4) 463ad20fe3SChristian Brauner 473ad20fe3SChristian Brauner static dev_t binderfs_dev; 483ad20fe3SChristian Brauner static DEFINE_MUTEX(binderfs_minors_mutex); 493ad20fe3SChristian Brauner static DEFINE_IDA(binderfs_minors); 503ad20fe3SChristian Brauner 51095cf502SChristian Brauner enum binderfs_param { 52849d540dSChristian Brauner Opt_max, 53f0083451SHridya Valsaraju Opt_stats_mode, 54849d540dSChristian Brauner }; 55849d540dSChristian Brauner 56f0083451SHridya Valsaraju enum binderfs_stats_mode { 57095cf502SChristian Brauner binderfs_stats_mode_unset, 58095cf502SChristian Brauner binderfs_stats_mode_global, 59f0083451SHridya Valsaraju }; 60f0083451SHridya Valsaraju 61*fc470abfSCarlos Llamas struct binder_features { 62*fc470abfSCarlos Llamas bool oneway_spam_detection; 63*fc470abfSCarlos Llamas }; 64*fc470abfSCarlos Llamas 65095cf502SChristian Brauner static const struct constant_table binderfs_param_stats[] = { 66095cf502SChristian Brauner { "global", binderfs_stats_mode_global }, 67095cf502SChristian Brauner {} 68849d540dSChristian Brauner }; 69849d540dSChristian Brauner 7089320020SWei Yongjun static const struct fs_parameter_spec binderfs_fs_parameters[] = { 71095cf502SChristian Brauner fsparam_u32("max", Opt_max), 72095cf502SChristian Brauner fsparam_enum("stats", Opt_stats_mode, binderfs_param_stats), 73095cf502SChristian Brauner {} 74095cf502SChristian Brauner }; 75095cf502SChristian Brauner 76*fc470abfSCarlos Llamas static struct binder_features binder_features = { 77*fc470abfSCarlos Llamas .oneway_spam_detection = true, 78*fc470abfSCarlos Llamas }; 79*fc470abfSCarlos Llamas 80095cf502SChristian Brauner static inline struct binderfs_info *BINDERFS_SB(const struct super_block *sb) 813ad20fe3SChristian Brauner { 82095cf502SChristian Brauner return sb->s_fs_info; 833ad20fe3SChristian Brauner } 843ad20fe3SChristian Brauner 853ad20fe3SChristian Brauner bool is_binderfs_device(const struct inode *inode) 863ad20fe3SChristian Brauner { 873ad20fe3SChristian Brauner if (inode->i_sb->s_magic == BINDERFS_SUPER_MAGIC) 883ad20fe3SChristian Brauner return true; 893ad20fe3SChristian Brauner 903ad20fe3SChristian Brauner return false; 913ad20fe3SChristian Brauner } 923ad20fe3SChristian Brauner 933ad20fe3SChristian Brauner /** 943ad20fe3SChristian Brauner * binderfs_binder_device_create - allocate inode from super block of a 953ad20fe3SChristian Brauner * binderfs mount 963ad20fe3SChristian Brauner * @ref_inode: inode from wich the super block will be taken 973ad20fe3SChristian Brauner * @userp: buffer to copy information about new device for userspace to 983ad20fe3SChristian Brauner * @req: struct binderfs_device as copied from userspace 993ad20fe3SChristian Brauner * 10001b3f1fcSChristian Brauner * This function allocates a new binder_device and reserves a new minor 1013ad20fe3SChristian Brauner * number for it. 1023ad20fe3SChristian Brauner * Minor numbers are limited and tracked globally in binderfs_minors. The 1033ad20fe3SChristian Brauner * function will stash a struct binder_device for the specific binder 1043ad20fe3SChristian Brauner * device in i_private of the inode. 1053ad20fe3SChristian Brauner * It will go on to allocate a new inode from the super block of the 1063ad20fe3SChristian Brauner * filesystem mount, stash a struct binder_device in its i_private field 1073ad20fe3SChristian Brauner * and attach a dentry to that inode. 1083ad20fe3SChristian Brauner * 1093ad20fe3SChristian Brauner * Return: 0 on success, negative errno on failure 1103ad20fe3SChristian Brauner */ 1113ad20fe3SChristian Brauner static int binderfs_binder_device_create(struct inode *ref_inode, 1123ad20fe3SChristian Brauner struct binderfs_device __user *userp, 1133ad20fe3SChristian Brauner struct binderfs_device *req) 1143ad20fe3SChristian Brauner { 1153ad20fe3SChristian Brauner int minor, ret; 11601b3f1fcSChristian Brauner struct dentry *dentry, *root; 1173ad20fe3SChristian Brauner struct binder_device *device; 1183ad20fe3SChristian Brauner char *name = NULL; 11901b3f1fcSChristian Brauner size_t name_len; 1203ad20fe3SChristian Brauner struct inode *inode = NULL; 1213ad20fe3SChristian Brauner struct super_block *sb = ref_inode->i_sb; 1223ad20fe3SChristian Brauner struct binderfs_info *info = sb->s_fs_info; 1237fefaaddSChristian Brauner #if defined(CONFIG_IPC_NS) 12436bdf3caSChristian Brauner bool use_reserve = (info->ipc_ns == &init_ipc_ns); 1257fefaaddSChristian Brauner #else 1267fefaaddSChristian Brauner bool use_reserve = true; 1277fefaaddSChristian Brauner #endif 1283ad20fe3SChristian Brauner 1293ad20fe3SChristian Brauner /* Reserve new minor number for the new device. */ 1303ad20fe3SChristian Brauner mutex_lock(&binderfs_minors_mutex); 131849d540dSChristian Brauner if (++info->device_count <= info->mount_opts.max) 13236bdf3caSChristian Brauner minor = ida_alloc_max(&binderfs_minors, 13336bdf3caSChristian Brauner use_reserve ? BINDERFS_MAX_MINOR : 13436bdf3caSChristian Brauner BINDERFS_MAX_MINOR_CAPPED, 135849d540dSChristian Brauner GFP_KERNEL); 136849d540dSChristian Brauner else 137849d540dSChristian Brauner minor = -ENOSPC; 138849d540dSChristian Brauner if (minor < 0) { 139849d540dSChristian Brauner --info->device_count; 1403ad20fe3SChristian Brauner mutex_unlock(&binderfs_minors_mutex); 1413ad20fe3SChristian Brauner return minor; 142849d540dSChristian Brauner } 143849d540dSChristian Brauner mutex_unlock(&binderfs_minors_mutex); 1443ad20fe3SChristian Brauner 1453ad20fe3SChristian Brauner ret = -ENOMEM; 1463ad20fe3SChristian Brauner device = kzalloc(sizeof(*device), GFP_KERNEL); 1473ad20fe3SChristian Brauner if (!device) 1483ad20fe3SChristian Brauner goto err; 1493ad20fe3SChristian Brauner 1503ad20fe3SChristian Brauner inode = new_inode(sb); 1513ad20fe3SChristian Brauner if (!inode) 1523ad20fe3SChristian Brauner goto err; 1533ad20fe3SChristian Brauner 1543ad20fe3SChristian Brauner inode->i_ino = minor + INODE_OFFSET; 1553ad20fe3SChristian Brauner inode->i_mtime = inode->i_atime = inode->i_ctime = current_time(inode); 1563ad20fe3SChristian Brauner init_special_inode(inode, S_IFCHR | 0600, 1573ad20fe3SChristian Brauner MKDEV(MAJOR(binderfs_dev), minor)); 1583ad20fe3SChristian Brauner inode->i_fop = &binder_fops; 1593ad20fe3SChristian Brauner inode->i_uid = info->root_uid; 1603ad20fe3SChristian Brauner inode->i_gid = info->root_gid; 1613ad20fe3SChristian Brauner 16201b3f1fcSChristian Brauner req->name[BINDERFS_MAX_NAME] = '\0'; /* NUL-terminate */ 16301b3f1fcSChristian Brauner name_len = strlen(req->name); 16401b3f1fcSChristian Brauner /* Make sure to include terminating NUL byte */ 16501b3f1fcSChristian Brauner name = kmemdup(req->name, name_len + 1, GFP_KERNEL); 1663ad20fe3SChristian Brauner if (!name) 1673ad20fe3SChristian Brauner goto err; 1683ad20fe3SChristian Brauner 169f0fe2c0fSChristian Brauner refcount_set(&device->ref, 1); 1703ad20fe3SChristian Brauner device->binderfs_inode = inode; 1713ad20fe3SChristian Brauner device->context.binder_context_mgr_uid = INVALID_UID; 1723ad20fe3SChristian Brauner device->context.name = name; 1733ad20fe3SChristian Brauner device->miscdev.name = name; 1743ad20fe3SChristian Brauner device->miscdev.minor = minor; 1753ad20fe3SChristian Brauner mutex_init(&device->context.context_mgr_node_lock); 1763ad20fe3SChristian Brauner 1773ad20fe3SChristian Brauner req->major = MAJOR(binderfs_dev); 1783ad20fe3SChristian Brauner req->minor = minor; 1793ad20fe3SChristian Brauner 180ca2864c6SHridya Valsaraju if (userp && copy_to_user(userp, req, sizeof(*req))) { 1813ad20fe3SChristian Brauner ret = -EFAULT; 1823ad20fe3SChristian Brauner goto err; 1833ad20fe3SChristian Brauner } 1843ad20fe3SChristian Brauner 1853ad20fe3SChristian Brauner root = sb->s_root; 1863ad20fe3SChristian Brauner inode_lock(d_inode(root)); 18701b3f1fcSChristian Brauner 18801b3f1fcSChristian Brauner /* look it up */ 18901b3f1fcSChristian Brauner dentry = lookup_one_len(name, root, name_len); 19001b3f1fcSChristian Brauner if (IS_ERR(dentry)) { 1913ad20fe3SChristian Brauner inode_unlock(d_inode(root)); 19201b3f1fcSChristian Brauner ret = PTR_ERR(dentry); 1933ad20fe3SChristian Brauner goto err; 1943ad20fe3SChristian Brauner } 1953ad20fe3SChristian Brauner 19601b3f1fcSChristian Brauner if (d_really_is_positive(dentry)) { 19701b3f1fcSChristian Brauner /* already exists */ 1983ad20fe3SChristian Brauner dput(dentry); 1993ad20fe3SChristian Brauner inode_unlock(d_inode(root)); 2003ad20fe3SChristian Brauner ret = -EEXIST; 2013ad20fe3SChristian Brauner goto err; 2023ad20fe3SChristian Brauner } 2033ad20fe3SChristian Brauner 2043ad20fe3SChristian Brauner inode->i_private = device; 20501684db9SChristian Brauner d_instantiate(dentry, inode); 2063ad20fe3SChristian Brauner fsnotify_create(root->d_inode, dentry); 2073ad20fe3SChristian Brauner inode_unlock(d_inode(root)); 2083ad20fe3SChristian Brauner 2093ad20fe3SChristian Brauner return 0; 2103ad20fe3SChristian Brauner 2113ad20fe3SChristian Brauner err: 2123ad20fe3SChristian Brauner kfree(name); 2133ad20fe3SChristian Brauner kfree(device); 2143ad20fe3SChristian Brauner mutex_lock(&binderfs_minors_mutex); 215849d540dSChristian Brauner --info->device_count; 2163ad20fe3SChristian Brauner ida_free(&binderfs_minors, minor); 2173ad20fe3SChristian Brauner mutex_unlock(&binderfs_minors_mutex); 2183ad20fe3SChristian Brauner iput(inode); 2193ad20fe3SChristian Brauner 2203ad20fe3SChristian Brauner return ret; 2213ad20fe3SChristian Brauner } 2223ad20fe3SChristian Brauner 2233ad20fe3SChristian Brauner /** 2243ad20fe3SChristian Brauner * binderfs_ctl_ioctl - handle binder device node allocation requests 2253ad20fe3SChristian Brauner * 2263ad20fe3SChristian Brauner * The request handler for the binder-control device. All requests operate on 2273ad20fe3SChristian Brauner * the binderfs mount the binder-control device resides in: 2283ad20fe3SChristian Brauner * - BINDER_CTL_ADD 2293ad20fe3SChristian Brauner * Allocate a new binder device. 2303ad20fe3SChristian Brauner * 2313ad20fe3SChristian Brauner * Return: 0 on success, negative errno on failure 2323ad20fe3SChristian Brauner */ 2333ad20fe3SChristian Brauner static long binder_ctl_ioctl(struct file *file, unsigned int cmd, 2343ad20fe3SChristian Brauner unsigned long arg) 2353ad20fe3SChristian Brauner { 2363ad20fe3SChristian Brauner int ret = -EINVAL; 2373ad20fe3SChristian Brauner struct inode *inode = file_inode(file); 2383ad20fe3SChristian Brauner struct binderfs_device __user *device = (struct binderfs_device __user *)arg; 2393ad20fe3SChristian Brauner struct binderfs_device device_req; 2403ad20fe3SChristian Brauner 2413ad20fe3SChristian Brauner switch (cmd) { 2423ad20fe3SChristian Brauner case BINDER_CTL_ADD: 2433ad20fe3SChristian Brauner ret = copy_from_user(&device_req, device, sizeof(device_req)); 2443ad20fe3SChristian Brauner if (ret) { 2453ad20fe3SChristian Brauner ret = -EFAULT; 2463ad20fe3SChristian Brauner break; 2473ad20fe3SChristian Brauner } 2483ad20fe3SChristian Brauner 2493ad20fe3SChristian Brauner ret = binderfs_binder_device_create(inode, device, &device_req); 2503ad20fe3SChristian Brauner break; 2513ad20fe3SChristian Brauner default: 2523ad20fe3SChristian Brauner break; 2533ad20fe3SChristian Brauner } 2543ad20fe3SChristian Brauner 2553ad20fe3SChristian Brauner return ret; 2563ad20fe3SChristian Brauner } 2573ad20fe3SChristian Brauner 2583ad20fe3SChristian Brauner static void binderfs_evict_inode(struct inode *inode) 2593ad20fe3SChristian Brauner { 2603ad20fe3SChristian Brauner struct binder_device *device = inode->i_private; 261095cf502SChristian Brauner struct binderfs_info *info = BINDERFS_SB(inode->i_sb); 2623ad20fe3SChristian Brauner 2633ad20fe3SChristian Brauner clear_inode(inode); 2643ad20fe3SChristian Brauner 2650e13e452SHridya Valsaraju if (!S_ISCHR(inode->i_mode) || !device) 2663ad20fe3SChristian Brauner return; 2673ad20fe3SChristian Brauner 2683ad20fe3SChristian Brauner mutex_lock(&binderfs_minors_mutex); 269849d540dSChristian Brauner --info->device_count; 2703ad20fe3SChristian Brauner ida_free(&binderfs_minors, device->miscdev.minor); 2713ad20fe3SChristian Brauner mutex_unlock(&binderfs_minors_mutex); 2723ad20fe3SChristian Brauner 273f0fe2c0fSChristian Brauner if (refcount_dec_and_test(&device->ref)) { 2743ad20fe3SChristian Brauner kfree(device->context.name); 2753ad20fe3SChristian Brauner kfree(device); 2763ad20fe3SChristian Brauner } 277f0fe2c0fSChristian Brauner } 2783ad20fe3SChristian Brauner 279095cf502SChristian Brauner static int binderfs_fs_context_parse_param(struct fs_context *fc, 280095cf502SChristian Brauner struct fs_parameter *param) 281849d540dSChristian Brauner { 282095cf502SChristian Brauner int opt; 283095cf502SChristian Brauner struct binderfs_mount_opts *ctx = fc->fs_private; 284095cf502SChristian Brauner struct fs_parse_result result; 285849d540dSChristian Brauner 286095cf502SChristian Brauner opt = fs_parse(fc, binderfs_fs_parameters, param, &result); 287095cf502SChristian Brauner if (opt < 0) 288095cf502SChristian Brauner return opt; 289849d540dSChristian Brauner 290095cf502SChristian Brauner switch (opt) { 291849d540dSChristian Brauner case Opt_max: 292095cf502SChristian Brauner if (result.uint_32 > BINDERFS_MAX_MINOR) 293095cf502SChristian Brauner return invalfc(fc, "Bad value for '%s'", param->key); 294849d540dSChristian Brauner 295095cf502SChristian Brauner ctx->max = result.uint_32; 296849d540dSChristian Brauner break; 297f0083451SHridya Valsaraju case Opt_stats_mode: 298f0083451SHridya Valsaraju if (!capable(CAP_SYS_ADMIN)) 299095cf502SChristian Brauner return -EPERM; 300f0083451SHridya Valsaraju 301095cf502SChristian Brauner ctx->stats_mode = result.uint_32; 302f0083451SHridya Valsaraju break; 303849d540dSChristian Brauner default: 304095cf502SChristian Brauner return invalfc(fc, "Unsupported parameter '%s'", param->key); 305849d540dSChristian Brauner } 306849d540dSChristian Brauner 307849d540dSChristian Brauner return 0; 308849d540dSChristian Brauner } 309849d540dSChristian Brauner 310095cf502SChristian Brauner static int binderfs_fs_context_reconfigure(struct fs_context *fc) 311849d540dSChristian Brauner { 312095cf502SChristian Brauner struct binderfs_mount_opts *ctx = fc->fs_private; 313095cf502SChristian Brauner struct binderfs_info *info = BINDERFS_SB(fc->root->d_sb); 314f0083451SHridya Valsaraju 315095cf502SChristian Brauner if (info->mount_opts.stats_mode != ctx->stats_mode) 316095cf502SChristian Brauner return invalfc(fc, "Binderfs stats mode cannot be changed during a remount"); 317f0083451SHridya Valsaraju 318095cf502SChristian Brauner info->mount_opts.stats_mode = ctx->stats_mode; 319095cf502SChristian Brauner info->mount_opts.max = ctx->max; 320f0083451SHridya Valsaraju return 0; 321849d540dSChristian Brauner } 322849d540dSChristian Brauner 323095cf502SChristian Brauner static int binderfs_show_options(struct seq_file *seq, struct dentry *root) 324849d540dSChristian Brauner { 325095cf502SChristian Brauner struct binderfs_info *info = BINDERFS_SB(root->d_sb); 326849d540dSChristian Brauner 327849d540dSChristian Brauner if (info->mount_opts.max <= BINDERFS_MAX_MINOR) 328849d540dSChristian Brauner seq_printf(seq, ",max=%d", info->mount_opts.max); 329095cf502SChristian Brauner 330095cf502SChristian Brauner switch (info->mount_opts.stats_mode) { 331095cf502SChristian Brauner case binderfs_stats_mode_unset: 332095cf502SChristian Brauner break; 333095cf502SChristian Brauner case binderfs_stats_mode_global: 334f0083451SHridya Valsaraju seq_printf(seq, ",stats=global"); 335095cf502SChristian Brauner break; 336095cf502SChristian Brauner } 337849d540dSChristian Brauner 338849d540dSChristian Brauner return 0; 339849d540dSChristian Brauner } 340849d540dSChristian Brauner 341095cf502SChristian Brauner static void binderfs_put_super(struct super_block *sb) 342095cf502SChristian Brauner { 343095cf502SChristian Brauner struct binderfs_info *info = sb->s_fs_info; 344095cf502SChristian Brauner 345095cf502SChristian Brauner if (info && info->ipc_ns) 346095cf502SChristian Brauner put_ipc_ns(info->ipc_ns); 347095cf502SChristian Brauner 348095cf502SChristian Brauner kfree(info); 349095cf502SChristian Brauner sb->s_fs_info = NULL; 350095cf502SChristian Brauner } 351095cf502SChristian Brauner 3523ad20fe3SChristian Brauner static const struct super_operations binderfs_super_ops = { 3533ad20fe3SChristian Brauner .evict_inode = binderfs_evict_inode, 354095cf502SChristian Brauner .show_options = binderfs_show_options, 355849d540dSChristian Brauner .statfs = simple_statfs, 356095cf502SChristian Brauner .put_super = binderfs_put_super, 3573ad20fe3SChristian Brauner }; 3583ad20fe3SChristian Brauner 359e98e6fa1SChristian Brauner static inline bool is_binderfs_control_device(const struct dentry *dentry) 360e98e6fa1SChristian Brauner { 361e98e6fa1SChristian Brauner struct binderfs_info *info = dentry->d_sb->s_fs_info; 36281195f96SMrinal Pandey 363e98e6fa1SChristian Brauner return info->control_dentry == dentry; 364e98e6fa1SChristian Brauner } 365e98e6fa1SChristian Brauner 366549c7297SChristian Brauner static int binderfs_rename(struct user_namespace *mnt_userns, 367549c7297SChristian Brauner struct inode *old_dir, struct dentry *old_dentry, 3683ad20fe3SChristian Brauner struct inode *new_dir, struct dentry *new_dentry, 3693ad20fe3SChristian Brauner unsigned int flags) 3703ad20fe3SChristian Brauner { 371e98e6fa1SChristian Brauner if (is_binderfs_control_device(old_dentry) || 372e98e6fa1SChristian Brauner is_binderfs_control_device(new_dentry)) 3733ad20fe3SChristian Brauner return -EPERM; 3743ad20fe3SChristian Brauner 375549c7297SChristian Brauner return simple_rename(&init_user_ns, old_dir, old_dentry, new_dir, 376549c7297SChristian Brauner new_dentry, flags); 3773ad20fe3SChristian Brauner } 3783ad20fe3SChristian Brauner 3793ad20fe3SChristian Brauner static int binderfs_unlink(struct inode *dir, struct dentry *dentry) 3803ad20fe3SChristian Brauner { 381e98e6fa1SChristian Brauner if (is_binderfs_control_device(dentry)) 3823ad20fe3SChristian Brauner return -EPERM; 3833ad20fe3SChristian Brauner 3843ad20fe3SChristian Brauner return simple_unlink(dir, dentry); 3853ad20fe3SChristian Brauner } 3863ad20fe3SChristian Brauner 3873ad20fe3SChristian Brauner static const struct file_operations binder_ctl_fops = { 3883ad20fe3SChristian Brauner .owner = THIS_MODULE, 3893ad20fe3SChristian Brauner .open = nonseekable_open, 3903ad20fe3SChristian Brauner .unlocked_ioctl = binder_ctl_ioctl, 3913ad20fe3SChristian Brauner .compat_ioctl = binder_ctl_ioctl, 3923ad20fe3SChristian Brauner .llseek = noop_llseek, 3933ad20fe3SChristian Brauner }; 3943ad20fe3SChristian Brauner 3953ad20fe3SChristian Brauner /** 3963ad20fe3SChristian Brauner * binderfs_binder_ctl_create - create a new binder-control device 3973ad20fe3SChristian Brauner * @sb: super block of the binderfs mount 3983ad20fe3SChristian Brauner * 3993ad20fe3SChristian Brauner * This function creates a new binder-control device node in the binderfs mount 4003ad20fe3SChristian Brauner * referred to by @sb. 4013ad20fe3SChristian Brauner * 4023ad20fe3SChristian Brauner * Return: 0 on success, negative errno on failure 4033ad20fe3SChristian Brauner */ 4043ad20fe3SChristian Brauner static int binderfs_binder_ctl_create(struct super_block *sb) 4053ad20fe3SChristian Brauner { 4063ad20fe3SChristian Brauner int minor, ret; 4073ad20fe3SChristian Brauner struct dentry *dentry; 4083ad20fe3SChristian Brauner struct binder_device *device; 4093ad20fe3SChristian Brauner struct inode *inode = NULL; 4103ad20fe3SChristian Brauner struct dentry *root = sb->s_root; 4113ad20fe3SChristian Brauner struct binderfs_info *info = sb->s_fs_info; 412da8ddba5SChristian Brauner #if defined(CONFIG_IPC_NS) 413da8ddba5SChristian Brauner bool use_reserve = (info->ipc_ns == &init_ipc_ns); 414da8ddba5SChristian Brauner #else 415da8ddba5SChristian Brauner bool use_reserve = true; 416da8ddba5SChristian Brauner #endif 4173ad20fe3SChristian Brauner 4183ad20fe3SChristian Brauner device = kzalloc(sizeof(*device), GFP_KERNEL); 4193ad20fe3SChristian Brauner if (!device) 4203ad20fe3SChristian Brauner return -ENOMEM; 4213ad20fe3SChristian Brauner 4223ad20fe3SChristian Brauner /* If we have already created a binder-control node, return. */ 4233ad20fe3SChristian Brauner if (info->control_dentry) { 4243ad20fe3SChristian Brauner ret = 0; 4253ad20fe3SChristian Brauner goto out; 4263ad20fe3SChristian Brauner } 4273ad20fe3SChristian Brauner 4283ad20fe3SChristian Brauner ret = -ENOMEM; 4293ad20fe3SChristian Brauner inode = new_inode(sb); 4303ad20fe3SChristian Brauner if (!inode) 4313ad20fe3SChristian Brauner goto out; 4323ad20fe3SChristian Brauner 4333ad20fe3SChristian Brauner /* Reserve a new minor number for the new device. */ 4343ad20fe3SChristian Brauner mutex_lock(&binderfs_minors_mutex); 435da8ddba5SChristian Brauner minor = ida_alloc_max(&binderfs_minors, 436da8ddba5SChristian Brauner use_reserve ? BINDERFS_MAX_MINOR : 437da8ddba5SChristian Brauner BINDERFS_MAX_MINOR_CAPPED, 438da8ddba5SChristian Brauner GFP_KERNEL); 4393ad20fe3SChristian Brauner mutex_unlock(&binderfs_minors_mutex); 4403ad20fe3SChristian Brauner if (minor < 0) { 4413ad20fe3SChristian Brauner ret = minor; 4423ad20fe3SChristian Brauner goto out; 4433ad20fe3SChristian Brauner } 4443ad20fe3SChristian Brauner 4453ad20fe3SChristian Brauner inode->i_ino = SECOND_INODE; 4463ad20fe3SChristian Brauner inode->i_mtime = inode->i_atime = inode->i_ctime = current_time(inode); 4473ad20fe3SChristian Brauner init_special_inode(inode, S_IFCHR | 0600, 4483ad20fe3SChristian Brauner MKDEV(MAJOR(binderfs_dev), minor)); 4493ad20fe3SChristian Brauner inode->i_fop = &binder_ctl_fops; 4503ad20fe3SChristian Brauner inode->i_uid = info->root_uid; 4513ad20fe3SChristian Brauner inode->i_gid = info->root_gid; 4523ad20fe3SChristian Brauner 453211b64e4SChristian Brauner refcount_set(&device->ref, 1); 4543ad20fe3SChristian Brauner device->binderfs_inode = inode; 4553ad20fe3SChristian Brauner device->miscdev.minor = minor; 4563ad20fe3SChristian Brauner 4573ad20fe3SChristian Brauner dentry = d_alloc_name(root, "binder-control"); 4583ad20fe3SChristian Brauner if (!dentry) 4593ad20fe3SChristian Brauner goto out; 4603ad20fe3SChristian Brauner 4613ad20fe3SChristian Brauner inode->i_private = device; 4623ad20fe3SChristian Brauner info->control_dentry = dentry; 4633ad20fe3SChristian Brauner d_add(dentry, inode); 4643ad20fe3SChristian Brauner 4653ad20fe3SChristian Brauner return 0; 4663ad20fe3SChristian Brauner 4673ad20fe3SChristian Brauner out: 4683ad20fe3SChristian Brauner kfree(device); 4693ad20fe3SChristian Brauner iput(inode); 4703ad20fe3SChristian Brauner 4713ad20fe3SChristian Brauner return ret; 4723ad20fe3SChristian Brauner } 4733ad20fe3SChristian Brauner 4743ad20fe3SChristian Brauner static const struct inode_operations binderfs_dir_inode_operations = { 4753ad20fe3SChristian Brauner .lookup = simple_lookup, 4763ad20fe3SChristian Brauner .rename = binderfs_rename, 4773ad20fe3SChristian Brauner .unlink = binderfs_unlink, 4783ad20fe3SChristian Brauner }; 4793ad20fe3SChristian Brauner 4800e13e452SHridya Valsaraju static struct inode *binderfs_make_inode(struct super_block *sb, int mode) 4810e13e452SHridya Valsaraju { 4820e13e452SHridya Valsaraju struct inode *ret; 4830e13e452SHridya Valsaraju 4840e13e452SHridya Valsaraju ret = new_inode(sb); 4850e13e452SHridya Valsaraju if (ret) { 4860e13e452SHridya Valsaraju ret->i_ino = iunique(sb, BINDERFS_MAX_MINOR + INODE_OFFSET); 4870e13e452SHridya Valsaraju ret->i_mode = mode; 4880e13e452SHridya Valsaraju ret->i_atime = ret->i_mtime = ret->i_ctime = current_time(ret); 4890e13e452SHridya Valsaraju } 4900e13e452SHridya Valsaraju return ret; 4910e13e452SHridya Valsaraju } 4920e13e452SHridya Valsaraju 4930e13e452SHridya Valsaraju static struct dentry *binderfs_create_dentry(struct dentry *parent, 4940e13e452SHridya Valsaraju const char *name) 4950e13e452SHridya Valsaraju { 4960e13e452SHridya Valsaraju struct dentry *dentry; 4970e13e452SHridya Valsaraju 4980e13e452SHridya Valsaraju dentry = lookup_one_len(name, parent, strlen(name)); 4990e13e452SHridya Valsaraju if (IS_ERR(dentry)) 5000e13e452SHridya Valsaraju return dentry; 5010e13e452SHridya Valsaraju 5020e13e452SHridya Valsaraju /* Return error if the file/dir already exists. */ 5030e13e452SHridya Valsaraju if (d_really_is_positive(dentry)) { 5040e13e452SHridya Valsaraju dput(dentry); 5050e13e452SHridya Valsaraju return ERR_PTR(-EEXIST); 5060e13e452SHridya Valsaraju } 5070e13e452SHridya Valsaraju 5080e13e452SHridya Valsaraju return dentry; 5090e13e452SHridya Valsaraju } 5100e13e452SHridya Valsaraju 5114feb80faSHridya Valsaraju void binderfs_remove_file(struct dentry *dentry) 5124feb80faSHridya Valsaraju { 5134feb80faSHridya Valsaraju struct inode *parent_inode; 5144feb80faSHridya Valsaraju 5154feb80faSHridya Valsaraju parent_inode = d_inode(dentry->d_parent); 5164feb80faSHridya Valsaraju inode_lock(parent_inode); 5174feb80faSHridya Valsaraju if (simple_positive(dentry)) { 5184feb80faSHridya Valsaraju dget(dentry); 5194feb80faSHridya Valsaraju simple_unlink(parent_inode, dentry); 5204feb80faSHridya Valsaraju d_delete(dentry); 5214feb80faSHridya Valsaraju dput(dentry); 5224feb80faSHridya Valsaraju } 5234feb80faSHridya Valsaraju inode_unlock(parent_inode); 5244feb80faSHridya Valsaraju } 5254feb80faSHridya Valsaraju 5264feb80faSHridya Valsaraju struct dentry *binderfs_create_file(struct dentry *parent, const char *name, 5270e13e452SHridya Valsaraju const struct file_operations *fops, 5280e13e452SHridya Valsaraju void *data) 5290e13e452SHridya Valsaraju { 5300e13e452SHridya Valsaraju struct dentry *dentry; 5310e13e452SHridya Valsaraju struct inode *new_inode, *parent_inode; 5320e13e452SHridya Valsaraju struct super_block *sb; 5330e13e452SHridya Valsaraju 5340e13e452SHridya Valsaraju parent_inode = d_inode(parent); 5350e13e452SHridya Valsaraju inode_lock(parent_inode); 5360e13e452SHridya Valsaraju 5370e13e452SHridya Valsaraju dentry = binderfs_create_dentry(parent, name); 5380e13e452SHridya Valsaraju if (IS_ERR(dentry)) 5390e13e452SHridya Valsaraju goto out; 5400e13e452SHridya Valsaraju 5410e13e452SHridya Valsaraju sb = parent_inode->i_sb; 5420e13e452SHridya Valsaraju new_inode = binderfs_make_inode(sb, S_IFREG | 0444); 5430e13e452SHridya Valsaraju if (!new_inode) { 5440e13e452SHridya Valsaraju dput(dentry); 5450e13e452SHridya Valsaraju dentry = ERR_PTR(-ENOMEM); 5460e13e452SHridya Valsaraju goto out; 5470e13e452SHridya Valsaraju } 5480e13e452SHridya Valsaraju 5490e13e452SHridya Valsaraju new_inode->i_fop = fops; 5500e13e452SHridya Valsaraju new_inode->i_private = data; 5510e13e452SHridya Valsaraju d_instantiate(dentry, new_inode); 5520e13e452SHridya Valsaraju fsnotify_create(parent_inode, dentry); 5530e13e452SHridya Valsaraju 5540e13e452SHridya Valsaraju out: 5550e13e452SHridya Valsaraju inode_unlock(parent_inode); 5560e13e452SHridya Valsaraju return dentry; 5570e13e452SHridya Valsaraju } 5580e13e452SHridya Valsaraju 5590e13e452SHridya Valsaraju static struct dentry *binderfs_create_dir(struct dentry *parent, 5600e13e452SHridya Valsaraju const char *name) 5610e13e452SHridya Valsaraju { 5620e13e452SHridya Valsaraju struct dentry *dentry; 5630e13e452SHridya Valsaraju struct inode *new_inode, *parent_inode; 5640e13e452SHridya Valsaraju struct super_block *sb; 5650e13e452SHridya Valsaraju 5660e13e452SHridya Valsaraju parent_inode = d_inode(parent); 5670e13e452SHridya Valsaraju inode_lock(parent_inode); 5680e13e452SHridya Valsaraju 5690e13e452SHridya Valsaraju dentry = binderfs_create_dentry(parent, name); 5700e13e452SHridya Valsaraju if (IS_ERR(dentry)) 5710e13e452SHridya Valsaraju goto out; 5720e13e452SHridya Valsaraju 5730e13e452SHridya Valsaraju sb = parent_inode->i_sb; 5740e13e452SHridya Valsaraju new_inode = binderfs_make_inode(sb, S_IFDIR | 0755); 5750e13e452SHridya Valsaraju if (!new_inode) { 5760e13e452SHridya Valsaraju dput(dentry); 5770e13e452SHridya Valsaraju dentry = ERR_PTR(-ENOMEM); 5780e13e452SHridya Valsaraju goto out; 5790e13e452SHridya Valsaraju } 5800e13e452SHridya Valsaraju 5810e13e452SHridya Valsaraju new_inode->i_fop = &simple_dir_operations; 5820e13e452SHridya Valsaraju new_inode->i_op = &simple_dir_inode_operations; 5830e13e452SHridya Valsaraju 5840e13e452SHridya Valsaraju set_nlink(new_inode, 2); 5850e13e452SHridya Valsaraju d_instantiate(dentry, new_inode); 5860e13e452SHridya Valsaraju inc_nlink(parent_inode); 5870e13e452SHridya Valsaraju fsnotify_mkdir(parent_inode, dentry); 5880e13e452SHridya Valsaraju 5890e13e452SHridya Valsaraju out: 5900e13e452SHridya Valsaraju inode_unlock(parent_inode); 5910e13e452SHridya Valsaraju return dentry; 5920e13e452SHridya Valsaraju } 5930e13e452SHridya Valsaraju 594*fc470abfSCarlos Llamas static int binder_features_show(struct seq_file *m, void *unused) 595*fc470abfSCarlos Llamas { 596*fc470abfSCarlos Llamas bool *feature = m->private; 597*fc470abfSCarlos Llamas 598*fc470abfSCarlos Llamas seq_printf(m, "%d\n", *feature); 599*fc470abfSCarlos Llamas 600*fc470abfSCarlos Llamas return 0; 601*fc470abfSCarlos Llamas } 602*fc470abfSCarlos Llamas DEFINE_SHOW_ATTRIBUTE(binder_features); 603*fc470abfSCarlos Llamas 604*fc470abfSCarlos Llamas static int init_binder_features(struct super_block *sb) 605*fc470abfSCarlos Llamas { 606*fc470abfSCarlos Llamas struct dentry *dentry, *dir; 607*fc470abfSCarlos Llamas 608*fc470abfSCarlos Llamas dir = binderfs_create_dir(sb->s_root, "features"); 609*fc470abfSCarlos Llamas if (IS_ERR(dir)) 610*fc470abfSCarlos Llamas return PTR_ERR(dir); 611*fc470abfSCarlos Llamas 612*fc470abfSCarlos Llamas dentry = binderfs_create_file(dir, "oneway_spam_detection", 613*fc470abfSCarlos Llamas &binder_features_fops, 614*fc470abfSCarlos Llamas &binder_features.oneway_spam_detection); 615*fc470abfSCarlos Llamas if (IS_ERR(dentry)) 616*fc470abfSCarlos Llamas return PTR_ERR(dentry); 617*fc470abfSCarlos Llamas 618*fc470abfSCarlos Llamas return 0; 619*fc470abfSCarlos Llamas } 620*fc470abfSCarlos Llamas 6210e13e452SHridya Valsaraju static int init_binder_logs(struct super_block *sb) 6220e13e452SHridya Valsaraju { 6234feb80faSHridya Valsaraju struct dentry *binder_logs_root_dir, *dentry, *proc_log_dir; 6244feb80faSHridya Valsaraju struct binderfs_info *info; 6250e13e452SHridya Valsaraju int ret = 0; 6260e13e452SHridya Valsaraju 6270e13e452SHridya Valsaraju binder_logs_root_dir = binderfs_create_dir(sb->s_root, 6280e13e452SHridya Valsaraju "binder_logs"); 6290e13e452SHridya Valsaraju if (IS_ERR(binder_logs_root_dir)) { 6300e13e452SHridya Valsaraju ret = PTR_ERR(binder_logs_root_dir); 6310e13e452SHridya Valsaraju goto out; 6320e13e452SHridya Valsaraju } 6330e13e452SHridya Valsaraju 6340e13e452SHridya Valsaraju dentry = binderfs_create_file(binder_logs_root_dir, "stats", 6350e13e452SHridya Valsaraju &binder_stats_fops, NULL); 6360e13e452SHridya Valsaraju if (IS_ERR(dentry)) { 6370e13e452SHridya Valsaraju ret = PTR_ERR(dentry); 6380e13e452SHridya Valsaraju goto out; 6390e13e452SHridya Valsaraju } 6400e13e452SHridya Valsaraju 6410e13e452SHridya Valsaraju dentry = binderfs_create_file(binder_logs_root_dir, "state", 6420e13e452SHridya Valsaraju &binder_state_fops, NULL); 6430e13e452SHridya Valsaraju if (IS_ERR(dentry)) { 6440e13e452SHridya Valsaraju ret = PTR_ERR(dentry); 6450e13e452SHridya Valsaraju goto out; 6460e13e452SHridya Valsaraju } 6470e13e452SHridya Valsaraju 6480e13e452SHridya Valsaraju dentry = binderfs_create_file(binder_logs_root_dir, "transactions", 6490e13e452SHridya Valsaraju &binder_transactions_fops, NULL); 65003e2e07eSHridya Valsaraju if (IS_ERR(dentry)) { 65103e2e07eSHridya Valsaraju ret = PTR_ERR(dentry); 65203e2e07eSHridya Valsaraju goto out; 65303e2e07eSHridya Valsaraju } 65403e2e07eSHridya Valsaraju 65503e2e07eSHridya Valsaraju dentry = binderfs_create_file(binder_logs_root_dir, 65603e2e07eSHridya Valsaraju "transaction_log", 65703e2e07eSHridya Valsaraju &binder_transaction_log_fops, 65803e2e07eSHridya Valsaraju &binder_transaction_log); 65903e2e07eSHridya Valsaraju if (IS_ERR(dentry)) { 66003e2e07eSHridya Valsaraju ret = PTR_ERR(dentry); 66103e2e07eSHridya Valsaraju goto out; 66203e2e07eSHridya Valsaraju } 66303e2e07eSHridya Valsaraju 66403e2e07eSHridya Valsaraju dentry = binderfs_create_file(binder_logs_root_dir, 66503e2e07eSHridya Valsaraju "failed_transaction_log", 66603e2e07eSHridya Valsaraju &binder_transaction_log_fops, 66703e2e07eSHridya Valsaraju &binder_transaction_log_failed); 6684feb80faSHridya Valsaraju if (IS_ERR(dentry)) { 6690e13e452SHridya Valsaraju ret = PTR_ERR(dentry); 6704feb80faSHridya Valsaraju goto out; 6714feb80faSHridya Valsaraju } 6724feb80faSHridya Valsaraju 6734feb80faSHridya Valsaraju proc_log_dir = binderfs_create_dir(binder_logs_root_dir, "proc"); 6744feb80faSHridya Valsaraju if (IS_ERR(proc_log_dir)) { 6754feb80faSHridya Valsaraju ret = PTR_ERR(proc_log_dir); 6764feb80faSHridya Valsaraju goto out; 6774feb80faSHridya Valsaraju } 6784feb80faSHridya Valsaraju info = sb->s_fs_info; 6794feb80faSHridya Valsaraju info->proc_log_dir = proc_log_dir; 6800e13e452SHridya Valsaraju 6810e13e452SHridya Valsaraju out: 6820e13e452SHridya Valsaraju return ret; 6830e13e452SHridya Valsaraju } 6840e13e452SHridya Valsaraju 685095cf502SChristian Brauner static int binderfs_fill_super(struct super_block *sb, struct fs_context *fc) 6863ad20fe3SChristian Brauner { 68736975fc3SChristian Brauner int ret; 6883ad20fe3SChristian Brauner struct binderfs_info *info; 689095cf502SChristian Brauner struct binderfs_mount_opts *ctx = fc->fs_private; 6903ad20fe3SChristian Brauner struct inode *inode = NULL; 6917a1c4f28STang Bin struct binderfs_device device_info = {}; 692ca2864c6SHridya Valsaraju const char *name; 693ca2864c6SHridya Valsaraju size_t len; 6943ad20fe3SChristian Brauner 6953ad20fe3SChristian Brauner sb->s_blocksize = PAGE_SIZE; 6963ad20fe3SChristian Brauner sb->s_blocksize_bits = PAGE_SHIFT; 6973ad20fe3SChristian Brauner 6983ad20fe3SChristian Brauner /* 6993ad20fe3SChristian Brauner * The binderfs filesystem can be mounted by userns root in a 7003ad20fe3SChristian Brauner * non-initial userns. By default such mounts have the SB_I_NODEV flag 7013ad20fe3SChristian Brauner * set in s_iflags to prevent security issues where userns root can 7023ad20fe3SChristian Brauner * just create random device nodes via mknod() since it owns the 7033ad20fe3SChristian Brauner * filesystem mount. But binderfs does not allow to create any files 7043ad20fe3SChristian Brauner * including devices nodes. The only way to create binder devices nodes 7053ad20fe3SChristian Brauner * is through the binder-control device which userns root is explicitly 7063ad20fe3SChristian Brauner * allowed to do. So removing the SB_I_NODEV flag from s_iflags is both 7073ad20fe3SChristian Brauner * necessary and safe. 7083ad20fe3SChristian Brauner */ 7093ad20fe3SChristian Brauner sb->s_iflags &= ~SB_I_NODEV; 7103ad20fe3SChristian Brauner sb->s_iflags |= SB_I_NOEXEC; 7113ad20fe3SChristian Brauner sb->s_magic = BINDERFS_SUPER_MAGIC; 7123ad20fe3SChristian Brauner sb->s_op = &binderfs_super_ops; 7133ad20fe3SChristian Brauner sb->s_time_gran = 1; 7143ad20fe3SChristian Brauner 71536975fc3SChristian Brauner sb->s_fs_info = kzalloc(sizeof(struct binderfs_info), GFP_KERNEL); 71636975fc3SChristian Brauner if (!sb->s_fs_info) 71736975fc3SChristian Brauner return -ENOMEM; 71836975fc3SChristian Brauner info = sb->s_fs_info; 71936975fc3SChristian Brauner 72036975fc3SChristian Brauner info->ipc_ns = get_ipc_ns(current->nsproxy->ipc_ns); 7213ad20fe3SChristian Brauner 7223ad20fe3SChristian Brauner info->root_gid = make_kgid(sb->s_user_ns, 0); 7233ad20fe3SChristian Brauner if (!gid_valid(info->root_gid)) 7243ad20fe3SChristian Brauner info->root_gid = GLOBAL_ROOT_GID; 7253ad20fe3SChristian Brauner info->root_uid = make_kuid(sb->s_user_ns, 0); 7263ad20fe3SChristian Brauner if (!uid_valid(info->root_uid)) 7273ad20fe3SChristian Brauner info->root_uid = GLOBAL_ROOT_UID; 728095cf502SChristian Brauner info->mount_opts.max = ctx->max; 729095cf502SChristian Brauner info->mount_opts.stats_mode = ctx->stats_mode; 7303ad20fe3SChristian Brauner 7313ad20fe3SChristian Brauner inode = new_inode(sb); 7323ad20fe3SChristian Brauner if (!inode) 73336975fc3SChristian Brauner return -ENOMEM; 7343ad20fe3SChristian Brauner 7353ad20fe3SChristian Brauner inode->i_ino = FIRST_INODE; 7363ad20fe3SChristian Brauner inode->i_fop = &simple_dir_operations; 7373ad20fe3SChristian Brauner inode->i_mode = S_IFDIR | 0755; 7383ad20fe3SChristian Brauner inode->i_mtime = inode->i_atime = inode->i_ctime = current_time(inode); 7393ad20fe3SChristian Brauner inode->i_op = &binderfs_dir_inode_operations; 7403ad20fe3SChristian Brauner set_nlink(inode, 2); 7413ad20fe3SChristian Brauner 7423ad20fe3SChristian Brauner sb->s_root = d_make_root(inode); 7433ad20fe3SChristian Brauner if (!sb->s_root) 74436975fc3SChristian Brauner return -ENOMEM; 7453ad20fe3SChristian Brauner 746ca2864c6SHridya Valsaraju ret = binderfs_binder_ctl_create(sb); 747ca2864c6SHridya Valsaraju if (ret) 748ca2864c6SHridya Valsaraju return ret; 749ca2864c6SHridya Valsaraju 750ca2864c6SHridya Valsaraju name = binder_devices_param; 751ca2864c6SHridya Valsaraju for (len = strcspn(name, ","); len > 0; len = strcspn(name, ",")) { 752ca2864c6SHridya Valsaraju strscpy(device_info.name, name, len + 1); 753ca2864c6SHridya Valsaraju ret = binderfs_binder_device_create(inode, NULL, &device_info); 754ca2864c6SHridya Valsaraju if (ret) 755ca2864c6SHridya Valsaraju return ret; 756ca2864c6SHridya Valsaraju name += len; 757ca2864c6SHridya Valsaraju if (*name == ',') 758ca2864c6SHridya Valsaraju name++; 759ca2864c6SHridya Valsaraju } 760ca2864c6SHridya Valsaraju 761*fc470abfSCarlos Llamas ret = init_binder_features(sb); 762*fc470abfSCarlos Llamas if (ret) 763*fc470abfSCarlos Llamas return ret; 764*fc470abfSCarlos Llamas 765095cf502SChristian Brauner if (info->mount_opts.stats_mode == binderfs_stats_mode_global) 7660e13e452SHridya Valsaraju return init_binder_logs(sb); 7670e13e452SHridya Valsaraju 768ca2864c6SHridya Valsaraju return 0; 7693ad20fe3SChristian Brauner } 7703ad20fe3SChristian Brauner 771095cf502SChristian Brauner static int binderfs_fs_context_get_tree(struct fs_context *fc) 7723ad20fe3SChristian Brauner { 773095cf502SChristian Brauner return get_tree_nodev(fc, binderfs_fill_super); 7743ad20fe3SChristian Brauner } 7753ad20fe3SChristian Brauner 776095cf502SChristian Brauner static void binderfs_fs_context_free(struct fs_context *fc) 7773ad20fe3SChristian Brauner { 778095cf502SChristian Brauner struct binderfs_mount_opts *ctx = fc->fs_private; 7793ad20fe3SChristian Brauner 780095cf502SChristian Brauner kfree(ctx); 781095cf502SChristian Brauner } 78241984795SChristian Brauner 783095cf502SChristian Brauner static const struct fs_context_operations binderfs_fs_context_ops = { 784095cf502SChristian Brauner .free = binderfs_fs_context_free, 785095cf502SChristian Brauner .get_tree = binderfs_fs_context_get_tree, 786095cf502SChristian Brauner .parse_param = binderfs_fs_context_parse_param, 787095cf502SChristian Brauner .reconfigure = binderfs_fs_context_reconfigure, 788095cf502SChristian Brauner }; 7893ad20fe3SChristian Brauner 790095cf502SChristian Brauner static int binderfs_init_fs_context(struct fs_context *fc) 791095cf502SChristian Brauner { 7929e306ba3SColin Ian King struct binderfs_mount_opts *ctx; 793095cf502SChristian Brauner 794095cf502SChristian Brauner ctx = kzalloc(sizeof(struct binderfs_mount_opts), GFP_KERNEL); 795095cf502SChristian Brauner if (!ctx) 796095cf502SChristian Brauner return -ENOMEM; 797095cf502SChristian Brauner 798095cf502SChristian Brauner ctx->max = BINDERFS_MAX_MINOR; 799095cf502SChristian Brauner ctx->stats_mode = binderfs_stats_mode_unset; 800095cf502SChristian Brauner 801095cf502SChristian Brauner fc->fs_private = ctx; 802095cf502SChristian Brauner fc->ops = &binderfs_fs_context_ops; 803095cf502SChristian Brauner 804095cf502SChristian Brauner return 0; 8053ad20fe3SChristian Brauner } 8063ad20fe3SChristian Brauner 8073ad20fe3SChristian Brauner static struct file_system_type binder_fs_type = { 8083ad20fe3SChristian Brauner .name = "binder", 809095cf502SChristian Brauner .init_fs_context = binderfs_init_fs_context, 810095cf502SChristian Brauner .parameters = binderfs_fs_parameters, 811095cf502SChristian Brauner .kill_sb = kill_litter_super, 8123ad20fe3SChristian Brauner .fs_flags = FS_USERNS_MOUNT, 8133ad20fe3SChristian Brauner }; 8143ad20fe3SChristian Brauner 8155b9633afSChristian Brauner int __init init_binderfs(void) 8163ad20fe3SChristian Brauner { 8173ad20fe3SChristian Brauner int ret; 818028fb582SHridya Valsaraju const char *name; 819028fb582SHridya Valsaraju size_t len; 820028fb582SHridya Valsaraju 821028fb582SHridya Valsaraju /* Verify that the default binderfs device names are valid. */ 822028fb582SHridya Valsaraju name = binder_devices_param; 823028fb582SHridya Valsaraju for (len = strcspn(name, ","); len > 0; len = strcspn(name, ",")) { 824028fb582SHridya Valsaraju if (len > BINDERFS_MAX_NAME) 825028fb582SHridya Valsaraju return -E2BIG; 826028fb582SHridya Valsaraju name += len; 827028fb582SHridya Valsaraju if (*name == ',') 828028fb582SHridya Valsaraju name++; 829028fb582SHridya Valsaraju } 8303ad20fe3SChristian Brauner 8313ad20fe3SChristian Brauner /* Allocate new major number for binderfs. */ 8323ad20fe3SChristian Brauner ret = alloc_chrdev_region(&binderfs_dev, 0, BINDERFS_MAX_MINOR, 8333ad20fe3SChristian Brauner "binder"); 8343ad20fe3SChristian Brauner if (ret) 8353ad20fe3SChristian Brauner return ret; 8363ad20fe3SChristian Brauner 8373ad20fe3SChristian Brauner ret = register_filesystem(&binder_fs_type); 8383ad20fe3SChristian Brauner if (ret) { 8393ad20fe3SChristian Brauner unregister_chrdev_region(binderfs_dev, BINDERFS_MAX_MINOR); 8403ad20fe3SChristian Brauner return ret; 8413ad20fe3SChristian Brauner } 8423ad20fe3SChristian Brauner 8433ad20fe3SChristian Brauner return ret; 8443ad20fe3SChristian Brauner } 845