162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci 362306a36Sopenharmony_ci#include <linux/compiler_types.h> 462306a36Sopenharmony_ci#include <linux/errno.h> 562306a36Sopenharmony_ci#include <linux/fs.h> 662306a36Sopenharmony_ci#include <linux/fsnotify.h> 762306a36Sopenharmony_ci#include <linux/gfp.h> 862306a36Sopenharmony_ci#include <linux/idr.h> 962306a36Sopenharmony_ci#include <linux/init.h> 1062306a36Sopenharmony_ci#include <linux/ipc_namespace.h> 1162306a36Sopenharmony_ci#include <linux/kdev_t.h> 1262306a36Sopenharmony_ci#include <linux/kernel.h> 1362306a36Sopenharmony_ci#include <linux/list.h> 1462306a36Sopenharmony_ci#include <linux/namei.h> 1562306a36Sopenharmony_ci#include <linux/magic.h> 1662306a36Sopenharmony_ci#include <linux/major.h> 1762306a36Sopenharmony_ci#include <linux/miscdevice.h> 1862306a36Sopenharmony_ci#include <linux/module.h> 1962306a36Sopenharmony_ci#include <linux/mutex.h> 2062306a36Sopenharmony_ci#include <linux/mount.h> 2162306a36Sopenharmony_ci#include <linux/fs_parser.h> 2262306a36Sopenharmony_ci#include <linux/sched.h> 2362306a36Sopenharmony_ci#include <linux/seq_file.h> 2462306a36Sopenharmony_ci#include <linux/slab.h> 2562306a36Sopenharmony_ci#include <linux/spinlock_types.h> 2662306a36Sopenharmony_ci#include <linux/stddef.h> 2762306a36Sopenharmony_ci#include <linux/string.h> 2862306a36Sopenharmony_ci#include <linux/types.h> 2962306a36Sopenharmony_ci#include <linux/uaccess.h> 3062306a36Sopenharmony_ci#include <linux/user_namespace.h> 3162306a36Sopenharmony_ci#include <linux/xarray.h> 3262306a36Sopenharmony_ci#include <uapi/asm-generic/errno-base.h> 3362306a36Sopenharmony_ci#include <uapi/linux/android/binder.h> 3462306a36Sopenharmony_ci#include <uapi/linux/android/binderfs.h> 3562306a36Sopenharmony_ci 3662306a36Sopenharmony_ci#include "binder_internal.h" 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_ci#define FIRST_INODE 1 3962306a36Sopenharmony_ci#define SECOND_INODE 2 4062306a36Sopenharmony_ci#define INODE_OFFSET 3 4162306a36Sopenharmony_ci#define BINDERFS_MAX_MINOR (1U << MINORBITS) 4262306a36Sopenharmony_ci/* Ensure that the initial ipc namespace always has devices available. */ 4362306a36Sopenharmony_ci#define BINDERFS_MAX_MINOR_CAPPED (BINDERFS_MAX_MINOR - 4) 4462306a36Sopenharmony_ci 4562306a36Sopenharmony_cistatic dev_t binderfs_dev; 4662306a36Sopenharmony_cistatic DEFINE_MUTEX(binderfs_minors_mutex); 4762306a36Sopenharmony_cistatic DEFINE_IDA(binderfs_minors); 4862306a36Sopenharmony_ci 4962306a36Sopenharmony_cienum binderfs_param { 5062306a36Sopenharmony_ci Opt_max, 5162306a36Sopenharmony_ci Opt_stats_mode, 5262306a36Sopenharmony_ci}; 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_cienum binderfs_stats_mode { 5562306a36Sopenharmony_ci binderfs_stats_mode_unset, 5662306a36Sopenharmony_ci binderfs_stats_mode_global, 5762306a36Sopenharmony_ci}; 5862306a36Sopenharmony_ci 5962306a36Sopenharmony_cistruct binder_features { 6062306a36Sopenharmony_ci bool oneway_spam_detection; 6162306a36Sopenharmony_ci bool extended_error; 6262306a36Sopenharmony_ci}; 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_cistatic const struct constant_table binderfs_param_stats[] = { 6562306a36Sopenharmony_ci { "global", binderfs_stats_mode_global }, 6662306a36Sopenharmony_ci {} 6762306a36Sopenharmony_ci}; 6862306a36Sopenharmony_ci 6962306a36Sopenharmony_cistatic const struct fs_parameter_spec binderfs_fs_parameters[] = { 7062306a36Sopenharmony_ci fsparam_u32("max", Opt_max), 7162306a36Sopenharmony_ci fsparam_enum("stats", Opt_stats_mode, binderfs_param_stats), 7262306a36Sopenharmony_ci {} 7362306a36Sopenharmony_ci}; 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_cistatic struct binder_features binder_features = { 7662306a36Sopenharmony_ci .oneway_spam_detection = true, 7762306a36Sopenharmony_ci .extended_error = true, 7862306a36Sopenharmony_ci}; 7962306a36Sopenharmony_ci 8062306a36Sopenharmony_cistatic inline struct binderfs_info *BINDERFS_SB(const struct super_block *sb) 8162306a36Sopenharmony_ci{ 8262306a36Sopenharmony_ci return sb->s_fs_info; 8362306a36Sopenharmony_ci} 8462306a36Sopenharmony_ci 8562306a36Sopenharmony_cibool is_binderfs_device(const struct inode *inode) 8662306a36Sopenharmony_ci{ 8762306a36Sopenharmony_ci if (inode->i_sb->s_magic == BINDERFS_SUPER_MAGIC) 8862306a36Sopenharmony_ci return true; 8962306a36Sopenharmony_ci 9062306a36Sopenharmony_ci return false; 9162306a36Sopenharmony_ci} 9262306a36Sopenharmony_ci 9362306a36Sopenharmony_ci/** 9462306a36Sopenharmony_ci * binderfs_binder_device_create - allocate inode from super block of a 9562306a36Sopenharmony_ci * binderfs mount 9662306a36Sopenharmony_ci * @ref_inode: inode from wich the super block will be taken 9762306a36Sopenharmony_ci * @userp: buffer to copy information about new device for userspace to 9862306a36Sopenharmony_ci * @req: struct binderfs_device as copied from userspace 9962306a36Sopenharmony_ci * 10062306a36Sopenharmony_ci * This function allocates a new binder_device and reserves a new minor 10162306a36Sopenharmony_ci * number for it. 10262306a36Sopenharmony_ci * Minor numbers are limited and tracked globally in binderfs_minors. The 10362306a36Sopenharmony_ci * function will stash a struct binder_device for the specific binder 10462306a36Sopenharmony_ci * device in i_private of the inode. 10562306a36Sopenharmony_ci * It will go on to allocate a new inode from the super block of the 10662306a36Sopenharmony_ci * filesystem mount, stash a struct binder_device in its i_private field 10762306a36Sopenharmony_ci * and attach a dentry to that inode. 10862306a36Sopenharmony_ci * 10962306a36Sopenharmony_ci * Return: 0 on success, negative errno on failure 11062306a36Sopenharmony_ci */ 11162306a36Sopenharmony_cistatic int binderfs_binder_device_create(struct inode *ref_inode, 11262306a36Sopenharmony_ci struct binderfs_device __user *userp, 11362306a36Sopenharmony_ci struct binderfs_device *req) 11462306a36Sopenharmony_ci{ 11562306a36Sopenharmony_ci int minor, ret; 11662306a36Sopenharmony_ci struct dentry *dentry, *root; 11762306a36Sopenharmony_ci struct binder_device *device; 11862306a36Sopenharmony_ci char *name = NULL; 11962306a36Sopenharmony_ci size_t name_len; 12062306a36Sopenharmony_ci struct inode *inode = NULL; 12162306a36Sopenharmony_ci struct super_block *sb = ref_inode->i_sb; 12262306a36Sopenharmony_ci struct binderfs_info *info = sb->s_fs_info; 12362306a36Sopenharmony_ci#if defined(CONFIG_IPC_NS) 12462306a36Sopenharmony_ci bool use_reserve = (info->ipc_ns == &init_ipc_ns); 12562306a36Sopenharmony_ci#else 12662306a36Sopenharmony_ci bool use_reserve = true; 12762306a36Sopenharmony_ci#endif 12862306a36Sopenharmony_ci 12962306a36Sopenharmony_ci /* Reserve new minor number for the new device. */ 13062306a36Sopenharmony_ci mutex_lock(&binderfs_minors_mutex); 13162306a36Sopenharmony_ci if (++info->device_count <= info->mount_opts.max) 13262306a36Sopenharmony_ci minor = ida_alloc_max(&binderfs_minors, 13362306a36Sopenharmony_ci use_reserve ? BINDERFS_MAX_MINOR : 13462306a36Sopenharmony_ci BINDERFS_MAX_MINOR_CAPPED, 13562306a36Sopenharmony_ci GFP_KERNEL); 13662306a36Sopenharmony_ci else 13762306a36Sopenharmony_ci minor = -ENOSPC; 13862306a36Sopenharmony_ci if (minor < 0) { 13962306a36Sopenharmony_ci --info->device_count; 14062306a36Sopenharmony_ci mutex_unlock(&binderfs_minors_mutex); 14162306a36Sopenharmony_ci return minor; 14262306a36Sopenharmony_ci } 14362306a36Sopenharmony_ci mutex_unlock(&binderfs_minors_mutex); 14462306a36Sopenharmony_ci 14562306a36Sopenharmony_ci ret = -ENOMEM; 14662306a36Sopenharmony_ci device = kzalloc(sizeof(*device), GFP_KERNEL); 14762306a36Sopenharmony_ci if (!device) 14862306a36Sopenharmony_ci goto err; 14962306a36Sopenharmony_ci 15062306a36Sopenharmony_ci inode = new_inode(sb); 15162306a36Sopenharmony_ci if (!inode) 15262306a36Sopenharmony_ci goto err; 15362306a36Sopenharmony_ci 15462306a36Sopenharmony_ci inode->i_ino = minor + INODE_OFFSET; 15562306a36Sopenharmony_ci inode->i_mtime = inode->i_atime = inode_set_ctime_current(inode); 15662306a36Sopenharmony_ci init_special_inode(inode, S_IFCHR | 0600, 15762306a36Sopenharmony_ci MKDEV(MAJOR(binderfs_dev), minor)); 15862306a36Sopenharmony_ci inode->i_fop = &binder_fops; 15962306a36Sopenharmony_ci inode->i_uid = info->root_uid; 16062306a36Sopenharmony_ci inode->i_gid = info->root_gid; 16162306a36Sopenharmony_ci 16262306a36Sopenharmony_ci req->name[BINDERFS_MAX_NAME] = '\0'; /* NUL-terminate */ 16362306a36Sopenharmony_ci name_len = strlen(req->name); 16462306a36Sopenharmony_ci /* Make sure to include terminating NUL byte */ 16562306a36Sopenharmony_ci name = kmemdup(req->name, name_len + 1, GFP_KERNEL); 16662306a36Sopenharmony_ci if (!name) 16762306a36Sopenharmony_ci goto err; 16862306a36Sopenharmony_ci 16962306a36Sopenharmony_ci refcount_set(&device->ref, 1); 17062306a36Sopenharmony_ci device->binderfs_inode = inode; 17162306a36Sopenharmony_ci device->context.binder_context_mgr_uid = INVALID_UID; 17262306a36Sopenharmony_ci device->context.name = name; 17362306a36Sopenharmony_ci device->miscdev.name = name; 17462306a36Sopenharmony_ci device->miscdev.minor = minor; 17562306a36Sopenharmony_ci mutex_init(&device->context.context_mgr_node_lock); 17662306a36Sopenharmony_ci 17762306a36Sopenharmony_ci req->major = MAJOR(binderfs_dev); 17862306a36Sopenharmony_ci req->minor = minor; 17962306a36Sopenharmony_ci 18062306a36Sopenharmony_ci if (userp && copy_to_user(userp, req, sizeof(*req))) { 18162306a36Sopenharmony_ci ret = -EFAULT; 18262306a36Sopenharmony_ci goto err; 18362306a36Sopenharmony_ci } 18462306a36Sopenharmony_ci 18562306a36Sopenharmony_ci root = sb->s_root; 18662306a36Sopenharmony_ci inode_lock(d_inode(root)); 18762306a36Sopenharmony_ci 18862306a36Sopenharmony_ci /* look it up */ 18962306a36Sopenharmony_ci dentry = lookup_one_len(name, root, name_len); 19062306a36Sopenharmony_ci if (IS_ERR(dentry)) { 19162306a36Sopenharmony_ci inode_unlock(d_inode(root)); 19262306a36Sopenharmony_ci ret = PTR_ERR(dentry); 19362306a36Sopenharmony_ci goto err; 19462306a36Sopenharmony_ci } 19562306a36Sopenharmony_ci 19662306a36Sopenharmony_ci if (d_really_is_positive(dentry)) { 19762306a36Sopenharmony_ci /* already exists */ 19862306a36Sopenharmony_ci dput(dentry); 19962306a36Sopenharmony_ci inode_unlock(d_inode(root)); 20062306a36Sopenharmony_ci ret = -EEXIST; 20162306a36Sopenharmony_ci goto err; 20262306a36Sopenharmony_ci } 20362306a36Sopenharmony_ci 20462306a36Sopenharmony_ci inode->i_private = device; 20562306a36Sopenharmony_ci d_instantiate(dentry, inode); 20662306a36Sopenharmony_ci fsnotify_create(root->d_inode, dentry); 20762306a36Sopenharmony_ci inode_unlock(d_inode(root)); 20862306a36Sopenharmony_ci 20962306a36Sopenharmony_ci return 0; 21062306a36Sopenharmony_ci 21162306a36Sopenharmony_cierr: 21262306a36Sopenharmony_ci kfree(name); 21362306a36Sopenharmony_ci kfree(device); 21462306a36Sopenharmony_ci mutex_lock(&binderfs_minors_mutex); 21562306a36Sopenharmony_ci --info->device_count; 21662306a36Sopenharmony_ci ida_free(&binderfs_minors, minor); 21762306a36Sopenharmony_ci mutex_unlock(&binderfs_minors_mutex); 21862306a36Sopenharmony_ci iput(inode); 21962306a36Sopenharmony_ci 22062306a36Sopenharmony_ci return ret; 22162306a36Sopenharmony_ci} 22262306a36Sopenharmony_ci 22362306a36Sopenharmony_ci/** 22462306a36Sopenharmony_ci * binder_ctl_ioctl - handle binder device node allocation requests 22562306a36Sopenharmony_ci * 22662306a36Sopenharmony_ci * The request handler for the binder-control device. All requests operate on 22762306a36Sopenharmony_ci * the binderfs mount the binder-control device resides in: 22862306a36Sopenharmony_ci * - BINDER_CTL_ADD 22962306a36Sopenharmony_ci * Allocate a new binder device. 23062306a36Sopenharmony_ci * 23162306a36Sopenharmony_ci * Return: %0 on success, negative errno on failure. 23262306a36Sopenharmony_ci */ 23362306a36Sopenharmony_cistatic long binder_ctl_ioctl(struct file *file, unsigned int cmd, 23462306a36Sopenharmony_ci unsigned long arg) 23562306a36Sopenharmony_ci{ 23662306a36Sopenharmony_ci int ret = -EINVAL; 23762306a36Sopenharmony_ci struct inode *inode = file_inode(file); 23862306a36Sopenharmony_ci struct binderfs_device __user *device = (struct binderfs_device __user *)arg; 23962306a36Sopenharmony_ci struct binderfs_device device_req; 24062306a36Sopenharmony_ci 24162306a36Sopenharmony_ci switch (cmd) { 24262306a36Sopenharmony_ci case BINDER_CTL_ADD: 24362306a36Sopenharmony_ci ret = copy_from_user(&device_req, device, sizeof(device_req)); 24462306a36Sopenharmony_ci if (ret) { 24562306a36Sopenharmony_ci ret = -EFAULT; 24662306a36Sopenharmony_ci break; 24762306a36Sopenharmony_ci } 24862306a36Sopenharmony_ci 24962306a36Sopenharmony_ci ret = binderfs_binder_device_create(inode, device, &device_req); 25062306a36Sopenharmony_ci break; 25162306a36Sopenharmony_ci default: 25262306a36Sopenharmony_ci break; 25362306a36Sopenharmony_ci } 25462306a36Sopenharmony_ci 25562306a36Sopenharmony_ci return ret; 25662306a36Sopenharmony_ci} 25762306a36Sopenharmony_ci 25862306a36Sopenharmony_cistatic void binderfs_evict_inode(struct inode *inode) 25962306a36Sopenharmony_ci{ 26062306a36Sopenharmony_ci struct binder_device *device = inode->i_private; 26162306a36Sopenharmony_ci struct binderfs_info *info = BINDERFS_SB(inode->i_sb); 26262306a36Sopenharmony_ci 26362306a36Sopenharmony_ci clear_inode(inode); 26462306a36Sopenharmony_ci 26562306a36Sopenharmony_ci if (!S_ISCHR(inode->i_mode) || !device) 26662306a36Sopenharmony_ci return; 26762306a36Sopenharmony_ci 26862306a36Sopenharmony_ci mutex_lock(&binderfs_minors_mutex); 26962306a36Sopenharmony_ci --info->device_count; 27062306a36Sopenharmony_ci ida_free(&binderfs_minors, device->miscdev.minor); 27162306a36Sopenharmony_ci mutex_unlock(&binderfs_minors_mutex); 27262306a36Sopenharmony_ci 27362306a36Sopenharmony_ci if (refcount_dec_and_test(&device->ref)) { 27462306a36Sopenharmony_ci kfree(device->context.name); 27562306a36Sopenharmony_ci kfree(device); 27662306a36Sopenharmony_ci } 27762306a36Sopenharmony_ci} 27862306a36Sopenharmony_ci 27962306a36Sopenharmony_cistatic int binderfs_fs_context_parse_param(struct fs_context *fc, 28062306a36Sopenharmony_ci struct fs_parameter *param) 28162306a36Sopenharmony_ci{ 28262306a36Sopenharmony_ci int opt; 28362306a36Sopenharmony_ci struct binderfs_mount_opts *ctx = fc->fs_private; 28462306a36Sopenharmony_ci struct fs_parse_result result; 28562306a36Sopenharmony_ci 28662306a36Sopenharmony_ci opt = fs_parse(fc, binderfs_fs_parameters, param, &result); 28762306a36Sopenharmony_ci if (opt < 0) 28862306a36Sopenharmony_ci return opt; 28962306a36Sopenharmony_ci 29062306a36Sopenharmony_ci switch (opt) { 29162306a36Sopenharmony_ci case Opt_max: 29262306a36Sopenharmony_ci if (result.uint_32 > BINDERFS_MAX_MINOR) 29362306a36Sopenharmony_ci return invalfc(fc, "Bad value for '%s'", param->key); 29462306a36Sopenharmony_ci 29562306a36Sopenharmony_ci ctx->max = result.uint_32; 29662306a36Sopenharmony_ci break; 29762306a36Sopenharmony_ci case Opt_stats_mode: 29862306a36Sopenharmony_ci if (!capable(CAP_SYS_ADMIN)) 29962306a36Sopenharmony_ci return -EPERM; 30062306a36Sopenharmony_ci 30162306a36Sopenharmony_ci ctx->stats_mode = result.uint_32; 30262306a36Sopenharmony_ci break; 30362306a36Sopenharmony_ci default: 30462306a36Sopenharmony_ci return invalfc(fc, "Unsupported parameter '%s'", param->key); 30562306a36Sopenharmony_ci } 30662306a36Sopenharmony_ci 30762306a36Sopenharmony_ci return 0; 30862306a36Sopenharmony_ci} 30962306a36Sopenharmony_ci 31062306a36Sopenharmony_cistatic int binderfs_fs_context_reconfigure(struct fs_context *fc) 31162306a36Sopenharmony_ci{ 31262306a36Sopenharmony_ci struct binderfs_mount_opts *ctx = fc->fs_private; 31362306a36Sopenharmony_ci struct binderfs_info *info = BINDERFS_SB(fc->root->d_sb); 31462306a36Sopenharmony_ci 31562306a36Sopenharmony_ci if (info->mount_opts.stats_mode != ctx->stats_mode) 31662306a36Sopenharmony_ci return invalfc(fc, "Binderfs stats mode cannot be changed during a remount"); 31762306a36Sopenharmony_ci 31862306a36Sopenharmony_ci info->mount_opts.stats_mode = ctx->stats_mode; 31962306a36Sopenharmony_ci info->mount_opts.max = ctx->max; 32062306a36Sopenharmony_ci return 0; 32162306a36Sopenharmony_ci} 32262306a36Sopenharmony_ci 32362306a36Sopenharmony_cistatic int binderfs_show_options(struct seq_file *seq, struct dentry *root) 32462306a36Sopenharmony_ci{ 32562306a36Sopenharmony_ci struct binderfs_info *info = BINDERFS_SB(root->d_sb); 32662306a36Sopenharmony_ci 32762306a36Sopenharmony_ci if (info->mount_opts.max <= BINDERFS_MAX_MINOR) 32862306a36Sopenharmony_ci seq_printf(seq, ",max=%d", info->mount_opts.max); 32962306a36Sopenharmony_ci 33062306a36Sopenharmony_ci switch (info->mount_opts.stats_mode) { 33162306a36Sopenharmony_ci case binderfs_stats_mode_unset: 33262306a36Sopenharmony_ci break; 33362306a36Sopenharmony_ci case binderfs_stats_mode_global: 33462306a36Sopenharmony_ci seq_printf(seq, ",stats=global"); 33562306a36Sopenharmony_ci break; 33662306a36Sopenharmony_ci } 33762306a36Sopenharmony_ci 33862306a36Sopenharmony_ci return 0; 33962306a36Sopenharmony_ci} 34062306a36Sopenharmony_ci 34162306a36Sopenharmony_cistatic const struct super_operations binderfs_super_ops = { 34262306a36Sopenharmony_ci .evict_inode = binderfs_evict_inode, 34362306a36Sopenharmony_ci .show_options = binderfs_show_options, 34462306a36Sopenharmony_ci .statfs = simple_statfs, 34562306a36Sopenharmony_ci}; 34662306a36Sopenharmony_ci 34762306a36Sopenharmony_cistatic inline bool is_binderfs_control_device(const struct dentry *dentry) 34862306a36Sopenharmony_ci{ 34962306a36Sopenharmony_ci struct binderfs_info *info = dentry->d_sb->s_fs_info; 35062306a36Sopenharmony_ci 35162306a36Sopenharmony_ci return info->control_dentry == dentry; 35262306a36Sopenharmony_ci} 35362306a36Sopenharmony_ci 35462306a36Sopenharmony_cistatic int binderfs_rename(struct mnt_idmap *idmap, 35562306a36Sopenharmony_ci struct inode *old_dir, struct dentry *old_dentry, 35662306a36Sopenharmony_ci struct inode *new_dir, struct dentry *new_dentry, 35762306a36Sopenharmony_ci unsigned int flags) 35862306a36Sopenharmony_ci{ 35962306a36Sopenharmony_ci if (is_binderfs_control_device(old_dentry) || 36062306a36Sopenharmony_ci is_binderfs_control_device(new_dentry)) 36162306a36Sopenharmony_ci return -EPERM; 36262306a36Sopenharmony_ci 36362306a36Sopenharmony_ci return simple_rename(idmap, old_dir, old_dentry, new_dir, 36462306a36Sopenharmony_ci new_dentry, flags); 36562306a36Sopenharmony_ci} 36662306a36Sopenharmony_ci 36762306a36Sopenharmony_cistatic int binderfs_unlink(struct inode *dir, struct dentry *dentry) 36862306a36Sopenharmony_ci{ 36962306a36Sopenharmony_ci if (is_binderfs_control_device(dentry)) 37062306a36Sopenharmony_ci return -EPERM; 37162306a36Sopenharmony_ci 37262306a36Sopenharmony_ci return simple_unlink(dir, dentry); 37362306a36Sopenharmony_ci} 37462306a36Sopenharmony_ci 37562306a36Sopenharmony_cistatic const struct file_operations binder_ctl_fops = { 37662306a36Sopenharmony_ci .owner = THIS_MODULE, 37762306a36Sopenharmony_ci .open = nonseekable_open, 37862306a36Sopenharmony_ci .unlocked_ioctl = binder_ctl_ioctl, 37962306a36Sopenharmony_ci .compat_ioctl = binder_ctl_ioctl, 38062306a36Sopenharmony_ci .llseek = noop_llseek, 38162306a36Sopenharmony_ci}; 38262306a36Sopenharmony_ci 38362306a36Sopenharmony_ci/** 38462306a36Sopenharmony_ci * binderfs_binder_ctl_create - create a new binder-control device 38562306a36Sopenharmony_ci * @sb: super block of the binderfs mount 38662306a36Sopenharmony_ci * 38762306a36Sopenharmony_ci * This function creates a new binder-control device node in the binderfs mount 38862306a36Sopenharmony_ci * referred to by @sb. 38962306a36Sopenharmony_ci * 39062306a36Sopenharmony_ci * Return: 0 on success, negative errno on failure 39162306a36Sopenharmony_ci */ 39262306a36Sopenharmony_cistatic int binderfs_binder_ctl_create(struct super_block *sb) 39362306a36Sopenharmony_ci{ 39462306a36Sopenharmony_ci int minor, ret; 39562306a36Sopenharmony_ci struct dentry *dentry; 39662306a36Sopenharmony_ci struct binder_device *device; 39762306a36Sopenharmony_ci struct inode *inode = NULL; 39862306a36Sopenharmony_ci struct dentry *root = sb->s_root; 39962306a36Sopenharmony_ci struct binderfs_info *info = sb->s_fs_info; 40062306a36Sopenharmony_ci#if defined(CONFIG_IPC_NS) 40162306a36Sopenharmony_ci bool use_reserve = (info->ipc_ns == &init_ipc_ns); 40262306a36Sopenharmony_ci#else 40362306a36Sopenharmony_ci bool use_reserve = true; 40462306a36Sopenharmony_ci#endif 40562306a36Sopenharmony_ci 40662306a36Sopenharmony_ci device = kzalloc(sizeof(*device), GFP_KERNEL); 40762306a36Sopenharmony_ci if (!device) 40862306a36Sopenharmony_ci return -ENOMEM; 40962306a36Sopenharmony_ci 41062306a36Sopenharmony_ci /* If we have already created a binder-control node, return. */ 41162306a36Sopenharmony_ci if (info->control_dentry) { 41262306a36Sopenharmony_ci ret = 0; 41362306a36Sopenharmony_ci goto out; 41462306a36Sopenharmony_ci } 41562306a36Sopenharmony_ci 41662306a36Sopenharmony_ci ret = -ENOMEM; 41762306a36Sopenharmony_ci inode = new_inode(sb); 41862306a36Sopenharmony_ci if (!inode) 41962306a36Sopenharmony_ci goto out; 42062306a36Sopenharmony_ci 42162306a36Sopenharmony_ci /* Reserve a new minor number for the new device. */ 42262306a36Sopenharmony_ci mutex_lock(&binderfs_minors_mutex); 42362306a36Sopenharmony_ci minor = ida_alloc_max(&binderfs_minors, 42462306a36Sopenharmony_ci use_reserve ? BINDERFS_MAX_MINOR : 42562306a36Sopenharmony_ci BINDERFS_MAX_MINOR_CAPPED, 42662306a36Sopenharmony_ci GFP_KERNEL); 42762306a36Sopenharmony_ci mutex_unlock(&binderfs_minors_mutex); 42862306a36Sopenharmony_ci if (minor < 0) { 42962306a36Sopenharmony_ci ret = minor; 43062306a36Sopenharmony_ci goto out; 43162306a36Sopenharmony_ci } 43262306a36Sopenharmony_ci 43362306a36Sopenharmony_ci inode->i_ino = SECOND_INODE; 43462306a36Sopenharmony_ci inode->i_mtime = inode->i_atime = inode_set_ctime_current(inode); 43562306a36Sopenharmony_ci init_special_inode(inode, S_IFCHR | 0600, 43662306a36Sopenharmony_ci MKDEV(MAJOR(binderfs_dev), minor)); 43762306a36Sopenharmony_ci inode->i_fop = &binder_ctl_fops; 43862306a36Sopenharmony_ci inode->i_uid = info->root_uid; 43962306a36Sopenharmony_ci inode->i_gid = info->root_gid; 44062306a36Sopenharmony_ci 44162306a36Sopenharmony_ci refcount_set(&device->ref, 1); 44262306a36Sopenharmony_ci device->binderfs_inode = inode; 44362306a36Sopenharmony_ci device->miscdev.minor = minor; 44462306a36Sopenharmony_ci 44562306a36Sopenharmony_ci dentry = d_alloc_name(root, "binder-control"); 44662306a36Sopenharmony_ci if (!dentry) 44762306a36Sopenharmony_ci goto out; 44862306a36Sopenharmony_ci 44962306a36Sopenharmony_ci inode->i_private = device; 45062306a36Sopenharmony_ci info->control_dentry = dentry; 45162306a36Sopenharmony_ci d_add(dentry, inode); 45262306a36Sopenharmony_ci 45362306a36Sopenharmony_ci return 0; 45462306a36Sopenharmony_ci 45562306a36Sopenharmony_ciout: 45662306a36Sopenharmony_ci kfree(device); 45762306a36Sopenharmony_ci iput(inode); 45862306a36Sopenharmony_ci 45962306a36Sopenharmony_ci return ret; 46062306a36Sopenharmony_ci} 46162306a36Sopenharmony_ci 46262306a36Sopenharmony_cistatic const struct inode_operations binderfs_dir_inode_operations = { 46362306a36Sopenharmony_ci .lookup = simple_lookup, 46462306a36Sopenharmony_ci .rename = binderfs_rename, 46562306a36Sopenharmony_ci .unlink = binderfs_unlink, 46662306a36Sopenharmony_ci}; 46762306a36Sopenharmony_ci 46862306a36Sopenharmony_cistatic struct inode *binderfs_make_inode(struct super_block *sb, int mode) 46962306a36Sopenharmony_ci{ 47062306a36Sopenharmony_ci struct inode *ret; 47162306a36Sopenharmony_ci 47262306a36Sopenharmony_ci ret = new_inode(sb); 47362306a36Sopenharmony_ci if (ret) { 47462306a36Sopenharmony_ci ret->i_ino = iunique(sb, BINDERFS_MAX_MINOR + INODE_OFFSET); 47562306a36Sopenharmony_ci ret->i_mode = mode; 47662306a36Sopenharmony_ci ret->i_atime = ret->i_mtime = inode_set_ctime_current(ret); 47762306a36Sopenharmony_ci } 47862306a36Sopenharmony_ci return ret; 47962306a36Sopenharmony_ci} 48062306a36Sopenharmony_ci 48162306a36Sopenharmony_cistatic struct dentry *binderfs_create_dentry(struct dentry *parent, 48262306a36Sopenharmony_ci const char *name) 48362306a36Sopenharmony_ci{ 48462306a36Sopenharmony_ci struct dentry *dentry; 48562306a36Sopenharmony_ci 48662306a36Sopenharmony_ci dentry = lookup_one_len(name, parent, strlen(name)); 48762306a36Sopenharmony_ci if (IS_ERR(dentry)) 48862306a36Sopenharmony_ci return dentry; 48962306a36Sopenharmony_ci 49062306a36Sopenharmony_ci /* Return error if the file/dir already exists. */ 49162306a36Sopenharmony_ci if (d_really_is_positive(dentry)) { 49262306a36Sopenharmony_ci dput(dentry); 49362306a36Sopenharmony_ci return ERR_PTR(-EEXIST); 49462306a36Sopenharmony_ci } 49562306a36Sopenharmony_ci 49662306a36Sopenharmony_ci return dentry; 49762306a36Sopenharmony_ci} 49862306a36Sopenharmony_ci 49962306a36Sopenharmony_civoid binderfs_remove_file(struct dentry *dentry) 50062306a36Sopenharmony_ci{ 50162306a36Sopenharmony_ci struct inode *parent_inode; 50262306a36Sopenharmony_ci 50362306a36Sopenharmony_ci parent_inode = d_inode(dentry->d_parent); 50462306a36Sopenharmony_ci inode_lock(parent_inode); 50562306a36Sopenharmony_ci if (simple_positive(dentry)) { 50662306a36Sopenharmony_ci dget(dentry); 50762306a36Sopenharmony_ci simple_unlink(parent_inode, dentry); 50862306a36Sopenharmony_ci d_delete(dentry); 50962306a36Sopenharmony_ci dput(dentry); 51062306a36Sopenharmony_ci } 51162306a36Sopenharmony_ci inode_unlock(parent_inode); 51262306a36Sopenharmony_ci} 51362306a36Sopenharmony_ci 51462306a36Sopenharmony_cistruct dentry *binderfs_create_file(struct dentry *parent, const char *name, 51562306a36Sopenharmony_ci const struct file_operations *fops, 51662306a36Sopenharmony_ci void *data) 51762306a36Sopenharmony_ci{ 51862306a36Sopenharmony_ci struct dentry *dentry; 51962306a36Sopenharmony_ci struct inode *new_inode, *parent_inode; 52062306a36Sopenharmony_ci struct super_block *sb; 52162306a36Sopenharmony_ci 52262306a36Sopenharmony_ci parent_inode = d_inode(parent); 52362306a36Sopenharmony_ci inode_lock(parent_inode); 52462306a36Sopenharmony_ci 52562306a36Sopenharmony_ci dentry = binderfs_create_dentry(parent, name); 52662306a36Sopenharmony_ci if (IS_ERR(dentry)) 52762306a36Sopenharmony_ci goto out; 52862306a36Sopenharmony_ci 52962306a36Sopenharmony_ci sb = parent_inode->i_sb; 53062306a36Sopenharmony_ci new_inode = binderfs_make_inode(sb, S_IFREG | 0444); 53162306a36Sopenharmony_ci if (!new_inode) { 53262306a36Sopenharmony_ci dput(dentry); 53362306a36Sopenharmony_ci dentry = ERR_PTR(-ENOMEM); 53462306a36Sopenharmony_ci goto out; 53562306a36Sopenharmony_ci } 53662306a36Sopenharmony_ci 53762306a36Sopenharmony_ci new_inode->i_fop = fops; 53862306a36Sopenharmony_ci new_inode->i_private = data; 53962306a36Sopenharmony_ci d_instantiate(dentry, new_inode); 54062306a36Sopenharmony_ci fsnotify_create(parent_inode, dentry); 54162306a36Sopenharmony_ci 54262306a36Sopenharmony_ciout: 54362306a36Sopenharmony_ci inode_unlock(parent_inode); 54462306a36Sopenharmony_ci return dentry; 54562306a36Sopenharmony_ci} 54662306a36Sopenharmony_ci 54762306a36Sopenharmony_cistatic struct dentry *binderfs_create_dir(struct dentry *parent, 54862306a36Sopenharmony_ci const char *name) 54962306a36Sopenharmony_ci{ 55062306a36Sopenharmony_ci struct dentry *dentry; 55162306a36Sopenharmony_ci struct inode *new_inode, *parent_inode; 55262306a36Sopenharmony_ci struct super_block *sb; 55362306a36Sopenharmony_ci 55462306a36Sopenharmony_ci parent_inode = d_inode(parent); 55562306a36Sopenharmony_ci inode_lock(parent_inode); 55662306a36Sopenharmony_ci 55762306a36Sopenharmony_ci dentry = binderfs_create_dentry(parent, name); 55862306a36Sopenharmony_ci if (IS_ERR(dentry)) 55962306a36Sopenharmony_ci goto out; 56062306a36Sopenharmony_ci 56162306a36Sopenharmony_ci sb = parent_inode->i_sb; 56262306a36Sopenharmony_ci new_inode = binderfs_make_inode(sb, S_IFDIR | 0755); 56362306a36Sopenharmony_ci if (!new_inode) { 56462306a36Sopenharmony_ci dput(dentry); 56562306a36Sopenharmony_ci dentry = ERR_PTR(-ENOMEM); 56662306a36Sopenharmony_ci goto out; 56762306a36Sopenharmony_ci } 56862306a36Sopenharmony_ci 56962306a36Sopenharmony_ci new_inode->i_fop = &simple_dir_operations; 57062306a36Sopenharmony_ci new_inode->i_op = &simple_dir_inode_operations; 57162306a36Sopenharmony_ci 57262306a36Sopenharmony_ci set_nlink(new_inode, 2); 57362306a36Sopenharmony_ci d_instantiate(dentry, new_inode); 57462306a36Sopenharmony_ci inc_nlink(parent_inode); 57562306a36Sopenharmony_ci fsnotify_mkdir(parent_inode, dentry); 57662306a36Sopenharmony_ci 57762306a36Sopenharmony_ciout: 57862306a36Sopenharmony_ci inode_unlock(parent_inode); 57962306a36Sopenharmony_ci return dentry; 58062306a36Sopenharmony_ci} 58162306a36Sopenharmony_ci 58262306a36Sopenharmony_cistatic int binder_features_show(struct seq_file *m, void *unused) 58362306a36Sopenharmony_ci{ 58462306a36Sopenharmony_ci bool *feature = m->private; 58562306a36Sopenharmony_ci 58662306a36Sopenharmony_ci seq_printf(m, "%d\n", *feature); 58762306a36Sopenharmony_ci 58862306a36Sopenharmony_ci return 0; 58962306a36Sopenharmony_ci} 59062306a36Sopenharmony_ciDEFINE_SHOW_ATTRIBUTE(binder_features); 59162306a36Sopenharmony_ci 59262306a36Sopenharmony_cistatic int init_binder_features(struct super_block *sb) 59362306a36Sopenharmony_ci{ 59462306a36Sopenharmony_ci struct dentry *dentry, *dir; 59562306a36Sopenharmony_ci 59662306a36Sopenharmony_ci dir = binderfs_create_dir(sb->s_root, "features"); 59762306a36Sopenharmony_ci if (IS_ERR(dir)) 59862306a36Sopenharmony_ci return PTR_ERR(dir); 59962306a36Sopenharmony_ci 60062306a36Sopenharmony_ci dentry = binderfs_create_file(dir, "oneway_spam_detection", 60162306a36Sopenharmony_ci &binder_features_fops, 60262306a36Sopenharmony_ci &binder_features.oneway_spam_detection); 60362306a36Sopenharmony_ci if (IS_ERR(dentry)) 60462306a36Sopenharmony_ci return PTR_ERR(dentry); 60562306a36Sopenharmony_ci 60662306a36Sopenharmony_ci dentry = binderfs_create_file(dir, "extended_error", 60762306a36Sopenharmony_ci &binder_features_fops, 60862306a36Sopenharmony_ci &binder_features.extended_error); 60962306a36Sopenharmony_ci if (IS_ERR(dentry)) 61062306a36Sopenharmony_ci return PTR_ERR(dentry); 61162306a36Sopenharmony_ci 61262306a36Sopenharmony_ci return 0; 61362306a36Sopenharmony_ci} 61462306a36Sopenharmony_ci 61562306a36Sopenharmony_cistatic int init_binder_logs(struct super_block *sb) 61662306a36Sopenharmony_ci{ 61762306a36Sopenharmony_ci struct dentry *binder_logs_root_dir, *dentry, *proc_log_dir; 61862306a36Sopenharmony_ci const struct binder_debugfs_entry *db_entry; 61962306a36Sopenharmony_ci struct binderfs_info *info; 62062306a36Sopenharmony_ci int ret = 0; 62162306a36Sopenharmony_ci 62262306a36Sopenharmony_ci binder_logs_root_dir = binderfs_create_dir(sb->s_root, 62362306a36Sopenharmony_ci "binder_logs"); 62462306a36Sopenharmony_ci if (IS_ERR(binder_logs_root_dir)) { 62562306a36Sopenharmony_ci ret = PTR_ERR(binder_logs_root_dir); 62662306a36Sopenharmony_ci goto out; 62762306a36Sopenharmony_ci } 62862306a36Sopenharmony_ci 62962306a36Sopenharmony_ci binder_for_each_debugfs_entry(db_entry) { 63062306a36Sopenharmony_ci dentry = binderfs_create_file(binder_logs_root_dir, 63162306a36Sopenharmony_ci db_entry->name, 63262306a36Sopenharmony_ci db_entry->fops, 63362306a36Sopenharmony_ci db_entry->data); 63462306a36Sopenharmony_ci if (IS_ERR(dentry)) { 63562306a36Sopenharmony_ci ret = PTR_ERR(dentry); 63662306a36Sopenharmony_ci goto out; 63762306a36Sopenharmony_ci } 63862306a36Sopenharmony_ci } 63962306a36Sopenharmony_ci 64062306a36Sopenharmony_ci proc_log_dir = binderfs_create_dir(binder_logs_root_dir, "proc"); 64162306a36Sopenharmony_ci if (IS_ERR(proc_log_dir)) { 64262306a36Sopenharmony_ci ret = PTR_ERR(proc_log_dir); 64362306a36Sopenharmony_ci goto out; 64462306a36Sopenharmony_ci } 64562306a36Sopenharmony_ci info = sb->s_fs_info; 64662306a36Sopenharmony_ci info->proc_log_dir = proc_log_dir; 64762306a36Sopenharmony_ci 64862306a36Sopenharmony_ciout: 64962306a36Sopenharmony_ci return ret; 65062306a36Sopenharmony_ci} 65162306a36Sopenharmony_ci 65262306a36Sopenharmony_cistatic int binderfs_fill_super(struct super_block *sb, struct fs_context *fc) 65362306a36Sopenharmony_ci{ 65462306a36Sopenharmony_ci int ret; 65562306a36Sopenharmony_ci struct binderfs_info *info; 65662306a36Sopenharmony_ci struct binderfs_mount_opts *ctx = fc->fs_private; 65762306a36Sopenharmony_ci struct inode *inode = NULL; 65862306a36Sopenharmony_ci struct binderfs_device device_info = {}; 65962306a36Sopenharmony_ci const char *name; 66062306a36Sopenharmony_ci size_t len; 66162306a36Sopenharmony_ci 66262306a36Sopenharmony_ci sb->s_blocksize = PAGE_SIZE; 66362306a36Sopenharmony_ci sb->s_blocksize_bits = PAGE_SHIFT; 66462306a36Sopenharmony_ci 66562306a36Sopenharmony_ci /* 66662306a36Sopenharmony_ci * The binderfs filesystem can be mounted by userns root in a 66762306a36Sopenharmony_ci * non-initial userns. By default such mounts have the SB_I_NODEV flag 66862306a36Sopenharmony_ci * set in s_iflags to prevent security issues where userns root can 66962306a36Sopenharmony_ci * just create random device nodes via mknod() since it owns the 67062306a36Sopenharmony_ci * filesystem mount. But binderfs does not allow to create any files 67162306a36Sopenharmony_ci * including devices nodes. The only way to create binder devices nodes 67262306a36Sopenharmony_ci * is through the binder-control device which userns root is explicitly 67362306a36Sopenharmony_ci * allowed to do. So removing the SB_I_NODEV flag from s_iflags is both 67462306a36Sopenharmony_ci * necessary and safe. 67562306a36Sopenharmony_ci */ 67662306a36Sopenharmony_ci sb->s_iflags &= ~SB_I_NODEV; 67762306a36Sopenharmony_ci sb->s_iflags |= SB_I_NOEXEC; 67862306a36Sopenharmony_ci sb->s_magic = BINDERFS_SUPER_MAGIC; 67962306a36Sopenharmony_ci sb->s_op = &binderfs_super_ops; 68062306a36Sopenharmony_ci sb->s_time_gran = 1; 68162306a36Sopenharmony_ci 68262306a36Sopenharmony_ci sb->s_fs_info = kzalloc(sizeof(struct binderfs_info), GFP_KERNEL); 68362306a36Sopenharmony_ci if (!sb->s_fs_info) 68462306a36Sopenharmony_ci return -ENOMEM; 68562306a36Sopenharmony_ci info = sb->s_fs_info; 68662306a36Sopenharmony_ci 68762306a36Sopenharmony_ci info->ipc_ns = get_ipc_ns(current->nsproxy->ipc_ns); 68862306a36Sopenharmony_ci 68962306a36Sopenharmony_ci info->root_gid = make_kgid(sb->s_user_ns, 0); 69062306a36Sopenharmony_ci if (!gid_valid(info->root_gid)) 69162306a36Sopenharmony_ci info->root_gid = GLOBAL_ROOT_GID; 69262306a36Sopenharmony_ci info->root_uid = make_kuid(sb->s_user_ns, 0); 69362306a36Sopenharmony_ci if (!uid_valid(info->root_uid)) 69462306a36Sopenharmony_ci info->root_uid = GLOBAL_ROOT_UID; 69562306a36Sopenharmony_ci info->mount_opts.max = ctx->max; 69662306a36Sopenharmony_ci info->mount_opts.stats_mode = ctx->stats_mode; 69762306a36Sopenharmony_ci 69862306a36Sopenharmony_ci inode = new_inode(sb); 69962306a36Sopenharmony_ci if (!inode) 70062306a36Sopenharmony_ci return -ENOMEM; 70162306a36Sopenharmony_ci 70262306a36Sopenharmony_ci inode->i_ino = FIRST_INODE; 70362306a36Sopenharmony_ci inode->i_fop = &simple_dir_operations; 70462306a36Sopenharmony_ci inode->i_mode = S_IFDIR | 0755; 70562306a36Sopenharmony_ci inode->i_mtime = inode->i_atime = inode_set_ctime_current(inode); 70662306a36Sopenharmony_ci inode->i_op = &binderfs_dir_inode_operations; 70762306a36Sopenharmony_ci set_nlink(inode, 2); 70862306a36Sopenharmony_ci 70962306a36Sopenharmony_ci sb->s_root = d_make_root(inode); 71062306a36Sopenharmony_ci if (!sb->s_root) 71162306a36Sopenharmony_ci return -ENOMEM; 71262306a36Sopenharmony_ci 71362306a36Sopenharmony_ci ret = binderfs_binder_ctl_create(sb); 71462306a36Sopenharmony_ci if (ret) 71562306a36Sopenharmony_ci return ret; 71662306a36Sopenharmony_ci 71762306a36Sopenharmony_ci name = binder_devices_param; 71862306a36Sopenharmony_ci for (len = strcspn(name, ","); len > 0; len = strcspn(name, ",")) { 71962306a36Sopenharmony_ci strscpy(device_info.name, name, len + 1); 72062306a36Sopenharmony_ci ret = binderfs_binder_device_create(inode, NULL, &device_info); 72162306a36Sopenharmony_ci if (ret) 72262306a36Sopenharmony_ci return ret; 72362306a36Sopenharmony_ci name += len; 72462306a36Sopenharmony_ci if (*name == ',') 72562306a36Sopenharmony_ci name++; 72662306a36Sopenharmony_ci } 72762306a36Sopenharmony_ci 72862306a36Sopenharmony_ci ret = init_binder_features(sb); 72962306a36Sopenharmony_ci if (ret) 73062306a36Sopenharmony_ci return ret; 73162306a36Sopenharmony_ci 73262306a36Sopenharmony_ci if (info->mount_opts.stats_mode == binderfs_stats_mode_global) 73362306a36Sopenharmony_ci return init_binder_logs(sb); 73462306a36Sopenharmony_ci 73562306a36Sopenharmony_ci return 0; 73662306a36Sopenharmony_ci} 73762306a36Sopenharmony_ci 73862306a36Sopenharmony_cistatic int binderfs_fs_context_get_tree(struct fs_context *fc) 73962306a36Sopenharmony_ci{ 74062306a36Sopenharmony_ci return get_tree_nodev(fc, binderfs_fill_super); 74162306a36Sopenharmony_ci} 74262306a36Sopenharmony_ci 74362306a36Sopenharmony_cistatic void binderfs_fs_context_free(struct fs_context *fc) 74462306a36Sopenharmony_ci{ 74562306a36Sopenharmony_ci struct binderfs_mount_opts *ctx = fc->fs_private; 74662306a36Sopenharmony_ci 74762306a36Sopenharmony_ci kfree(ctx); 74862306a36Sopenharmony_ci} 74962306a36Sopenharmony_ci 75062306a36Sopenharmony_cistatic const struct fs_context_operations binderfs_fs_context_ops = { 75162306a36Sopenharmony_ci .free = binderfs_fs_context_free, 75262306a36Sopenharmony_ci .get_tree = binderfs_fs_context_get_tree, 75362306a36Sopenharmony_ci .parse_param = binderfs_fs_context_parse_param, 75462306a36Sopenharmony_ci .reconfigure = binderfs_fs_context_reconfigure, 75562306a36Sopenharmony_ci}; 75662306a36Sopenharmony_ci 75762306a36Sopenharmony_cistatic int binderfs_init_fs_context(struct fs_context *fc) 75862306a36Sopenharmony_ci{ 75962306a36Sopenharmony_ci struct binderfs_mount_opts *ctx; 76062306a36Sopenharmony_ci 76162306a36Sopenharmony_ci ctx = kzalloc(sizeof(struct binderfs_mount_opts), GFP_KERNEL); 76262306a36Sopenharmony_ci if (!ctx) 76362306a36Sopenharmony_ci return -ENOMEM; 76462306a36Sopenharmony_ci 76562306a36Sopenharmony_ci ctx->max = BINDERFS_MAX_MINOR; 76662306a36Sopenharmony_ci ctx->stats_mode = binderfs_stats_mode_unset; 76762306a36Sopenharmony_ci 76862306a36Sopenharmony_ci fc->fs_private = ctx; 76962306a36Sopenharmony_ci fc->ops = &binderfs_fs_context_ops; 77062306a36Sopenharmony_ci 77162306a36Sopenharmony_ci return 0; 77262306a36Sopenharmony_ci} 77362306a36Sopenharmony_ci 77462306a36Sopenharmony_cistatic void binderfs_kill_super(struct super_block *sb) 77562306a36Sopenharmony_ci{ 77662306a36Sopenharmony_ci struct binderfs_info *info = sb->s_fs_info; 77762306a36Sopenharmony_ci 77862306a36Sopenharmony_ci /* 77962306a36Sopenharmony_ci * During inode eviction struct binderfs_info is needed. 78062306a36Sopenharmony_ci * So first wipe the super_block then free struct binderfs_info. 78162306a36Sopenharmony_ci */ 78262306a36Sopenharmony_ci kill_litter_super(sb); 78362306a36Sopenharmony_ci 78462306a36Sopenharmony_ci if (info && info->ipc_ns) 78562306a36Sopenharmony_ci put_ipc_ns(info->ipc_ns); 78662306a36Sopenharmony_ci 78762306a36Sopenharmony_ci kfree(info); 78862306a36Sopenharmony_ci} 78962306a36Sopenharmony_ci 79062306a36Sopenharmony_cistatic struct file_system_type binder_fs_type = { 79162306a36Sopenharmony_ci .name = "binder", 79262306a36Sopenharmony_ci .init_fs_context = binderfs_init_fs_context, 79362306a36Sopenharmony_ci .parameters = binderfs_fs_parameters, 79462306a36Sopenharmony_ci .kill_sb = binderfs_kill_super, 79562306a36Sopenharmony_ci .fs_flags = FS_USERNS_MOUNT, 79662306a36Sopenharmony_ci}; 79762306a36Sopenharmony_ci 79862306a36Sopenharmony_ciint __init init_binderfs(void) 79962306a36Sopenharmony_ci{ 80062306a36Sopenharmony_ci int ret; 80162306a36Sopenharmony_ci const char *name; 80262306a36Sopenharmony_ci size_t len; 80362306a36Sopenharmony_ci 80462306a36Sopenharmony_ci /* Verify that the default binderfs device names are valid. */ 80562306a36Sopenharmony_ci name = binder_devices_param; 80662306a36Sopenharmony_ci for (len = strcspn(name, ","); len > 0; len = strcspn(name, ",")) { 80762306a36Sopenharmony_ci if (len > BINDERFS_MAX_NAME) 80862306a36Sopenharmony_ci return -E2BIG; 80962306a36Sopenharmony_ci name += len; 81062306a36Sopenharmony_ci if (*name == ',') 81162306a36Sopenharmony_ci name++; 81262306a36Sopenharmony_ci } 81362306a36Sopenharmony_ci 81462306a36Sopenharmony_ci /* Allocate new major number for binderfs. */ 81562306a36Sopenharmony_ci ret = alloc_chrdev_region(&binderfs_dev, 0, BINDERFS_MAX_MINOR, 81662306a36Sopenharmony_ci "binder"); 81762306a36Sopenharmony_ci if (ret) 81862306a36Sopenharmony_ci return ret; 81962306a36Sopenharmony_ci 82062306a36Sopenharmony_ci ret = register_filesystem(&binder_fs_type); 82162306a36Sopenharmony_ci if (ret) { 82262306a36Sopenharmony_ci unregister_chrdev_region(binderfs_dev, BINDERFS_MAX_MINOR); 82362306a36Sopenharmony_ci return ret; 82462306a36Sopenharmony_ci } 82562306a36Sopenharmony_ci 82662306a36Sopenharmony_ci return ret; 82762306a36Sopenharmony_ci} 828