Commit 0fb5acc4 authored by Johan Hovold's avatar Johan Hovold Committed by Greg Kroah-Hartman

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: default avatarJohan Hovold <johan@hovoldconsulting.com>
Reviewed-by: default avatarAlex Elder <elder@linaro.org>
Signed-off-by: default avatarGreg Kroah-Hartman <greg@kroah.com>
parent 37754030
...@@ -719,6 +719,8 @@ EXPORT_SYMBOL_GPL(gb_operation_request_send_sync); ...@@ -719,6 +719,8 @@ EXPORT_SYMBOL_GPL(gb_operation_request_send_sync);
*/ */
int gb_operation_response_send(struct gb_operation *operation, int errno) int gb_operation_response_send(struct gb_operation *operation, int errno)
{ {
int ret;
/* Record the result */ /* Record the result */
if (!gb_operation_result_set(operation, errno)) { if (!gb_operation_result_set(operation, errno)) {
pr_err("request result already set\n"); pr_err("request result already set\n");
...@@ -733,10 +735,17 @@ int gb_operation_response_send(struct gb_operation *operation, int errno) ...@@ -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 */ /* Fill in the response header and send it */
operation->response->header->result = gb_operation_errno_map(errno); 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); EXPORT_SYMBOL_GPL(gb_operation_response_send);
...@@ -802,8 +811,8 @@ static void gb_connection_recv_request(struct gb_connection *connection, ...@@ -802,8 +811,8 @@ static void gb_connection_recv_request(struct gb_connection *connection,
* request handler to be the operation's callback function. * request handler to be the operation's callback function.
* *
* The last thing the handler does is send a response * The last thing the handler does is send a response
* message. The original reference to the operation will be * message. The initial reference to the operation will be
* dropped when the response has been sent. * dropped when the handler returns.
*/ */
operation->callback = gb_operation_request_handle; operation->callback = gb_operation_request_handle;
if (gb_operation_result_set(operation, -EINPROGRESS)) if (gb_operation_result_set(operation, -EINPROGRESS))
......
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