greybus: operation: fix another cancellation use-after-free
authorJohan Hovold <johan@hovoldconsulting.com>
Tue, 14 Jul 2015 13:43:23 +0000 (15:43 +0200)
committerGreg Kroah-Hartman <gregkh@google.com>
Wed, 15 Jul 2015 19:39:13 +0000 (12:39 -0700)
An incoming operation could already be scheduled even if
gb_operation_result_set succeeds as its initial status is -EINPROGRESS.

Avoid potential use-after-free by never dropping the reference count for
incoming operations as part of cancellation.

Signed-off-by: Johan Hovold <johan@hovoldconsulting.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@google.com>
drivers/staging/greybus/operation.c

index b78c55fac8cc075805d58d96b6ce35b8d66ee67e..41aec7647b2b12eda72e5ed6a2aa4e68e790ac45 100644 (file)
@@ -853,12 +853,17 @@ void gb_connection_recv(struct gb_connection *connection,
  */
 void gb_operation_cancel(struct gb_operation *operation, int errno)
 {
-       if (gb_operation_result_set(operation, errno)) {
-               gb_message_cancel(operation->request);
-               gb_operation_put(operation);
-       } else if (gb_operation_is_incoming(operation)) {
-               if (!gb_operation_is_unidirectional(operation))
+       if (gb_operation_is_incoming(operation)) {
+               /* Cancel response if it has been allocated */
+               if (!gb_operation_result_set(operation, errno) &&
+                               !gb_operation_is_unidirectional(operation)) {
                        gb_message_cancel(operation->response);
+               }
+       } else {
+               if (gb_operation_result_set(operation, errno)) {
+                       gb_message_cancel(operation->request);
+                       gb_operation_put(operation);
+               }
        }
 }
 EXPORT_SYMBOL_GPL(gb_operation_cancel);