Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

forcedeth: Do a dma_mapping_error check after skb_frag_dma_map

This backtrace was recently reported on a 3.9 kernel:

Actual results: from syslog /var/log/messsages:
kernel: [17539.340285] ------------[ cut here ]------------
kernel: [17539.341012] WARNING: at lib/dma-debug.c:937 check_unmap+0x493/0x960()
kernel: [17539.341012] Hardware name: MS-7125
kernel: [17539.341012] forcedeth 0000:00:0a.0: DMA-API: device driver failed to
check map error[device address=0x0000000013c88000] [size=544 bytes] [mapped as
page]
kernel: [17539.341012] Modules linked in: fuse ebtable_nat ipt_MASQUERADE
nf_conntrack_netbios_ns nf_conntrack_broadcast ip6table_nat nf_nat_ipv6
ip6table_mangle ip6t_REJECT nf_conntrack_ipv6 nf_defrag_ipv6 iptable_nat
nf_nat_ipv4 nf_nat iptable_mangle nf_conntrack_ipv4 nf_defrag_ipv4 xt_conntrack
nf_conntrack bnep bluetooth rfkill ebtable_filter ebtables ip6table_filter
ip6_tables snd_hda_codec_hdmi snd_cmipci snd_mpu401_uart snd_hda_intel
snd_intel8x0 snd_opl3_lib snd_ac97_codec gameport snd_hda_codec snd_rawmidi
ac97_bus snd_hwdep snd_seq snd_seq_device snd_pcm snd_page_alloc snd_timer snd
k8temp soundcore serio_raw i2c_nforce2 forcedeth ata_generic pata_acpi nouveau
video mxm_wmi wmi i2c_algo_bit drm_kms_helper ttm drm i2c_core sata_sil pata_amd
sata_nv uinput
kernel: [17539.341012] Pid: 17340, comm: sshd Not tainted
3.9.0-0.rc4.git0.1.fc19.i686.PAE #1
kernel: [17539.341012] Call Trace:
kernel: [17539.341012] [<c045573c>] warn_slowpath_common+0x6c/0xa0
kernel: [17539.341012] [<c0701953>] ? check_unmap+0x493/0x960
kernel: [17539.341012] [<c0701953>] ? check_unmap+0x493/0x960
kernel: [17539.341012] [<c04557a3>] warn_slowpath_fmt+0x33/0x40
kernel: [17539.341012] [<c0701953>] check_unmap+0x493/0x960
kernel: [17539.341012] [<c049238f>] ? sched_clock_cpu+0xdf/0x150
kernel: [17539.341012] [<c0701e87>] debug_dma_unmap_page+0x67/0x70
kernel: [17539.341012] [<f7eae8f2>] nv_unmap_txskb.isra.32+0x92/0x100

Its pretty plainly the result of an skb fragment getting unmapped without having
its initial mapping operation checked for errors. This patch corrects that.

Signed-off-by: Neil Horman <nhorman@tuxdriver.com>
CC: "David S. Miller" <davem@davemloft.net>
Signed-off-by: David S. Miller <davem@davemloft.net>

authored by

Neil Horman and committed by
David S. Miller
f7f22874 287ecefb

+40 -1
+40 -1
drivers/net/ethernet/nvidia/forcedeth.c
··· 2200 2200 struct ring_desc *start_tx; 2201 2201 struct ring_desc *prev_tx; 2202 2202 struct nv_skb_map *prev_tx_ctx; 2203 + struct nv_skb_map *tmp_tx_ctx = NULL, *start_tx_ctx = NULL; 2203 2204 unsigned long flags; 2204 2205 2205 2206 /* add fragments to entries count */ ··· 2262 2261 do { 2263 2262 prev_tx = put_tx; 2264 2263 prev_tx_ctx = np->put_tx_ctx; 2264 + if (!start_tx_ctx) 2265 + start_tx_ctx = tmp_tx_ctx = np->put_tx_ctx; 2266 + 2265 2267 bcnt = (frag_size > NV_TX2_TSO_MAX_SIZE) ? NV_TX2_TSO_MAX_SIZE : frag_size; 2266 2268 np->put_tx_ctx->dma = skb_frag_dma_map( 2267 2269 &np->pci_dev->dev, 2268 2270 frag, offset, 2269 2271 bcnt, 2270 2272 DMA_TO_DEVICE); 2273 + if (dma_mapping_error(&np->pci_dev->dev, np->put_tx_ctx->dma)) { 2274 + 2275 + /* Unwind the mapped fragments */ 2276 + do { 2277 + nv_unmap_txskb(np, start_tx_ctx); 2278 + if (unlikely(tmp_tx_ctx++ == np->last_tx_ctx)) 2279 + tmp_tx_ctx = np->first_tx_ctx; 2280 + } while (tmp_tx_ctx != np->put_tx_ctx); 2281 + kfree_skb(skb); 2282 + np->put_tx_ctx = start_tx_ctx; 2283 + u64_stats_update_begin(&np->swstats_tx_syncp); 2284 + np->stat_tx_dropped++; 2285 + u64_stats_update_end(&np->swstats_tx_syncp); 2286 + return NETDEV_TX_OK; 2287 + } 2288 + 2271 2289 np->put_tx_ctx->dma_len = bcnt; 2272 2290 np->put_tx_ctx->dma_single = 0; 2273 2291 put_tx->buf = cpu_to_le32(np->put_tx_ctx->dma); ··· 2347 2327 struct ring_desc_ex *start_tx; 2348 2328 struct ring_desc_ex *prev_tx; 2349 2329 struct nv_skb_map *prev_tx_ctx; 2350 - struct nv_skb_map *start_tx_ctx; 2330 + struct nv_skb_map *start_tx_ctx = NULL; 2331 + struct nv_skb_map *tmp_tx_ctx = NULL; 2351 2332 unsigned long flags; 2352 2333 2353 2334 /* add fragments to entries count */ ··· 2413 2392 prev_tx = put_tx; 2414 2393 prev_tx_ctx = np->put_tx_ctx; 2415 2394 bcnt = (frag_size > NV_TX2_TSO_MAX_SIZE) ? NV_TX2_TSO_MAX_SIZE : frag_size; 2395 + if (!start_tx_ctx) 2396 + start_tx_ctx = tmp_tx_ctx = np->put_tx_ctx; 2416 2397 np->put_tx_ctx->dma = skb_frag_dma_map( 2417 2398 &np->pci_dev->dev, 2418 2399 frag, offset, 2419 2400 bcnt, 2420 2401 DMA_TO_DEVICE); 2402 + 2403 + if (dma_mapping_error(&np->pci_dev->dev, np->put_tx_ctx->dma)) { 2404 + 2405 + /* Unwind the mapped fragments */ 2406 + do { 2407 + nv_unmap_txskb(np, start_tx_ctx); 2408 + if (unlikely(tmp_tx_ctx++ == np->last_tx_ctx)) 2409 + tmp_tx_ctx = np->first_tx_ctx; 2410 + } while (tmp_tx_ctx != np->put_tx_ctx); 2411 + kfree_skb(skb); 2412 + np->put_tx_ctx = start_tx_ctx; 2413 + u64_stats_update_begin(&np->swstats_tx_syncp); 2414 + np->stat_tx_dropped++; 2415 + u64_stats_update_end(&np->swstats_tx_syncp); 2416 + return NETDEV_TX_OK; 2417 + } 2421 2418 np->put_tx_ctx->dma_len = bcnt; 2422 2419 np->put_tx_ctx->dma_single = 0; 2423 2420 put_tx->bufhigh = cpu_to_le32(dma_high(np->put_tx_ctx->dma));