This implements three sysctls that have very specific goals: 1. /proc/sys/fs/binder/max: Allow global root to globally limit the number of allocatable binder devices. 2. /proc/sys/fs/binder/nr: Allow global root to easily detect how many binder devices are currently in use across all binderfs mounts. 3. /proc/sys/fs/binder/reserved: Ensure that global root can reserve binder devices for the initial binderfs mount in the initial ipc namespace to prevent DOS attacks. This is equivalent to sysctls of devpts. Signed-off-by: Christian Brauner <christian.brauner@xxxxxxxxxx> --- drivers/android/binderfs.c | 81 +++++++++++++++++++++++++++++++++++++- 1 file changed, 79 insertions(+), 2 deletions(-) diff --git a/drivers/android/binderfs.c b/drivers/android/binderfs.c index 7496b10532aa..5ff015f82314 100644 --- a/drivers/android/binderfs.c +++ b/drivers/android/binderfs.c @@ -64,6 +64,71 @@ struct binderfs_info { }; +/* Global default limit on the number of binder devices. */ +static int device_limit = 4096; + +/* + * Number of binder devices reserved for the initial binderfs mount in the + * initial ipc namespace. + */ +static int device_reserve = 1024; + +/* Dummy sysctl minimum. */ +static int device_limit_min; + +/* Cap sysctl at BINDERFS_MAX_MINOR. */ +static int device_limit_max = BINDERFS_MAX_MINOR; + +/* Current number of allocated binder devices. */ +static atomic_t device_count = ATOMIC_INIT(0); + +static struct ctl_table binderfs_table[] = { + { + .procname = "max", + .maxlen = sizeof(int), + .mode = 0644, + .data = &device_limit, + .proc_handler = proc_dointvec_minmax, + .extra1 = &device_limit_min, + .extra2 = &device_limit_max, + }, + { + .procname = "reserve", + .maxlen = sizeof(int), + .mode = 0644, + .data = &device_reserve, + .proc_handler = proc_dointvec_minmax, + .extra1 = &device_limit_min, + .extra2 = &device_limit_max, + }, + { + .procname = "nr", + .maxlen = sizeof(int), + .mode = 0444, + .data = &device_count, + .proc_handler = proc_dointvec, + }, + {} +}; + +static struct ctl_table binderfs_fs_table[] = { + { + .procname = "binder", + .mode = 0555, + .child = binderfs_table, + }, + {} +}; + +static struct ctl_table binderfs_root_table[] = { + { + .procname = "fs", + .mode = 0555, + .child = binderfs_fs_table, + }, + {} +}; + static inline struct binderfs_info *BINDERFS_I(const struct inode *inode) { return inode->i_sb->s_fs_info; @@ -107,13 +172,21 @@ static int binderfs_binder_device_create(struct inode *ref_inode, struct inode *inode = NULL; struct super_block *sb = ref_inode->i_sb; struct binderfs_info *info = sb->s_fs_info; + bool use_reserved = (info->ipc_ns == &init_ipc_ns); /* Reserve new minor number for the new device. */ mutex_lock(&binderfs_minors_mutex); - minor = ida_alloc_max(&binderfs_minors, BINDERFS_MAX_MINOR, GFP_KERNEL); + if (atomic_inc_return(&device_count) < + (device_limit - (use_reserved ? 0 : device_reserve))) + minor = ida_alloc_max(&binderfs_minors, BINDERFS_MAX_MINOR, + GFP_KERNEL); + else + minor = -ENOSPC; mutex_unlock(&binderfs_minors_mutex); - if (minor < 0) + if (minor < 0) { + atomic_dec(&device_count); return minor; + } ret = -ENOMEM; device = kzalloc(sizeof(*device), GFP_KERNEL); @@ -187,6 +260,7 @@ static int binderfs_binder_device_create(struct inode *ref_inode, kfree(name); kfree(device); mutex_lock(&binderfs_minors_mutex); + atomic_dec(&device_count); ida_free(&binderfs_minors, minor); mutex_unlock(&binderfs_minors_mutex); iput(inode); @@ -239,6 +313,7 @@ static void binderfs_evict_inode(struct inode *inode) return; mutex_lock(&binderfs_minors_mutex); + atomic_dec(&device_count); ida_free(&binderfs_minors, device->miscdev.minor); mutex_unlock(&binderfs_minors_mutex); @@ -536,6 +611,8 @@ static int __init init_binderfs(void) binderfs_mnt = NULL; unregister_filesystem(&binder_fs_type); unregister_chrdev_region(binderfs_dev, BINDERFS_MAX_MINOR); + } else { + register_sysctl_table(binderfs_root_table); } return ret; -- 2.19.1 _______________________________________________ devel mailing list devel@xxxxxxxxxxxxxxxxxxxxxx http://driverdev.linuxdriverproject.org/mailman/listinfo/driverdev-devel