diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2018-06-06 17:27:14 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2018-06-06 17:27:14 -0700 |
commit | 285767604576148fc1be7fcd112e4a90eb0d6ad2 (patch) | |
tree | b4c611689f95e1a2ba0fe7b6407e05469251fc2f | |
parent | 5eb6eed7e0fe880dc8de8da203cc888716bbf196 (diff) | |
parent | 0ed2dd03b94b7b7f66e23f25073b5385d0416589 (diff) | |
download | op-kernel-dev-285767604576148fc1be7fcd112e4a90eb0d6ad2.zip op-kernel-dev-285767604576148fc1be7fcd112e4a90eb0d6ad2.tar.gz |
Merge tag 'overflow-v4.18-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/kees/linux
Pull overflow updates from Kees Cook:
"This adds the new overflow checking helpers and adds them to the
2-factor argument allocators. And this adds the saturating size
helpers and does a treewide replacement for the struct_size() usage.
Additionally this adds the overflow testing modules to make sure
everything works.
I'm still working on the treewide replacements for allocators with
"simple" multiplied arguments:
*alloc(a * b, ...) -> *alloc_array(a, b, ...)
and
*zalloc(a * b, ...) -> *calloc(a, b, ...)
as well as the more complex cases, but that's separable from this
portion of the series. I expect to have the rest sent before -rc1
closes; there are a lot of messy cases to clean up.
Summary:
- Introduce arithmetic overflow test helper functions (Rasmus)
- Use overflow helpers in 2-factor allocators (Kees, Rasmus)
- Introduce overflow test module (Rasmus, Kees)
- Introduce saturating size helper functions (Matthew, Kees)
- Treewide use of struct_size() for allocators (Kees)"
* tag 'overflow-v4.18-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/kees/linux:
treewide: Use struct_size() for devm_kmalloc() and friends
treewide: Use struct_size() for vmalloc()-family
treewide: Use struct_size() for kmalloc()-family
device: Use overflow helpers for devm_kmalloc()
mm: Use overflow helpers in kvmalloc()
mm: Use overflow helpers in kmalloc_array*()
test_overflow: Add memory allocation overflow tests
overflow.h: Add allocation size calculation helpers
test_overflow: Report test failures
test_overflow: macrofy some more, do more tests for free
lib: add runtime test of check_*_overflow functions
compiler.h: enable builtin overflow checkers and add fallback code
99 files changed, 916 insertions, 205 deletions
diff --git a/crypto/af_alg.c b/crypto/af_alg.c index 89ed613..49fa858 100644 --- a/crypto/af_alg.c +++ b/crypto/af_alg.c @@ -500,8 +500,8 @@ int af_alg_alloc_tsgl(struct sock *sk) sg = sgl->sg; if (!sg || sgl->cur >= MAX_SGL_ENTS) { - sgl = sock_kmalloc(sk, sizeof(*sgl) + - sizeof(sgl->sg[0]) * (MAX_SGL_ENTS + 1), + sgl = sock_kmalloc(sk, + struct_size(sgl, sg, (MAX_SGL_ENTS + 1)), GFP_KERNEL); if (!sgl) return -ENOMEM; diff --git a/drivers/base/devres.c b/drivers/base/devres.c index 95b6728..f98a097 100644 --- a/drivers/base/devres.c +++ b/drivers/base/devres.c @@ -84,9 +84,14 @@ static struct devres_group * node_to_group(struct devres_node *node) static __always_inline struct devres * alloc_dr(dr_release_t release, size_t size, gfp_t gfp, int nid) { - size_t tot_size = sizeof(struct devres) + size; + size_t tot_size; struct devres *dr; + /* We must catch any near-SIZE_MAX cases that could overflow. */ + if (unlikely(check_add_overflow(sizeof(struct devres), size, + &tot_size))) + return NULL; + dr = kmalloc_node_track_caller(tot_size, gfp, nid); if (unlikely(!dr)) return NULL; diff --git a/drivers/clk/bcm/clk-bcm2835-aux.c b/drivers/clk/bcm/clk-bcm2835-aux.c index 77e276d..f225ad2 100644 --- a/drivers/clk/bcm/clk-bcm2835-aux.c +++ b/drivers/clk/bcm/clk-bcm2835-aux.c @@ -40,8 +40,10 @@ static int bcm2835_aux_clk_probe(struct platform_device *pdev) if (IS_ERR(reg)) return PTR_ERR(reg); - onecell = devm_kmalloc(dev, sizeof(*onecell) + sizeof(*onecell->hws) * - BCM2835_AUX_CLOCK_COUNT, GFP_KERNEL); + onecell = devm_kmalloc(dev, + struct_size(onecell, hws, + BCM2835_AUX_CLOCK_COUNT), + GFP_KERNEL); if (!onecell) return -ENOMEM; onecell->num = BCM2835_AUX_CLOCK_COUNT; diff --git a/drivers/clk/bcm/clk-bcm2835.c b/drivers/clk/bcm/clk-bcm2835.c index fa0d5c8..6d4e69e 100644 --- a/drivers/clk/bcm/clk-bcm2835.c +++ b/drivers/clk/bcm/clk-bcm2835.c @@ -2147,8 +2147,8 @@ static int bcm2835_clk_probe(struct platform_device *pdev) size_t i; int ret; - cprman = devm_kzalloc(dev, sizeof(*cprman) + - sizeof(*cprman->onecell.hws) * asize, + cprman = devm_kzalloc(dev, + struct_size(cprman, onecell.hws, asize), GFP_KERNEL); if (!cprman) return -ENOMEM; diff --git a/drivers/clk/bcm/clk-iproc-asiu.c b/drivers/clk/bcm/clk-iproc-asiu.c index 4360e48..6fb8af5 100644 --- a/drivers/clk/bcm/clk-iproc-asiu.c +++ b/drivers/clk/bcm/clk-iproc-asiu.c @@ -197,8 +197,8 @@ void __init iproc_asiu_setup(struct device_node *node, if (WARN_ON(!asiu)) return; - asiu->clk_data = kzalloc(sizeof(*asiu->clk_data->hws) * num_clks + - sizeof(*asiu->clk_data), GFP_KERNEL); + asiu->clk_data = kzalloc(struct_size(asiu->clk_data, hws, num_clks), + GFP_KERNEL); if (WARN_ON(!asiu->clk_data)) goto err_clks; asiu->clk_data->num = num_clks; diff --git a/drivers/clk/bcm/clk-iproc-pll.c b/drivers/clk/bcm/clk-iproc-pll.c index 43a58ae..274441e 100644 --- a/drivers/clk/bcm/clk-iproc-pll.c +++ b/drivers/clk/bcm/clk-iproc-pll.c @@ -744,8 +744,7 @@ void iproc_pll_clk_setup(struct device_node *node, if (WARN_ON(!pll)) return; - clk_data = kzalloc(sizeof(*clk_data->hws) * num_clks + - sizeof(*clk_data), GFP_KERNEL); + clk_data = kzalloc(struct_size(clk_data, hws, num_clks), GFP_KERNEL); if (WARN_ON(!clk_data)) goto err_clk_data; clk_data->num = num_clks; diff --git a/drivers/clk/berlin/bg2.c b/drivers/clk/berlin/bg2.c index e7331ac..45fb888 100644 --- a/drivers/clk/berlin/bg2.c +++ b/drivers/clk/berlin/bg2.c @@ -509,8 +509,7 @@ static void __init berlin2_clock_setup(struct device_node *np) u8 avpll_flags = 0; int n, ret; - clk_data = kzalloc(sizeof(*clk_data) + - sizeof(*clk_data->hws) * MAX_CLKS, GFP_KERNEL); + clk_data = kzalloc(struct_size(clk_data, hws, MAX_CLKS), GFP_KERNEL); if (!clk_data) return; clk_data->num = MAX_CLKS; diff --git a/drivers/clk/berlin/bg2q.c b/drivers/clk/berlin/bg2q.c index 67c270b..db7364e 100644 --- a/drivers/clk/berlin/bg2q.c +++ b/drivers/clk/berlin/bg2q.c @@ -295,8 +295,7 @@ static void __init berlin2q_clock_setup(struct device_node *np) struct clk_hw **hws; int n, ret; - clk_data = kzalloc(sizeof(*clk_data) + - sizeof(*clk_data->hws) * MAX_CLKS, GFP_KERNEL); + clk_data = kzalloc(struct_size(clk_data, hws, MAX_CLKS), GFP_KERNEL); if (!clk_data) return; clk_data->num = MAX_CLKS; diff --git a/drivers/clk/clk-asm9260.c b/drivers/clk/clk-asm9260.c index bf0582c..44b5441 100644 --- a/drivers/clk/clk-asm9260.c +++ b/drivers/clk/clk-asm9260.c @@ -273,8 +273,7 @@ static void __init asm9260_acc_init(struct device_node *np) int n; u32 accuracy = 0; - clk_data = kzalloc(sizeof(*clk_data) + - sizeof(*clk_data->hws) * MAX_CLKS, GFP_KERNEL); + clk_data = kzalloc(struct_size(clk_data, hws, MAX_CLKS), GFP_KERNEL); if (!clk_data) return; clk_data->num = MAX_CLKS; diff --git a/drivers/clk/clk-aspeed.c b/drivers/clk/clk-aspeed.c index 5eb50c3..7abe423 100644 --- a/drivers/clk/clk-aspeed.c +++ b/drivers/clk/clk-aspeed.c @@ -627,9 +627,9 @@ static void __init aspeed_cc_init(struct device_node *np) if (!scu_base) return; - aspeed_clk_data = kzalloc(sizeof(*aspeed_clk_data) + - sizeof(*aspeed_clk_data->hws) * ASPEED_NUM_CLKS, - GFP_KERNEL); + aspeed_clk_data = kzalloc(struct_size(aspeed_clk_data, hws, + ASPEED_NUM_CLKS), + GFP_KERNEL); if (!aspeed_clk_data) return; diff --git a/drivers/clk/clk-clps711x.c b/drivers/clk/clk-clps711x.c index 9193f64..2c04396 100644 --- a/drivers/clk/clk-clps711x.c +++ b/drivers/clk/clk-clps711x.c @@ -54,9 +54,9 @@ static struct clps711x_clk * __init _clps711x_clk_init(void __iomem *base, if (!base) return ERR_PTR(-ENOMEM); - clps711x_clk = kzalloc(sizeof(*clps711x_clk) + - sizeof(*clps711x_clk->clk_data.hws) * CLPS711X_CLK_MAX, - GFP_KERNEL); + clps711x_clk = kzalloc(struct_size(clps711x_clk, clk_data.hws, + CLPS711X_CLK_MAX), + GFP_KERNEL); if (!clps711x_clk) return ERR_PTR(-ENOMEM); diff --git a/drivers/clk/clk-efm32gg.c b/drivers/clk/clk-efm32gg.c index f674778..f37cf08 100644 --- a/drivers/clk/clk-efm32gg.c +++ b/drivers/clk/clk-efm32gg.c @@ -25,8 +25,8 @@ static void __init efm32gg_cmu_init(struct device_node *np) void __iomem *base; struct clk_hw **hws; - clk_data = kzalloc(sizeof(*clk_data) + - sizeof(*clk_data->hws) * CMU_MAX_CLKS, GFP_KERNEL); + clk_data = kzalloc(struct_size(clk_data, hws, CMU_MAX_CLKS), + GFP_KERNEL); if (!clk_data) return; diff --git a/drivers/clk/clk-gemini.c b/drivers/clk/clk-gemini.c index 5e66e6c..b51069e 100644 --- a/drivers/clk/clk-gemini.c +++ b/drivers/clk/clk-gemini.c @@ -399,9 +399,9 @@ static void __init gemini_cc_init(struct device_node *np) int ret; int i; - gemini_clk_data = kzalloc(sizeof(*gemini_clk_data) + - sizeof(*gemini_clk_data->hws) * GEMINI_NUM_CLKS, - GFP_KERNEL); + gemini_clk_data = kzalloc(struct_size(gemini_clk_data, hws, + GEMINI_NUM_CLKS), + GFP_KERNEL); if (!gemini_clk_data) return; diff --git a/drivers/clk/clk-s2mps11.c b/drivers/clk/clk-s2mps11.c index fbaa84a..d44e0ee 100644 --- a/drivers/clk/clk-s2mps11.c +++ b/drivers/clk/clk-s2mps11.c @@ -147,8 +147,8 @@ static int s2mps11_clk_probe(struct platform_device *pdev) if (!s2mps11_clks) return -ENOMEM; - clk_data = devm_kzalloc(&pdev->dev, sizeof(*clk_data) + - sizeof(*clk_data->hws) * S2MPS11_CLKS_NUM, + clk_data = devm_kzalloc(&pdev->dev, + struct_size(clk_data, hws, S2MPS11_CLKS_NUM), GFP_KERNEL); if (!clk_data) return -ENOMEM; diff --git a/drivers/clk/clk-scmi.c b/drivers/clk/clk-scmi.c index 488c213..bb2a6f2 100644 --- a/drivers/clk/clk-scmi.c +++ b/drivers/clk/clk-scmi.c @@ -137,8 +137,8 @@ static int scmi_clocks_probe(struct scmi_device *sdev) return -EINVAL; } - clk_data = devm_kzalloc(dev, sizeof(*clk_data) + - sizeof(*clk_data->hws) * count, GFP_KERNEL); + clk_data = devm_kzalloc(dev, struct_size(clk_data, hws, count), + GFP_KERNEL); if (!clk_data) return -ENOMEM; diff --git a/drivers/clk/clk-stm32h7.c b/drivers/clk/clk-stm32h7.c index db2b162..d3271ec 100644 --- a/drivers/clk/clk-stm32h7.c +++ b/drivers/clk/clk-stm32h7.c @@ -1201,9 +1201,8 @@ static void __init stm32h7_rcc_init(struct device_node *np) const char *hse_clk, *lse_clk, *i2s_clk; struct regmap *pdrm; - clk_data = kzalloc(sizeof(*clk_data) + - sizeof(*clk_data->hws) * STM32H7_MAX_CLKS, - GFP_KERNEL); + clk_data = kzalloc(struct_size(clk_data, hws, STM32H7_MAX_CLKS), + GFP_KERNEL); if (!clk_data) return; diff --git a/drivers/clk/clk-stm32mp1.c b/drivers/clk/clk-stm32mp1.c index edd3cf4..83e8cd81 100644 --- a/drivers/clk/clk-stm32mp1.c +++ b/drivers/clk/clk-stm32mp1.c @@ -2060,9 +2060,8 @@ static int stm32_rcc_init(struct device_node *np, max_binding = data->maxbinding; - clk_data = kzalloc(sizeof(*clk_data) + - sizeof(*clk_data->hws) * max_binding, - GFP_KERNEL); + clk_data = kzalloc(struct_size(clk_data, hws, max_binding), + GFP_KERNEL); if (!clk_data) return -ENOMEM; diff --git a/drivers/clk/davinci/da8xx-cfgchip.c b/drivers/clk/davinci/da8xx-cfgchip.c index c971111..aae62a5 100644 --- a/drivers/clk/davinci/da8xx-cfgchip.c +++ b/drivers/clk/davinci/da8xx-cfgchip.c @@ -650,8 +650,8 @@ static int of_da8xx_usb_phy_clk_init(struct device *dev, struct regmap *regmap) struct da8xx_usb0_clk48 *usb0; struct da8xx_usb1_clk48 *usb1; - clk_data = devm_kzalloc(dev, sizeof(*clk_data) + 2 * - sizeof(*clk_data->hws), GFP_KERNEL); + clk_data = devm_kzalloc(dev, struct_size(clk_data, hws, 2), + GFP_KERNEL); if (!clk_data) return -ENOMEM; diff --git a/drivers/clk/mvebu/armada-37xx-periph.c b/drivers/clk/mvebu/armada-37xx-periph.c index 87213ea..6860bd5 100644 --- a/drivers/clk/mvebu/armada-37xx-periph.c +++ b/drivers/clk/mvebu/armada-37xx-periph.c @@ -667,9 +667,10 @@ static int armada_3700_periph_clock_probe(struct platform_device *pdev) if (!driver_data) return -ENOMEM; - driver_data->hw_data = devm_kzalloc(dev, sizeof(*driver_data->hw_data) + - sizeof(*driver_data->hw_data->hws) * num_periph, - GFP_KERNEL); + driver_data->hw_data = devm_kzalloc(dev, + struct_size(driver_data->hw_data, + hws, num_periph), + GFP_KERNEL); if (!driver_data->hw_data) return -ENOMEM; driver_data->hw_data->num = num_periph; diff --git a/drivers/clk/mvebu/armada-37xx-tbg.c b/drivers/clk/mvebu/armada-37xx-tbg.c index aa80db1..7ff041f 100644 --- a/drivers/clk/mvebu/armada-37xx-tbg.c +++ b/drivers/clk/mvebu/armada-37xx-tbg.c @@ -91,8 +91,8 @@ static int armada_3700_tbg_clock_probe(struct platform_device *pdev) void __iomem *reg; int i, ret; - hw_tbg_data = devm_kzalloc(&pdev->dev, sizeof(*hw_tbg_data) - + sizeof(*hw_tbg_data->hws) * NUM_TBG, + hw_tbg_data = devm_kzalloc(&pdev->dev, + struct_size(hw_tbg_data, hws, NUM_TBG), GFP_KERNEL); if (!hw_tbg_data) return -ENOMEM; diff --git a/drivers/clk/qcom/clk-spmi-pmic-div.c b/drivers/clk/qcom/clk-spmi-pmic-div.c index 8672ab8..c90dfdd 100644 --- a/drivers/clk/qcom/clk-spmi-pmic-div.c +++ b/drivers/clk/qcom/clk-spmi-pmic-div.c @@ -239,8 +239,7 @@ static int spmi_pmic_clkdiv_probe(struct platform_device *pdev) if (!nclks) return -EINVAL; - cc = devm_kzalloc(dev, sizeof(*cc) + sizeof(*cc->clks) * nclks, - GFP_KERNEL); + cc = devm_kzalloc(dev, struct_size(cc, clks, nclks), GFP_KERNEL); if (!cc) return -ENOMEM; cc->nclks = nclks; diff --git a/drivers/clk/samsung/clk-exynos-audss.c b/drivers/clk/samsung/clk-exynos-audss.c index b4b057c..f659c5c 100644 --- a/drivers/clk/samsung/clk-exynos-audss.c +++ b/drivers/clk/samsung/clk-exynos-audss.c @@ -149,8 +149,8 @@ static int exynos_audss_clk_probe(struct platform_device *pdev) epll = ERR_PTR(-ENODEV); clk_data = devm_kzalloc(dev, - sizeof(*clk_data) + - sizeof(*clk_data->hws) * EXYNOS_AUDSS_MAX_CLKS, + struct_size(clk_data, hws, + EXYNOS_AUDSS_MAX_CLKS), GFP_KERNEL); if (!clk_data) return -ENOMEM; diff --git a/drivers/clk/samsung/clk-exynos-clkout.c b/drivers/clk/samsung/clk-exynos-clkout.c index f29fb58..9c95390 100644 --- a/drivers/clk/samsung/clk-exynos-clkout.c +++ b/drivers/clk/samsung/clk-exynos-clkout.c @@ -61,8 +61,7 @@ static void __init exynos_clkout_init(struct device_node *node, u32 mux_mask) int ret; int i; - clkout = kzalloc(sizeof(*clkout) + - sizeof(*clkout->data.hws) * EXYNOS_CLKOUT_NR_CLKS, + clkout = kzalloc(struct_size(clkout, data.hws, EXYNOS_CLKOUT_NR_CLKS), GFP_KERNEL); if (!clkout) return; diff --git a/drivers/clk/samsung/clk-exynos5433.c b/drivers/clk/samsung/clk-exynos5433.c index 5305ace..162de44 100644 --- a/drivers/clk/samsung/clk-exynos5433.c +++ b/drivers/clk/samsung/clk-exynos5433.c @@ -5505,8 +5505,8 @@ static int __init exynos5433_cmu_probe(struct platform_device *pdev) info = of_device_get_match_data(dev); - data = devm_kzalloc(dev, sizeof(*data) + - sizeof(*data->ctx.clk_data.hws) * info->nr_clk_ids, + data = devm_kzalloc(dev, + struct_size(data, ctx.clk_data.hws, info->nr_clk_ids), GFP_KERNEL); if (!data) return -ENOMEM; diff --git a/drivers/clk/samsung/clk-s3c2410-dclk.c b/drivers/clk/samsung/clk-s3c2410-dclk.c index 077df3e..66a9047 100644 --- a/drivers/clk/samsung/clk-s3c2410-dclk.c +++ b/drivers/clk/samsung/clk-s3c2410-dclk.c @@ -247,9 +247,10 @@ static int s3c24xx_dclk_probe(struct platform_device *pdev) struct clk_hw **clk_table; int ret, i; - s3c24xx_dclk = devm_kzalloc(&pdev->dev, sizeof(*s3c24xx_dclk) + - sizeof(*s3c24xx_dclk->clk_data.hws) * DCLK_MAX_CLKS, - GFP_KERNEL); + s3c24xx_dclk = devm_kzalloc(&pdev->dev, + struct_size(s3c24xx_dclk, clk_data.hws, + DCLK_MAX_CLKS), + GFP_KERNEL); if (!s3c24xx_dclk) return -ENOMEM; diff --git a/drivers/clk/samsung/clk-s5pv210-audss.c b/drivers/clk/samsung/clk-s5pv210-audss.c index b964141..22b18e7 100644 --- a/drivers/clk/samsung/clk-s5pv210-audss.c +++ b/drivers/clk/samsung/clk-s5pv210-audss.c @@ -81,8 +81,7 @@ static int s5pv210_audss_clk_probe(struct platform_device *pdev) } clk_data = devm_kzalloc(&pdev->dev, - sizeof(*clk_data) + - sizeof(*clk_data->hws) * AUDSS_MAX_CLKS, + struct_size(clk_data, hws, AUDSS_MAX_CLKS), GFP_KERNEL); if (!clk_data) diff --git a/drivers/dax/device.c b/drivers/dax/device.c index aff2c15..de2f829 100644 --- a/drivers/dax/device.c +++ b/drivers/dax/device.c @@ -594,7 +594,7 @@ struct dev_dax *devm_create_dev_dax(struct dax_region *dax_region, if (!count) return ERR_PTR(-EINVAL); - dev_dax = kzalloc(sizeof(*dev_dax) + sizeof(*res) * count, GFP_KERNEL); + dev_dax = kzalloc(struct_size(dev_dax, res, count), GFP_KERNEL); if (!dev_dax) return ERR_PTR(-ENOMEM); diff --git a/drivers/dma/bcm-sba-raid.c b/drivers/dma/bcm-sba-raid.c index 3956a01..72878ac 100644 --- a/drivers/dma/bcm-sba-raid.c +++ b/drivers/dma/bcm-sba-raid.c @@ -1499,9 +1499,8 @@ static int sba_prealloc_channel_resources(struct sba_device *sba) for (i = 0; i < sba->max_req; i++) { req = devm_kzalloc(sba->dev, - sizeof(*req) + - sba->max_cmd_per_req * sizeof(req->cmds[0]), - GFP_KERNEL); + struct_size(req, cmds, sba->max_cmd_per_req), + GFP_KERNEL); if (!req) { ret = -ENOMEM; goto fail_free_cmds_pool; diff --git a/drivers/dma/edma.c b/drivers/dma/edma.c index 85ea92f..9bc722c 100644 --- a/drivers/dma/edma.c +++ b/drivers/dma/edma.c @@ -1074,8 +1074,7 @@ static struct dma_async_tx_descriptor *edma_prep_slave_sg( return NULL; } - edesc = kzalloc(sizeof(*edesc) + sg_len * sizeof(edesc->pset[0]), - GFP_ATOMIC); + edesc = kzalloc(struct_size(edesc, pset, sg_len), GFP_ATOMIC); if (!edesc) return NULL; @@ -1192,8 +1191,7 @@ static struct dma_async_tx_descriptor *edma_prep_dma_memcpy( nslots = 2; } - edesc = kzalloc(sizeof(*edesc) + nslots * sizeof(edesc->pset[0]), - GFP_ATOMIC); + edesc = kzalloc(struct_size(edesc, pset, nslots), GFP_ATOMIC); if (!edesc) return NULL; @@ -1315,8 +1313,7 @@ static struct dma_async_tx_descriptor *edma_prep_dma_cyclic( } } - edesc = kzalloc(sizeof(*edesc) + nslots * sizeof(edesc->pset[0]), - GFP_ATOMIC); + edesc = kzalloc(struct_size(edesc, pset, nslots), GFP_ATOMIC); if (!edesc) return NULL; diff --git a/drivers/dma/moxart-dma.c b/drivers/dma/moxart-dma.c index e1a5c22..e04499c1f 100644 --- a/drivers/dma/moxart-dma.c +++ b/drivers/dma/moxart-dma.c @@ -309,7 +309,7 @@ static struct dma_async_tx_descriptor *moxart_prep_slave_sg( return NULL; } - d = kzalloc(sizeof(*d) + sg_len * sizeof(d->sg[0]), GFP_ATOMIC); + d = kzalloc(struct_size(d, sg, sg_len), GFP_ATOMIC); if (!d) return NULL; diff --git a/drivers/dma/nbpfaxi.c b/drivers/dma/nbpfaxi.c index 5055933..2f9974d 100644 --- a/drivers/dma/nbpfaxi.c +++ b/drivers/dma/nbpfaxi.c @@ -1305,8 +1305,8 @@ static int nbpf_probe(struct platform_device *pdev) cfg = of_device_get_match_data(dev); num_channels = cfg->num_channels; - nbpf = devm_kzalloc(dev, sizeof(*nbpf) + num_channels * - sizeof(nbpf->chan[0]), GFP_KERNEL); + nbpf = devm_kzalloc(dev, struct_size(nbpf, chan, num_channels), + GFP_KERNEL); if (!nbpf) return -ENOMEM; diff --git a/drivers/dma/omap-dma.c b/drivers/dma/omap-dma.c index d21c198..9483000 100644 --- a/drivers/dma/omap-dma.c +++ b/drivers/dma/omap-dma.c @@ -917,7 +917,7 @@ static struct dma_async_tx_descriptor *omap_dma_prep_slave_sg( } /* Now allocate and setup the descriptor. */ - d = kzalloc(sizeof(*d) + sglen * sizeof(d->sg[0]), GFP_ATOMIC); + d = kzalloc(struct_size(d, sg, sglen), GFP_ATOMIC); if (!d) return NULL; diff --git a/drivers/dma/sa11x0-dma.c b/drivers/dma/sa11x0-dma.c index c7a89c2..b31d07c 100644 --- a/drivers/dma/sa11x0-dma.c +++ b/drivers/dma/sa11x0-dma.c @@ -557,7 +557,7 @@ static struct dma_async_tx_descriptor *sa11x0_dma_prep_slave_sg( } } - txd = kzalloc(sizeof(*txd) + j * sizeof(txd->sg[0]), GFP_ATOMIC); + txd = kzalloc(struct_size(txd, sg, j), GFP_ATOMIC); if (!txd) { dev_dbg(chan->device->dev, "vchan %p: kzalloc failed\n", &c->vc); return NULL; @@ -627,7 +627,7 @@ static struct dma_async_tx_descriptor *sa11x0_dma_prep_dma_cyclic( if (sglen == 0) return NULL; - txd = kzalloc(sizeof(*txd) + sglen * sizeof(txd->sg[0]), GFP_ATOMIC); + txd = kzalloc(struct_size(txd, sg, sglen), GFP_ATOMIC); if (!txd) { dev_dbg(chan->device->dev, "vchan %p: kzalloc failed\n", &c->vc); return NULL; diff --git a/drivers/dma/sh/usb-dmac.c b/drivers/dma/sh/usb-dmac.c index 31a1451..1bb1a8e 100644 --- a/drivers/dma/sh/usb-dmac.c +++ b/drivers/dma/sh/usb-dmac.c @@ -269,7 +269,7 @@ static int usb_dmac_desc_alloc(struct usb_dmac_chan *chan, unsigned int sg_len, struct usb_dmac_desc *desc; unsigned long flags; - desc = kzalloc(sizeof(*desc) + sg_len * sizeof(desc->sg[0]), gfp); + desc = kzalloc(struct_size(desc, sg, sg_len), gfp); if (!desc) return -ENOMEM; diff --git a/drivers/dma/sprd-dma.c b/drivers/dma/sprd-dma.c index b106e8a..52ebccb 100644 --- a/drivers/dma/sprd-dma.c +++ b/drivers/dma/sprd-dma.c @@ -805,8 +805,8 @@ static int sprd_dma_probe(struct platform_device *pdev) return ret; } - sdev = devm_kzalloc(&pdev->dev, sizeof(*sdev) + - sizeof(*dma_chn) * chn_count, + sdev = devm_kzalloc(&pdev->dev, + struct_size(sdev, channels, chn_count), GFP_KERNEL); if (!sdev) return -ENOMEM; diff --git a/drivers/firewire/core-topology.c b/drivers/firewire/core-topology.c index 939d259..7db234d 100644 --- a/drivers/firewire/core-topology.c +++ b/drivers/firewire/core-topology.c @@ -112,8 +112,7 @@ static struct fw_node *fw_node_create(u32 sid, int port_count, int color) { struct fw_node *node; - node = kzalloc(sizeof(*node) + port_count * sizeof(node->ports[0]), - GFP_ATOMIC); + node = kzalloc(struct_size(node, ports, port_count), GFP_ATOMIC); if (node == NULL) return NULL; diff --git a/drivers/gpio/gpio-uniphier.c b/drivers/gpio/gpio-uniphier.c index 761d827..d3cf950 100644 --- a/drivers/gpio/gpio-uniphier.c +++ b/drivers/gpio/gpio-uniphier.c @@ -371,8 +371,7 @@ static int uniphier_gpio_probe(struct platform_device *pdev) return ret; nregs = uniphier_gpio_get_nbanks(ngpios) * 2 + 3; - priv = devm_kzalloc(dev, - sizeof(*priv) + sizeof(priv->saved_vals[0]) * nregs, + priv = devm_kzalloc(dev, struct_size(priv, saved_vals, nregs), GFP_KERNEL); if (!priv) return -ENOMEM; diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index d8ccb50..55d596f 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -4023,8 +4023,7 @@ struct gpio_descs *__must_check gpiod_get_array(struct device *dev, if (count < 0) return ERR_PTR(count); - descs = kzalloc(sizeof(*descs) + sizeof(descs->desc[0]) * count, - GFP_KERNEL); + descs = kzalloc(struct_size(descs, desc, count), GFP_KERNEL); if (!descs) return ERR_PTR(-ENOMEM); diff --git a/drivers/gpu/drm/nouveau/nvkm/core/ramht.c b/drivers/gpu/drm/nouveau/nvkm/core/ramht.c index ccba4ae..8162e3d 100644 --- a/drivers/gpu/drm/nouveau/nvkm/core/ramht.c +++ b/drivers/gpu/drm/nouveau/nvkm/core/ramht.c @@ -144,8 +144,7 @@ nvkm_ramht_new(struct nvkm_device *device, u32 size, u32 align, struct nvkm_ramht *ramht; int ret, i; - if (!(ramht = *pramht = vzalloc(sizeof(*ramht) + - (size >> 3) * sizeof(*ramht->data)))) + if (!(ramht = *pramht = vzalloc(struct_size(ramht, data, (size >> 3))))) return -ENOMEM; ramht->device = device; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/pm/base.c b/drivers/gpu/drm/nouveau/nvkm/engine/pm/base.c index 53859b6..b2785be 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/pm/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/pm/base.c @@ -779,8 +779,8 @@ nvkm_perfdom_new(struct nvkm_pm *pm, const char *name, u32 mask, sdom = spec; while (sdom->signal_nr) { - dom = kzalloc(sizeof(*dom) + sdom->signal_nr * - sizeof(*dom->signal), GFP_KERNEL); + dom = kzalloc(struct_size(dom, signal, sdom->signal_nr), + GFP_KERNEL); if (!dom) return -ENOMEM; diff --git a/drivers/hwspinlock/omap_hwspinlock.c b/drivers/hwspinlock/omap_hwspinlock.c index ad2f8ca..d897e52 100644 --- a/drivers/hwspinlock/omap_hwspinlock.c +++ b/drivers/hwspinlock/omap_hwspinlock.c @@ -132,7 +132,7 @@ static int omap_hwspinlock_probe(struct platform_device *pdev) num_locks = i * 32; /* actual number of locks in this device */ - bank = kzalloc(sizeof(*bank) + num_locks * sizeof(*hwlock), GFP_KERNEL); + bank = kzalloc(struct_size(bank, lock, num_locks), GFP_KERNEL); if (!bank) { ret = -ENOMEM; goto iounmap_base; diff --git a/drivers/hwspinlock/sirf_hwspinlock.c b/drivers/hwspinlock/sirf_hwspinlock.c index 1601854..cb38e48 100644 --- a/drivers/hwspinlock/sirf_hwspinlock.c +++ b/drivers/hwspinlock/sirf_hwspinlock.c @@ -62,8 +62,10 @@ static int sirf_hwspinlock_probe(struct platform_device *pdev) if (!pdev->dev.of_node) return -ENODEV; - hwspin = devm_kzalloc(&pdev->dev, sizeof(*hwspin) + - sizeof(*hwlock) * HW_SPINLOCK_NUMBER, GFP_KERNEL); + hwspin = devm_kzalloc(&pdev->dev, + struct_size(hwspin, bank.lock, + HW_SPINLOCK_NUMBER), + GFP_KERNEL); if (!hwspin) return -ENOMEM; diff --git a/drivers/hwspinlock/u8500_hsem.c b/drivers/hwspinlock/u8500_hsem.c index e93eabb..0128d8f 100644 --- a/drivers/hwspinlock/u8500_hsem.c +++ b/drivers/hwspinlock/u8500_hsem.c @@ -119,7 +119,7 @@ static int u8500_hsem_probe(struct platform_device *pdev) /* clear all interrupts */ writel(0xFFFF, io_base + HSEM_ICRALL); - bank = kzalloc(sizeof(*bank) + num_locks * sizeof(*hwlock), GFP_KERNEL); + bank = kzalloc(struct_size(bank, lock, num_locks), GFP_KERNEL); if (!bank) { ret = -ENOMEM; goto iounmap_base; diff --git a/drivers/infiniband/core/cache.c b/drivers/infiniband/core/cache.c index ecc55e9..3330d97 100644 --- a/drivers/infiniband/core/cache.c +++ b/drivers/infiniband/core/cache.c @@ -1157,8 +1157,9 @@ static void ib_cache_update(struct ib_device *device, goto err; } - pkey_cache = kmalloc(sizeof *pkey_cache + tprops->pkey_tbl_len * - sizeof *pkey_cache->table, GFP_KERNEL); + pkey_cache = kmalloc(struct_size(pkey_cache, table, + tprops->pkey_tbl_len), + GFP_KERNEL); if (!pkey_cache) goto err; diff --git a/drivers/infiniband/core/cm.c b/drivers/infiniband/core/cm.c index a92e1a5..36a4d90 100644 --- a/drivers/infiniband/core/cm.c +++ b/drivers/infiniband/core/cm.c @@ -4298,8 +4298,8 @@ static void cm_add_one(struct ib_device *ib_device) int count = 0; u8 i; - cm_dev = kzalloc(sizeof(*cm_dev) + sizeof(*port) * - ib_device->phys_port_cnt, GFP_KERNEL); + cm_dev = kzalloc(struct_size(cm_dev, port, ib_device->phys_port_cnt), + GFP_KERNEL); if (!cm_dev) return; diff --git a/drivers/infiniband/core/multicast.c b/drivers/infiniband/core/multicast.c index 4eb72ff..6c48f41 100644 --- a/drivers/infiniband/core/multicast.c +++ b/drivers/infiniband/core/multicast.c @@ -813,7 +813,7 @@ static void mcast_add_one(struct ib_device *device) int i; int count = 0; - dev = kmalloc(sizeof *dev + device->phys_port_cnt * sizeof *port, + dev = kmalloc(struct_size(dev, port, device->phys_port_cnt), GFP_KERNEL); if (!dev) return; diff --git a/drivers/infiniband/core/uverbs_cmd.c b/drivers/infiniband/core/uverbs_cmd.c index 21a887c9..e3662a8e 100644 --- a/drivers/infiniband/core/uverbs_cmd.c +++ b/drivers/infiniband/core/uverbs_cmd.c @@ -2756,8 +2756,8 @@ static struct ib_uflow_resources *flow_resources_alloc(size_t num_specs) struct ib_uflow_resources *resources; resources = - kmalloc(sizeof(*resources) + - num_specs * sizeof(*resources->collection), GFP_KERNEL); + kmalloc(struct_size(resources, collection, num_specs), + GFP_KERNEL); if (!resources) return NULL; diff --git a/drivers/infiniband/core/uverbs_ioctl_merge.c b/drivers/infiniband/core/uverbs_ioctl_merge.c index 0f88a19..6ceb672 100644 --- a/drivers/infiniband/core/uverbs_ioctl_merge.c +++ b/drivers/infiniband/core/uverbs_ioctl_merge.c @@ -297,8 +297,7 @@ static struct uverbs_method_spec *build_method_with_attrs(const struct uverbs_me if (max_attr_buckets >= 0) num_attr_buckets = max_attr_buckets + 1; - method = kzalloc(sizeof(*method) + - num_attr_buckets * sizeof(*method->attr_buckets), + method = kzalloc(struct_size(method, attr_buckets, num_attr_buckets), GFP_KERNEL); if (!method) return ERR_PTR(-ENOMEM); @@ -446,9 +445,9 @@ static struct uverbs_object_spec *build_object_with_methods(const struct uverbs_ if (max_method_buckets >= 0) num_method_buckets = max_method_buckets + 1; - object = kzalloc(sizeof(*object) + - num_method_buckets * - sizeof(*object->method_buckets), GFP_KERNEL); + object = kzalloc(struct_size(object, method_buckets, + num_method_buckets), + GFP_KERNEL); if (!object) return ERR_PTR(-ENOMEM); @@ -469,8 +468,8 @@ static struct uverbs_object_spec *build_object_with_methods(const struct uverbs_ if (methods_max_bucket < 0) continue; - hash = kzalloc(sizeof(*hash) + - sizeof(*hash->methods) * (methods_max_bucket + 1), + hash = kzalloc(struct_size(hash, methods, + methods_max_bucket + 1), GFP_KERNEL); if (!hash) { res = -ENOMEM; @@ -579,8 +578,8 @@ struct uverbs_root_spec *uverbs_alloc_spec_tree(unsigned int num_trees, if (max_object_buckets >= 0) num_objects_buckets = max_object_buckets + 1; - root_spec = kzalloc(sizeof(*root_spec) + - num_objects_buckets * sizeof(*root_spec->object_buckets), + root_spec = kzalloc(struct_size(root_spec, object_buckets, + num_objects_buckets), GFP_KERNEL); if (!root_spec) return ERR_PTR(-ENOMEM); @@ -603,8 +602,8 @@ struct uverbs_root_spec *uverbs_alloc_spec_tree(unsigned int num_trees, if (objects_max_bucket < 0) continue; - hash = kzalloc(sizeof(*hash) + - sizeof(*hash->objects) * (objects_max_bucket + 1), + hash = kzalloc(struct_size(hash, objects, + objects_max_bucket + 1), GFP_KERNEL); if (!hash) { res = -ENOMEM; diff --git a/drivers/infiniband/hw/mthca/mthca_memfree.c b/drivers/infiniband/hw/mthca/mthca_memfree.c index 2fe503e..7a31be3 100644 --- a/drivers/infiniband/hw/mthca/mthca_memfree.c +++ b/drivers/infiniband/hw/mthca/mthca_memfree.c @@ -367,7 +367,7 @@ struct mthca_icm_table *mthca_alloc_icm_table(struct mthca_dev *dev, obj_per_chunk = MTHCA_TABLE_CHUNK_SIZE / obj_size; num_icm = DIV_ROUND_UP(nobj, obj_per_chunk); - table = kmalloc(sizeof *table + num_icm * sizeof *table->icm, GFP_KERNEL); + table = kmalloc(struct_size(table, icm, num_icm), GFP_KERNEL); if (!table) return NULL; @@ -529,7 +529,7 @@ struct mthca_user_db_table *mthca_init_user_db_tab(struct mthca_dev *dev) return NULL; npages = dev->uar_table.uarc_size / MTHCA_ICM_PAGE_SIZE; - db_tab = kmalloc(sizeof *db_tab + npages * sizeof *db_tab->page, GFP_KERNEL); + db_tab = kmalloc(struct_size(db_tab, page, npages), GFP_KERNEL); if (!db_tab) return ERR_PTR(-ENOMEM); diff --git a/drivers/infiniband/sw/rdmavt/mr.c b/drivers/infiniband/sw/rdmavt/mr.c index cc429b5..49c9541 100644 --- a/drivers/infiniband/sw/rdmavt/mr.c +++ b/drivers/infiniband/sw/rdmavt/mr.c @@ -283,7 +283,7 @@ static struct rvt_mr *__rvt_alloc_mr(int count, struct ib_pd *pd) /* Allocate struct plus pointers to first level page tables. */ m = (count + RVT_SEGSZ - 1) / RVT_SEGSZ; - mr = kzalloc(sizeof(*mr) + m * sizeof(mr->mr.map[0]), GFP_KERNEL); + mr = kzalloc(struct_size(mr, mr.map, m), GFP_KERNEL); if (!mr) goto bail; @@ -730,7 +730,7 @@ struct ib_fmr *rvt_alloc_fmr(struct ib_pd *pd, int mr_access_flags, /* Allocate struct plus pointers to first level page tables. */ m = (fmr_attr->max_pages + RVT_SEGSZ - 1) / RVT_SEGSZ; - fmr = kzalloc(sizeof(*fmr) + m * sizeof(fmr->mr.map[0]), GFP_KERNEL); + fmr = kzalloc(struct_size(fmr, mr.map, m), GFP_KERNEL); if (!fmr) goto bail; diff --git a/drivers/input/input-leds.c b/drivers/input/input-leds.c index 5f04b2d..99cc784 100644 --- a/drivers/input/input-leds.c +++ b/drivers/input/input-leds.c @@ -98,8 +98,7 @@ static int input_leds_connect(struct input_handler *handler, if (!num_leds) return -ENXIO; - leds = kzalloc(sizeof(*leds) + num_leds * sizeof(*leds->leds), - GFP_KERNEL); + leds = kzalloc(struct_size(leds, leds, num_leds), GFP_KERNEL); if (!leds) return -ENOMEM; diff --git a/drivers/input/input-mt.c b/drivers/input/input-mt.c index a1bbec9..cf30523 100644 --- a/drivers/input/input-mt.c +++ b/drivers/input/input-mt.c @@ -49,7 +49,7 @@ int input_mt_init_slots(struct input_dev *dev, unsigned int num_slots, if (mt) return mt->num_slots != num_slots ? -EINVAL : 0; - mt = kzalloc(sizeof(*mt) + num_slots * sizeof(*mt->slots), GFP_KERNEL); + mt = kzalloc(struct_size(mt, slots, num_slots), GFP_KERNEL); if (!mt) goto err_mem; diff --git a/drivers/input/keyboard/cap11xx.c b/drivers/input/keyboard/cap11xx.c index 1a1eaca..312916f 100644 --- a/drivers/input/keyboard/cap11xx.c +++ b/drivers/input/keyboard/cap11xx.c @@ -357,8 +357,7 @@ static int cap11xx_i2c_probe(struct i2c_client *i2c_client, } priv = devm_kzalloc(dev, - sizeof(*priv) + - cap->num_channels * sizeof(priv->keycodes[0]), + struct_size(priv, keycodes, cap->num_channels), GFP_KERNEL); if (!priv) return -ENOMEM; diff --git a/drivers/md/dm-raid.c b/drivers/md/dm-raid.c index 6f823f4..ab13fce 100644 --- a/drivers/md/dm-raid.c +++ b/drivers/md/dm-raid.c @@ -756,7 +756,7 @@ static struct raid_set *raid_set_alloc(struct dm_target *ti, struct raid_type *r return ERR_PTR(-EINVAL); } - rs = kzalloc(sizeof(*rs) + raid_devs * sizeof(rs->dev[0]), GFP_KERNEL); + rs = kzalloc(struct_size(rs, dev, raid_devs), GFP_KERNEL); if (!rs) { ti->error = "Cannot allocate raid context"; return ERR_PTR(-ENOMEM); diff --git a/drivers/md/dm-table.c b/drivers/md/dm-table.c index 0589a4d..caa51dd 100644 --- a/drivers/md/dm-table.c +++ b/drivers/md/dm-table.c @@ -548,14 +548,14 @@ static int adjoin(struct dm_table *table, struct dm_target *ti) * On the other hand, dm-switch needs to process bulk data using messages and * excessive use of GFP_NOIO could cause trouble. */ -static char **realloc_argv(unsigned *array_size, char **old_argv) +static char **realloc_argv(unsigned *size, char **old_argv) { char **argv; unsigned new_size; gfp_t gfp; - if (*array_size) { - new_size = *array_size * 2; + if (*size) { + new_size = *size * 2; gfp = GFP_KERNEL; } else { new_size = 8; @@ -563,8 +563,8 @@ static char **realloc_argv(unsigned *array_size, char **old_argv) } argv = kmalloc(new_size * sizeof(*argv), gfp); if (argv) { - memcpy(argv, old_argv, *array_size * sizeof(*argv)); - *array_size = new_size; + memcpy(argv, old_argv, *size * sizeof(*argv)); + *size = new_size; } kfree(old_argv); diff --git a/drivers/mfd/qcom-pm8xxx.c b/drivers/mfd/qcom-pm8xxx.c index f08758f..e6e8d81 100644 --- a/drivers/mfd/qcom-pm8xxx.c +++ b/drivers/mfd/qcom-pm8xxx.c @@ -563,8 +563,8 @@ static int pm8xxx_probe(struct platform_device *pdev) pr_info("PMIC revision 2: %02X\n", val); rev |= val << BITS_PER_BYTE; - chip = devm_kzalloc(&pdev->dev, sizeof(*chip) + - sizeof(chip->config[0]) * data->num_irqs, + chip = devm_kzalloc(&pdev->dev, + struct_size(chip, config, data->num_irqs), GFP_KERNEL); if (!chip) return -ENOMEM; diff --git a/drivers/misc/cb710/core.c b/drivers/misc/cb710/core.c index fb397e7..4d4acf7 100644 --- a/drivers/misc/cb710/core.c +++ b/drivers/misc/cb710/core.c @@ -232,8 +232,8 @@ static int cb710_probe(struct pci_dev *pdev, if (val & CB710_SLOT_SM) ++n; - chip = devm_kzalloc(&pdev->dev, - sizeof(*chip) + n * sizeof(*chip->slot), GFP_KERNEL); + chip = devm_kzalloc(&pdev->dev, struct_size(chip, slot, n), + GFP_KERNEL); if (!chip) return -ENOMEM; diff --git a/drivers/misc/vexpress-syscfg.c b/drivers/misc/vexpress-syscfg.c index 9eea30f..80a6f19 100644 --- a/drivers/misc/vexpress-syscfg.c +++ b/drivers/misc/vexpress-syscfg.c @@ -182,8 +182,7 @@ static struct regmap *vexpress_syscfg_regmap_init(struct device *dev, val = energy_quirk; } - func = kzalloc(sizeof(*func) + sizeof(*func->template) * num, - GFP_KERNEL); + func = kzalloc(struct_size(func, template, num), GFP_KERNEL); if (!func) return ERR_PTR(-ENOMEM); diff --git a/drivers/mtd/spi-nor/aspeed-smc.c b/drivers/mtd/spi-nor/aspeed-smc.c index 8d3cbe2..95e5446 100644 --- a/drivers/mtd/spi-nor/aspeed-smc.c +++ b/drivers/mtd/spi-nor/aspeed-smc.c @@ -861,8 +861,9 @@ static int aspeed_smc_probe(struct platform_device *pdev) return -ENODEV; info = match->data; - controller = devm_kzalloc(&pdev->dev, sizeof(*controller) + - info->nce * sizeof(controller->chips[0]), GFP_KERNEL); + controller = devm_kzalloc(&pdev->dev, + struct_size(controller, chips, info->nce), + GFP_KERNEL); if (!controller) return -ENOMEM; controller->info = info; diff --git a/drivers/net/can/peak_canfd/peak_pciefd_main.c b/drivers/net/can/peak_canfd/peak_pciefd_main.c index 3c51a88..b9e2857 100644 --- a/drivers/net/can/peak_canfd/peak_pciefd_main.c +++ b/drivers/net/can/peak_canfd/peak_pciefd_main.c @@ -752,8 +752,7 @@ static int peak_pciefd_probe(struct pci_dev *pdev, can_count = 1; /* allocate board structure object */ - pciefd = devm_kzalloc(&pdev->dev, sizeof(*pciefd) + - can_count * sizeof(*pciefd->can), + pciefd = devm_kzalloc(&pdev->dev, struct_size(pciefd, can, can_count), GFP_KERNEL); if (!pciefd) { err = -ENOMEM; diff --git a/drivers/net/ethernet/mellanox/mlx5/core/debugfs.c b/drivers/net/ethernet/mellanox/mlx5/core/debugfs.c index 7ecadb5..413080a 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/debugfs.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/debugfs.c @@ -494,7 +494,7 @@ static int add_res_tree(struct mlx5_core_dev *dev, enum dbg_rsc_type type, int err; int i; - d = kzalloc(sizeof(*d) + nfile * sizeof(d->fields[0]), GFP_KERNEL); + d = kzalloc(struct_size(d, fields, nfile), GFP_KERNEL); if (!d) return -ENOMEM; diff --git a/drivers/net/ethernet/mellanox/mlx5/core/fs_core.c b/drivers/net/ethernet/mellanox/mlx5/core/fs_core.c index c39c169..56e2751 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/fs_core.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/fs_core.c @@ -1191,8 +1191,7 @@ static struct mlx5_flow_handle *alloc_handle(int num_rules) { struct mlx5_flow_handle *handle; - handle = kzalloc(sizeof(*handle) + sizeof(handle->rule[0]) * - num_rules, GFP_KERNEL); + handle = kzalloc(struct_size(handle, rule, num_rules), GFP_KERNEL); if (!handle) return NULL; diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c index 90f8c89..9b2e1cb 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c @@ -2987,9 +2987,8 @@ static int iwl_mvm_mac_set_key(struct ieee80211_hw *hw, mvmsta = iwl_mvm_sta_from_mac80211(sta); WARN_ON(rcu_access_pointer(mvmsta->ptk_pn[keyidx])); - ptk_pn = kzalloc(sizeof(*ptk_pn) + - mvm->trans->num_rx_queues * - sizeof(ptk_pn->q[0]), + ptk_pn = kzalloc(struct_size(ptk_pn, q, + mvm->trans->num_rx_queues), GFP_KERNEL); if (!ptk_pn) { ret = -ENOMEM; diff --git a/drivers/net/wireless/mediatek/mt76/agg-rx.c b/drivers/net/wireless/mediatek/mt76/agg-rx.c index fcb208d..89c7d8c 100644 --- a/drivers/net/wireless/mediatek/mt76/agg-rx.c +++ b/drivers/net/wireless/mediatek/mt76/agg-rx.c @@ -236,8 +236,7 @@ int mt76_rx_aggr_start(struct mt76_dev *dev, struct mt76_wcid *wcid, u8 tidno, mt76_rx_aggr_stop(dev, wcid, tidno); - tid = kzalloc(sizeof(*tid) + size * sizeof(tid->reorder_buf[0]), - GFP_KERNEL); + tid = kzalloc(struct_size(tid, reorder_buf, size), GFP_KERNEL); if (!tid) return -ENOMEM; diff --git a/drivers/pinctrl/samsung/pinctrl-s3c64xx.c b/drivers/pinctrl/samsung/pinctrl-s3c64xx.c index 288e656..c399f09 100644 --- a/drivers/pinctrl/samsung/pinctrl-s3c64xx.c +++ b/drivers/pinctrl/samsung/pinctrl-s3c64xx.c @@ -483,8 +483,8 @@ static int s3c64xx_eint_gpio_init(struct samsung_pinctrl_drv_data *d) ++nr_domains; } - data = devm_kzalloc(dev, sizeof(*data) - + nr_domains * sizeof(*data->domains), GFP_KERNEL); + data = devm_kzalloc(dev, struct_size(data, domains, nr_domains), + GFP_KERNEL); if (!data) return -ENOMEM; data->drvdata = d; diff --git a/drivers/pinctrl/uniphier/pinctrl-uniphier-core.c b/drivers/pinctrl/uniphier/pinctrl-uniphier-core.c index ec0f77a..add8e87 100644 --- a/drivers/pinctrl/uniphier/pinctrl-uniphier-core.c +++ b/drivers/pinctrl/uniphier/pinctrl-uniphier-core.c @@ -759,8 +759,7 @@ static int uniphier_pinctrl_add_reg_region(struct device *dev, nregs = DIV_ROUND_UP(count * width, 32); - region = devm_kzalloc(dev, - sizeof(*region) + sizeof(region->vals[0]) * nregs, + region = devm_kzalloc(dev, struct_size(region, vals, nregs), GFP_KERNEL); if (!region) return -ENOMEM; diff --git a/drivers/regulator/mc13783-regulator.c b/drivers/regulator/mc13783-regulator.c index fe4c7d6..0e0277b 100644 --- a/drivers/regulator/mc13783-regulator.c +++ b/drivers/regulator/mc13783-regulator.c @@ -409,9 +409,9 @@ static int mc13783_regulator_probe(struct platform_device *pdev) if (num_regulators <= 0) return -EINVAL; - priv = devm_kzalloc(&pdev->dev, sizeof(*priv) + - num_regulators * sizeof(priv->regulators[0]), - GFP_KERNEL); + priv = devm_kzalloc(&pdev->dev, + struct_size(priv, regulators, num_regulators), + GFP_KERNEL); if (!priv) return -ENOMEM; diff --git a/drivers/regulator/mc13892-regulator.c b/drivers/regulator/mc13892-regulator.c index 0d17c92..15dd7bc 100644 --- a/drivers/regulator/mc13892-regulator.c +++ b/drivers/regulator/mc13892-regulator.c @@ -547,9 +547,9 @@ static int mc13892_regulator_probe(struct platform_device *pdev) if (num_regulators <= 0) return -EINVAL; - priv = devm_kzalloc(&pdev->dev, sizeof(*priv) + - num_regulators * sizeof(priv->regulators[0]), - GFP_KERNEL); + priv = devm_kzalloc(&pdev->dev, + struct_size(priv, regulators, num_regulators), + GFP_KERNEL); if (!priv) return -ENOMEM; diff --git a/drivers/reset/core.c b/drivers/reset/core.c index 6488292..225e34c 100644 --- a/drivers/reset/core.c +++ b/drivers/reset/core.c @@ -730,8 +730,7 @@ of_reset_control_array_get(struct device_node *np, bool shared, bool optional) if (num < 0) return optional ? NULL : ERR_PTR(num); - resets = kzalloc(sizeof(*resets) + sizeof(resets->rstc[0]) * num, - GFP_KERNEL); + resets = kzalloc(struct_size(resets, rstc, num), GFP_KERNEL); if (!resets) return ERR_PTR(-ENOMEM); diff --git a/drivers/rtc/rtc-ac100.c b/drivers/rtc/rtc-ac100.c index 3fe576f..784b676 100644 --- a/drivers/rtc/rtc-ac100.c +++ b/drivers/rtc/rtc-ac100.c @@ -317,10 +317,10 @@ static int ac100_rtc_register_clks(struct ac100_rtc_dev *chip) const char *parents[2] = {AC100_RTC_32K_NAME}; int i, ret; - chip->clk_data = devm_kzalloc(chip->dev, sizeof(*chip->clk_data) + - sizeof(*chip->clk_data->hws) * - AC100_CLKOUT_NUM, - GFP_KERNEL); + chip->clk_data = devm_kzalloc(chip->dev, + struct_size(chip->clk_data, hws, + AC100_CLKOUT_NUM), + GFP_KERNEL); if (!chip->clk_data) return -ENOMEM; diff --git a/drivers/s390/cio/ccwgroup.c b/drivers/s390/cio/ccwgroup.c index db9c854..93b2862 100644 --- a/drivers/s390/cio/ccwgroup.c +++ b/drivers/s390/cio/ccwgroup.c @@ -326,8 +326,7 @@ int ccwgroup_create_dev(struct device *parent, struct ccwgroup_driver *gdrv, if (num_devices < 1) return -EINVAL; - gdev = kzalloc(sizeof(*gdev) + num_devices * sizeof(gdev->cdev[0]), - GFP_KERNEL); + gdev = kzalloc(struct_size(gdev, cdev, num_devices), GFP_KERNEL); if (!gdev) return -ENOMEM; diff --git a/drivers/soc/actions/owl-sps.c b/drivers/soc/actions/owl-sps.c index 8477f0f..032921d 100644 --- a/drivers/soc/actions/owl-sps.c +++ b/drivers/soc/actions/owl-sps.c @@ -117,8 +117,8 @@ static int owl_sps_probe(struct platform_device *pdev) sps_info = match->data; - sps = devm_kzalloc(&pdev->dev, sizeof(*sps) + - sps_info->num_domains * sizeof(sps->domains[0]), + sps = devm_kzalloc(&pdev->dev, + struct_size(sps, domains, sps_info->num_domains), GFP_KERNEL); if (!sps) return -ENOMEM; diff --git a/drivers/soc/rockchip/pm_domains.c b/drivers/soc/rockchip/pm_domains.c index 53efc38..111c44f 100644 --- a/drivers/soc/rockchip/pm_domains.c +++ b/drivers/soc/rockchip/pm_domains.c @@ -626,8 +626,7 @@ static int rockchip_pm_domain_probe(struct platform_device *pdev) pmu_info = match->data; pmu = devm_kzalloc(dev, - sizeof(*pmu) + - pmu_info->num_domains * sizeof(pmu->domains[0]), + struct_size(pmu, domains, pmu_info->num_domains), GFP_KERNEL); if (!pmu) return -ENOMEM; diff --git a/drivers/staging/greybus/module.c b/drivers/staging/greybus/module.c index b785382..894d02e 100644 --- a/drivers/staging/greybus/module.c +++ b/drivers/staging/greybus/module.c @@ -94,8 +94,8 @@ struct gb_module *gb_module_create(struct gb_host_device *hd, u8 module_id, struct gb_module *module; int i; - module = kzalloc(sizeof(*module) + num_interfaces * sizeof(intf), - GFP_KERNEL); + module = kzalloc(struct_size(module, interfaces, num_interfaces), + GFP_KERNEL); if (!module) return NULL; diff --git a/drivers/thermal/qcom/tsens.c b/drivers/thermal/qcom/tsens.c index 3f9fe6a..c2c3442 100644 --- a/drivers/thermal/qcom/tsens.c +++ b/drivers/thermal/qcom/tsens.c @@ -112,7 +112,6 @@ static int tsens_probe(struct platform_device *pdev) int ret, i; struct device *dev; struct device_node *np; - struct tsens_sensor *s; struct tsens_device *tmdev; const struct tsens_data *data; const struct of_device_id *id; @@ -135,8 +134,9 @@ static int tsens_probe(struct platform_device *pdev) return -EINVAL; } - tmdev = devm_kzalloc(dev, sizeof(*tmdev) + - data->num_sensors * sizeof(*s), GFP_KERNEL); + tmdev = devm_kzalloc(dev, + struct_size(tmdev, sensor, data->num_sensors), + GFP_KERNEL); if (!tmdev) return -ENOMEM; diff --git a/drivers/usb/gadget/function/f_midi.c b/drivers/usb/gadget/function/f_midi.c index f806997..46af0aa 100644 --- a/drivers/usb/gadget/function/f_midi.c +++ b/drivers/usb/gadget/function/f_midi.c @@ -1301,9 +1301,8 @@ static struct usb_function *f_midi_alloc(struct usb_function_instance *fi) } /* allocate and initialize one new instance */ - midi = kzalloc( - sizeof(*midi) + opts->in_ports * sizeof(*midi->in_ports_array), - GFP_KERNEL); + midi = kzalloc(struct_size(midi, in_ports_array, opts->in_ports), + GFP_KERNEL); if (!midi) { status = -ENOMEM; goto setup_fail; diff --git a/drivers/zorro/zorro.c b/drivers/zorro/zorro.c index 67fa900..8eeb84c 100644 --- a/drivers/zorro/zorro.c +++ b/drivers/zorro/zorro.c @@ -138,8 +138,7 @@ static int __init amiga_zorro_probe(struct platform_device *pdev) int error; /* Initialize the Zorro bus */ - bus = kzalloc(sizeof(*bus) + - zorro_num_autocon * sizeof(bus->devices[0]), + bus = kzalloc(struct_size(bus, devices, zorro_num_autocon), GFP_KERNEL); if (!bus) return -ENOMEM; diff --git a/fs/afs/addr_list.c b/fs/afs/addr_list.c index 7587fb6..2c46c46 100644 --- a/fs/afs/addr_list.c +++ b/fs/afs/addr_list.c @@ -43,8 +43,7 @@ struct afs_addr_list *afs_alloc_addrlist(unsigned int nr, _enter("%u,%u,%u", nr, service, port); - alist = kzalloc(sizeof(*alist) + sizeof(alist->addrs[0]) * nr, - GFP_KERNEL); + alist = kzalloc(struct_size(alist, addrs, nr), GFP_KERNEL); if (!alist) return NULL; diff --git a/include/linux/compiler-clang.h b/include/linux/compiler-clang.h index 7d98e26..7087446c 100644 --- a/include/linux/compiler-clang.h +++ b/include/linux/compiler-clang.h @@ -32,3 +32,17 @@ #ifdef __noretpoline #undef __noretpoline #endif + +/* + * Not all versions of clang implement the the type-generic versions + * of the builtin overflow checkers. Fortunately, clang implements + * __has_builtin allowing us to avoid awkward version + * checks. Unfortunately, we don't know which version of gcc clang + * pretends to be, so the macro may or may not be defined. + */ +#undef COMPILER_HAS_GENERIC_BUILTIN_OVERFLOW +#if __has_builtin(__builtin_mul_overflow) && \ + __has_builtin(__builtin_add_overflow) && \ + __has_builtin(__builtin_sub_overflow) +#define COMPILER_HAS_GENERIC_BUILTIN_OVERFLOW 1 +#endif diff --git a/include/linux/compiler-gcc.h b/include/linux/compiler-gcc.h index b4bf73f..f1a7492 100644 --- a/include/linux/compiler-gcc.h +++ b/include/linux/compiler-gcc.h @@ -343,3 +343,7 @@ * code */ #define uninitialized_var(x) x = x + +#if GCC_VERSION >= 50100 +#define COMPILER_HAS_GENERIC_BUILTIN_OVERFLOW 1 +#endif diff --git a/include/linux/compiler-intel.h b/include/linux/compiler-intel.h index bfa0816..547cdc9 100644 --- a/include/linux/compiler-intel.h +++ b/include/linux/compiler-intel.h @@ -44,3 +44,7 @@ #define __builtin_bswap16 _bswap16 #endif +/* + * icc defines __GNUC__, but does not implement the builtin overflow checkers. + */ +#undef COMPILER_HAS_GENERIC_BUILTIN_OVERFLOW diff --git a/include/linux/device.h b/include/linux/device.h index e9d4b43..055a69d 100644 --- a/include/linux/device.h +++ b/include/linux/device.h @@ -25,6 +25,7 @@ #include <linux/ratelimit.h> #include <linux/uidgid.h> #include <linux/gfp.h> +#include <linux/overflow.h> #include <asm/device.h> struct device; @@ -672,9 +673,12 @@ static inline void *devm_kzalloc(struct device *dev, size_t size, gfp_t gfp) static inline void *devm_kmalloc_array(struct device *dev, size_t n, size_t size, gfp_t flags) { - if (size != 0 && n > SIZE_MAX / size) + size_t bytes; + + if (unlikely(check_mul_overflow(n, size, &bytes))) return NULL; - return devm_kmalloc(dev, n * size, flags); + + return devm_kmalloc(dev, bytes, flags); } static inline void *devm_kcalloc(struct device *dev, size_t n, size_t size, gfp_t flags) diff --git a/include/linux/mm.h b/include/linux/mm.h index 02a616e..611f19d 100644 --- a/include/linux/mm.h +++ b/include/linux/mm.h @@ -25,6 +25,7 @@ #include <linux/err.h> #include <linux/page_ref.h> #include <linux/memremap.h> +#include <linux/overflow.h> struct mempolicy; struct anon_vma; @@ -560,10 +561,12 @@ static inline void *kvzalloc(size_t size, gfp_t flags) static inline void *kvmalloc_array(size_t n, size_t size, gfp_t flags) { - if (size != 0 && n > SIZE_MAX / size) + size_t bytes; + + if (unlikely(check_mul_overflow(n, size, &bytes))) return NULL; - return kvmalloc(n * size, flags); + return kvmalloc(bytes, flags); } extern void kvfree(const void *addr); diff --git a/include/linux/overflow.h b/include/linux/overflow.h new file mode 100644 index 0000000..8712ff7 --- /dev/null +++ b/include/linux/overflow.h @@ -0,0 +1,278 @@ +/* SPDX-License-Identifier: GPL-2.0 OR MIT */ +#ifndef __LINUX_OVERFLOW_H +#define __LINUX_OVERFLOW_H + +#include <linux/compiler.h> + +/* + * In the fallback code below, we need to compute the minimum and + * maximum values representable in a given type. These macros may also + * be useful elsewhere, so we provide them outside the + * COMPILER_HAS_GENERIC_BUILTIN_OVERFLOW block. + * + * It would seem more obvious to do something like + * + * #define type_min(T) (T)(is_signed_type(T) ? (T)1 << (8*sizeof(T)-1) : 0) + * #define type_max(T) (T)(is_signed_type(T) ? ((T)1 << (8*sizeof(T)-1)) - 1 : ~(T)0) + * + * Unfortunately, the middle expressions, strictly speaking, have + * undefined behaviour, and at least some versions of gcc warn about + * the type_max expression (but not if -fsanitize=undefined is in + * effect; in that case, the warning is deferred to runtime...). + * + * The slightly excessive casting in type_min is to make sure the + * macros also produce sensible values for the exotic type _Bool. [The + * overflow checkers only almost work for _Bool, but that's + * a-feature-not-a-bug, since people shouldn't be doing arithmetic on + * _Bools. Besides, the gcc builtins don't allow _Bool* as third + * argument.] + * + * Idea stolen from + * https://mail-index.netbsd.org/tech-misc/2007/02/05/0000.html - + * credit to Christian Biere. + */ +#define is_signed_type(type) (((type)(-1)) < (type)1) +#define __type_half_max(type) ((type)1 << (8*sizeof(type) - 1 - is_signed_type(type))) +#define type_max(T) ((T)((__type_half_max(T) - 1) + __type_half_max(T))) +#define type_min(T) ((T)((T)-type_max(T)-(T)1)) + + +#ifdef COMPILER_HAS_GENERIC_BUILTIN_OVERFLOW +/* + * For simplicity and code hygiene, the fallback code below insists on + * a, b and *d having the same type (similar to the min() and max() + * macros), whereas gcc's type-generic overflow checkers accept + * different types. Hence we don't just make check_add_overflow an + * alias for __builtin_add_overflow, but add type checks similar to + * below. + */ +#define check_add_overflow(a, b, d) ({ \ + typeof(a) __a = (a); \ + typeof(b) __b = (b); \ + typeof(d) __d = (d); \ + (void) (&__a == &__b); \ + (void) (&__a == __d); \ + __builtin_add_overflow(__a, __b, __d); \ +}) + +#define check_sub_overflow(a, b, d) ({ \ + typeof(a) __a = (a); \ + typeof(b) __b = (b); \ + typeof(d) __d = (d); \ + (void) (&__a == &__b); \ + (void) (&__a == __d); \ + __builtin_sub_overflow(__a, __b, __d); \ +}) + +#define check_mul_overflow(a, b, d) ({ \ + typeof(a) __a = (a); \ + typeof(b) __b = (b); \ + typeof(d) __d = (d); \ + (void) (&__a == &__b); \ + (void) (&__a == __d); \ + __builtin_mul_overflow(__a, __b, __d); \ +}) + +#else + + +/* Checking for unsigned overflow is relatively easy without causing UB. */ +#define __unsigned_add_overflow(a, b, d) ({ \ + typeof(a) __a = (a); \ + typeof(b) __b = (b); \ + typeof(d) __d = (d); \ + (void) (&__a == &__b); \ + (void) (&__a == __d); \ + *__d = __a + __b; \ + *__d < __a; \ +}) +#define __unsigned_sub_overflow(a, b, d) ({ \ + typeof(a) __a = (a); \ + typeof(b) __b = (b); \ + typeof(d) __d = (d); \ + (void) (&__a == &__b); \ + (void) (&__a == __d); \ + *__d = __a - __b; \ + __a < __b; \ +}) +/* + * If one of a or b is a compile-time constant, this avoids a division. + */ +#define __unsigned_mul_overflow(a, b, d) ({ \ + typeof(a) __a = (a); \ + typeof(b) __b = (b); \ + typeof(d) __d = (d); \ + (void) (&__a == &__b); \ + (void) (&__a == __d); \ + *__d = __a * __b; \ + __builtin_constant_p(__b) ? \ + __b > 0 && __a > type_max(typeof(__a)) / __b : \ + __a > 0 && __b > type_max(typeof(__b)) / __a; \ +}) + +/* + * For signed types, detecting overflow is much harder, especially if + * we want to avoid UB. But the interface of these macros is such that + * we must provide a result in *d, and in fact we must produce the + * result promised by gcc's builtins, which is simply the possibly + * wrapped-around value. Fortunately, we can just formally do the + * operations in the widest relevant unsigned type (u64) and then + * truncate the result - gcc is smart enough to generate the same code + * with and without the (u64) casts. + */ + +/* + * Adding two signed integers can overflow only if they have the same + * sign, and overflow has happened iff the result has the opposite + * sign. + */ +#define __signed_add_overflow(a, b, d) ({ \ + typeof(a) __a = (a); \ + typeof(b) __b = (b); \ + typeof(d) __d = (d); \ + (void) (&__a == &__b); \ + (void) (&__a == __d); \ + *__d = (u64)__a + (u64)__b; \ + (((~(__a ^ __b)) & (*__d ^ __a)) \ + & type_min(typeof(__a))) != 0; \ +}) + +/* + * Subtraction is similar, except that overflow can now happen only + * when the signs are opposite. In this case, overflow has happened if + * the result has the opposite sign of a. + */ +#define __signed_sub_overflow(a, b, d) ({ \ + typeof(a) __a = (a); \ + typeof(b) __b = (b); \ + typeof(d) __d = (d); \ + (void) (&__a == &__b); \ + (void) (&__a == __d); \ + *__d = (u64)__a - (u64)__b; \ + ((((__a ^ __b)) & (*__d ^ __a)) \ + & type_min(typeof(__a))) != 0; \ +}) + +/* + * Signed multiplication is rather hard. gcc always follows C99, so + * division is truncated towards 0. This means that we can write the + * overflow check like this: + * + * (a > 0 && (b > MAX/a || b < MIN/a)) || + * (a < -1 && (b > MIN/a || b < MAX/a) || + * (a == -1 && b == MIN) + * + * The redundant casts of -1 are to silence an annoying -Wtype-limits + * (included in -Wextra) warning: When the type is u8 or u16, the + * __b_c_e in check_mul_overflow obviously selects + * __unsigned_mul_overflow, but unfortunately gcc still parses this + * code and warns about the limited range of __b. + */ + +#define __signed_mul_overflow(a, b, d) ({ \ + typeof(a) __a = (a); \ + typeof(b) __b = (b); \ + typeof(d) __d = (d); \ + typeof(a) __tmax = type_max(typeof(a)); \ + typeof(a) __tmin = type_min(typeof(a)); \ + (void) (&__a == &__b); \ + (void) (&__a == __d); \ + *__d = (u64)__a * (u64)__b; \ + (__b > 0 && (__a > __tmax/__b || __a < __tmin/__b)) || \ + (__b < (typeof(__b))-1 && (__a > __tmin/__b || __a < __tmax/__b)) || \ + (__b == (typeof(__b))-1 && __a == __tmin); \ +}) + + +#define check_add_overflow(a, b, d) \ + __builtin_choose_expr(is_signed_type(typeof(a)), \ + __signed_add_overflow(a, b, d), \ + __unsigned_add_overflow(a, b, d)) + +#define check_sub_overflow(a, b, d) \ + __builtin_choose_expr(is_signed_type(typeof(a)), \ + __signed_sub_overflow(a, b, d), \ + __unsigned_sub_overflow(a, b, d)) + +#define check_mul_overflow(a, b, d) \ + __builtin_choose_expr(is_signed_type(typeof(a)), \ + __signed_mul_overflow(a, b, d), \ + __unsigned_mul_overflow(a, b, d)) + + +#endif /* COMPILER_HAS_GENERIC_BUILTIN_OVERFLOW */ + +/** + * array_size() - Calculate size of 2-dimensional array. + * + * @a: dimension one + * @b: dimension two + * + * Calculates size of 2-dimensional array: @a * @b. + * + * Returns: number of bytes needed to represent the array or SIZE_MAX on + * overflow. + */ +static inline __must_check size_t array_size(size_t a, size_t b) +{ + size_t bytes; + + if (check_mul_overflow(a, b, &bytes)) + return SIZE_MAX; + + return bytes; +} + +/** + * array3_size() - Calculate size of 3-dimensional array. + * + * @a: dimension one + * @b: dimension two + * @c: dimension three + * + * Calculates size of 3-dimensional array: @a * @b * @c. + * + * Returns: number of bytes needed to represent the array or SIZE_MAX on + * overflow. + */ +static inline __must_check size_t array3_size(size_t a, size_t b, size_t c) +{ + size_t bytes; + + if (check_mul_overflow(a, b, &bytes)) + return SIZE_MAX; + if (check_mul_overflow(bytes, c, &bytes)) + return SIZE_MAX; + + return bytes; +} + +static inline __must_check size_t __ab_c_size(size_t n, size_t size, size_t c) +{ + size_t bytes; + + if (check_mul_overflow(n, size, &bytes)) + return SIZE_MAX; + if (check_add_overflow(bytes, c, &bytes)) + return SIZE_MAX; + + return bytes; +} + +/** + * struct_size() - Calculate size of structure with trailing array. + * @p: Pointer to the structure. + * @member: Name of the array member. + * @n: Number of elements in the array. + * + * Calculates size of memory needed for structure @p followed by an + * array of @n @member elements. + * + * Return: number of bytes needed or SIZE_MAX on overflow. + */ +#define struct_size(p, member, n) \ + __ab_c_size(n, \ + sizeof(*(p)->member) + __must_be_array((p)->member),\ + sizeof(*(p))) + +#endif /* __LINUX_OVERFLOW_H */ diff --git a/include/linux/slab.h b/include/linux/slab.h index 81ebd71..4d759e1 100644 --- a/include/linux/slab.h +++ b/include/linux/slab.h @@ -13,6 +13,7 @@ #define _LINUX_SLAB_H #include <linux/gfp.h> +#include <linux/overflow.h> #include <linux/types.h> #include <linux/workqueue.h> @@ -624,11 +625,13 @@ int memcg_update_all_caches(int num_memcgs); */ static inline void *kmalloc_array(size_t n, size_t size, gfp_t flags) { - if (size != 0 && n > SIZE_MAX / size) + size_t bytes; + + if (unlikely(check_mul_overflow(n, size, &bytes))) return NULL; if (__builtin_constant_p(n) && __builtin_constant_p(size)) - return kmalloc(n * size, flags); - return __kmalloc(n * size, flags); + return kmalloc(bytes, flags); + return __kmalloc(bytes, flags); } /** @@ -657,11 +660,13 @@ extern void *__kmalloc_track_caller(size_t, gfp_t, unsigned long); static inline void *kmalloc_array_node(size_t n, size_t size, gfp_t flags, int node) { - if (size != 0 && n > SIZE_MAX / size) + size_t bytes; + + if (unlikely(check_mul_overflow(n, size, &bytes))) return NULL; if (__builtin_constant_p(n) && __builtin_constant_p(size)) - return kmalloc_node(n * size, flags, node); - return __kmalloc_node(n * size, flags, node); + return kmalloc_node(bytes, flags, node); + return __kmalloc_node(bytes, flags, node); } static inline void *kcalloc_node(size_t n, size_t size, gfp_t flags, int node) diff --git a/include/linux/vmalloc.h b/include/linux/vmalloc.h index 1e5d8c3..398e9c9 100644 --- a/include/linux/vmalloc.h +++ b/include/linux/vmalloc.h @@ -8,6 +8,7 @@ #include <linux/llist.h> #include <asm/page.h> /* pgprot_t */ #include <linux/rbtree.h> +#include <linux/overflow.h> struct vm_area_struct; /* vma defining user mapping in mm_types.h */ struct notifier_block; /* in notifier.h */ diff --git a/kernel/cgroup/cgroup.c b/kernel/cgroup/cgroup.c index acb66713..077370b 100644 --- a/kernel/cgroup/cgroup.c +++ b/kernel/cgroup/cgroup.c @@ -4820,8 +4820,8 @@ static struct cgroup *cgroup_create(struct cgroup *parent) int ret; /* allocate the cgroup and its ID, 0 is reserved for the root */ - cgrp = kzalloc(sizeof(*cgrp) + - sizeof(cgrp->ancestor_ids[0]) * (level + 1), GFP_KERNEL); + cgrp = kzalloc(struct_size(cgrp, ancestor_ids, (level + 1)), + GFP_KERNEL); if (!cgrp) return ERR_PTR(-ENOMEM); diff --git a/kernel/module.c b/kernel/module.c index c9bea7f..68469b3 100644 --- a/kernel/module.c +++ b/kernel/module.c @@ -1604,8 +1604,7 @@ static void add_notes_attrs(struct module *mod, const struct load_info *info) if (notes == 0) return; - notes_attrs = kzalloc(sizeof(*notes_attrs) - + notes * sizeof(notes_attrs->attrs[0]), + notes_attrs = kzalloc(struct_size(notes_attrs, attrs, notes), GFP_KERNEL); if (notes_attrs == NULL) return; diff --git a/kernel/workqueue.c b/kernel/workqueue.c index 7ea7552..9f9983b 100644 --- a/kernel/workqueue.c +++ b/kernel/workqueue.c @@ -3714,8 +3714,7 @@ apply_wqattrs_prepare(struct workqueue_struct *wq, lockdep_assert_held(&wq_pool_mutex); - ctx = kzalloc(sizeof(*ctx) + nr_node_ids * sizeof(ctx->pwq_tbl[0]), - GFP_KERNEL); + ctx = kzalloc(struct_size(ctx, pwq_tbl, nr_node_ids), GFP_KERNEL); new_attrs = alloc_workqueue_attrs(GFP_KERNEL); tmp_attrs = alloc_workqueue_attrs(GFP_KERNEL); diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug index 7655547..eb885942 100644 --- a/lib/Kconfig.debug +++ b/lib/Kconfig.debug @@ -1802,6 +1802,9 @@ config TEST_BITMAP config TEST_UUID tristate "Test functions located in the uuid module at runtime" +config TEST_OVERFLOW + tristate "Test check_*_overflow() functions at runtime" + config TEST_RHASHTABLE tristate "Perform selftest on resizable hash table" default n diff --git a/lib/Makefile b/lib/Makefile index 9f18c81..84c6dcb 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -60,6 +60,7 @@ UBSAN_SANITIZE_test_ubsan.o := y obj-$(CONFIG_TEST_KSTRTOX) += test-kstrtox.o obj-$(CONFIG_TEST_LIST_SORT) += test_list_sort.o obj-$(CONFIG_TEST_LKM) += test_module.o +obj-$(CONFIG_TEST_OVERFLOW) += test_overflow.o obj-$(CONFIG_TEST_RHASHTABLE) += test_rhashtable.o obj-$(CONFIG_TEST_SORT) += test_sort.o obj-$(CONFIG_TEST_USER_COPY) += test_user_copy.o diff --git a/lib/test_overflow.c b/lib/test_overflow.c new file mode 100644 index 0000000..aecbbb2 --- /dev/null +++ b/lib/test_overflow.c @@ -0,0 +1,417 @@ +// SPDX-License-Identifier: GPL-2.0 OR MIT +/* + * Test cases for arithmetic overflow checks. + */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include <linux/device.h> +#include <linux/init.h> +#include <linux/kernel.h> +#include <linux/mm.h> +#include <linux/module.h> +#include <linux/overflow.h> +#include <linux/slab.h> +#include <linux/types.h> +#include <linux/vmalloc.h> + +#define DEFINE_TEST_ARRAY(t) \ + static const struct test_ ## t { \ + t a, b; \ + t sum, diff, prod; \ + bool s_of, d_of, p_of; \ + } t ## _tests[] __initconst + +DEFINE_TEST_ARRAY(u8) = { + {0, 0, 0, 0, 0, false, false, false}, + {1, 1, 2, 0, 1, false, false, false}, + {0, 1, 1, U8_MAX, 0, false, true, false}, + {1, 0, 1, 1, 0, false, false, false}, + {0, U8_MAX, U8_MAX, 1, 0, false, true, false}, + {U8_MAX, 0, U8_MAX, U8_MAX, 0, false, false, false}, + {1, U8_MAX, 0, 2, U8_MAX, true, true, false}, + {U8_MAX, 1, 0, U8_MAX-1, U8_MAX, true, false, false}, + {U8_MAX, U8_MAX, U8_MAX-1, 0, 1, true, false, true}, + + {U8_MAX, U8_MAX-1, U8_MAX-2, 1, 2, true, false, true}, + {U8_MAX-1, U8_MAX, U8_MAX-2, U8_MAX, 2, true, true, true}, + + {1U << 3, 1U << 3, 1U << 4, 0, 1U << 6, false, false, false}, + {1U << 4, 1U << 4, 1U << 5, 0, 0, false, false, true}, + {1U << 4, 1U << 3, 3*(1U << 3), 1U << 3, 1U << 7, false, false, false}, + {1U << 7, 1U << 7, 0, 0, 0, true, false, true}, + + {48, 32, 80, 16, 0, false, false, true}, + {128, 128, 0, 0, 0, true, false, true}, + {123, 234, 101, 145, 110, true, true, true}, +}; +DEFINE_TEST_ARRAY(u16) = { + {0, 0, 0, 0, 0, false, false, false}, + {1, 1, 2, 0, 1, false, false, false}, + {0, 1, 1, U16_MAX, 0, false, true, false}, + {1, 0, 1, 1, 0, false, false, false}, + {0, U16_MAX, U16_MAX, 1, 0, false, true, false}, + {U16_MAX, 0, U16_MAX, U16_MAX, 0, false, false, false}, + {1, U16_MAX, 0, 2, U16_MAX, true, true, false}, + {U16_MAX, 1, 0, U16_MAX-1, U16_MAX, true, false, false}, + {U16_MAX, U16_MAX, U16_MAX-1, 0, 1, true, false, true}, + + {U16_MAX, U16_MAX-1, U16_MAX-2, 1, 2, true, false, true}, + {U16_MAX-1, U16_MAX, U16_MAX-2, U16_MAX, 2, true, true, true}, + + {1U << 7, 1U << 7, 1U << 8, 0, 1U << 14, false, false, false}, + {1U << 8, 1U << 8, 1U << 9, 0, 0, false, false, true}, + {1U << 8, 1U << 7, 3*(1U << 7), 1U << 7, 1U << 15, false, false, false}, + {1U << 15, 1U << 15, 0, 0, 0, true, false, true}, + + {123, 234, 357, 65425, 28782, false, true, false}, + {1234, 2345, 3579, 64425, 10146, false, true, true}, +}; +DEFINE_TEST_ARRAY(u32) = { + {0, 0, 0, 0, 0, false, false, false}, + {1, 1, 2, 0, 1, false, false, false}, + {0, 1, 1, U32_MAX, 0, false, true, false}, + {1, 0, 1, 1, 0, false, false, false}, + {0, U32_MAX, U32_MAX, 1, 0, false, true, false}, + {U32_MAX, 0, U32_MAX, U32_MAX, 0, false, false, false}, + {1, U32_MAX, 0, 2, U32_MAX, true, true, false}, + {U32_MAX, 1, 0, U32_MAX-1, U32_MAX, true, false, false}, + {U32_MAX, U32_MAX, U32_MAX-1, 0, 1, true, false, true}, + + {U32_MAX, U32_MAX-1, U32_MAX-2, 1, 2, true, false, true}, + {U32_MAX-1, U32_MAX, U32_MAX-2, U32_MAX, 2, true, true, true}, + + {1U << 15, 1U << 15, 1U << 16, 0, 1U << 30, false, false, false}, + {1U << 16, 1U << 16, 1U << 17, 0, 0, false, false, true}, + {1U << 16, 1U << 15, 3*(1U << 15), 1U << 15, 1U << 31, false, false, false}, + {1U << 31, 1U << 31, 0, 0, 0, true, false, true}, + + {-2U, 1U, -1U, -3U, -2U, false, false, false}, + {-4U, 5U, 1U, -9U, -20U, true, false, true}, +}; + +DEFINE_TEST_ARRAY(u64) = { + {0, 0, 0, 0, 0, false, false, false}, + {1, 1, 2, 0, 1, false, false, false}, + {0, 1, 1, U64_MAX, 0, false, true, false}, + {1, 0, 1, 1, 0, false, false, false}, + {0, U64_MAX, U64_MAX, 1, 0, false, true, false}, + {U64_MAX, 0, U64_MAX, U64_MAX, 0, false, false, false}, + {1, U64_MAX, 0, 2, U64_MAX, true, true, false}, + {U64_MAX, 1, 0, U64_MAX-1, U64_MAX, true, false, false}, + {U64_MAX, U64_MAX, U64_MAX-1, 0, 1, true, false, true}, + + {U64_MAX, U64_MAX-1, U64_MAX-2, 1, 2, true, false, true}, + {U64_MAX-1, U64_MAX, U64_MAX-2, U64_MAX, 2, true, true, true}, + + {1ULL << 31, 1ULL << 31, 1ULL << 32, 0, 1ULL << 62, false, false, false}, + {1ULL << 32, 1ULL << 32, 1ULL << 33, 0, 0, false, false, true}, + {1ULL << 32, 1ULL << 31, 3*(1ULL << 31), 1ULL << 31, 1ULL << 63, false, false, false}, + {1ULL << 63, 1ULL << 63, 0, 0, 0, true, false, true}, + {1000000000ULL /* 10^9 */, 10000000000ULL /* 10^10 */, + 11000000000ULL, 18446744064709551616ULL, 10000000000000000000ULL, + false, true, false}, + {-15ULL, 10ULL, -5ULL, -25ULL, -150ULL, false, false, true}, +}; + +DEFINE_TEST_ARRAY(s8) = { + {0, 0, 0, 0, 0, false, false, false}, + + {0, S8_MAX, S8_MAX, -S8_MAX, 0, false, false, false}, + {S8_MAX, 0, S8_MAX, S8_MAX, 0, false, false, false}, + {0, S8_MIN, S8_MIN, S8_MIN, 0, false, true, false}, + {S8_MIN, 0, S8_MIN, S8_MIN, 0, false, false, false}, + + {-1, S8_MIN, S8_MAX, S8_MAX, S8_MIN, true, false, true}, + {S8_MIN, -1, S8_MAX, -S8_MAX, S8_MIN, true, false, true}, + {-1, S8_MAX, S8_MAX-1, S8_MIN, -S8_MAX, false, false, false}, + {S8_MAX, -1, S8_MAX-1, S8_MIN, -S8_MAX, false, true, false}, + {-1, -S8_MAX, S8_MIN, S8_MAX-1, S8_MAX, false, false, false}, + {-S8_MAX, -1, S8_MIN, S8_MIN+2, S8_MAX, false, false, false}, + + {1, S8_MIN, -S8_MAX, -S8_MAX, S8_MIN, false, true, false}, + {S8_MIN, 1, -S8_MAX, S8_MAX, S8_MIN, false, true, false}, + {1, S8_MAX, S8_MIN, S8_MIN+2, S8_MAX, true, false, false}, + {S8_MAX, 1, S8_MIN, S8_MAX-1, S8_MAX, true, false, false}, + + {S8_MIN, S8_MIN, 0, 0, 0, true, false, true}, + {S8_MAX, S8_MAX, -2, 0, 1, true, false, true}, + + {-4, -32, -36, 28, -128, false, false, true}, + {-4, 32, 28, -36, -128, false, false, false}, +}; + +DEFINE_TEST_ARRAY(s16) = { + {0, 0, 0, 0, 0, false, false, false}, + + {0, S16_MAX, S16_MAX, -S16_MAX, 0, false, false, false}, + {S16_MAX, 0, S16_MAX, S16_MAX, 0, false, false, false}, + {0, S16_MIN, S16_MIN, S16_MIN, 0, false, true, false}, + {S16_MIN, 0, S16_MIN, S16_MIN, 0, false, false, false}, + + {-1, S16_MIN, S16_MAX, S16_MAX, S16_MIN, true, false, true}, + {S16_MIN, -1, S16_MAX, -S16_MAX, S16_MIN, true, false, true}, + {-1, S16_MAX, S16_MAX-1, S16_MIN, -S16_MAX, false, false, false}, + {S16_MAX, -1, S16_MAX-1, S16_MIN, -S16_MAX, false, true, false}, + {-1, -S16_MAX, S16_MIN, S16_MAX-1, S16_MAX, false, false, false}, + {-S16_MAX, -1, S16_MIN, S16_MIN+2, S16_MAX, false, false, false}, + + {1, S16_MIN, -S16_MAX, -S16_MAX, S16_MIN, false, true, false}, + {S16_MIN, 1, -S16_MAX, S16_MAX, S16_MIN, false, true, false}, + {1, S16_MAX, S16_MIN, S16_MIN+2, S16_MAX, true, false, false}, + {S16_MAX, 1, S16_MIN, S16_MAX-1, S16_MAX, true, false, false}, + + {S16_MIN, S16_MIN, 0, 0, 0, true, false, true}, + {S16_MAX, S16_MAX, -2, 0, 1, true, false, true}, +}; +DEFINE_TEST_ARRAY(s32) = { + {0, 0, 0, 0, 0, false, false, false}, + + {0, S32_MAX, S32_MAX, -S32_MAX, 0, false, false, false}, + {S32_MAX, 0, S32_MAX, S32_MAX, 0, false, false, false}, + {0, S32_MIN, S32_MIN, S32_MIN, 0, false, true, false}, + {S32_MIN, 0, S32_MIN, S32_MIN, 0, false, false, false}, + + {-1, S32_MIN, S32_MAX, S32_MAX, S32_MIN, true, false, true}, + {S32_MIN, -1, S32_MAX, -S32_MAX, S32_MIN, true, false, true}, + {-1, S32_MAX, S32_MAX-1, S32_MIN, -S32_MAX, false, false, false}, + {S32_MAX, -1, S32_MAX-1, S32_MIN, -S32_MAX, false, true, false}, + {-1, -S32_MAX, S32_MIN, S32_MAX-1, S32_MAX, false, false, false}, + {-S32_MAX, -1, S32_MIN, S32_MIN+2, S32_MAX, false, false, false}, + + {1, S32_MIN, -S32_MAX, -S32_MAX, S32_MIN, false, true, false}, + {S32_MIN, 1, -S32_MAX, S32_MAX, S32_MIN, false, true, false}, + {1, S32_MAX, S32_MIN, S32_MIN+2, S32_MAX, true, false, false}, + {S32_MAX, 1, S32_MIN, S32_MAX-1, S32_MAX, true, false, false}, + + {S32_MIN, S32_MIN, 0, 0, 0, true, false, true}, + {S32_MAX, S32_MAX, -2, 0, 1, true, false, true}, +}; +DEFINE_TEST_ARRAY(s64) = { + {0, 0, 0, 0, 0, false, false, false}, + + {0, S64_MAX, S64_MAX, -S64_MAX, 0, false, false, false}, + {S64_MAX, 0, S64_MAX, S64_MAX, 0, false, false, false}, + {0, S64_MIN, S64_MIN, S64_MIN, 0, false, true, false}, + {S64_MIN, 0, S64_MIN, S64_MIN, 0, false, false, false}, + + {-1, S64_MIN, S64_MAX, S64_MAX, S64_MIN, true, false, true}, + {S64_MIN, -1, S64_MAX, -S64_MAX, S64_MIN, true, false, true}, + {-1, S64_MAX, S64_MAX-1, S64_MIN, -S64_MAX, false, false, false}, + {S64_MAX, -1, S64_MAX-1, S64_MIN, -S64_MAX, false, true, false}, + {-1, -S64_MAX, S64_MIN, S64_MAX-1, S64_MAX, false, false, false}, + {-S64_MAX, -1, S64_MIN, S64_MIN+2, S64_MAX, false, false, false}, + + {1, S64_MIN, -S64_MAX, -S64_MAX, S64_MIN, false, true, false}, + {S64_MIN, 1, -S64_MAX, S64_MAX, S64_MIN, false, true, false}, + {1, S64_MAX, S64_MIN, S64_MIN+2, S64_MAX, true, false, false}, + {S64_MAX, 1, S64_MIN, S64_MAX-1, S64_MAX, true, false, false}, + + {S64_MIN, S64_MIN, 0, 0, 0, true, false, true}, + {S64_MAX, S64_MAX, -2, 0, 1, true, false, true}, + + {-1, -1, -2, 0, 1, false, false, false}, + {-1, -128, -129, 127, 128, false, false, false}, + {-128, -1, -129, -127, 128, false, false, false}, + {0, -S64_MAX, -S64_MAX, S64_MAX, 0, false, false, false}, +}; + +#define check_one_op(t, fmt, op, sym, a, b, r, of) do { \ + t _r; \ + bool _of; \ + \ + _of = check_ ## op ## _overflow(a, b, &_r); \ + if (_of != of) { \ + pr_warn("expected "fmt" "sym" "fmt \ + " to%s overflow (type %s)\n", \ + a, b, of ? "" : " not", #t); \ + err = 1; \ + } \ + if (_r != r) { \ + pr_warn("expected "fmt" "sym" "fmt" == " \ + fmt", got "fmt" (type %s)\n", \ + a, b, r, _r, #t); \ + err = 1; \ + } \ +} while (0) + +#define DEFINE_TEST_FUNC(t, fmt) \ +static int __init do_test_ ## t(const struct test_ ## t *p) \ +{ \ + int err = 0; \ + \ + check_one_op(t, fmt, add, "+", p->a, p->b, p->sum, p->s_of); \ + check_one_op(t, fmt, add, "+", p->b, p->a, p->sum, p->s_of); \ + check_one_op(t, fmt, sub, "-", p->a, p->b, p->diff, p->d_of); \ + check_one_op(t, fmt, mul, "*", p->a, p->b, p->prod, p->p_of); \ + check_one_op(t, fmt, mul, "*", p->b, p->a, p->prod, p->p_of); \ + \ + return err; \ +} \ + \ +static int __init test_ ## t ## _overflow(void) { \ + int err = 0; \ + unsigned i; \ + \ + pr_info("%-3s: %zu tests\n", #t, ARRAY_SIZE(t ## _tests)); \ + for (i = 0; i < ARRAY_SIZE(t ## _tests); ++i) \ + err |= do_test_ ## t(&t ## _tests[i]); \ + return err; \ +} + +DEFINE_TEST_FUNC(u8, "%d"); +DEFINE_TEST_FUNC(s8, "%d"); +DEFINE_TEST_FUNC(u16, "%d"); +DEFINE_TEST_FUNC(s16, "%d"); +DEFINE_TEST_FUNC(u32, "%u"); +DEFINE_TEST_FUNC(s32, "%d"); +#if BITS_PER_LONG == 64 +DEFINE_TEST_FUNC(u64, "%llu"); +DEFINE_TEST_FUNC(s64, "%lld"); +#endif + +static int __init test_overflow_calculation(void) +{ + int err = 0; + + err |= test_u8_overflow(); + err |= test_s8_overflow(); + err |= test_u16_overflow(); + err |= test_s16_overflow(); + err |= test_u32_overflow(); + err |= test_s32_overflow(); +#if BITS_PER_LONG == 64 + err |= test_u64_overflow(); + err |= test_s64_overflow(); +#endif + + return err; +} + +/* + * Deal with the various forms of allocator arguments. See comments above + * the DEFINE_TEST_ALLOC() instances for mapping of the "bits". + */ +#define alloc010(alloc, arg, sz) alloc(sz, GFP_KERNEL) +#define alloc011(alloc, arg, sz) alloc(sz, GFP_KERNEL, NUMA_NO_NODE) +#define alloc000(alloc, arg, sz) alloc(sz) +#define alloc001(alloc, arg, sz) alloc(sz, NUMA_NO_NODE) +#define alloc110(alloc, arg, sz) alloc(arg, sz, GFP_KERNEL) +#define free0(free, arg, ptr) free(ptr) +#define free1(free, arg, ptr) free(arg, ptr) + +/* Wrap around to 8K */ +#define TEST_SIZE (9 << PAGE_SHIFT) + +#define DEFINE_TEST_ALLOC(func, free_func, want_arg, want_gfp, want_node)\ +static int __init test_ ## func (void *arg) \ +{ \ + volatile size_t a = TEST_SIZE; \ + volatile size_t b = (SIZE_MAX / TEST_SIZE) + 1; \ + void *ptr; \ + \ + /* Tiny allocation test. */ \ + ptr = alloc ## want_arg ## want_gfp ## want_node (func, arg, 1);\ + if (!ptr) { \ + pr_warn(#func " failed regular allocation?!\n"); \ + return 1; \ + } \ + free ## want_arg (free_func, arg, ptr); \ + \ + /* Wrapped allocation test. */ \ + ptr = alloc ## want_arg ## want_gfp ## want_node (func, arg, \ + a * b); \ + if (!ptr) { \ + pr_warn(#func " unexpectedly failed bad wrapping?!\n"); \ + return 1; \ + } \ + free ## want_arg (free_func, arg, ptr); \ + \ + /* Saturated allocation test. */ \ + ptr = alloc ## want_arg ## want_gfp ## want_node (func, arg, \ + array_size(a, b)); \ + if (ptr) { \ + pr_warn(#func " missed saturation!\n"); \ + free ## want_arg (free_func, arg, ptr); \ + return 1; \ + } \ + pr_info(#func " detected saturation\n"); \ + return 0; \ +} + +/* + * Allocator uses a trailing node argument --------+ (e.g. kmalloc_node()) + * Allocator uses the gfp_t argument -----------+ | (e.g. kmalloc()) + * Allocator uses a special leading argument + | | (e.g. devm_kmalloc()) + * | | | + */ +DEFINE_TEST_ALLOC(kmalloc, kfree, 0, 1, 0); +DEFINE_TEST_ALLOC(kmalloc_node, kfree, 0, 1, 1); +DEFINE_TEST_ALLOC(kzalloc, kfree, 0, 1, 0); +DEFINE_TEST_ALLOC(kzalloc_node, kfree, 0, 1, 1); +DEFINE_TEST_ALLOC(vmalloc, vfree, 0, 0, 0); +DEFINE_TEST_ALLOC(vmalloc_node, vfree, 0, 0, 1); +DEFINE_TEST_ALLOC(vzalloc, vfree, 0, 0, 0); +DEFINE_TEST_ALLOC(vzalloc_node, vfree, 0, 0, 1); +DEFINE_TEST_ALLOC(kvmalloc, kvfree, 0, 1, 0); +DEFINE_TEST_ALLOC(kvmalloc_node, kvfree, 0, 1, 1); +DEFINE_TEST_ALLOC(kvzalloc, kvfree, 0, 1, 0); +DEFINE_TEST_ALLOC(kvzalloc_node, kvfree, 0, 1, 1); +DEFINE_TEST_ALLOC(devm_kmalloc, devm_kfree, 1, 1, 0); +DEFINE_TEST_ALLOC(devm_kzalloc, devm_kfree, 1, 1, 0); + +static int __init test_overflow_allocation(void) +{ + const char device_name[] = "overflow-test"; + struct device *dev; + int err = 0; + + /* Create dummy device for devm_kmalloc()-family tests. */ + dev = root_device_register(device_name); + if (!dev) { + pr_warn("Cannot register test device\n"); + return 1; + } + + err |= test_kmalloc(NULL); + err |= test_kmalloc_node(NULL); + err |= test_kzalloc(NULL); + err |= test_kzalloc_node(NULL); + err |= test_kvmalloc(NULL); + err |= test_kvmalloc_node(NULL); + err |= test_kvzalloc(NULL); + err |= test_kvzalloc_node(NULL); + err |= test_vmalloc(NULL); + err |= test_vmalloc_node(NULL); + err |= test_vzalloc(NULL); + err |= test_vzalloc_node(NULL); + err |= test_devm_kmalloc(dev); + err |= test_devm_kzalloc(dev); + + device_unregister(dev); + + return err; +} + +static int __init test_module_init(void) +{ + int err = 0; + + err |= test_overflow_calculation(); + err |= test_overflow_allocation(); + + if (err) { + pr_warn("FAIL!\n"); + err = -EINVAL; + } else { + pr_info("all tests passed\n"); + } + + return err; +} + +static void __exit test_module_exit(void) +{ } + +module_init(test_module_init); +module_exit(test_module_exit); +MODULE_LICENSE("Dual MIT/GPL"); diff --git a/net/ceph/mon_client.c b/net/ceph/mon_client.c index 21ac6e3..d7a7a23 100644 --- a/net/ceph/mon_client.c +++ b/net/ceph/mon_client.c @@ -62,7 +62,7 @@ struct ceph_monmap *ceph_monmap_decode(void *p, void *end) if (num_mon > CEPH_MAX_MON) goto bad; - m = kmalloc(sizeof(*m) + sizeof(m->mon_inst[0])*num_mon, GFP_NOFS); + m = kmalloc(struct_size(m, mon_inst, num_mon), GFP_NOFS); if (m == NULL) return ERR_PTR(-ENOMEM); m->fsid = fsid; @@ -1000,8 +1000,7 @@ static int build_initial_monmap(struct ceph_mon_client *monc) int i; /* build initial monmap */ - monc->monmap = kzalloc(sizeof(*monc->monmap) + - num_mon*sizeof(monc->monmap->mon_inst[0]), + monc->monmap = kzalloc(struct_size(monc->monmap, mon_inst, num_mon), GFP_KERNEL); if (!monc->monmap) return -ENOMEM; diff --git a/net/ceph/osd_client.c b/net/ceph/osd_client.c index d2667e5..69a2581 100644 --- a/net/ceph/osd_client.c +++ b/net/ceph/osd_client.c @@ -584,8 +584,7 @@ struct ceph_osd_request *ceph_osdc_alloc_request(struct ceph_osd_client *osdc, req = kmem_cache_alloc(ceph_osd_request_cache, gfp_flags); } else { BUG_ON(num_ops > CEPH_OSD_MAX_OPS); - req = kmalloc(sizeof(*req) + num_ops * sizeof(req->r_ops[0]), - gfp_flags); + req = kmalloc(struct_size(req, r_ops, num_ops), gfp_flags); } if (unlikely(!req)) return NULL; diff --git a/net/netfilter/xt_recent.c b/net/netfilter/xt_recent.c index 9bbfc17..07085c2 100644 --- a/net/netfilter/xt_recent.c +++ b/net/netfilter/xt_recent.c @@ -184,8 +184,7 @@ recent_entry_init(struct recent_table *t, const union nf_inet_addr *addr, } nstamps_max += 1; - e = kmalloc(sizeof(*e) + sizeof(e->stamps[0]) * nstamps_max, - GFP_ATOMIC); + e = kmalloc(struct_size(e, stamps, nstamps_max), GFP_ATOMIC); if (e == NULL) return NULL; memcpy(&e->addr, addr, sizeof(e->addr)); diff --git a/net/sctp/endpointola.c b/net/sctp/endpointola.c index e2f5a3e..40c7eb9 100644 --- a/net/sctp/endpointola.c +++ b/net/sctp/endpointola.c @@ -73,8 +73,8 @@ static struct sctp_endpoint *sctp_endpoint_init(struct sctp_endpoint *ep, * variables. There are arrays that we encode directly * into parameters to make the rest of the operations easier. */ - auth_hmacs = kzalloc(sizeof(*auth_hmacs) + - sizeof(__u16) * SCTP_AUTH_NUM_HMACS, gfp); + auth_hmacs = kzalloc(struct_size(auth_hmacs, hmac_ids, + SCTP_AUTH_NUM_HMACS), gfp); if (!auth_hmacs) goto nomem; diff --git a/sound/core/vmaster.c b/sound/core/vmaster.c index 58fa3f9..fd99d8a 100644 --- a/sound/core/vmaster.c +++ b/sound/core/vmaster.c @@ -259,8 +259,8 @@ int _snd_ctl_add_slave(struct snd_kcontrol *master, struct snd_kcontrol *slave, struct link_master *master_link = snd_kcontrol_chip(master); struct link_slave *srec; - srec = kzalloc(sizeof(*srec) + - slave->count * sizeof(*slave->vd), GFP_KERNEL); + srec = kzalloc(struct_size(srec, slave.vd, slave->count), + GFP_KERNEL); if (!srec) return -ENOMEM; srec->kctl = slave; diff --git a/sound/soc/qcom/apq8016_sbc.c b/sound/soc/qcom/apq8016_sbc.c index 7044287..1dd23bb 100644 --- a/sound/soc/qcom/apq8016_sbc.c +++ b/sound/soc/qcom/apq8016_sbc.c @@ -147,7 +147,8 @@ static struct apq8016_sbc_data *apq8016_sbc_parse_of(struct snd_soc_card *card) num_links = of_get_child_count(node); /* Allocate the private data and the DAI link array */ - data = devm_kzalloc(dev, sizeof(*data) + sizeof(*link) * num_links, + data = devm_kzalloc(dev, + struct_size(data, dai_link, num_links), GFP_KERNEL); if (!data) return ERR_PTR(-ENOMEM); diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index 36a39ba..255cad4 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -1086,7 +1086,7 @@ static int dapm_widget_list_create(struct snd_soc_dapm_widget_list **list, list_for_each(it, widgets) size++; - *list = kzalloc(sizeof(**list) + size * sizeof(*w), GFP_KERNEL); + *list = kzalloc(struct_size(*list, widgets, size), GFP_KERNEL); if (*list == NULL) return -ENOMEM; |