From 0fb5acc4018c0da61f9084932d0cd816fab77eec Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Fri, 27 Mar 2015 12:41:13 +0100 Subject: [PATCH] greybus: operation: fix use-after-free when sending responses Fix use-after-free when sending responses due to reference imbalance. Make sure to take a reference to the operation when sending responses. This reference is dropped in greybus_data_sent when the message has been sent, while the initial reference is dropped in gb_operation_work after processing the corresponding request. Signed-off-by: Johan Hovold Reviewed-by: Alex Elder Signed-off-by: Greg Kroah-Hartman --- drivers/staging/greybus/operation.c | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/drivers/staging/greybus/operation.c b/drivers/staging/greybus/operation.c index c64b2bf47a43..ad45dee19a5a 100644 --- a/drivers/staging/greybus/operation.c +++ b/drivers/staging/greybus/operation.c @@ -719,6 +719,8 @@ EXPORT_SYMBOL_GPL(gb_operation_request_send_sync); */ int gb_operation_response_send(struct gb_operation *operation, int errno) { + int ret; + /* Record the result */ if (!gb_operation_result_set(operation, errno)) { pr_err("request result already set\n"); @@ -733,10 +735,17 @@ int gb_operation_response_send(struct gb_operation *operation, int errno) } } + /* Reference will be dropped when message has been sent. */ + gb_operation_get(operation); + /* Fill in the response header and send it */ operation->response->header->result = gb_operation_errno_map(errno); - return gb_message_send(operation->response); + ret = gb_message_send(operation->response); + if (ret) + gb_operation_put(operation); + + return ret; } EXPORT_SYMBOL_GPL(gb_operation_response_send); @@ -802,8 +811,8 @@ static void gb_connection_recv_request(struct gb_connection *connection, * request handler to be the operation's callback function. * * The last thing the handler does is send a response - * message. The original reference to the operation will be - * dropped when the response has been sent. + * message. The initial reference to the operation will be + * dropped when the handler returns. */ operation->callback = gb_operation_request_handle; if (gb_operation_result_set(operation, -EINPROGRESS)) -- 2.39.5