From fa1215f91a629c099402da383b00f90a4ae1fca2 Mon Sep 17 00:00:00 2001 From: Juhyung Park Date: Sat, 18 Sep 2021 20:38:35 +0900 Subject: [PATCH] binder: Extend kmem_cache to binder_task_work_cb and binder_txn_fd_fixup Change-Id: Ifcbf563b624871f28e9da1d7a367d48e90cab81c Signed-off-by: Juhyung Park Signed-off-by: Helium-Studio <67852324+Helium-Studio@users.noreply.github.com> Signed-off-by: onettboots --- drivers/android/binder.c | 110 +++++++++++++++++++++++++++++++++++++-- 1 file changed, 106 insertions(+), 4 deletions(-) diff --git a/drivers/android/binder.c b/drivers/android/binder.c index 6817e85d88d2..5dccd7345142 100644 --- a/drivers/android/binder.c +++ b/drivers/android/binder.c @@ -225,6 +225,8 @@ static struct kmem_cache *binder_ref_pool; static struct kmem_cache *binder_thread_pool; static struct kmem_cache *binder_transaction_pool; static struct kmem_cache *binder_work_pool; +static struct kmem_cache *binder_twcb_pool; +static struct kmem_cache *binder_fixup_pool; static struct binder_transaction_log_entry *binder_transaction_log_add( struct binder_transaction_log *log) @@ -1970,6 +1972,27 @@ static struct binder_thread *binder_get_txn_from_and_acq_inner( return NULL; } +/** + * binder_free_txn_fixups() - free unprocessed fd fixups + * @t: binder transaction for t->from + * + * If the transaction is being torn down prior to being + * processed by the target process, free all of the + * fd fixups and fput the file structs. It is safe to + * call this function after the fixups have been + * processed -- in that case, the list will be empty. + */ +static void binder_free_txn_fixups(struct binder_transaction *t) +{ + struct binder_txn_fd_fixup *fixup, *tmp; + + list_for_each_entry_safe(fixup, tmp, &t->fd_fixups, fixup_entry) { + fput(fixup->file); + list_del(&fixup->fixup_entry); + kmem_cache_free(binder_fixup_pool, fixup); + } +} + static void binder_free_transaction(struct binder_transaction *t) { struct binder_proc *target_proc; @@ -2316,7 +2339,7 @@ static void binder_do_fd_close(struct callback_head *twork) struct binder_task_work_cb, twork); fput(twcb->file); - kfree(twcb); + kmem_cache_free(binder_twcb_pool, twcb); } /** @@ -2330,7 +2353,7 @@ static void binder_deferred_fd_close(int fd) { struct binder_task_work_cb *twcb; - twcb = kmalloc(sizeof(*twcb), GFP_KERNEL); + twcb = kmem_cache_alloc(binder_twcb_pool, GFP_KERNEL); if (!twcb) return; init_task_work(&twcb->twork, binder_do_fd_close); @@ -2339,7 +2362,7 @@ static void binder_deferred_fd_close(int fd) filp_close(twcb->file, current->files); task_work_add(current, &twcb->twork, true); } else { - kfree(twcb); + kmem_cache_free(binder_twcb_pool, twcb); } } @@ -2681,7 +2704,7 @@ static int binder_translate_fd(int fd, * of the fd in the target needs to be done from a * target thread. */ - fixup = kmalloc(sizeof(*fixup), GFP_KERNEL); + fixup = kmem_cache_alloc(binder_fixup_pool, GFP_KERNEL); if (!fixup) { ret = -ENOMEM; goto err_get_unused_fd; @@ -4569,6 +4592,71 @@ static int binder_wait_for_work(struct binder_thread *thread, return ret; } +/** + * binder_apply_fd_fixups() - finish fd translation + * @proc: binder_proc associated @t->buffer + * @t: binder transaction with list of fd fixups + * + * Now that we are in the context of the transaction target + * process, we can allocate and install fds. Process the + * list of fds to translate and fixup the buffer with the + * new fds. + * + * If we fail to allocate an fd, then free the resources by + * fput'ing files that have not been processed and ksys_close'ing + * any fds that have already been allocated. + */ +static int binder_apply_fd_fixups(struct binder_proc *proc, + struct binder_transaction *t) +{ + struct binder_txn_fd_fixup *fixup, *tmp; + int ret = 0; + + list_for_each_entry(fixup, &t->fd_fixups, fixup_entry) { + int fd = get_unused_fd_flags(O_CLOEXEC); + + if (fd < 0) { + binder_debug(BINDER_DEBUG_TRANSACTION, + "failed fd fixup txn %d fd %d\n", + t->debug_id, fd); + ret = -ENOMEM; + break; + } + binder_debug(BINDER_DEBUG_TRANSACTION, + "fd fixup txn %d fd %d\n", + t->debug_id, fd); + trace_binder_transaction_fd_recv(t, fd, fixup->offset); + fd_install(fd, fixup->file); + fixup->file = NULL; + if (binder_alloc_copy_to_buffer(&proc->alloc, t->buffer, + fixup->offset, &fd, + sizeof(u32))) { + ret = -EINVAL; + break; + } + } + list_for_each_entry_safe(fixup, tmp, &t->fd_fixups, fixup_entry) { + if (fixup->file) { + fput(fixup->file); + } else if (ret) { + u32 fd; + int err; + + err = binder_alloc_copy_from_buffer(&proc->alloc, &fd, + t->buffer, + fixup->offset, + sizeof(fd)); + WARN_ON(err); + if (!err) + binder_deferred_fd_close(fd); + } + list_del(&fixup->fixup_entry); + kmem_cache_free(binder_fixup_pool, fixup); + } + + return ret; +} + static int binder_thread_read(struct binder_proc *proc, struct binder_thread *thread, binder_uintptr_t binder_buffer, size_t size, @@ -6776,8 +6864,20 @@ static int __init binder_create_pools(void) if (!binder_work_pool) goto err_work_pool; + binder_twcb_pool = KMEM_CACHE(binder_task_work_cb, SLAB_HWCACHE_ALIGN); + if (!binder_twcb_pool) + goto err_twcb_pool; + + binder_fixup_pool = KMEM_CACHE(binder_txn_fd_fixup, SLAB_HWCACHE_ALIGN); + if (!binder_fixup_pool) + goto err_fixup_pool; + return 0; +err_fixup_pool: + kmem_cache_destroy(binder_twcb_pool); +err_twcb_pool: + kmem_cache_destroy(binder_work_pool); err_work_pool: kmem_cache_destroy(binder_transaction_pool); err_transaction_pool: @@ -6805,6 +6905,8 @@ static void __init binder_destroy_pools(void) kmem_cache_destroy(binder_thread_pool); kmem_cache_destroy(binder_transaction_pool); kmem_cache_destroy(binder_work_pool); + kmem_cache_destroy(binder_twcb_pool); + kmem_cache_destroy(binder_fixup_pool); } static int __init binder_init(void)