History

binderfs: implement "max" mount option

Since binderfs can be mounted by userns root in non-initial user namespaces some precautions are in order. First, a way to set a maximum on the number of binder devices that can be allocated per binderfs instance and second, a way to reserve a reasonable chunk of binderfs devices for the initial ipc namespace. A first approach as seen in [1] used sysctls similiar to devpts but was shown to be flawed (cf. [2] and [3]) since some aspects were unneeded. This is an alternative approach which avoids sysctls completely and instead switches to a single mount option. Starting with this commit binderfs instances can be mounted with a limit on the number of binder devices that can be allocated. The max=<count> mount option serves as a per-instance limit. If max=<count> is set then only <count> number of binder devices can be allocated in this binderfs instance. This allows to safely bind-mount binderfs instances into unprivileged user namespaces since userns root in a non-initial user namespace cannot change the mount option as long as it does not own the mount namespace the binderfs mount was created in and hence cannot drain the host of minor device numbers [1]: https://lore.kernel.org/lkml/20181221133909.18794-1-christian@brauner.io/ [2]; https://lore.kernel.org/lkml/20181221163316.GA8517@kroah.com/ [3]: https://lore.kernel.org/lkml/CAHRSSEx+gDVW4fKKK8oZNAir9G5icJLyodO8hykv3O0O1jt2FQ@mail.gmail.com/ [4]: https://lore.kernel.org/lkml/20181221192044.5yvfnuri7gdop4rs@brauner.io/

Christian Brauner committed 7 years ago

Commit 849d5401 parent b6c770d1 file · +98 −6Browse files

Unified · Split

