Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 3217cccb authored by Martijn Coenen's avatar Martijn Coenen
Browse files

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).

Bug: 63117588
Test: binderLibTest

Change-Id: Ia98db8cd82ce354a4cdc8811c969988d585c7e31
Signed-off-by: default avatarMartijn Coenen <maco@android.com>
parent 81402ead
Loading
Loading
Loading
Loading
+31 −9
Original line number Diff line number Diff line
@@ -2105,6 +2105,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.
 * @buffer:	binder_buffer that we're parsing.
@@ -4187,12 +4207,20 @@ static int binder_thread_read(struct binder_proc *proc,
		if (put_user(cmd, (uint32_t __user *)ptr)) {
			if (t_from)
				binder_thread_dec_tmpref(t_from);

			binder_cleanup_transaction(t, "put_user failed",
						   BR_FAILED_REPLY);

			return -EFAULT;
		}
		ptr += sizeof(uint32_t);
		if (copy_to_user(ptr, &tr, sizeof(tr))) {
			if (t_from)
				binder_thread_dec_tmpref(t_from);

			binder_cleanup_transaction(t, "copy_to_user failed",
						   BR_FAILED_REPLY);

			return -EFAULT;
		}
		ptr += sizeof(tr);
@@ -4262,15 +4290,9 @@ static void binder_release_work(struct binder_proc *proc,
			struct binder_transaction *t;

			t = container_of(w, struct binder_transaction, work);
			if (t->buffer->target_node &&
			    !(t->flags & TF_ONE_WAY)) {
				binder_send_failed_reply(t, BR_DEAD_REPLY);
			} else {
				binder_debug(BINDER_DEBUG_DEAD_TRANSACTION,
					"undelivered transaction %d\n",
					t->debug_id);
				binder_free_transaction(t);
			}

			binder_cleanup_transaction(t, "process died.",
						   BR_DEAD_REPLY);
		} break;
		case BINDER_WORK_RETURN_ERROR: {
			struct binder_error *e = container_of(