summaryrefslogtreecommitdiffstats
path: root/drivers/staging/greybus/operation.c
diff options
context:
space:
mode:
authorJohan Hovold2015-03-27 12:41:13 +0100
committerGreg Kroah-Hartman2015-03-30 15:10:06 +0200
commit0fb5acc4018c0da61f9084932d0cd816fab77eec (patch)
tree0c4561950289a390654b936143cb4b8385f157a4 /drivers/staging/greybus/operation.c
parentgreybus: operation: fix callback handling and documentation (diff)
downloadkernel-qcow2-linux-0fb5acc4018c0da61f9084932d0cd816fab77eec.tar.gz
kernel-qcow2-linux-0fb5acc4018c0da61f9084932d0cd816fab77eec.tar.xz
kernel-qcow2-linux-0fb5acc4018c0da61f9084932d0cd816fab77eec.zip
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.c15
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))