Commit fb2c4452 authored by Martijn Coenen's avatar Martijn Coenen Committed by Greg Kroah-Hartman

ANDROID: binder: fix transaction leak.

If a call to put_user() fails, we failed to
properly free a transaction and send a failed
reply (if necessary).
Signed-off-by: default avatarMartijn Coenen <maco@android.com>
Cc: stable <stable@vger.kernel.org> # 4.14
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent 4fbd8d19
...@@ -1947,6 +1947,26 @@ static void binder_send_failed_reply(struct binder_transaction *t, ...@@ -1947,6 +1947,26 @@ static void binder_send_failed_reply(struct binder_transaction *t,
} }
} }
/**
* binder_cleanup_transaction() - cleans up undelivered transaction
* @t: transaction that needs to be cleaned up
* @reason: reason the transaction wasn't delivered
* @error_code: error to return to caller (if synchronous call)
*/
static void binder_cleanup_transaction(struct binder_transaction *t,
const char *reason,
uint32_t error_code)
{
if (t->buffer->target_node && !(t->flags & TF_ONE_WAY)) {
binder_send_failed_reply(t, error_code);
} else {
binder_debug(BINDER_DEBUG_DEAD_TRANSACTION,
"undelivered transaction %d, %s\n",
t->debug_id, reason);
binder_free_transaction(t);
}
}
/** /**
* binder_validate_object() - checks for a valid metadata object in a buffer. * binder_validate_object() - checks for a valid metadata object in a buffer.
* @buffer: binder_buffer that we're parsing. * @buffer: binder_buffer that we're parsing.
...@@ -4015,12 +4035,20 @@ static int binder_thread_read(struct binder_proc *proc, ...@@ -4015,12 +4035,20 @@ static int binder_thread_read(struct binder_proc *proc,
if (put_user(cmd, (uint32_t __user *)ptr)) { if (put_user(cmd, (uint32_t __user *)ptr)) {
if (t_from) if (t_from)
binder_thread_dec_tmpref(t_from); binder_thread_dec_tmpref(t_from);
binder_cleanup_transaction(t, "put_user failed",
BR_FAILED_REPLY);
return -EFAULT; return -EFAULT;
} }
ptr += sizeof(uint32_t); ptr += sizeof(uint32_t);
if (copy_to_user(ptr, &tr, sizeof(tr))) { if (copy_to_user(ptr, &tr, sizeof(tr))) {
if (t_from) if (t_from)
binder_thread_dec_tmpref(t_from); binder_thread_dec_tmpref(t_from);
binder_cleanup_transaction(t, "copy_to_user failed",
BR_FAILED_REPLY);
return -EFAULT; return -EFAULT;
} }
ptr += sizeof(tr); ptr += sizeof(tr);
...@@ -4090,15 +4118,9 @@ static void binder_release_work(struct binder_proc *proc, ...@@ -4090,15 +4118,9 @@ static void binder_release_work(struct binder_proc *proc,
struct binder_transaction *t; struct binder_transaction *t;
t = container_of(w, struct binder_transaction, work); t = container_of(w, struct binder_transaction, work);
if (t->buffer->target_node &&
!(t->flags & TF_ONE_WAY)) { binder_cleanup_transaction(t, "process died.",
binder_send_failed_reply(t, BR_DEAD_REPLY); BR_DEAD_REPLY);
} else {
binder_debug(BINDER_DEBUG_DEAD_TRANSACTION,
"undelivered transaction %d\n",
t->debug_id);
binder_free_transaction(t);
}
} break; } break;
case BINDER_WORK_RETURN_ERROR: { case BINDER_WORK_RETURN_ERROR: {
struct binder_error *e = container_of( struct binder_error *e = container_of(
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment