greybus: operation: fix use-after-free when sending responses
authorJohan Hovold <johan@hovoldconsulting.com>
Fri, 27 Mar 2015 11:41:13 +0000 (12:41 +0100)
committerGreg Kroah-Hartman <greg@kroah.com>
Mon, 30 Mar 2015 13:10:06 +0000 (15:10 +0200)
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>
drivers/staging/greybus/operation.c

index c64b2bf..ad45dee 100644 (file)
@@ -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))