greybus: power_supply: rework get descriptors
authorRui Miguel Silva <rui.silva@linaro.org>
Thu, 4 Feb 2016 14:00:36 +0000 (14:00 +0000)
committerGreg Kroah-Hartman <gregkh@google.com>
Sat, 6 Feb 2016 00:37:34 +0000 (16:37 -0800)
Rework the get property descriptors function to fix a memory handling
error for the response structure. This could corrupt the stack and
throw nonalignment PC or SP error:

Internal error: SP or PC abort: 8a000000 1 PREEMPT SMP
Modules linked in: gb_power_supply(O) gb_arche(O) gb_camera(O) gb_es2(O) gb_vibrator(O) gb_raw(O) g]
CPU: 3 PID: 51 Comm: kworker/u16:2 Tainted: G W O 3.10.73-g8a6af60-00118-g599a5c1 #1
Workqueue: greybus1:svc gb_svc_connection_destroy [greybus]
task: ffffffc0ba249580 ti: ffffffc0ba294000 task.ti: ffffffc0ba294000
PC is at gb_power_supply_connection_init+0x81/0x1dc [gb_power_supply]
LR is at gb_power_supply_connection_init+0x81/0x1dc [gb_power_supply]
pc : [<ffffffbffc03b901>] lr : [<ffffffbffc03b901>] pstate: 80000145
sp : ffffffc0ba297a00
x29: 32002e002a001100 x28: ffffffc042cb2c80

To fix this, allocate firstly the operation and handle request and
response using operation payload.

Signed-off-by: Rui Miguel Silva <rui.silva@linaro.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@google.com>
drivers/staging/greybus/power_supply.c

index 2dc193a..37bea9c 100644 (file)
@@ -249,39 +249,53 @@ static int gb_power_supply_description_get(struct gb_power_supply *gbpsy)
 static int gb_power_supply_prop_descriptors_get(struct gb_power_supply *gbpsy)
 {
        struct gb_connection *connection = get_conn_from_psy(gbpsy);
-       struct gb_power_supply_get_property_descriptors_request req;
-       struct gb_power_supply_get_property_descriptors_response resp;
+       struct gb_power_supply_get_property_descriptors_request *req;
+       struct gb_power_supply_get_property_descriptors_response *resp;
+       struct gb_operation *op;
+       u8 props_count = gbpsy->properties_count;
        int ret;
        int i;
 
-       if (gbpsy->properties_count == 0)
+       if (props_count == 0)
                return 0;
 
-       req.psy_id = gbpsy->id;
+       op = gb_operation_create(connection,
+                                GB_POWER_SUPPLY_TYPE_GET_PROP_DESCRIPTORS,
+                                sizeof(req), sizeof(*resp) + props_count *
+                                sizeof(struct gb_power_supply_props_desc),
+                                GFP_KERNEL);
+       if (!op)
+               return -ENOMEM;
 
-       ret = gb_operation_sync(connection,
-                               GB_POWER_SUPPLY_TYPE_GET_PROP_DESCRIPTORS,
-                               &req, sizeof(req), &resp,
-                               sizeof(resp) + gbpsy->properties_count *
-                               sizeof(struct gb_power_supply_props_desc));
+       req = op->request->payload;
+       req->psy_id = gbpsy->id;
+
+       ret = gb_operation_request_send_sync(op);
        if (ret < 0)
-               return ret;
+               goto out_put_operation;
+
+       resp = op->response->payload;
 
        gbpsy->props = kcalloc(gbpsy->properties_count, sizeof(*gbpsy->props),
                              GFP_KERNEL);
-       if (!gbpsy->props)
-               return -ENOMEM;
+       if (!gbpsy->props) {
+               ret = -ENOMEM;
+               goto out_put_operation;
+       }
+
+       gbpsy->props_raw = kcalloc(gbpsy->properties_count,
+                                  sizeof(*gbpsy->props_raw), GFP_KERNEL);
+       if (!gbpsy->props_raw) {
+               ret = -ENOMEM;
+               goto out_put_operation;
+       }
 
-       gbpsy->props_raw = kzalloc(gbpsy->properties_count *
-                                 sizeof(*gbpsy->props_raw), GFP_KERNEL);
-       if (!gbpsy->props_raw)
-               return -ENOMEM;
 
        /* Store available properties */
        for (i = 0; i < gbpsy->properties_count; i++) {
-               gbpsy->props[i].prop = resp.props[i].property;
-               gbpsy->props_raw[i] = resp.props[i].property;
-               if (resp.props[i].is_writeable)
+               gbpsy->props[i].prop = resp->props[i].property;
+               gbpsy->props_raw[i] = resp->props[i].property;
+               if (resp->props[i].is_writeable)
                        gbpsy->props[i].is_writeable = true;
        }
 
@@ -291,7 +305,10 @@ static int gb_power_supply_prop_descriptors_get(struct gb_power_supply *gbpsy)
         */
        _gb_power_supply_append_props(gbpsy);
 
-       return 0;
+out_put_operation:
+       gb_operation_put(op);
+
+       return ret;
 }
 
 static int __gb_power_supply_property_update(struct gb_power_supply *gbpsy,