Skip to content

Commit 3ad20fe

Browse files
braunergregkh
authored andcommitted
binder: implement binderfs
As discussed at Linux Plumbers Conference 2018 in Vancouver [1] this is the implementation of binderfs. /* Abstract */ binderfs is a backwards-compatible filesystem for Android's binder ipc mechanism. Each ipc namespace will mount a new binderfs instance. Mounting binderfs multiple times at different locations in the same ipc namespace will not cause a new super block to be allocated and hence it will be the same filesystem instance. Each new binderfs mount will have its own set of binder devices only visible in the ipc namespace it has been mounted in. All devices in a new binderfs mount will follow the scheme binder%d and numbering will always start at 0. /* Backwards compatibility */ Devices requested in the Kconfig via CONFIG_ANDROID_BINDER_DEVICES for the initial ipc namespace will work as before. They will be registered via misc_register() and appear in the devtmpfs mount. Specifically, the standard devices binder, hwbinder, and vndbinder will all appear in their standard locations in /dev. Mounting or unmounting the binderfs mount in the initial ipc namespace will have no effect on these devices, i.e. they will neither show up in the binderfs mount nor will they disappear when the binderfs mount is gone. /* binder-control */ Each new binderfs instance comes with a binder-control device. No other devices will be present at first. The binder-control device can be used to dynamically allocate binder devices. All requests operate on the binderfs mount the binder-control device resides in. Assuming a new instance of binderfs has been mounted at /dev/binderfs via mount -t binderfs binderfs /dev/binderfs. Then a request to create a new binder device can be made as illustrated in [2]. Binderfs devices can simply be removed via unlink(). /* Implementation details */ - dynamic major number allocation: When binderfs is registered as a new filesystem it will dynamically allocate a new major number. The allocated major number will be returned in struct binderfs_device when a new binder device is allocated. - global minor number tracking: Minor are tracked in a global idr struct that is capped at BINDERFS_MAX_MINOR. The minor number tracker is protected by a global mutex. This is the only point of contention between binderfs mounts. - struct binderfs_info: Each binderfs super block has its own struct binderfs_info that tracks specific details about a binderfs instance: - ipc namespace - dentry of the binder-control device - root uid and root gid of the user namespace the binderfs instance was mounted in - mountable by user namespace root: binderfs can be mounted by user namespace root in a non-initial user namespace. The devices will be owned by user namespace root. - binderfs binder devices without misc infrastructure: New binder devices associated with a binderfs mount do not use the full misc_register() infrastructure. The misc_register() infrastructure can only create new devices in the host's devtmpfs mount. binderfs does however only make devices appear under its own mountpoint and thus allocates new character device nodes from the inode of the root dentry of the super block. This will have the side-effect that binderfs specific device nodes do not appear in sysfs. This behavior is similar to devpts allocated pts devices and has no effect on the functionality of the ipc mechanism itself. [1]: https://goo.gl/JL2tfX [2]: program to allocate a new binderfs binder device: #define _GNU_SOURCE #include <errno.h> #include <fcntl.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/ioctl.h> #include <sys/stat.h> #include <sys/types.h> #include <unistd.h> #include <linux/android/binder_ctl.h> int main(int argc, char *argv[]) { int fd, ret, saved_errno; size_t len; struct binderfs_device device = { 0 }; if (argc < 2) exit(EXIT_FAILURE); len = strlen(argv[1]); if (len > BINDERFS_MAX_NAME) exit(EXIT_FAILURE); memcpy(device.name, argv[1], len); fd = open("/dev/binderfs/binder-control", O_RDONLY | O_CLOEXEC); if (fd < 0) { printf("%s - Failed to open binder-control device\n", strerror(errno)); exit(EXIT_FAILURE); } ret = ioctl(fd, BINDER_CTL_ADD, &device); saved_errno = errno; close(fd); errno = saved_errno; if (ret < 0) { printf("%s - Failed to allocate new binder device\n", strerror(errno)); exit(EXIT_FAILURE); } printf("Allocated new binder device with major %d, minor %d, and " "name %s\n", device.major, device.minor, device.name); exit(EXIT_SUCCESS); } Cc: Martijn Coenen <[email protected]> Cc: Greg Kroah-Hartman <[email protected]> Signed-off-by: Christian Brauner <[email protected]> Acked-by: Todd Kjos <[email protected]> Signed-off-by: Greg Kroah-Hartman <[email protected]>
1 parent 80cd795 commit 3ad20fe

File tree

7 files changed

+650
-17
lines changed

7 files changed

+650
-17
lines changed

drivers/android/Kconfig

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,18 @@ config ANDROID_BINDER_IPC
2020
Android process, using Binder to identify, invoke and pass arguments
2121
between said processes.
2222

