From patchwork Thu Apr 20 11:16:51 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: James Hughes X-Patchwork-Id: 752748 X-Patchwork-Delegate: davem@davemloft.net Return-Path: X-Original-To: patchwork-incoming@ozlabs.org Delivered-To: patchwork-incoming@ozlabs.org Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 3w7xD31W3kz9s7B for ; Thu, 20 Apr 2017 21:17:23 +1000 (AEST) Authentication-Results: ozlabs.org; dkim=pass (2048-bit key; secure) header.d=raspberrypi.org header.i=@raspberrypi.org header.b="xEs4Tevb"; dkim=pass (2048-bit key; unprotected) header.d=raspberrypi-org.20150623.gappssmtp.com header.i=@raspberrypi-org.20150623.gappssmtp.com header.b="hJY4RY8t"; dkim-atps=neutral Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S944844AbdDTLRQ (ORCPT ); Thu, 20 Apr 2017 07:17:16 -0400 Received: from mx08-00252a01.pphosted.com ([91.207.212.211]:52500 "EHLO mx08-00252a01.pphosted.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S944421AbdDTLRM (ORCPT ); Thu, 20 Apr 2017 07:17:12 -0400 Received: from pps.filterd (m0102629.ppops.net [127.0.0.1]) by mx08-00252a01.pphosted.com (8.16.0.20/8.16.0.20) with SMTP id v3KB7wBO020565 for ; Thu, 20 Apr 2017 12:17:11 +0100 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=raspberrypi.org; h=from : to : cc : subject : date : message-id; s=pp; bh=+Y5hxlOZNHIZYWkJTMqHNX+ZBTRTlBU27wZp6L1XF6w=; b=xEs4TevblVD0paWkCJbtJMUttvuZ5Qjii5JKra/oCR/NEvXNH30B7BZg3Leg1BNWKaQW fQuvsvlawn80+na/YWSqcgEQphk2d4cbg+Gwa1T5UWm5NouV/adFykTu++LEyyXUU23P XfiXeE8dLyoBUEYTjT4MzufW83TtBVgjF52lXsCtSmM2MndhNdbXAzKxcAa0Wa0DAipu XFzOgZ+GctdGwwCfDl9i44s3JjvmyH7glbHMZYTuLbvAX+nDgWKYbjCwJSAMjDw4gFAw wxKZusUE0IOh8Aa1KeosSrDsYC52gS8MhtLmS4dLecJtSzb6KRkx40w7/iU1lQ1v4b0B 2g== Received: from mail-wr0-f199.google.com (mail-wr0-f199.google.com [209.85.128.199]) by mx08-00252a01.pphosted.com with ESMTP id 29wqp28saq-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128 verify=OK) for ; Thu, 20 Apr 2017 12:17:11 +0100 Received: by mail-wr0-f199.google.com with SMTP id 18so5274926wrz.4 for ; Thu, 20 Apr 2017 04:17:11 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=raspberrypi-org.20150623.gappssmtp.com; s=20150623; h=from:to:cc:subject:date:message-id; bh=+Y5hxlOZNHIZYWkJTMqHNX+ZBTRTlBU27wZp6L1XF6w=; b=hJY4RY8tTwr5cgFezEZFHEIvTc2PyxYcp7LIzlKwGwoyz0CWEbqIyF+OHAM63/CEfs JHAdpKvZmOZUi2fT8ybEmnQUq1A2AlV3GpqgxBONxLMr5Dw4TyRk8pEbJNOw6Nc+eoSd a63OqQBS4UhRn487iXvHYns6du9J3P6DZNI/bIyr8CO5OwrqMyk3YpLymi4aQbMrsmrY GwXdJNsTTvCPT/E2DHmykOV14zeGKxWHVFpKkuQ6XJlt7l+bF1yF3I65N5IjpdL99abO Fe1VroeqHOZUYKb5qIKShQ2uxItaC+5EECgzoZMnhograICsRHv85Uksn2/RdAl8bJd8 SUNQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id; bh=+Y5hxlOZNHIZYWkJTMqHNX+ZBTRTlBU27wZp6L1XF6w=; b=T0jENMtmd1lM8Z5nFehmLM+vdwjnXlKSYQt2L4dyrmg3MYPDVdFBwcmy3G7CEV4EIf O7oSWt4h1VF/dcNfBSs/f0m0aYp+KzmMtCb2a4WPMcmTAQ2l6C/y/eIVevtIv+dI57kr QtVrFy4M+Bz2Q6IhxnuGA9woeIm+TUIXhtSem2qODeADu9jnK/TRtr99nVL4hQGG3itW M7ZfLic3uhnJQP1pCAIy6VR8RtRptZSzKw/sbUfANZi2xLgudoxr3Ic+gsxXSAPLXmoW 1qQv5QPGqXg+oeWInHo73fEVxrOAeVtvlHbzwKYsAuxUt1IMvPhj1l8r4K+HmjESv3J4 cfkw== X-Gm-Message-State: AN3rC/4zxK3AxhL/D6FwFdXgLpVwz5Wb71rM8p2NrZSmACWXXi1wI0y9 KCTOen+b3R4YJi/X8zE9Q9e2x5e7ZVnHz21inLU1RbFXuFMolWDoJ6UvxkbRSCREmyCJvp3yi4c rZFevRSU= X-Received: by 10.28.238.9 with SMTP id m9mr2641911wmh.72.1492687030207; Thu, 20 Apr 2017 04:17:10 -0700 (PDT) X-Received: by 10.28.238.9 with SMTP id m9mr2641882wmh.72.1492687029886; Thu, 20 Apr 2017 04:17:09 -0700 (PDT) Received: from jamesh-VirtualBox ([217.33.127.173]) by smtp.gmail.com with ESMTPSA id d23sm7208158wra.6.2017.04.20.04.17.09 (version=TLS1 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Thu, 20 Apr 2017 04:17:09 -0700 (PDT) From: James Hughes To: netdev@vger.kernel.org, Arend van Spriel , Franky Lin , Hante Meuleman , Kalle Valo Cc: James Hughes Subject: [PATCH] brcm80211: brcmfmac: Ensure that incoming skb's are writable Date: Thu, 20 Apr 2017 12:16:51 +0100 Message-Id: <20170420111651.10213-1-james.hughes@raspberrypi.org> X-Mailer: git-send-email 2.9.3 X-Proofpoint-Virus-Version: vendor=fsecure engine=2.50.10432:, , definitions=2017-04-20_10:, , signatures=0 X-Proofpoint-Spam-Details: rule=outbound_spam_notspam policy=outbound_spam score=0 priorityscore=1501 malwarescore=0 suspectscore=0 phishscore=0 bulkscore=0 spamscore=0 clxscore=1015 lowpriorityscore=0 impostorscore=0 adultscore=0 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.0.1-1703280000 definitions=main-1704200090 Sender: netdev-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org The driver was adding header information to incoming skb without ensuring the head was uncloned and hence writable. skb_cow_head has been used to ensure they are writable, however, this required some changes to error handling to ensure that if skb_cow_head failed it was not ignored. This really needs to be reviewed by someone who is more familiar with this code base to ensure any deallocation of skb's is still correct. Signed-off-by: James Hughes --- .../wireless/broadcom/brcm80211/brcmfmac/bcdc.c | 15 ++++++++-- .../wireless/broadcom/brcm80211/brcmfmac/core.c | 23 +++++----------- .../broadcom/brcm80211/brcmfmac/fwsignal.c | 32 +++++++++++++++++----- .../wireless/broadcom/brcm80211/brcmfmac/sdio.c | 7 ++++- 4 files changed, 51 insertions(+), 26 deletions(-) diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcdc.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcdc.c index 038a960..b9d7d08 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcdc.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcdc.c @@ -249,14 +249,19 @@ brcmf_proto_bcdc_set_dcmd(struct brcmf_pub *drvr, int ifidx, uint cmd, return ret; } -static void +static int brcmf_proto_bcdc_hdrpush(struct brcmf_pub *drvr, int ifidx, u8 offset, struct sk_buff *pktbuf) { struct brcmf_proto_bcdc_header *h; + int err; brcmf_dbg(BCDC, "Enter\n"); + err = skb_cow_head(pktbuf, BCDC_HEADER_LEN); + if (err) + return err; + /* Push BDC header used to convey priority for buses that don't */ skb_push(pktbuf, BCDC_HEADER_LEN); @@ -271,6 +276,8 @@ brcmf_proto_bcdc_hdrpush(struct brcmf_pub *drvr, int ifidx, u8 offset, h->data_offset = offset; BCDC_SET_IF_IDX(h, ifidx); trace_brcmf_bcdchdr(pktbuf->data); + + return 0; } static int @@ -330,7 +337,11 @@ static int brcmf_proto_bcdc_txdata(struct brcmf_pub *drvr, int ifidx, u8 offset, struct sk_buff *pktbuf) { - brcmf_proto_bcdc_hdrpush(drvr, ifidx, offset, pktbuf); + int err = brcmf_proto_bcdc_hdrpush(drvr, ifidx, offset, pktbuf); + + if (err) + return err; + return brcmf_bus_txdata(drvr->bus_if, pktbuf); } diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c index 5eaac13..08272e8 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c @@ -198,7 +198,7 @@ static netdev_tx_t brcmf_netdev_start_xmit(struct sk_buff *skb, int ret; struct brcmf_if *ifp = netdev_priv(ndev); struct brcmf_pub *drvr = ifp->drvr; - struct ethhdr *eh = (struct ethhdr *)(skb->data); + struct ethhdr *eh; brcmf_dbg(DATA, "Enter, bsscfgidx=%d\n", ifp->bsscfgidx); @@ -212,23 +212,14 @@ static netdev_tx_t brcmf_netdev_start_xmit(struct sk_buff *skb, } /* Make sure there's enough room for any header */ - if (skb_headroom(skb) < drvr->hdrlen) { - struct sk_buff *skb2; - - brcmf_dbg(INFO, "%s: insufficient headroom\n", - brcmf_ifname(ifp)); - drvr->bus_if->tx_realloc++; - skb2 = skb_realloc_headroom(skb, drvr->hdrlen); - dev_kfree_skb(skb); - skb = skb2; - if (skb == NULL) { - brcmf_err("%s: skb_realloc_headroom failed\n", - brcmf_ifname(ifp)); - ret = -ENOMEM; - goto done; - } + ret = skb_cow_head(skb, drvr->hdrlen); + if (ret) { + dev_kfree_skb_any(skb); + goto done; } + eh = (struct ethhdr *)(skb->data); + /* validate length for ether packet */ if (skb->len < sizeof(*eh)) { ret = -EINVAL; diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwsignal.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwsignal.c index a190f53..2510408 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwsignal.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwsignal.c @@ -877,12 +877,15 @@ static void brcmf_fws_cleanup(struct brcmf_fws_info *fws, int ifidx) brcmf_fws_hanger_cleanup(fws, matchfn, ifidx); } -static u8 brcmf_fws_hdrpush(struct brcmf_fws_info *fws, struct sk_buff *skb) +static int brcmf_fws_hdrpush(struct brcmf_fws_info *fws, struct sk_buff *skb, + u8 *offset) { struct brcmf_fws_mac_descriptor *entry = brcmf_skbcb(skb)->mac; u8 *wlh; u16 data_offset = 0; u8 fillers; + int err; + __le32 pkttag = cpu_to_le32(brcmf_skbcb(skb)->htod); __le16 pktseq = cpu_to_le16(brcmf_skbcb(skb)->htod_seq); @@ -899,6 +902,11 @@ static u8 brcmf_fws_hdrpush(struct brcmf_fws_info *fws, struct sk_buff *skb) fillers = round_up(data_offset, 4) - data_offset; data_offset += fillers; + err = skb_cow_head(skb, data_offset); + + if (err) + return err; + skb_push(skb, data_offset); wlh = skb->data; @@ -926,7 +934,9 @@ static u8 brcmf_fws_hdrpush(struct brcmf_fws_info *fws, struct sk_buff *skb) if (fillers) memset(wlh, BRCMF_FWS_TYPE_FILLER, fillers); - return (u8)(data_offset >> 2); + *offset = (u8)(data_offset >> 2); + + return 0; } static bool brcmf_fws_tim_update(struct brcmf_fws_info *fws, @@ -966,7 +976,8 @@ static bool brcmf_fws_tim_update(struct brcmf_fws_info *fws, skcb->state = BRCMF_FWS_SKBSTATE_TIM; skcb->htod = 0; skcb->htod_seq = 0; - data_offset = brcmf_fws_hdrpush(fws, skb); + if (brcmf_fws_hdrpush(fws, skb, &data_offset)) + return false; ifidx = brcmf_skb_if_flags_get_field(skb, INDEX); brcmf_fws_unlock(fws); err = brcmf_proto_txdata(fws->drvr, ifidx, data_offset, skb); @@ -1945,12 +1956,13 @@ void brcmf_fws_hdrpull(struct brcmf_if *ifp, s16 siglen, struct sk_buff *skb) fws->stats.header_only_pkt++; } -static u8 brcmf_fws_precommit_skb(struct brcmf_fws_info *fws, int fifo, - struct sk_buff *p) +static int brcmf_fws_precommit_skb(struct brcmf_fws_info *fws, int fifo, + struct sk_buff *p, u8 *offset) { struct brcmf_skbuff_cb *skcb = brcmf_skbcb(p); struct brcmf_fws_mac_descriptor *entry = skcb->mac; u8 flags; + int err; if (skcb->state != BRCMF_FWS_SKBSTATE_SUPPRESSED) brcmf_skb_htod_tag_set_field(p, GENERATION, entry->generation); @@ -1963,7 +1975,10 @@ static u8 brcmf_fws_precommit_skb(struct brcmf_fws_info *fws, int fifo, flags |= BRCMF_FWS_HTOD_FLAG_PKT_REQUESTED; } brcmf_skb_htod_tag_set_field(p, FLAGS, flags); - return brcmf_fws_hdrpush(fws, p); + + err = brcmf_fws_hdrpush(fws, p, offset); + + return err; } static void brcmf_fws_rollback_toq(struct brcmf_fws_info *fws, @@ -2039,7 +2054,9 @@ static int brcmf_fws_commit_skb(struct brcmf_fws_info *fws, int fifo, if (IS_ERR(entry)) return PTR_ERR(entry); - data_offset = brcmf_fws_precommit_skb(fws, fifo, skb); + if (!brcmf_fws_precommit_skb(fws, fifo, skb, &data_offset)) + return PTR_ERR(entry); + entry->transit_count++; if (entry->suppressed) entry->suppr_transit_count++; @@ -2100,6 +2117,7 @@ int brcmf_fws_process_skb(struct brcmf_if *ifp, struct sk_buff *skb) int rc = 0; brcmf_dbg(DATA, "tx proto=0x%X\n", ntohs(eh->h_proto)); + /* determine the priority */ if ((skb->priority == 0) || (skb->priority > 7)) skb->priority = cfg80211_classify8021d(skb, NULL); diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c index d138260..0e53c8a 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c @@ -2719,7 +2719,7 @@ static bool brcmf_sdio_prec_enq(struct pktq *q, struct sk_buff *pkt, int prec) static int brcmf_sdio_bus_txdata(struct device *dev, struct sk_buff *pkt) { - int ret = -EBADE; + int ret = -EBADE, err; uint prec; struct brcmf_bus *bus_if = dev_get_drvdata(dev); struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv.sdio; @@ -2729,6 +2729,11 @@ static int brcmf_sdio_bus_txdata(struct device *dev, struct sk_buff *pkt) if (sdiodev->state != BRCMF_SDIOD_DATA) return -EIO; + err = skb_cow_head(pkt, bus->tx_hdrlen); + + if (err) + return err; + /* Add space for the header */ skb_push(pkt, bus->tx_hdrlen); /* precondition: IS_ALIGNED((unsigned long)(pkt->data), 2) */