net: rmnet_data: Fix use after free when sending MAP command ACK

Following stack trace was seen while doing a data transfer

Unable to handle kernel paging request at virtual address
6b6b6b6b6b6b6ef3
pgd = ffffffc01c7c5000 [6b6b6b6b6b6b6ef3] *pgd=0000000000000000,
*pud=0000000000000000
Internal error: Oops: 96000004 [#1] PREEMPT SMP
Call trace:
[<ffffffc000f669ac>] rmnet_map_command+0x19c/0x238
[<ffffffc000f6504c>] _rmnet_map_ingress_handler+0x3c/0x264
[<ffffffc000f65500>] rmnet_ingress_handler+0x1b4/0x3a4
[<ffffffc000f65704>] rmnet_rx_handler+0x14/0x2c
[<ffffffc000d8b5ac>] __netif_receive_skb_core+0x514/0x71c
[<ffffffc000d8c270>] __netif_receive_skb+0x30/0x98
[<ffffffc000d8d3bc>] process_backlog+0xb0/0x184
[<ffffffc000d8d1f8>] net_rx_action+0xfc/0x210
[<ffffffc00016a2e0>] __do_softirq+0x1c0/0x39c
[<ffffffc00016a824>] irq_exit+0x88/0xf4
[<ffffffc0001565e8>] handle_IPI+0x340/0x4b4
[<ffffffc0001455e8>] gic_handle_irq+0xc4/0xec

This is because an invalid MAP command was received and was freed
and rmnet_data was trying to send the freed skb as an ACK. Fix this
by returning if an invalid MAP command is detected.

CRs-Fixed: 1019188
Change-Id: Ib52e6551ac67215dab2bc5770ddcf037568f8b77
Signed-off-by: Subash Abhinov Kasiviswanathan <subashab@codeaurora.org>
This commit is contained in:
Subash Abhinov Kasiviswanathan 2016-05-20 17:33:13 -06:00 committed by Kyle Yan
parent 16ce590689
commit c6e1ec80cd
2 changed files with 9 additions and 4 deletions

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2014, The Linux Foundation. All rights reserved.
* Copyright (c) 2014, 2016 The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@ -39,6 +39,7 @@ enum rmnet_skb_free_e {
RMNET_STATS_SKBFREE_DEAGG_UNKOWN_IP_TYP,
RMNET_STATS_SKBFREE_DEAGG_DATA_LEN_0,
RMNET_STATS_SKBFREE_INGRESS_BAD_MAP_CKSUM,
RMNET_STATS_SKBFREE_MAPC_UNSUPPORTED,
RMNET_STATS_SKBFREE_MAX
};

View file

@ -93,10 +93,12 @@ static uint8_t rmnet_map_do_flow_control(struct sk_buff *skb,
LOGD("dev:%s, qos_id:0x%08X, ip_family:%hd, fc_seq %hd, en:%d",
skb->dev->name, qos_id, ip_family & 3, fc_seq, enable);
if (r)
if (r) {
rmnet_kfree_skb(skb, RMNET_STATS_SKBFREE_MAPC_UNSUPPORTED);
return RMNET_MAP_COMMAND_UNSUPPORTED;
else
} else {
return RMNET_MAP_COMMAND_ACK;
}
}
/**
@ -188,8 +190,10 @@ rx_handler_result_t rmnet_map_command(struct sk_buff *skb,
rmnet_map_command_stats[RMNET_MAP_COMMAND_UNKNOWN]++;
LOGM("Uknown MAP command: %d", command_name);
rc = RMNET_MAP_COMMAND_UNSUPPORTED;
rmnet_kfree_skb(skb, RMNET_STATS_SKBFREE_MAPC_UNSUPPORTED);
break;
}
rmnet_map_send_ack(skb, rc, config);
if (rc == RMNET_MAP_COMMAND_ACK)
rmnet_map_send_ack(skb, rc, config);
return RX_HANDLER_CONSUMED;
}