aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBen Hutchings <bhutchings@solarflare.com>2012-02-20 21:57:33 -0500
committerBen Hutchings <bhutchings@solarflare.com>2012-02-22 15:48:08 -0500
commit01cb543db8a2d2dbcea5f357365ce1327ac46193 (patch)
tree34f19534fcc79f1e2616424fa26fda2851918335
parentc3cb2a874122889c036934294dbbb8ad82f53060 (diff)
sfc: Correct validation of peer_page_count in efx_vfdi_set_status_page()
efx_vfdi_set_status_page() validates the peer page count by calculating the size of a request containing that many addresses and comparing that with the maximum valid request size (4KB). The calculation involves a multiplication that may overflow on a 32-bit system. We use kcalloc() to allocate memory to store the addresses; that also does a multiplication and it does check for integer overflow, so any values larger than 0x1fffffff will be rejected. However, values in the range [0x1fffffffc, 0x1fffffff] pass boh tests and result in an attempt to allocate nearly 4GB on the heap. This should be rejected rather quickly as it's obviously impossible on a 32-bit system, and indeed the maximum possible heap allocation is 32MB. Still, let's make absolutely sure by fixing the initial validation. Signed-off-by: Ben Hutchings <bhutchings@solarflare.com>
-rw-r--r--drivers/net/ethernet/sfc/siena_sriov.c11
1 files changed, 6 insertions, 5 deletions
diff --git a/drivers/net/ethernet/sfc/siena_sriov.c b/drivers/net/ethernet/sfc/siena_sriov.c
index 5c6839ec3a83..80976e84eee6 100644
--- a/drivers/net/ethernet/sfc/siena_sriov.c
+++ b/drivers/net/ethernet/sfc/siena_sriov.c
@@ -796,12 +796,13 @@ static int efx_vfdi_set_status_page(struct efx_vf *vf)
796{ 796{
797 struct efx_nic *efx = vf->efx; 797 struct efx_nic *efx = vf->efx;
798 struct vfdi_req *req = vf->buf.addr; 798 struct vfdi_req *req = vf->buf.addr;
799 unsigned int page_count; 799 u64 page_count = req->u.set_status_page.peer_page_count;
800 u64 max_page_count =
801 (EFX_PAGE_SIZE -
802 offsetof(struct vfdi_req, u.set_status_page.peer_page_addr[0]))
803 / sizeof(req->u.set_status_page.peer_page_addr[0]);
800 804
801 page_count = req->u.set_status_page.peer_page_count; 805 if (!req->u.set_status_page.dma_addr || page_count > max_page_count) {
802 if (!req->u.set_status_page.dma_addr || EFX_PAGE_SIZE <
803 offsetof(struct vfdi_req,
804 u.set_status_page.peer_page_addr[page_count])) {
805 if (net_ratelimit()) 806 if (net_ratelimit())
806 netif_err(efx, hw, efx->net_dev, 807 netif_err(efx, hw, efx->net_dev,
807 "ERROR: Invalid SET_STATUS_PAGE from %s\n", 808 "ERROR: Invalid SET_STATUS_PAGE from %s\n",