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:
Alice Ryhl
2025-03-04 16:13:13 +00:00
parent bbd9da17d5
commit dd55f14624
3 changed files with 103 additions and 31 deletions
+86 -31
View File
@@ -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);
+8
View File
@@ -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;
+9
View File
@@ -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);
}