qed: Prevent stack corruption on MFW interaction
authorMintz, Yuval <Yuval.Mintz@cavium.com>
Sun, 6 Nov 2016 15:12:27 +0000 (17:12 +0200)
committerDavid S. Miller <davem@davemloft.net>
Wed, 9 Nov 2016 18:27:25 +0000 (13:27 -0500)
Driver uses a union for copying data to & from management firmware
when interacting with it.
Problem is that the function always copies sizeof(union) while commit
2edbff8dcb5d ("qed: Learn resources from management firmware") is casting
a union elements which is of smaller size [24-byte instead of 88-bytes].

Also, the union contains some inappropriate elements which increase its
size [should have been 32-bytes]. While this shouldn't corrupt other
PF messages to the MFW [as management firmware enforces permissions so
that each PF is allowed to write only to its own mailbox] we fix this
here as well.

Fixes: 2edbff8dcb5d ("qed: Learn resources from management firmware")
Signed-off-by: Yuval Mintz <Yuval.Mintz@cavium.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/ethernet/qlogic/qed/qed_hsi.h
drivers/net/ethernet/qlogic/qed/qed_mcp.c

index 048f9a342413c4820b503b8f6887527b8b5d7999..f5a4ebb3963fb3efc9f5e157f185e848548350ef 100644 (file)
@@ -8581,7 +8581,6 @@ union drv_union_data {
        struct drv_version_stc drv_version;
 
        struct lan_stats_stc lan_stats;
-       u64 reserved_stats[11];
        struct ocbb_data_stc ocbb_info;
        struct temperature_status_stc temp_info;
        struct resource_info resource;
index d8e499ebb99d22a20728820dabb22d6af4b044fa..6dd3ce443484b5f75cb0a1b7d3cfcdece593fc96 100644 (file)
@@ -1697,19 +1697,27 @@ int qed_mcp_get_resc_info(struct qed_hwfn *p_hwfn,
                          u32 *p_mcp_resp, u32 *p_mcp_param)
 {
        struct qed_mcp_mb_params mb_params;
-       union drv_union_data *p_union_data;
+       union drv_union_data union_data;
        int rc;
 
        memset(&mb_params, 0, sizeof(mb_params));
+       memset(&union_data, 0, sizeof(union_data));
        mb_params.cmd = DRV_MSG_GET_RESOURCE_ALLOC_MSG;
        mb_params.param = QED_RESC_ALLOC_VERSION;
-       p_union_data = (union drv_union_data *)p_resc_info;
-       mb_params.p_data_src = p_union_data;
-       mb_params.p_data_dst = p_union_data;
+
+       /* Need to have a sufficient large struct, as the cmd_and_union
+        * is going to do memcpy from and to it.
+        */
+       memcpy(&union_data.resource, p_resc_info, sizeof(*p_resc_info));
+
+       mb_params.p_data_src = &union_data;
+       mb_params.p_data_dst = &union_data;
        rc = qed_mcp_cmd_and_union(p_hwfn, p_ptt, &mb_params);
        if (rc)
                return rc;
 
+       /* Copy the data back */
+       memcpy(p_resc_info, &union_data.resource, sizeof(*p_resc_info));
        *p_mcp_resp = mb_params.mcp_resp;
        *p_mcp_param = mb_params.mcp_param;