ANDROID: binder: change how Rust Binder is loaded
The binder.impl parameter currently controls whether C Binder is loaded or not, even if no Rust Binder driver is present. This patch changes it so that C Binder always gets loaded even if binder.impl=rust is set. To actually load a different Binder driver, it must explicitly ask C Binder to unload itself. This ensures that: 1. If binder.impl=rust is set on a device without Rust Binder available, it will boot normally with C Binder instead of failing to boot. 2. By not listing unload_binder in the symbol list, we ensure that Binder can only be loaded as a GKI module, not as a vendor module. Bug: 388786466 Change-Id: I791154e8f10abd5c470bb697b5e1035c33af897f Signed-off-by: Alice Ryhl <aliceryhl@google.com>
This commit is contained in:
+86
-31
@@ -7196,34 +7196,6 @@ const struct binder_debugfs_entry binder_debugfs_entries[] = {
|
||||
{} /* terminator */
|
||||
};
|
||||
|
||||
bool binder_use_rust;
|
||||
EXPORT_SYMBOL_GPL(binder_use_rust);
|
||||
|
||||
static int binder_impl_param_set(const char *buffer, const struct kernel_param *kp)
|
||||
{
|
||||
if (!strcmp(buffer, "rust"))
|
||||
binder_use_rust = true;
|
||||
else if (!strcmp(buffer, "c"))
|
||||
binder_use_rust = false;
|
||||
else
|
||||
return -EINVAL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int binder_impl_param_get(char *buffer, const struct kernel_param *kp)
|
||||
{
|
||||
/* The buffer is 4k bytes, so this will not overflow. */
|
||||
return sprintf(buffer, "%s\n", binder_use_rust ? "rust" : "c");
|
||||
}
|
||||
|
||||
static const struct kernel_param_ops binder_impl_param_ops = {
|
||||
.set = binder_impl_param_set,
|
||||
.get = binder_impl_param_get,
|
||||
};
|
||||
|
||||
module_param_cb(impl, &binder_impl_param_ops, NULL, 0444);
|
||||
|
||||
static int __init init_binder_device(const char *name)
|
||||
{
|
||||
int ret;
|
||||
@@ -7262,9 +7234,6 @@ static int __init binder_init(void)
|
||||
char *device_names = NULL;
|
||||
const struct binder_debugfs_entry *db_entry;
|
||||
|
||||
if (binder_use_rust)
|
||||
return 0;
|
||||
|
||||
ret = binder_alloc_shrinker_init();
|
||||
if (ret)
|
||||
return ret;
|
||||
@@ -7328,6 +7297,92 @@ err_alloc_device_names_failed:
|
||||
|
||||
device_initcall(binder_init);
|
||||
|
||||
#define BINDER_USE_C 0
|
||||
#define BINDER_USE_RUST 1
|
||||
#define BINDER_USE_RUST_LOADED 2
|
||||
int binder_use_rust;
|
||||
EXPORT_SYMBOL_GPL(binder_use_rust);
|
||||
|
||||
static DEFINE_MUTEX(binder_use_rust_lock);
|
||||
|
||||
/*
|
||||
* Called by Rust Binder to unload the C Binder driver.
|
||||
*/
|
||||
int unload_binder(void)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
if (!IS_ENABLED(CONFIG_ANDROID_BINDERFS))
|
||||
return -EINVAL;
|
||||
|
||||
mutex_lock(&binder_use_rust_lock);
|
||||
if (binder_use_rust == BINDER_USE_RUST)
|
||||
binder_use_rust = BINDER_USE_RUST_LOADED;
|
||||
else
|
||||
ret = -EINVAL;
|
||||
mutex_unlock(&binder_use_rust_lock);
|
||||
|
||||
if (!ret) {
|
||||
unload_binderfs();
|
||||
debugfs_remove_recursive(binder_debugfs_dir_entry_root);
|
||||
binder_alloc_shrinker_exit();
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(unload_binder);
|
||||
|
||||
int on_binderfs_mount(void)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
mutex_lock(&binder_use_rust_lock);
|
||||
if (binder_use_rust == BINDER_USE_RUST) {
|
||||
/*
|
||||
* C binder was mounted before loading the Rust Binder module.
|
||||
* In this case, we fall back to using C Binder even though
|
||||
* Rust Binder was requested.
|
||||
*/
|
||||
pr_warn("Using C Binder even though binder.impl=rust is set.\n");
|
||||
binder_use_rust = BINDER_USE_C;
|
||||
}
|
||||
|
||||
if (binder_use_rust == BINDER_USE_RUST_LOADED) {
|
||||
/*
|
||||
* Rust Binder is requested *and* has already started unloading
|
||||
* C Binder. Fail the attempt to mount C Binder.
|
||||
*/
|
||||
ret = -EINVAL;
|
||||
}
|
||||
mutex_unlock(&binder_use_rust_lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int binder_impl_param_set(const char *buffer, const struct kernel_param *kp)
|
||||
{
|
||||
if (!strcmp(buffer, "rust"))
|
||||
binder_use_rust = true;
|
||||
else if (!strcmp(buffer, "c"))
|
||||
binder_use_rust = false;
|
||||
else
|
||||
return -EINVAL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int binder_impl_param_get(char *buffer, const struct kernel_param *kp)
|
||||
{
|
||||
/* The buffer is 4k bytes, so this will not overflow. */
|
||||
return sprintf(buffer, "%s\n", binder_use_rust ? "rust" : "c");
|
||||
}
|
||||
|
||||
static const struct kernel_param_ops binder_impl_param_ops = {
|
||||
.set = binder_impl_param_set,
|
||||
.get = binder_impl_param_get,
|
||||
};
|
||||
|
||||
module_param_cb(impl, &binder_impl_param_ops, NULL, 0444);
|
||||
|
||||
#define CREATE_TRACE_POINTS
|
||||
#include "binder_trace.h"
|
||||
EXPORT_TRACEPOINT_SYMBOL_GPL(binder_transaction_received);
|
||||
|
||||
@@ -17,6 +17,14 @@
|
||||
#include "binder_alloc.h"
|
||||
#include "dbitmap.h"
|
||||
|
||||
extern int binder_use_rust;
|
||||
#ifdef CONFIG_ANDROID_BINDERFS
|
||||
void unload_binderfs(void);
|
||||
int on_binderfs_mount(void);
|
||||
#else
|
||||
static inline void unload_binderfs(void) {}
|
||||
#endif
|
||||
|
||||
struct binder_context {
|
||||
struct binder_node *binder_context_mgr_node;
|
||||
struct mutex context_mgr_node_lock;
|
||||
|
||||
@@ -765,6 +765,9 @@ static int binderfs_init_fs_context(struct fs_context *fc)
|
||||
{
|
||||
struct binderfs_mount_opts *ctx;
|
||||
|
||||
if (on_binderfs_mount())
|
||||
return -EINVAL;
|
||||
|
||||
ctx = kzalloc(sizeof(struct binderfs_mount_opts), GFP_KERNEL);
|
||||
if (!ctx)
|
||||
return -ENOMEM;
|
||||
@@ -832,3 +835,9 @@ int __init init_binderfs(void)
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void unload_binderfs(void)
|
||||
{
|
||||
unregister_filesystem(&binder_fs_type);
|
||||
unregister_chrdev_region(binderfs_dev, BINDERFS_MAX_MINOR);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user