diff options
author | Johan Hovold <johan@hovoldconsulting.com> | 2015-03-27 12:41:13 +0100 |
---|---|---|
committer | Greg Kroah-Hartman <greg@kroah.com> | 2015-03-30 15:10:06 +0200 |
commit | 0fb5acc4018c0da61f9084932d0cd816fab77eec (patch) | |
tree | 0c4561950289a390654b936143cb4b8385f157a4 /drivers/staging/greybus/operation.c | |
parent | 37754030b0b9f7b81217b891cdc5f21dd7d29e4d (diff) |
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 <johan@hovoldconsulting.com>
Reviewed-by: Alex Elder <elder@linaro.org>
Signed-off-by: Greg Kroah-Hartman <greg@kroah.com>
Diffstat (limited to 'drivers/staging/greybus/operation.c')
-rw-r--r-- | drivers/staging/greybus/operation.c | 15 |
1 files 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)) |