drivers/android/binderfs.c+98−6
@@ -20,6 +20,7 @@ · 19 unmodified lines
2020 #include <linux/parser.h>
2121 #include <linux/radix-tree.h>
2222 #include <linux/sched.h>
23+#include <linux/seq_file.h>
2324 #include <linux/slab.h>
2425 #include <linux/spinlock_types.h>
2526 #include <linux/stddef.h>
@@ -44,6 +45,24 @@ static dev_t binderfs_dev; · 18 unmodified lines
4445 static DEFINE_MUTEX(binderfs_minors_mutex);
4546 static DEFINE_IDA(binderfs_minors);
4647
48+/**
49+ * binderfs_mount_opts - mount options for binderfs
50+ * @max: maximum number of allocatable binderfs binder devices
51+ */
52+struct binderfs_mount_opts {
53+ int max;
54+};
55+
56+enum {
57+ Opt_max,
58+ Opt_err
59+};
60+
61+static const match_table_t tokens = {
62+ { Opt_max, "max=%d" },
63+ { Opt_err, NULL }
64+};
65+
4766 /**
4867 * binderfs_info - information about a binderfs mount
4968 * @ipc_ns: The ipc namespace the binderfs mount belongs to.
@@ -53,13 +72,16 @@ static DEFINE_IDA(binderfs_minors); · 3 unmodified lines
5372 * created.
5473 * @root_gid: gid that needs to be used when a new binder device is
5574 * created.
75+ * @mount_opts: The mount options in use.
76+ * @device_count: The current number of allocated binder devices.
5677 */
5778 struct binderfs_info {
5879 struct ipc_namespace *ipc_ns;
5980 struct dentry *control_dentry;
6081 kuid_t root_uid;
6182 kgid_t root_gid;
62−
83+ struct binderfs_mount_opts mount_opts;
84+ int device_count;
6385 };
6486
6587 static inline struct binderfs_info *BINDERFS_I(const struct inode *inode)
@@ -108,10 +130,17 @@ static int binderfs_binder_device_create(struct inode *ref_inode, · 42 unmodified lines
108130
109131 /* Reserve new minor number for the new device. */
110132 mutex_lock(&binderfs_minors_mutex);
111− minor = ida_alloc_max(&binderfs_minors, BINDERFS_MAX_MINOR, GFP_KERNEL);
112− mutex_unlock(&binderfs_minors_mutex);
113− if (minor < 0)
133+ if (++info->device_count <= info->mount_opts.max)
134+ minor = ida_alloc_max(&binderfs_minors, BINDERFS_MAX_MINOR,
135+ GFP_KERNEL);
136+ else
137+ minor = -ENOSPC;
138+ if (minor < 0) {
139+ --info->device_count;
140+ mutex_unlock(&binderfs_minors_mutex);
114141 return minor;
142+ }
143+ mutex_unlock(&binderfs_minors_mutex);
115144
116145 ret = -ENOMEM;
117146 device = kzalloc(sizeof(*device), GFP_KERNEL);
@@ -185,6 +214,7 @@ err: · 67 unmodified lines
185214 kfree(name);
186215 kfree(device);
187216 mutex_lock(&binderfs_minors_mutex);
217+ --info->device_count;
188218 ida_free(&binderfs_minors, minor);
189219 mutex_unlock(&binderfs_minors_mutex);
190220 iput(inode);
@@ -230,6 +260,7 @@ static long binder_ctl_ioctl(struct file *file, unsigned int cmd, · 39 unmodified lines
230260 static void binderfs_evict_inode(struct inode *inode)
231261 {
232262 struct binder_device *device = inode->i_private;
263+ struct binderfs_info *info = BINDERFS_I(inode);
233264
234265 clear_inode(inode);
235266
@@ -237,6 +268,7 @@ static void binderfs_evict_inode(struct inode *inode) · 1 unmodified line
237268 return;
238269
239270 mutex_lock(&binderfs_minors_mutex);
271+ --info->device_count;
240272 ida_free(&binderfs_minors, device->miscdev.minor);
241273 mutex_unlock(&binderfs_minors_mutex);
242274
@@ -244,9 +276,65 @@ static void binderfs_evict_inode(struct inode *inode) · 1 unmodified line
244276 kfree(device);
245277 }
246278
279+/**
280+ * binderfs_parse_mount_opts - parse binderfs mount options
281+ * @data: options to set (can be NULL in which case defaults are used)
282+ */
283+static int binderfs_parse_mount_opts(char *data,
284+ struct binderfs_mount_opts *opts)
285+{
286+ char *p;
287+ opts->max = BINDERFS_MAX_MINOR;
288+
289+ while ((p = strsep(&data, ",")) != NULL) {
290+ substring_t args[MAX_OPT_ARGS];
291+ int token;
292+ int max_devices;
293+
294+ if (!*p)
295+ continue;
296+
297+ token = match_token(p, tokens, args);
298+ switch (token) {
299+ case Opt_max:
300+ if (match_int(&args[0], &max_devices) ||
301+ (max_devices < 0 ||
302+ (max_devices > BINDERFS_MAX_MINOR)))
303+ return -EINVAL;
304+
305+ opts->max = max_devices;
306+ break;
307+ default:
308+ pr_err("Invalid mount options\n");
309+ return -EINVAL;
310+ }
311+ }
312+
313+ return 0;
314+}
315+
316+static int binderfs_remount(struct super_block *sb, int *flags, char *data)
317+{
318+ struct binderfs_info *info = sb->s_fs_info;
319+ return binderfs_parse_mount_opts(data, &info->mount_opts);
320+}
321+
322+static int binderfs_show_mount_opts(struct seq_file *seq, struct dentry *root)
323+{
324+ struct binderfs_info *info;
325+
326+ info = root->d_sb->s_fs_info;
327+ if (info->mount_opts.max <= BINDERFS_MAX_MINOR)
328+ seq_printf(seq, ",max=%d", info->mount_opts.max);
329+
330+ return 0;
331+}
332+
247333 static const struct super_operations binderfs_super_ops = {
248− .statfs = simple_statfs,
249− .evict_inode = binderfs_evict_inode,
334+ .evict_inode = binderfs_evict_inode,
335+ .remount_fs = binderfs_remount,
336+ .show_options = binderfs_show_mount_opts,
337+ .statfs = simple_statfs,
250338 };
251339
252340 static int binderfs_rename(struct inode *old_dir, struct dentry *old_dentry,
@@ -407,6 +495,10 @@ static int binderfs_fill_super(struct super_block *sb, void *data, int silent) · 154 unmodified lines
407495 if (!info)
408496 goto err_without_dentry;
409497
498+ ret = binderfs_parse_mount_opts(data, &info->mount_opts);
499+ if (ret)
500+ goto err_without_dentry;
501+
410502 info->ipc_ns = ipc_ns;
411503 info->root_gid = make_kgid(sb->s_user_ns, 0);
412504 if (!gid_valid(info->root_gid))