23+
config ANDROID_BINDERFS
24+
bool "Android Binderfs filesystem"
25+
depends on ANDROID_BINDER_IPC
26+
default n
27+
---help---
28+
Binderfs is a pseudo-filesystem for the Android Binder IPC driver
29+
which can be mounted per-ipc namespace allowing to run multiple
30+
instances of Android.
31+
Each binderfs mount initially only contains a binder-control device.
32+
It can be used to dynamically allocate new binder IPC devices via
33+
ioctls.
34+
2335
config ANDROID_BINDER_DEVICES
2436
string "Android Binder devices"
2537
depends on ANDROID_BINDER_IPC

drivers/android/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
ccflags-y += -I$(src) # needed for trace events
22

3+
obj-$(CONFIG_ANDROID_BINDERFS) += binderfs.o
34
obj-$(CONFIG_ANDROID_BINDER_IPC) += binder.o binder_alloc.o
45
obj-$(CONFIG_ANDROID_BINDER_IPC_SELFTEST) += binder_alloc_selftest.o

drivers/android/binder.c

Lines changed: 8 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,7 @@
7979
#include <asm/cacheflush.h>
8080

8181
#include "binder_alloc.h"
82+
#include "binder_internal.h"
8283
#include "binder_trace.h"
8384

8485
static HLIST_HEAD(binder_deferred_list);
@@ -249,20 +250,6 @@ static struct binder_transaction_log_entry *binder_transaction_log_add(
249250
return e;
250251
}
251252

252-
struct binder_context {
253-
struct binder_node *binder_context_mgr_node;
254-
struct mutex context_mgr_node_lock;
255-
256-
kuid_t binder_context_mgr_uid;
257-
const char *name;
258-
};
259-
260-
struct binder_device {
261-
struct hlist_node hlist;
262-
struct miscdevice miscdev;
263-
struct binder_context context;
264-
};
265-
266253
/**
267254
* struct binder_work - work enqueued on a worklist
268255
* @entry: node enqueued on list
@@ -5024,8 +5011,12 @@ static int binder_open(struct inode *nodp, struct file *filp)
50245011
proc->tsk = current->group_leader;
50255012
INIT_LIST_HEAD(&proc->todo);
50265013
proc->default_priority = task_nice(current);
5027-
binder_dev = container_of(filp->private_data, struct binder_device,
5028-
miscdev);
5014+
/* binderfs stashes devices in i_private */
5015+
if (is_binderfs_device(nodp))
5016+
binder_dev = nodp->i_private;
5017+
else
5018+
binder_dev = container_of(filp->private_data,
5019+
struct binder_device, miscdev);
50295020
proc->context = &binder_dev->context;
50305021
binder_alloc_init(&proc->alloc);
50315022

@@ -5816,7 +5807,7 @@ static int transaction_log_show(struct seq_file *m, void *unused)
58165807
return 0;
58175808
}
58185809

5819-
static const struct file_operations binder_fops = {
5810+
const struct file_operations binder_fops = {
58205811
.owner = THIS_MODULE,
58215812
.poll = binder_poll,
58225813
.unlocked_ioctl = binder_ioctl,

drivers/android/binder_internal.h

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
/* SPDX-License-Identifier: GPL-2.0 */
2+
3+
#ifndef _LINUX_BINDER_INTERNAL_H
4+
#define _LINUX_BINDER_INTERNAL_H
5+
6+
#include <linux/export.h>
7+
#include <linux/fs.h>
8+
#include <linux/list.h>
9+
#include <linux/miscdevice.h>
10+
#include <linux/mutex.h>
11+
#include <linux/stddef.h>
12+
#include <linux/types.h>
13+
#include <linux/uidgid.h>
14+
15+
struct binder_context {
16+
struct binder_node *binder_context_mgr_node;
17+
struct mutex context_mgr_node_lock;
18+
kuid_t binder_context_mgr_uid;
19+
const char *name;
20+
};
21+
22+
/**
23+
* struct binder_device - information about a binder device node
24+
* @hlist: list of binder devices (only used for devices requested via
25+
* CONFIG_ANDROID_BINDER_DEVICES)
26+
* @miscdev: information about a binder character device node
27+
* @context: binder context information
28+
* @binderfs_inode: This is the inode of the root dentry of the super block
29+
* belonging to a binderfs mount.
30+
*/
31+
struct binder_device {
32+
struct hlist_node hlist;
33+
struct miscdevice miscdev;
34+
struct binder_context context;
35+
struct inode *binderfs_inode;
36+
};
37+
38+
extern const struct file_operations binder_fops;
39+
40+
#ifdef CONFIG_ANDROID_BINDERFS
41+
extern bool is_binderfs_device(const struct inode *inode);
42+
#else
43+
static inline bool is_binderfs_device(const struct inode *inode)
44+
{
45+
return false;
46+
}
47+
#endif
48+
49+
#endif /* _LINUX_BINDER_INTERNAL_H */

0 commit comments

Comments
 (0)