From 68d38571b07ee7335f0fcf34a1a060b406ba5e20 Mon Sep 17 00:00:00 2001 From: guyang Date: Wed, 28 Feb 2024 17:59:37 +0530 Subject: [PATCH 01/36] msm: kgsl: sensor: Proper handling of race condition in util api Power count is coming from user space which can be modified due to access to shared memory. This change scopes the data locally so as to avoid vulnerability of count being modified by external means while executing due to being in shared memory. CRs-Fixed: 3691744. Change-Id: Ia8c23000787aeb16c46d7f9c8eea68fcdd871d58 Signed-off-by: Shivi Mangal Signed-off-by: Guang Yang --- .../cam_sensor_utils/cam_sensor_util.c | 24 +++++++++++++------ .../cam_sensor_utils/cam_sensor_util.c | 23 +++++++++++++----- 2 files changed, 34 insertions(+), 13 deletions(-) diff --git a/drivers/media/platform/msm/ais/cam_sensor_module/cam_sensor_utils/cam_sensor_util.c b/drivers/media/platform/msm/ais/cam_sensor_module/cam_sensor_utils/cam_sensor_util.c index b3a74d6c80bf..d58762b44f3a 100644 --- a/drivers/media/platform/msm/ais/cam_sensor_module/cam_sensor_utils/cam_sensor_util.c +++ b/drivers/media/platform/msm/ais/cam_sensor_module/cam_sensor_utils/cam_sensor_util.c @@ -931,23 +931,29 @@ int32_t cam_sensor_update_power_settings(void *cmd_buf, int32_t i = 0, pwr_up = 0, pwr_down = 0; struct cam_sensor_power_setting *pwr_settings; void *ptr = cmd_buf, *scr; - struct cam_cmd_power *pwr_cmd = (struct cam_cmd_power *)cmd_buf; struct common_header *cmm_hdr = (struct common_header *)cmd_buf; + struct cam_cmd_power *pwr_cmd = + kzalloc(sizeof(struct cam_cmd_power), GFP_KERNEL); + if (!pwr_cmd) + return -ENOMEM; + memcpy(pwr_cmd, cmd_buf, sizeof(struct cam_cmd_power)); if (!pwr_cmd || !cmd_length || cmd_buf_len < (size_t)cmd_length || cam_sensor_validate(cmd_buf, cmd_buf_len)) { CAM_ERR(CAM_SENSOR, "Invalid Args: pwr_cmd %pK, cmd_length: %d", pwr_cmd, cmd_length); - return -EINVAL; + rc = -EINVAL; + goto free_power_command; } power_info->power_setting_size = 0; power_info->power_setting = - (struct cam_sensor_power_setting *) kzalloc(sizeof(struct cam_sensor_power_setting) * MAX_POWER_CONFIG, GFP_KERNEL); - if (!power_info->power_setting) - return -ENOMEM; + if (!power_info->power_setting) { + rc = -ENOMEM; + goto free_power_command; + } power_info->power_down_setting_size = 0; power_info->power_down_setting = @@ -958,7 +964,8 @@ int32_t cam_sensor_update_power_settings(void *cmd_buf, kfree(power_info->power_setting); power_info->power_setting = NULL; power_info->power_setting_size = 0; - return -ENOMEM; + rc = -ENOMEM; + goto free_power_command; } while (tot_size < cmd_length) { @@ -1142,7 +1149,7 @@ int32_t cam_sensor_update_power_settings(void *cmd_buf, } } - return rc; + goto free_power_command; free_power_settings: kfree(power_info->power_down_setting); kfree(power_info->power_setting); @@ -1150,6 +1157,9 @@ int32_t cam_sensor_update_power_settings(void *cmd_buf, power_info->power_setting = NULL; power_info->power_down_setting_size = 0; power_info->power_setting_size = 0; +free_power_command: + kfree(pwr_cmd); + pwr_cmd = NULL; return rc; } diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_utils/cam_sensor_util.c b/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_utils/cam_sensor_util.c index 0fd99b0a663f..2e8b6696af75 100644 --- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_utils/cam_sensor_util.c +++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_utils/cam_sensor_util.c @@ -865,14 +865,19 @@ int32_t cam_sensor_update_power_settings(void *cmd_buf, int32_t i = 0, pwr_up = 0, pwr_down = 0; struct cam_sensor_power_setting *pwr_settings; void *ptr = cmd_buf, *scr; - struct cam_cmd_power *pwr_cmd = (struct cam_cmd_power *)cmd_buf; struct common_header *cmm_hdr = (struct common_header *)cmd_buf; + struct cam_cmd_power *pwr_cmd = + kzalloc(sizeof(struct cam_cmd_power), GFP_KERNEL); + if (!pwr_cmd) + return -ENOMEM; + memcpy(pwr_cmd, cmd_buf, sizeof(struct cam_cmd_power)); if (!pwr_cmd || !cmd_length || cmd_buf_len < (size_t)cmd_length || cam_sensor_validate(cmd_buf, cmd_buf_len)) { CAM_ERR(CAM_SENSOR, "Invalid Args: pwr_cmd %pK, cmd_length: %d", pwr_cmd, cmd_length); - return -EINVAL; + rc = -EINVAL; + goto free_power_command; } power_info->power_setting_size = 0; @@ -880,8 +885,10 @@ int32_t cam_sensor_update_power_settings(void *cmd_buf, (struct cam_sensor_power_setting *) kzalloc(sizeof(struct cam_sensor_power_setting) * MAX_POWER_CONFIG, GFP_KERNEL); - if (!power_info->power_setting) - return -ENOMEM; + if (!power_info->power_setting) { + rc = -ENOMEM; + goto free_power_command; + } power_info->power_down_setting_size = 0; power_info->power_down_setting = @@ -892,7 +899,8 @@ int32_t cam_sensor_update_power_settings(void *cmd_buf, kfree(power_info->power_setting); power_info->power_setting = NULL; power_info->power_setting_size = 0; - return -ENOMEM; + rc = -ENOMEM; + goto free_power_command; } while (tot_size < cmd_length) { @@ -1076,7 +1084,7 @@ int32_t cam_sensor_update_power_settings(void *cmd_buf, } } - return rc; + goto free_power_command; free_power_settings: kfree(power_info->power_down_setting); kfree(power_info->power_setting); @@ -1084,6 +1092,9 @@ int32_t cam_sensor_update_power_settings(void *cmd_buf, power_info->power_setting = NULL; power_info->power_down_setting_size = 0; power_info->power_setting_size = 0; +free_power_command: + kfree(pwr_cmd); + pwr_cmd = NULL; return rc; } From 1ff87feff6d252c7e1e52e1fbceb1bb550a26c80 Mon Sep 17 00:00:00 2001 From: Rakesh Naidu Bhaviripudi Date: Fri, 2 Feb 2024 12:25:26 +0530 Subject: [PATCH 02/36] msm: kgsl: Update the protect register list Update the protect register list as per the latest recommendation. Since we are now relying on last-span-unbound feature, following are changed. 1. Last-span-unbound feature covers GMU_AO block, we have to replace A6XX_GMU_ALWAYS_ON_COUNTER_L with A6XX_CP_ALWAYS_ON_COUNTER_LO while accessing from GPU. 2. GMU power perf counters are unused and we are out of register address protection spans to make them available for on older targets. 3. Remove PWR counter group safely for a6xx targets and setup the counters internally 4. IFPC counters are moved to part of target specific code and enabled with ADRENO feature flag. Change-Id: Ifcff462b669bbf9da8e4d53c87affdc8a9fcb740 Signed-off-by: Rakesh Naidu Bhaviripudi --- drivers/gpu/msm/adreno.c | 13 +- drivers/gpu/msm/adreno_a6xx.c | 279 ++++++++++------------------ drivers/gpu/msm/adreno_ringbuffer.c | 5 +- 3 files changed, 108 insertions(+), 189 deletions(-) diff --git a/drivers/gpu/msm/adreno.c b/drivers/gpu/msm/adreno.c index 3c86b58b1165..c8337ecc4699 100644 --- a/drivers/gpu/msm/adreno.c +++ b/drivers/gpu/msm/adreno.c @@ -1,5 +1,5 @@ /* Copyright (c) 2002,2007-2020, The Linux Foundation. All rights reserved. - * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2022,2024 Qualcomm Innovation Center, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -2133,17 +2133,6 @@ static int _adreno_start(struct adreno_device *adreno_dev) } } - if (gmu_core_gpmu_isenabled(device) && - adreno_dev->perfctr_ifpc_lo == 0) { - ret = adreno_perfcounter_get(adreno_dev, - KGSL_PERFCOUNTER_GROUP_GPMU_PWR, 4, - &adreno_dev->perfctr_ifpc_lo, NULL, - PERFCOUNTER_FLAG_KERNEL); - if (ret) { - WARN_ONCE(1, "Unable to get perf counter for IFPC\n"); - adreno_dev->perfctr_ifpc_lo = 0; - } - } /* Clear the busy_data stats - we're starting over from scratch */ adreno_dev->busy_data.gpu_busy = 0; diff --git a/drivers/gpu/msm/adreno_a6xx.c b/drivers/gpu/msm/adreno_a6xx.c index 154e9b38ce60..fb25062e8c1a 100644 --- a/drivers/gpu/msm/adreno_a6xx.c +++ b/drivers/gpu/msm/adreno_a6xx.c @@ -1,4 +1,5 @@ /* Copyright (c)2017-2021, The Linux Foundation. All rights reserved. + * Copyright (c) 2024 Qualcomm Innovation Center, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -355,42 +356,6 @@ static const struct { {adreno_is_a610, a612_hwcg_regs, ARRAY_SIZE(a612_hwcg_regs)}, }; -static struct a6xx_protected_regs { - unsigned int base; - unsigned int count; - int read_protect; -} a6xx_protected_regs_group[] = { - { 0x600, 0x51, 0 }, - { 0xAE50, 0x2, 1 }, - { 0x9624, 0x13, 1 }, - { 0x8630, 0x8, 1 }, - { 0x9E70, 0x1, 1 }, - { 0x9E78, 0x187, 1 }, - { 0xF000, 0x810, 1 }, - { 0xFC00, 0x3, 0 }, - { 0x50E, 0x0, 1 }, - { 0x50F, 0x0, 0 }, - { 0x510, 0x0, 1 }, - { 0x0, 0x4F9, 0 }, - { 0x501, 0xA, 0 }, - { 0x511, 0x44, 0 }, - { 0xE00, 0x1, 1 }, - { 0xE03, 0xB, 1 }, - { 0x8E00, 0x0, 1 }, - { 0x8E50, 0xF, 1 }, - { 0xBE02, 0x0, 1 }, - { 0xBE20, 0x11F3, 1 }, - { 0x800, 0x82, 1 }, - { 0x8A0, 0x8, 1 }, - { 0x8AB, 0x19, 1 }, - { 0x900, 0x4D, 1 }, - { 0x98D, 0x76, 1 }, - { 0x8D0, 0x23, 0 }, - { 0x980, 0x4, 0 }, - { 0xA630, 0x0, 1 }, - { 0x1b400, 0x1fff, 1 }, -}; - /* IFPC & Preemption static powerup restore list */ static struct reg_list_pair { uint32_t offset; @@ -472,6 +437,60 @@ static struct reg_list_pair a615_pwrup_reglist[] = { { A6XX_UCHE_GBIF_GX_CONFIG, 0x0 }, }; +/** + * struct a6xx_protected_regs - container for a protect register span + */ +static const struct a6xx_protected_regs { + /** @reg: Physical protected mode register to write to */ + u32 reg; + /** @start: Dword offset of the starting register in the range */ + u32 start; + /** + * @end: Dword offset of the ending register in the range + * (inclusive) + */ + u32 end; + /** + * @noaccess: 1 if the register should not be accessible from + * userspace, 0 if it can be read (but not written) + */ + u32 noaccess; +} a630_protected_regs[] = { + { A6XX_CP_PROTECT_REG + 0, 0x00000, 0x004ff, 0 }, + { A6XX_CP_PROTECT_REG + 1, 0x00501, 0x00506, 0 }, + { A6XX_CP_PROTECT_REG + 2, 0x0050b, 0x007ff, 0 }, + { A6XX_CP_PROTECT_REG + 3, 0x0050e, 0x0050e, 1 }, + { A6XX_CP_PROTECT_REG + 4, 0x00510, 0x00510, 1 }, + { A6XX_CP_PROTECT_REG + 5, 0x00534, 0x00534, 1 }, + { A6XX_CP_PROTECT_REG + 6, 0x00800, 0x00882, 1 }, + { A6XX_CP_PROTECT_REG + 7, 0x008a0, 0x008a8, 1 }, + { A6XX_CP_PROTECT_REG + 8, 0x008ab, 0x008cf, 1 }, + { A6XX_CP_PROTECT_REG + 9, 0x008d0, 0x0098c, 0 }, + { A6XX_CP_PROTECT_REG + 10, 0x00900, 0x0094d, 1 }, + { A6XX_CP_PROTECT_REG + 11, 0x0098d, 0x00bff, 1 }, + { A6XX_CP_PROTECT_REG + 12, 0x00e00, 0x00e01, 1 }, + { A6XX_CP_PROTECT_REG + 13, 0x00e03, 0x00e0f, 1 }, + { A6XX_CP_PROTECT_REG + 14, 0x03c00, 0x03cc3, 1 }, + { A6XX_CP_PROTECT_REG + 15, 0x03cc4, 0x05cc3, 0 }, + { A6XX_CP_PROTECT_REG + 16, 0x08630, 0x087ff, 1 }, + { A6XX_CP_PROTECT_REG + 17, 0x08e00, 0x08e00, 1 }, + { A6XX_CP_PROTECT_REG + 18, 0x08e08, 0x08e08, 1 }, + { A6XX_CP_PROTECT_REG + 19, 0x08e50, 0x08e6f, 1 }, + { A6XX_CP_PROTECT_REG + 20, 0x09624, 0x097ff, 1 }, + { A6XX_CP_PROTECT_REG + 21, 0x09e70, 0x09e71, 1 }, + { A6XX_CP_PROTECT_REG + 22, 0x09e78, 0x09fff, 1 }, + { A6XX_CP_PROTECT_REG + 23, 0x0a630, 0x0a7ff, 1 }, + { A6XX_CP_PROTECT_REG + 24, 0x0ae02, 0x0ae02, 1 }, + { A6XX_CP_PROTECT_REG + 25, 0x0ae50, 0x0b17f, 1 }, + { A6XX_CP_PROTECT_REG + 26, 0x0b604, 0x0b604, 1 }, + { A6XX_CP_PROTECT_REG + 27, 0x0be02, 0x0be03, 1 }, + { A6XX_CP_PROTECT_REG + 28, 0x0be20, 0x0d5ff, 1 }, + { A6XX_CP_PROTECT_REG + 29, 0x0f000, 0x0fbff, 1 }, + { A6XX_CP_PROTECT_REG + 30, 0x0fc00, 0x11bff, 0 }, + { A6XX_CP_PROTECT_REG + 31, 0x11c00, 0x11c00, 1 }, + { 0 }, +}; + static struct reg_list_pair a6xx_ifpc_perfctr_reglist[] = { { A6XX_RBBM_PERFCTR_CNTL, 0x0 }, }; @@ -519,55 +538,36 @@ static void a6xx_init(struct adreno_device *adreno_dev) /** * a6xx_protect_init() - Initializes register protection on a6xx * @device: Pointer to the device structure - * Performs register writes to enable protected access to sensitive - * registers */ static void a6xx_protect_init(struct adreno_device *adreno_dev) { struct kgsl_device *device = KGSL_DEVICE(adreno_dev); - struct kgsl_protected_registers *mmu_prot = - kgsl_mmu_get_prot_regs(&device->mmu); - int i, num_sets; - int req_sets = ARRAY_SIZE(a6xx_protected_regs_group); - int max_sets = adreno_dev->gpucore->num_protected_regs; - unsigned int mmu_base = 0, mmu_range = 0, cur_range; - - /* enable access protection to privileged registers */ - kgsl_regwrite(device, A6XX_CP_PROTECT_CNTL, 0x00000003); - - if (mmu_prot) { - mmu_base = mmu_prot->base; - mmu_range = mmu_prot->range; - req_sets += DIV_ROUND_UP(mmu_range, 0x2000); - } + const struct a6xx_protected_regs *regs = a630_protected_regs; + int i; - if (req_sets > max_sets) - WARN(1, "Size exceeds the num of protection regs available\n"); + /* + * Enable access protection to privileged registers, fault on an access + * protect violation and select the last span to protect from the start + * address all the way to the end of the register address space + */ - /* Protect GPU registers */ - num_sets = min_t(unsigned int, - ARRAY_SIZE(a6xx_protected_regs_group), max_sets); - for (i = 0; i < num_sets; i++) { - struct a6xx_protected_regs *regs = - &a6xx_protected_regs_group[i]; + kgsl_regwrite(device, A6XX_CP_PROTECT_CNTL, + (1 << 0) | (1 << 1) | (1 << 3)); - kgsl_regwrite(device, A6XX_CP_PROTECT_REG + i, - regs->base | (regs->count << 18) | - (regs->read_protect << 31)); - } + /* Program each register defined by the core definition */ + for (i = 0; regs[i].reg; i++) { + u32 count; - /* Protect MMU registers */ - if (mmu_prot) { - while ((i < max_sets) && (mmu_range > 0)) { - cur_range = min_t(unsigned int, mmu_range, - 0x2000); - kgsl_regwrite(device, A6XX_CP_PROTECT_REG + i, - mmu_base | ((cur_range - 1) << 18) | (1 << 31)); - - mmu_base += cur_range; - mmu_range -= cur_range; - i++; - } + /* + * This is the offset of the end register as counted from the + * start, i.e. # of registers in the range - 1 + */ + count = regs[i].end - regs[i].start; + + kgsl_regwrite(device, regs[i].reg, + (regs[i].start & 0x3ffff) | + ((count & 0x1fff) << 18) | + (regs[i].noaccess << 31)); } } @@ -866,6 +866,10 @@ static void a6xx_start(struct adreno_device *adreno_dev) /* Turn on performance counters */ kgsl_regwrite(device, A6XX_RBBM_PERFCTR_CNTL, 0x1); + /* Turn on the IFPC counter (countable 4 on XOCLK4) */ + if (gmu_core_isenabled(device)) + gmu_core_regrmw(device, A6XX_GMU_CX_GMU_POWER_COUNTER_SELECT_1, + 0xff, 0x4); /* Turn on GX_MEM retention */ if (gmu_core_gpmu_isenabled(device) && adreno_is_a612(adreno_dev)) { @@ -950,6 +954,20 @@ static void a6xx_start(struct adreno_device *adreno_dev) if (adreno_is_preemption_enabled(adreno_dev)) kgsl_regwrite(device, A6XX_RB_CONTEXT_SWITCH_GMEM_SAVE_RESTORE, 0x1); + /* + * Enable GMU power counter 0 to count GPU busy. This is applicable to + * all a6xx targets + */ + kgsl_regwrite(device, A6XX_GPU_GMU_AO_GPU_CX_BUSY_MASK, 0xff000000); + /* + * A610 GPU has only one power counter fixed to count GPU busy + * cycles with no select register. + */ + if (!adreno_is_a610(adreno_dev)) + kgsl_regrmw(device, + A6XX_GMU_CX_GMU_POWER_COUNTER_SELECT_0, + 0xff, 0x20); + kgsl_regwrite(device, A6XX_GMU_CX_GMU_POWER_COUNTER_ENABLE, 0x1); a6xx_protect_init(adreno_dev); @@ -2762,50 +2780,11 @@ static struct adreno_perfcount_register a6xx_perfcounters_gbif_pwr[] = { A6XX_GBIF_PWR_CNT_HIGH2, -1, A6XX_GBIF_PERF_PWR_CNT_EN }, }; -static struct adreno_perfcount_register a6xx_perfcounters_pwr[] = { - { KGSL_PERFCOUNTER_BROKEN, 0, 0, 0, 0, -1, 0 }, - { KGSL_PERFCOUNTER_NOT_USED, 0, 0, - A6XX_GMU_CX_GMU_POWER_COUNTER_XOCLK_0_L, - A6XX_GMU_CX_GMU_POWER_COUNTER_XOCLK_0_H, -1, 0 }, -}; - static struct adreno_perfcount_register a6xx_perfcounters_alwayson[] = { { KGSL_PERFCOUNTER_NOT_USED, 0, 0, A6XX_CP_ALWAYS_ON_COUNTER_LO, A6XX_CP_ALWAYS_ON_COUNTER_HI, -1 }, }; -static struct adreno_perfcount_register a6xx_pwrcounters_gpmu[] = { - /* - * A6XX_GMU_CX_GMU_POWER_COUNTER_XOCLK_0 is used for the GPU - * busy count (see the PWR group above). Mark it as broken - * so it's not re-used. - */ - { KGSL_PERFCOUNTER_BROKEN, 0, 0, - A6XX_GMU_CX_GMU_POWER_COUNTER_XOCLK_0_L, - A6XX_GMU_CX_GMU_POWER_COUNTER_XOCLK_0_H, -1, - A6XX_GMU_CX_GMU_POWER_COUNTER_SELECT_0, }, - { KGSL_PERFCOUNTER_NOT_USED, 0, 0, - A6XX_GMU_CX_GMU_POWER_COUNTER_XOCLK_1_L, - A6XX_GMU_CX_GMU_POWER_COUNTER_XOCLK_1_H, -1, - A6XX_GMU_CX_GMU_POWER_COUNTER_SELECT_0, }, - { KGSL_PERFCOUNTER_NOT_USED, 0, 0, - A6XX_GMU_CX_GMU_POWER_COUNTER_XOCLK_2_L, - A6XX_GMU_CX_GMU_POWER_COUNTER_XOCLK_2_H, -1, - A6XX_GMU_CX_GMU_POWER_COUNTER_SELECT_0, }, - { KGSL_PERFCOUNTER_NOT_USED, 0, 0, - A6XX_GMU_CX_GMU_POWER_COUNTER_XOCLK_3_L, - A6XX_GMU_CX_GMU_POWER_COUNTER_XOCLK_3_H, -1, - A6XX_GMU_CX_GMU_POWER_COUNTER_SELECT_0, }, - { KGSL_PERFCOUNTER_NOT_USED, 0, 0, - A6XX_GMU_CX_GMU_POWER_COUNTER_XOCLK_4_L, - A6XX_GMU_CX_GMU_POWER_COUNTER_XOCLK_4_H, -1, - A6XX_GMU_CX_GMU_POWER_COUNTER_SELECT_1, }, - { KGSL_PERFCOUNTER_NOT_USED, 0, 0, - A6XX_GMU_CX_GMU_POWER_COUNTER_XOCLK_5_L, - A6XX_GMU_CX_GMU_POWER_COUNTER_XOCLK_5_H, -1, - A6XX_GMU_CX_GMU_POWER_COUNTER_SELECT_1, }, -}; - /* * ADRENO_PERFCOUNTER_GROUP_RESTORE flag is enabled by default * because most of the perfcounter groups need to be restored @@ -2844,11 +2823,8 @@ static struct adreno_perfcount_group a6xx_perfcounter_groups A6XX_PERFCOUNTER_GROUP_FLAGS(VBIF, vbif, 0), A6XX_PERFCOUNTER_GROUP_FLAGS(VBIF_PWR, vbif_pwr, ADRENO_PERFCOUNTER_GROUP_FIXED), - A6XX_PERFCOUNTER_GROUP_FLAGS(PWR, pwr, - ADRENO_PERFCOUNTER_GROUP_FIXED), A6XX_PERFCOUNTER_GROUP_FLAGS(ALWAYSON, alwayson, ADRENO_PERFCOUNTER_GROUP_FIXED), - A6XX_POWER_COUNTER_GROUP(GPMU, gpmu), }; static struct adreno_perfcounters a6xx_perfcounters = { @@ -2856,39 +2832,6 @@ static struct adreno_perfcounters a6xx_perfcounters = { ARRAY_SIZE(a6xx_perfcounter_groups), }; -/* Program the GMU power counter to count GPU busy cycles */ -static int a6xx_enable_pwr_counters(struct adreno_device *adreno_dev, - unsigned int counter) -{ - struct kgsl_device *device = KGSL_DEVICE(adreno_dev); - - /* - * We have a limited number of power counters. Since we're not using - * total GPU cycle count, return error if requested. - */ - if (counter == 0) - return -EINVAL; - - /* We can use GPU without GMU and allow it to count GPU busy cycles */ - if (!gmu_core_isenabled(device) && - !kgsl_is_register_offset(device, - A6XX_GPU_GMU_AO_GPU_CX_BUSY_MASK)) - return -ENODEV; - - kgsl_regwrite(device, A6XX_GPU_GMU_AO_GPU_CX_BUSY_MASK, 0xFF000000); - - /* - * A610 GPU has only one power counter fixed to count GPU busy - * cycles with no select register. - */ - if (!adreno_is_a610(adreno_dev)) - kgsl_regrmw(device, - A6XX_GMU_CX_GMU_POWER_COUNTER_SELECT_0, 0xFF, 0x20); - kgsl_regwrite(device, A6XX_GMU_CX_GMU_POWER_COUNTER_ENABLE, 0x1); - - return 0; -} - static void a6xx_efuse_gaming_bin(struct adreno_device *adreno_dev) { unsigned int val; @@ -2984,6 +2927,14 @@ static void a6xx_platform_setup(struct adreno_device *adreno_dev) if (ADRENO_FEATURE(adreno_dev, ADRENO_SPTP_PC)) set_bit(ADRENO_SPTP_PC_CTRL, &adreno_dev->pwrctrl_flag); + /* Set the counter for IFPC */ + if (ADRENO_FEATURE(adreno_dev, ADRENO_IFPC)) + adreno_dev->perfctr_ifpc_lo = + A6XX_GMU_CX_GMU_POWER_COUNTER_XOCLK_4_L; + + /* Set the GPU busy counter for frequency scaling */ + adreno_dev->perfctr_pwr_lo = A6XX_GMU_CX_GMU_POWER_COUNTER_XOCLK_0_L; + /* Check efuse bits for various capabilties */ a6xx_check_features(adreno_dev); } @@ -3150,28 +3101,6 @@ static const struct adreno_reg_offsets a6xx_reg_offsets = { .offset_0 = ADRENO_REG_REGISTER_MAX, }; -static void a6xx_perfcounter_init(struct adreno_device *adreno_dev) -{ - /* - * A6XX_GMU_CX_GMU_POWER_COUNTER_XOCLK_4/5 is not present on A612. - * Mark them as broken so that they can't be used. - */ - if (adreno_is_a612(adreno_dev)) { - a6xx_pwrcounters_gpmu[4].countable = KGSL_PERFCOUNTER_BROKEN; - a6xx_pwrcounters_gpmu[5].countable = KGSL_PERFCOUNTER_BROKEN; - } else if (adreno_is_a610(adreno_dev)) { - /* - * A6XX_GMU_CX_GMU_POWER_COUNTER_XOCLK_1 to 5 are not - * present on A610. Mark them as broken so that they - * can't be used. - */ - a6xx_pwrcounters_gpmu[1].countable = KGSL_PERFCOUNTER_BROKEN; - a6xx_pwrcounters_gpmu[2].countable = KGSL_PERFCOUNTER_BROKEN; - a6xx_pwrcounters_gpmu[3].countable = KGSL_PERFCOUNTER_BROKEN; - a6xx_pwrcounters_gpmu[4].countable = KGSL_PERFCOUNTER_BROKEN; - a6xx_pwrcounters_gpmu[5].countable = KGSL_PERFCOUNTER_BROKEN; - } -} static int a6xx_perfcounter_update(struct adreno_device *adreno_dev, struct adreno_perfcount_register *reg, bool update_reg) @@ -3357,7 +3286,6 @@ struct adreno_gpudev adreno_a6xx_gpudev = { .regulator_enable = a6xx_sptprac_enable, .regulator_disable = a6xx_sptprac_disable, .perfcounters = &a6xx_perfcounters, - .enable_pwr_counters = a6xx_enable_pwr_counters, .read_throttling_counters = a6xx_read_throttling_counters, .count_throttles = a6xx_count_throttles, .microcode_read = a6xx_microcode_read, @@ -3380,7 +3308,6 @@ struct adreno_gpudev adreno_a6xx_gpudev = { .preemption_context_destroy = a6xx_preemption_context_destroy, .sptprac_is_on = a6xx_sptprac_is_on, .ccu_invalidate = a6xx_ccu_invalidate, - .perfcounter_init = a6xx_perfcounter_init, .perfcounter_update = a6xx_perfcounter_update, .coresight = {&a6xx_coresight, &a6xx_coresight_cx}, .clk_set_options = a6xx_clk_set_options, diff --git a/drivers/gpu/msm/adreno_ringbuffer.c b/drivers/gpu/msm/adreno_ringbuffer.c index 914014fe1ebc..42323dfadec7 100644 --- a/drivers/gpu/msm/adreno_ringbuffer.c +++ b/drivers/gpu/msm/adreno_ringbuffer.c @@ -1,5 +1,5 @@ /* Copyright (c) 2002,2007-2020, The Linux Foundation. All rights reserved. - * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2022,2024 Qualcomm Innovation Center, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -30,6 +30,7 @@ #include "adreno_trace.h" #include "a3xx_reg.h" +#include "a6xx_reg.h" #include "adreno_a5xx.h" #define RB_HOSTPTR(_rb, _pos) \ @@ -922,6 +923,8 @@ static inline int _get_alwayson_counter(struct adreno_device *adreno_dev, ADRENO_GPUREV(adreno_dev) <= ADRENO_REV_A530) *p++ = adreno_getreg(adreno_dev, ADRENO_REG_RBBM_ALWAYSON_COUNTER_LO); + else if (adreno_is_a6xx(adreno_dev)) + *p++ = A6XX_CP_ALWAYS_ON_COUNTER_LO | (1 << 30) | (2 << 18); else *p++ = adreno_getreg(adreno_dev, ADRENO_REG_RBBM_ALWAYSON_COUNTER_LO) | From 3ccb080148ecc9e39d724e458bebef01056ba63c Mon Sep 17 00:00:00 2001 From: spuligil Date: Tue, 2 Apr 2024 06:01:52 -0700 Subject: [PATCH 03/36] fw-api: CL 26384461 - update fw common interface files Change-Id: Ia9560e8f3754171cd7073f7ff5094251ff036599 CRs-Fixed: 2262693 --- fw/htt.h | 1 + 1 file changed, 1 insertion(+) diff --git a/fw/htt.h b/fw/htt.h index 23df62b46393..ed1862aea67b 100644 --- a/fw/htt.h +++ b/fw/htt.h @@ -22949,6 +22949,7 @@ typedef enum { HTT_SDWF_MSDUQ_CFG_IND_ERROR_DEACTIVATED_MSDUQ = 0x05, HTT_SDWF_MSDUQ_CFG_IND_ERROR_REACTIVATED_MSDUQ = 0x06, HTT_SDWF_MSDUQ_CFG_IND_ERROR_INVALID_SVC_CLASS = 0x07, + HTT_SDWF_MSDUQ_CFG_IND_ERROR_TIDQ_LOCATE_ERROR = 0x08, } HTT_SDWF_MSDUQ_CFG_IND_ERROR_CODE_E; PREPACK struct htt_t2h_sdwf_msduq_cfg_ind { From 3507c8f8c625f19c5e498e9d824a38a223113684 Mon Sep 17 00:00:00 2001 From: spuligil Date: Wed, 3 Apr 2024 06:01:58 -0700 Subject: [PATCH 04/36] fw-api: CL 26392958 - update fw common interface files Change-Id: Ic7c8ec6b61853fa501aedbae97dd3a024dd6c201 CRs-Fixed: 2262693 --- fw/wmi_unified.h | 3 +++ fw/wmi_version.h | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/fw/wmi_unified.h b/fw/wmi_unified.h index 848ae76ec2e4..60cfbee8da66 100644 --- a/fw/wmi_unified.h +++ b/fw/wmi_unified.h @@ -25667,6 +25667,9 @@ typedef enum */ WMI_VENDOR_OUI_ACTION_SEND_SMPS_FRAME_WITH_OMN = 12, + /* Restrict SLO if specific vendor OUI received in beacon. */ + WMI_VENDOR_OUI_ACTION_RESTRICT_SLO = 13, + /* Add any action before this line */ WMI_VENDOR_OUI_ACTION_MAX_ACTION_ID diff --git a/fw/wmi_version.h b/fw/wmi_version.h index 526ea5e2124c..9b9942583944 100644 --- a/fw/wmi_version.h +++ b/fw/wmi_version.h @@ -37,7 +37,7 @@ #define __WMI_VER_MINOR_ 0 /** WMI revision number has to be incremented when there is a * change that may or may not break compatibility. */ -#define __WMI_REVISION_ 1473 +#define __WMI_REVISION_ 1474 /** The Version Namespace should not be normally changed. Only * host and firmware of the same WMI namespace will work From c6cd7fd9a63cb4d62eb7f80b5436a5dab1cfdd61 Mon Sep 17 00:00:00 2001 From: spuligil Date: Fri, 5 Apr 2024 06:02:22 -0700 Subject: [PATCH 05/36] fw-api: CL 26403375 - update fw common interface files Change-Id: Iffbdb9b10ea111ec9fbdceefb893b6f0bb3e8f2f CRs-Fixed: 2262693 --- fw/wmi_unified.h | 4 +++- fw/wmi_version.h | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/fw/wmi_unified.h b/fw/wmi_unified.h index 60cfbee8da66..f87a3dc69035 100644 --- a/fw/wmi_unified.h +++ b/fw/wmi_unified.h @@ -27014,7 +27014,9 @@ typedef enum { /** Lower threshold for beacon-RSSI. Used to increase RX chainmask. */ WMI_STA_SMPS_PARAM_LOWER_BRSSI_THRESH = 4, /** Enable/Disable DTIM 1chRx feature */ - WMI_STA_SMPS_PARAM_DTIM_1CHRX_ENABLE = 5 + WMI_STA_SMPS_PARAM_DTIM_1CHRX_ENABLE = 5, + /** Enable/Disable dynamic bw feature */ + WMI_STA_SMPS_PARAM_DYNAMIC_BW_SWITCH = 6, } wmi_sta_smps_param; typedef struct { diff --git a/fw/wmi_version.h b/fw/wmi_version.h index 9b9942583944..d741a667f96e 100644 --- a/fw/wmi_version.h +++ b/fw/wmi_version.h @@ -37,7 +37,7 @@ #define __WMI_VER_MINOR_ 0 /** WMI revision number has to be incremented when there is a * change that may or may not break compatibility. */ -#define __WMI_REVISION_ 1474 +#define __WMI_REVISION_ 1475 /** The Version Namespace should not be normally changed. Only * host and firmware of the same WMI namespace will work From 9893e5b78729e78d3fe3e85fa702be947f76183c Mon Sep 17 00:00:00 2001 From: spuligil Date: Thu, 18 Apr 2024 06:02:04 -0700 Subject: [PATCH 06/36] fw-api: CL 26496317 - update fw common interface files Change-Id: Ie8cbf264cd9d5a4f6e6bf0f9fe1ff7b7452bfaec CRs-Fixed: 2262693 --- fw/wmi_services.h | 1 + fw/wmi_unified.h | 2 +- fw/wmi_version.h | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/fw/wmi_services.h b/fw/wmi_services.h index 66699c62a357..74bb0183131b 100644 --- a/fw/wmi_services.h +++ b/fw/wmi_services.h @@ -662,6 +662,7 @@ typedef enum { WMI_SERVICE_TRAFFIC_CONTEXT_SUPPORT = 408, /* FW supports traffic context aware manager */ WMI_SERVICE_STA_SAP_NDP_CONCURRENCY_SUPPORT = 409, /* FW supports STA + SAP + NDP concurrency */ WMI_SERVICE_THERM_THROT_POUT_REDUCTION = 410, /* FW supports thermal throttling Pout reduction */ + WMI_SERVICE_E2E_SDWF_SUPPORT = 411, /* FW supports end-to-end SDWF features like SDWF scheduler */ WMI_MAX_EXT2_SERVICE diff --git a/fw/wmi_unified.h b/fw/wmi_unified.h index f87a3dc69035..e5ebdc37616d 100644 --- a/fw/wmi_unified.h +++ b/fw/wmi_unified.h @@ -27016,7 +27016,7 @@ typedef enum { /** Enable/Disable DTIM 1chRx feature */ WMI_STA_SMPS_PARAM_DTIM_1CHRX_ENABLE = 5, /** Enable/Disable dynamic bw feature */ - WMI_STA_SMPS_PARAM_DYNAMIC_BW_SWITCH = 6, + WMI_STA_SMPS_PARAM_DYNAMIC_BW_SWITCH = 6, } wmi_sta_smps_param; typedef struct { diff --git a/fw/wmi_version.h b/fw/wmi_version.h index d741a667f96e..9fd0ff979bdb 100644 --- a/fw/wmi_version.h +++ b/fw/wmi_version.h @@ -37,7 +37,7 @@ #define __WMI_VER_MINOR_ 0 /** WMI revision number has to be incremented when there is a * change that may or may not break compatibility. */ -#define __WMI_REVISION_ 1475 +#define __WMI_REVISION_ 1476 /** The Version Namespace should not be normally changed. Only * host and firmware of the same WMI namespace will work From c2cd135c6b9787081b7545f3db5a6ddfd32f19b1 Mon Sep 17 00:00:00 2001 From: spuligil Date: Sat, 20 Apr 2024 06:02:15 -0700 Subject: [PATCH 07/36] fw-api: CL 26511260 - update fw common interface files Change-Id: I225300d0e9540034f044667efe1ba215675547a2 CRs-Fixed: 2262693 --- fw/wmi_services.h | 1 + fw/wmi_unified.h | 10 +++++++++- fw/wmi_version.h | 2 +- 3 files changed, 11 insertions(+), 2 deletions(-) diff --git a/fw/wmi_services.h b/fw/wmi_services.h index 74bb0183131b..048b6356d0b5 100644 --- a/fw/wmi_services.h +++ b/fw/wmi_services.h @@ -663,6 +663,7 @@ typedef enum { WMI_SERVICE_STA_SAP_NDP_CONCURRENCY_SUPPORT = 409, /* FW supports STA + SAP + NDP concurrency */ WMI_SERVICE_THERM_THROT_POUT_REDUCTION = 410, /* FW supports thermal throttling Pout reduction */ WMI_SERVICE_E2E_SDWF_SUPPORT = 411, /* FW supports end-to-end SDWF features like SDWF scheduler */ + WMI_SERVICE_EPM = 412, /* FW supports enhanced power management */ WMI_MAX_EXT2_SERVICE diff --git a/fw/wmi_unified.h b/fw/wmi_unified.h index e5ebdc37616d..61de66e2f7b6 100644 --- a/fw/wmi_unified.h +++ b/fw/wmi_unified.h @@ -4618,8 +4618,12 @@ typedef struct { * and 255 indicates an invalid service class * Refer to WMI_RSRC_CFG_FLAGS2_SAWF_255_SVC_CLASS_SUPPORT_GET/SET * macros. + * Bit 20 - enable feature EPM (Enhanced Power Management) + * 0 -> disable the feature + * 1 -> enable the feature + * Refer to the below WMI_RSRC_CFG_FLAGS2_EPM_GET/SET macros. * - * Bits 31:20 - Reserved + * Bits 31:21 - Reserved */ A_UINT32 flags2; /** @brief host_service_flags - can be used by Host to indicate @@ -5114,6 +5118,10 @@ typedef struct { #define WMI_RSRC_CFG_FLAGS2_SAWF_255_SVC_CLASS_SUPPORT_SET(flags2, value) \ WMI_SET_BITS(flags2, 19, 1, value) +#define WMI_RSRC_CFG_FLAGS2_EPM_GET(flags2) \ + WMI_GET_BITS(flags2, 20, 1) +#define WMI_RSRC_CFG_FLAGS2_EPM_SET(flags2, value) \ + WMI_SET_BITS(flags2, 20, 1, value) #define WMI_RSRC_CFG_HOST_SERVICE_FLAG_NAN_IFACE_SUPPORT_GET(host_service_flags) \ WMI_GET_BITS(host_service_flags, 0, 1) diff --git a/fw/wmi_version.h b/fw/wmi_version.h index 9fd0ff979bdb..b373ebea93ad 100644 --- a/fw/wmi_version.h +++ b/fw/wmi_version.h @@ -37,7 +37,7 @@ #define __WMI_VER_MINOR_ 0 /** WMI revision number has to be incremented when there is a * change that may or may not break compatibility. */ -#define __WMI_REVISION_ 1476 +#define __WMI_REVISION_ 1477 /** The Version Namespace should not be normally changed. Only * host and firmware of the same WMI namespace will work From 70ced62a3586f28557e11588cb0e40a96a84ad94 Mon Sep 17 00:00:00 2001 From: spuligil Date: Sun, 21 Apr 2024 06:02:03 -0700 Subject: [PATCH 08/36] fw-api: CL 26515067 - update fw common interface files Change-Id: I1e022af363e1c10869bf982b17d06875b03b30d7 CRs-Fixed: 2262693 --- fw/wmi_unified.h | 6 ++++++ fw/wmi_version.h | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/fw/wmi_unified.h b/fw/wmi_unified.h index 61de66e2f7b6..509b97e5dc03 100644 --- a/fw/wmi_unified.h +++ b/fw/wmi_unified.h @@ -25678,6 +25678,12 @@ typedef enum /* Restrict SLO if specific vendor OUI received in beacon. */ WMI_VENDOR_OUI_ACTION_RESTRICT_SLO = 13, + /* + * Force MLSR mode if specific vendor OUI received in beacon + * when connect with MLO. + */ + WMI_VENDOR_OUI_ACTION_FORCE_MLSR = 14, + /* Add any action before this line */ WMI_VENDOR_OUI_ACTION_MAX_ACTION_ID diff --git a/fw/wmi_version.h b/fw/wmi_version.h index b373ebea93ad..bed59b7d7a08 100644 --- a/fw/wmi_version.h +++ b/fw/wmi_version.h @@ -37,7 +37,7 @@ #define __WMI_VER_MINOR_ 0 /** WMI revision number has to be incremented when there is a * change that may or may not break compatibility. */ -#define __WMI_REVISION_ 1477 +#define __WMI_REVISION_ 1478 /** The Version Namespace should not be normally changed. Only * host and firmware of the same WMI namespace will work From 3171c45682cc131cca4988c16889d16f71ef817e Mon Sep 17 00:00:00 2001 From: spuligil Date: Sun, 21 Apr 2024 06:06:43 -0700 Subject: [PATCH 09/36] fw-api: CL 26515400 - update fw common interface files Change-Id: I2b88bdd8e3f3f003fb99e21102d0eddeb5fd2ced CRs-Fixed: 2262693 --- fw/htt_stats.h | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/fw/htt_stats.h b/fw/htt_stats.h index c6c6fee101eb..50006666d4dc 100644 --- a/fw/htt_stats.h +++ b/fw/htt_stats.h @@ -7600,6 +7600,14 @@ typedef struct { * bin2 contains the number of sampling windows that had > 4 interrupts */ A_UINT32 interrupts_hist[HTT_INTERRUPTS_LATENCY_PROFILE_MAX_HIST]; + /* min time in us for pcycles spent on q6 core on all HW threads */ + A_UINT32 min_pcycles_time; + /* max time in us for pcycles spent on q6 core on all HW threads */ + A_UINT32 max_pcycles_time; + /* total time in us for pcycles spent on q6 core on all HW threads */ + A_UINT32 tot_pcycles_time; + /* avg time in us for pcycles spent on q6 core on all HW threads */ + A_UINT32 avg_pcycles_time; } htt_stats_latency_prof_stats_tlv; /* preserve old name alias for new name consistent with the tag name */ typedef htt_stats_latency_prof_stats_tlv htt_latency_prof_stats_tlv; From f510082f0efca1269349d8b58e49b9f3e48a37da Mon Sep 17 00:00:00 2001 From: spuligil Date: Mon, 22 Apr 2024 00:08:37 -0700 Subject: [PATCH 10/36] fw-api: CL 26517090 - update fw common interface files Change-Id: Ia942b544736d20038027745e6b55d0eed41555ce CRs-Fixed: 2262693 --- fw/wmi_services.h | 1 + fw/wmi_unified.h | 2 ++ fw/wmi_version.h | 2 +- 3 files changed, 4 insertions(+), 1 deletion(-) diff --git a/fw/wmi_services.h b/fw/wmi_services.h index 048b6356d0b5..9f0ac38fc63d 100644 --- a/fw/wmi_services.h +++ b/fw/wmi_services.h @@ -664,6 +664,7 @@ typedef enum { WMI_SERVICE_THERM_THROT_POUT_REDUCTION = 410, /* FW supports thermal throttling Pout reduction */ WMI_SERVICE_E2E_SDWF_SUPPORT = 411, /* FW supports end-to-end SDWF features like SDWF scheduler */ WMI_SERVICE_EPM = 412, /* FW supports enhanced power management */ + WMI_SERVICE_CHIPSET_LOGGING_SUPPORT = 413, /* FW supports chipset logging feature */ WMI_MAX_EXT2_SERVICE diff --git a/fw/wmi_unified.h b/fw/wmi_unified.h index 509b97e5dc03..62f03b49ab27 100644 --- a/fw/wmi_unified.h +++ b/fw/wmi_unified.h @@ -9617,6 +9617,8 @@ typedef enum { * E.g. a value of 4 will result in a 1.0 dB tx power reduction. */ WMI_PDEV_PARAM_PWR_REDUCTION_IN_QUARTER_DB, + + WMI_PDEV_PARAM_ENABLE_CHIPSET_LOGGING, } WMI_PDEV_PARAM; #define WMI_PDEV_ONLY_BSR_TRIG_IS_ENABLED(trig_type) WMI_GET_BITS(trig_type, 0, 1) diff --git a/fw/wmi_version.h b/fw/wmi_version.h index bed59b7d7a08..c92dcf3a6360 100644 --- a/fw/wmi_version.h +++ b/fw/wmi_version.h @@ -37,7 +37,7 @@ #define __WMI_VER_MINOR_ 0 /** WMI revision number has to be incremented when there is a * change that may or may not break compatibility. */ -#define __WMI_REVISION_ 1478 +#define __WMI_REVISION_ 1479 /** The Version Namespace should not be normally changed. Only * host and firmware of the same WMI namespace will work From 6bc6c071412fa8ffcdcaacf8b20a0815db86c54b Mon Sep 17 00:00:00 2001 From: Sandhya Mutha Naga Venkata Date: Mon, 29 Apr 2024 14:05:28 +0530 Subject: [PATCH 11/36] Fix for OOB access issue Added payload size check to avoid OOB read issues. Change-Id: I601ab1ac26168db50a0ada1d202d6ca197dd0241 Signed-off-by: Sandhya Mutha Naga Venkata (Source change ID: Change-Id: I4f15bdfdcf15e388ebc49dd0e8cf7a99ed03d0d5 ) --- 4.0/dsp/q6adm.c | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/4.0/dsp/q6adm.c b/4.0/dsp/q6adm.c index 5a038c97796b..0eb010a2208c 100644 --- a/4.0/dsp/q6adm.c +++ b/4.0/dsp/q6adm.c @@ -1565,16 +1565,11 @@ static int32_t adm_callback(struct apr_client_data *data, void *priv) if (data->opcode == APR_BASIC_RSP_RESULT) { pr_debug("%s: APR_BASIC_RSP_RESULT id 0x%x\n", __func__, payload[0]); - - if (!((client_id != ADM_CLIENT_ID_SOURCE_TRACKING) && - ((payload[0] == ADM_CMD_SET_PP_PARAMS_V5) || - (payload[0] == ADM_CMD_SET_PP_PARAMS_V6)))) { - if (data->payload_size < - (2 * sizeof(uint32_t))) { - pr_err("%s: Invalid payload size %d\n", - __func__, data->payload_size); - return 0; - } + if (data->payload_size < + (2 * sizeof(uint32_t))) { + pr_err("%s: Invalid payload size %d\n", + __func__, data->payload_size); + return 0; } if (payload[1] != 0) { From 7ab5e2146ffb06f375bc2b848da06b8f96b929e7 Mon Sep 17 00:00:00 2001 From: spuligil Date: Wed, 24 Apr 2024 06:01:48 -0700 Subject: [PATCH 12/36] fw-api: CL 26534623 - update fw common interface files Change-Id: I00aef4a9ef40dd4791bb77a6079550d5c59a6155 CRs-Fixed: 2262693 --- fw/wmi_unified.h | 10 ++++++++++ fw/wmi_version.h | 2 +- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/fw/wmi_unified.h b/fw/wmi_unified.h index 62f03b49ab27..799c2e1c131f 100644 --- a/fw/wmi_unified.h +++ b/fw/wmi_unified.h @@ -9619,6 +9619,16 @@ typedef enum { WMI_PDEV_PARAM_PWR_REDUCTION_IN_QUARTER_DB, WMI_PDEV_PARAM_ENABLE_CHIPSET_LOGGING, + + /** SCAN MODE: + * bit | scan_mode + * ----------------- + * 0 | SISO SCAN - 1x1 scan + * | If this bit is 0, then use default scan (NxN). + * 1-31 | Reserved. + */ + WMI_PDEV_PARAM_SCAN_MODE, + } WMI_PDEV_PARAM; #define WMI_PDEV_ONLY_BSR_TRIG_IS_ENABLED(trig_type) WMI_GET_BITS(trig_type, 0, 1) diff --git a/fw/wmi_version.h b/fw/wmi_version.h index c92dcf3a6360..bc3c2b585b7c 100644 --- a/fw/wmi_version.h +++ b/fw/wmi_version.h @@ -37,7 +37,7 @@ #define __WMI_VER_MINOR_ 0 /** WMI revision number has to be incremented when there is a * change that may or may not break compatibility. */ -#define __WMI_REVISION_ 1479 +#define __WMI_REVISION_ 1480 /** The Version Namespace should not be normally changed. Only * host and firmware of the same WMI namespace will work From f4ec015bd4ffc72ee4099bcd72653a8b8d26f10f Mon Sep 17 00:00:00 2001 From: guyang Date: Thu, 11 Apr 2024 15:07:14 +0800 Subject: [PATCH 13/36] msm: camera: sensor: Handling race condition in util api I2C cmd is coming from user space which can be modified due to access to shared memory. This change scopes the data locally so as to avoid vulnerability of count being modified by external means while executing due to being in shared memory. CRs-Fixed: 3707472 Change-Id: I8a89e23e99b80b089ed4c4cf3098feead752356e Signed-off-by: Shivi Mangal Signed-off-by: Guang Yang --- .../cam_sensor_utils/cam_sensor_util.c | 20 +++++++++---------- .../cam_sensor_utils/cam_sensor_util.c | 20 +++++++++---------- 2 files changed, 20 insertions(+), 20 deletions(-) diff --git a/drivers/media/platform/msm/ais/cam_sensor_module/cam_sensor_utils/cam_sensor_util.c b/drivers/media/platform/msm/ais/cam_sensor_module/cam_sensor_utils/cam_sensor_util.c index d58762b44f3a..faa03af04289 100644 --- a/drivers/media/platform/msm/ais/cam_sensor_module/cam_sensor_utils/cam_sensor_util.c +++ b/drivers/media/platform/msm/ais/cam_sensor_module/cam_sensor_utils/cam_sensor_util.c @@ -157,10 +157,11 @@ int32_t cam_sensor_handle_random_write( struct list_head **list) { struct i2c_settings_list *i2c_list; - int32_t rc = 0, cnt; + int32_t rc = 0, cnt, payload_count; + payload_count = cam_cmd_i2c_random_wr->header.count; i2c_list = cam_sensor_get_i2c_ptr(i2c_reg_settings, - cam_cmd_i2c_random_wr->header.count); + payload_count); if (i2c_list == NULL || i2c_list->i2c_settings.reg_setting == NULL) { CAM_ERR(CAM_SENSOR, "Failed in allocating i2c_list"); @@ -169,15 +170,14 @@ int32_t cam_sensor_handle_random_write( *cmd_length_in_bytes = (sizeof(struct i2c_rdwr_header) + sizeof(struct i2c_random_wr_payload) * - (cam_cmd_i2c_random_wr->header.count)); + payload_count); i2c_list->op_code = CAM_SENSOR_I2C_WRITE_RANDOM; i2c_list->i2c_settings.addr_type = cam_cmd_i2c_random_wr->header.addr_type; i2c_list->i2c_settings.data_type = cam_cmd_i2c_random_wr->header.data_type; - for (cnt = 0; cnt < (cam_cmd_i2c_random_wr->header.count); - cnt++) { + for (cnt = 0; cnt < payload_count; cnt++) { i2c_list->i2c_settings.reg_setting[cnt].reg_addr = cam_cmd_i2c_random_wr->random_wr_payload[cnt].reg_addr; i2c_list->i2c_settings.reg_setting[cnt].reg_data = @@ -197,10 +197,11 @@ static int32_t cam_sensor_handle_continuous_write( struct list_head **list) { struct i2c_settings_list *i2c_list; - int32_t rc = 0, cnt; + int32_t rc = 0, cnt, payload_count; + payload_count = cam_cmd_i2c_continuous_wr->header.count; i2c_list = cam_sensor_get_i2c_ptr(i2c_reg_settings, - cam_cmd_i2c_continuous_wr->header.count); + payload_count); if (i2c_list == NULL || i2c_list->i2c_settings.reg_setting == NULL) { CAM_ERR(CAM_SENSOR, "Failed in allocating i2c_list"); @@ -210,7 +211,7 @@ static int32_t cam_sensor_handle_continuous_write( *cmd_length_in_bytes = (sizeof(struct i2c_rdwr_header) + sizeof(cam_cmd_i2c_continuous_wr->reg_addr) + sizeof(struct cam_cmd_read) * - (cam_cmd_i2c_continuous_wr->header.count)); + (payload_count)); if (cam_cmd_i2c_continuous_wr->header.op_code == CAMERA_SENSOR_I2C_OP_CONT_WR_BRST) i2c_list->op_code = CAM_SENSOR_I2C_WRITE_BURST; @@ -227,8 +228,7 @@ static int32_t cam_sensor_handle_continuous_write( i2c_list->i2c_settings.size = cam_cmd_i2c_continuous_wr->header.count; - for (cnt = 0; cnt < (cam_cmd_i2c_continuous_wr->header.count); - cnt++) { + for (cnt = 0; cnt < payload_count; cnt++) { i2c_list->i2c_settings.reg_setting[cnt].reg_addr = cam_cmd_i2c_continuous_wr->reg_addr; i2c_list->i2c_settings.reg_setting[cnt].reg_data = diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_utils/cam_sensor_util.c b/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_utils/cam_sensor_util.c index 2e8b6696af75..e9e43401d0d7 100644 --- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_utils/cam_sensor_util.c +++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_utils/cam_sensor_util.c @@ -157,10 +157,11 @@ int32_t cam_sensor_handle_random_write( struct list_head **list) { struct i2c_settings_list *i2c_list; - int32_t rc = 0, cnt; + int32_t rc = 0, cnt, payload_count; + payload_count = cam_cmd_i2c_random_wr->header.count; i2c_list = cam_sensor_get_i2c_ptr(i2c_reg_settings, - cam_cmd_i2c_random_wr->header.count); + payload_count); if (i2c_list == NULL || i2c_list->i2c_settings.reg_setting == NULL) { CAM_ERR(CAM_SENSOR, "Failed in allocating i2c_list"); @@ -169,15 +170,14 @@ int32_t cam_sensor_handle_random_write( *cmd_length_in_bytes = (sizeof(struct i2c_rdwr_header) + sizeof(struct i2c_random_wr_payload) * - (cam_cmd_i2c_random_wr->header.count)); + payload_count); i2c_list->op_code = CAM_SENSOR_I2C_WRITE_RANDOM; i2c_list->i2c_settings.addr_type = cam_cmd_i2c_random_wr->header.addr_type; i2c_list->i2c_settings.data_type = cam_cmd_i2c_random_wr->header.data_type; - for (cnt = 0; cnt < (cam_cmd_i2c_random_wr->header.count); - cnt++) { + for (cnt = 0; cnt < payload_count; cnt++) { i2c_list->i2c_settings.reg_setting[cnt].reg_addr = cam_cmd_i2c_random_wr->random_wr_payload[cnt].reg_addr; i2c_list->i2c_settings.reg_setting[cnt].reg_data = @@ -197,10 +197,11 @@ static int32_t cam_sensor_handle_continuous_write( struct list_head **list) { struct i2c_settings_list *i2c_list; - int32_t rc = 0, cnt; + int32_t rc = 0, cnt, payload_count; + payload_count = cam_cmd_i2c_continuous_wr->header.count; i2c_list = cam_sensor_get_i2c_ptr(i2c_reg_settings, - cam_cmd_i2c_continuous_wr->header.count); + payload_count); if (i2c_list == NULL || i2c_list->i2c_settings.reg_setting == NULL) { CAM_ERR(CAM_SENSOR, "Failed in allocating i2c_list"); @@ -210,7 +211,7 @@ static int32_t cam_sensor_handle_continuous_write( *cmd_length_in_bytes = (sizeof(struct i2c_rdwr_header) + sizeof(cam_cmd_i2c_continuous_wr->reg_addr) + sizeof(struct cam_cmd_read) * - (cam_cmd_i2c_continuous_wr->header.count)); + (payload_count)); if (cam_cmd_i2c_continuous_wr->header.op_code == CAMERA_SENSOR_I2C_OP_CONT_WR_BRST) i2c_list->op_code = CAM_SENSOR_I2C_WRITE_BURST; @@ -227,8 +228,7 @@ static int32_t cam_sensor_handle_continuous_write( i2c_list->i2c_settings.size = cam_cmd_i2c_continuous_wr->header.count; - for (cnt = 0; cnt < (cam_cmd_i2c_continuous_wr->header.count); - cnt++) { + for (cnt = 0; cnt < payload_count; cnt++) { i2c_list->i2c_settings.reg_setting[cnt].reg_addr = cam_cmd_i2c_continuous_wr->reg_addr; i2c_list->i2c_settings.reg_setting[cnt].reg_data = From a4e07b2b3b7357e8578832a4e2925278c9acf86d Mon Sep 17 00:00:00 2001 From: ppadasal Date: Thu, 2 May 2024 10:52:44 +0530 Subject: [PATCH 14/36] msm: vidc: Fix possible UAF during buffer unregister call [1] During buffer unregister, CVP buffer lock is released immediately after finding buffer in register buffer list. UAF might happen if two threads execute same unregister command as buffer free happens after unregister done. [2] Hold CVP buffer lock through out in unregister and unregister done calls. Change-Id: I8b6734410369ab990081c558ba846b6dfbfc8588 Signed-off-by: ppadasal --- drivers/media/platform/msm/vidc/msm_cvp.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/media/platform/msm/vidc/msm_cvp.c b/drivers/media/platform/msm/vidc/msm_cvp.c index f63c55c461d2..bde49c879f56 100644 --- a/drivers/media/platform/msm/vidc/msm_cvp.c +++ b/drivers/media/platform/msm/vidc/msm_cvp.c @@ -148,7 +148,6 @@ void handle_session_unregister_buffer_done(enum hal_command_response cmd, break; } } - mutex_unlock(&inst->cvpbufs.lock); if (!found) { dprintk(VIDC_ERR, "%s: client_data %x not found\n", __func__, response->data.unregbuf.client_data); @@ -170,12 +169,11 @@ void handle_session_unregister_buffer_done(enum hal_command_response cmd, data[3] = cbuf->buf.offset; v4l2_event_queue_fh(&inst->event_handler, &event); - mutex_lock(&inst->cvpbufs.lock); list_del(&cbuf->list); - mutex_unlock(&inst->cvpbufs.lock); kfree(cbuf); cbuf = NULL; exit: + mutex_unlock(&inst->cvpbufs.lock); put_inst(inst); } @@ -440,7 +438,6 @@ static int msm_cvp_unregister_buffer(struct msm_vidc_inst *inst, break; } } - mutex_unlock(&inst->cvpbufs.lock); if (!found) { print_client_buffer(VIDC_ERR, "invalid", inst, buf); return -EINVAL; @@ -458,6 +455,7 @@ static int msm_cvp_unregister_buffer(struct msm_vidc_inst *inst, if (rc) print_cvp_buffer(VIDC_ERR, "unregister failed", inst, cbuf); + mutex_unlock(&inst->cvpbufs.lock); return rc; } From 718b127edf748b07f8d1e6f74a7f3a08900179e0 Mon Sep 17 00:00:00 2001 From: spuligil Date: Thu, 2 May 2024 03:20:39 -0700 Subject: [PATCH 15/36] fw-api: CL 26587627 - update fw common interface files Change-Id: I9702a8ea7c84468105509fc3b23dbbe8776bb885 CRs-Fixed: 2262693 --- fw/wmi_services.h | 1 + fw/wmi_tlv_defs.h | 7 +++++++ fw/wmi_unified.h | 15 +++++++++++++++ fw/wmi_version.h | 2 +- 4 files changed, 24 insertions(+), 1 deletion(-) diff --git a/fw/wmi_services.h b/fw/wmi_services.h index 9f0ac38fc63d..e4badf6d1967 100644 --- a/fw/wmi_services.h +++ b/fw/wmi_services.h @@ -665,6 +665,7 @@ typedef enum { WMI_SERVICE_E2E_SDWF_SUPPORT = 411, /* FW supports end-to-end SDWF features like SDWF scheduler */ WMI_SERVICE_EPM = 412, /* FW supports enhanced power management */ WMI_SERVICE_CHIPSET_LOGGING_SUPPORT = 413, /* FW supports chipset logging feature */ + WMI_SERVICE_SUPPORT_AP_SUSPEND_RESUME = 414, /* FW supports SAP suspend feature */ WMI_MAX_EXT2_SERVICE diff --git a/fw/wmi_tlv_defs.h b/fw/wmi_tlv_defs.h index c807d87a4208..803e716caf51 100644 --- a/fw/wmi_tlv_defs.h +++ b/fw/wmi_tlv_defs.h @@ -1437,6 +1437,7 @@ typedef enum { WMITLV_TAG_STRUC_wmi_ctrl_path_vdev_bcn_tx_stats_struct, WMITLV_TAG_STRUC_wmi_ctrl_path_pdev_bcn_tx_stats_struct, WMITLV_TAG_STRUC_wmi_soc_tx_packet_custom_classify_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_set_ap_suspend_resume_cmd_fixed_param, } WMITLV_TAG_ID; /* * IMPORTANT: Please add _ALL_ WMI Commands Here. @@ -1986,6 +1987,7 @@ typedef enum { OP(WMI_PEER_ACTIVE_TRAFFIC_MAP_CMDID) \ OP(WMI_REQUEST_OPM_STATS_CMDID) \ OP(WMI_SOC_TX_PACKET_CUSTOM_CLASSIFY_CMDID) \ + OP(WMI_SET_AP_SUSPEND_RESUME_CMDID) \ /* add new CMD_LIST elements above this line */ @@ -5613,6 +5615,11 @@ WMITLV_CREATE_PARAM_STRUC(WMI_PEER_ACTIVE_TRAFFIC_MAP_CMDID); WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_request_opm_stats_cmd_fixed_param, wmi_request_opm_stats_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) WMITLV_CREATE_PARAM_STRUC(WMI_REQUEST_OPM_STATS_CMDID); +/* SAP suspend/resume command */ +#define WMITLV_TABLE_WMI_SET_AP_SUSPEND_RESUME_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_set_ap_suspend_resume_cmd_fixed_param, wmi_set_ap_suspend_resume_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_SET_AP_SUSPEND_RESUME_CMDID); + /************************** TLV definitions of WMI events *******************************/ diff --git a/fw/wmi_unified.h b/fw/wmi_unified.h index 799c2e1c131f..01caa7ccc56d 100644 --- a/fw/wmi_unified.h +++ b/fw/wmi_unified.h @@ -1308,6 +1308,9 @@ typedef enum { /** WMI command to Request Opportunistic Power Mgmt (OPM) stats */ WMI_REQUEST_OPM_STATS_CMDID, + /** WMI command to Request SAP suspend/resume */ + WMI_SET_AP_SUSPEND_RESUME_CMDID, + /* Offload 11k related requests */ WMI_11K_OFFLOAD_REPORT_CMDID = WMI_CMD_GRP_START_ID(WMI_GRP_11K_OFFLOAD), @@ -37805,6 +37808,7 @@ static INLINE A_UINT8 *wmi_id_to_name(A_UINT32 wmi_command) WMI_RETURN_STRING(WMI_PEER_ACTIVE_TRAFFIC_MAP_CMDID); WMI_RETURN_STRING(WMI_REQUEST_OPM_STATS_CMDID); WMI_RETURN_STRING(WMI_SOC_TX_PACKET_CUSTOM_CLASSIFY_CMDID); + WMI_RETURN_STRING(WMI_SET_AP_SUSPEND_RESUME_CMDID); } return (A_UINT8 *) "Invalid WMI cmd"; @@ -48511,6 +48515,17 @@ typedef struct { A_UINT32 pdev_id; /** pdev_id for identifying the MAC */ } wmi_request_opm_stats_cmd_fixed_param; +/* wmi command to suspend SAP vdev */ +typedef struct { + /** TLV tag and len; tag equals + * WMITLV_TAG_STRUC_wmi_set_ap_suspend_resume_cmd_fixed_param */ + A_UINT32 tlv_header; + /* VDEV identifier */ + A_UINT32 vdev_id; /* If 0xFF, find vdevs corresponding to MLD MAC address */ + wmi_mac_addr mld_mac_address; /* MLD MAC address */ + A_UINT32 is_ap_suspend; /* 1 = suspend, 0 = resume */ +} wmi_set_ap_suspend_resume_fixed_param; + /* ADD NEW DEFS HERE */ diff --git a/fw/wmi_version.h b/fw/wmi_version.h index bc3c2b585b7c..adf28bee1c98 100644 --- a/fw/wmi_version.h +++ b/fw/wmi_version.h @@ -37,7 +37,7 @@ #define __WMI_VER_MINOR_ 0 /** WMI revision number has to be incremented when there is a * change that may or may not break compatibility. */ -#define __WMI_REVISION_ 1480 +#define __WMI_REVISION_ 1481 /** The Version Namespace should not be normally changed. Only * host and firmware of the same WMI namespace will work From 6960301493481dbb1920ea128fa012bd8b60c9cd Mon Sep 17 00:00:00 2001 From: ppadasal Date: Mon, 6 May 2024 10:16:48 +0530 Subject: [PATCH 16/36] msm: vidc: Release cvp buffer lock in invalid buffer case If client tries to unregister invalid buffer, release cvp buffer lock before sending error. Change-Id: I968ff15673ae5e72299602f595f794658bb28e2a Signed-off-by: ppadasal --- drivers/media/platform/msm/vidc/msm_cvp.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/media/platform/msm/vidc/msm_cvp.c b/drivers/media/platform/msm/vidc/msm_cvp.c index bde49c879f56..8616f2a9a231 100644 --- a/drivers/media/platform/msm/vidc/msm_cvp.c +++ b/drivers/media/platform/msm/vidc/msm_cvp.c @@ -440,6 +440,7 @@ static int msm_cvp_unregister_buffer(struct msm_vidc_inst *inst, } if (!found) { print_client_buffer(VIDC_ERR, "invalid", inst, buf); + mutex_unlock(&inst->cvpbufs.lock); return -EINVAL; } From a39bc609e7499bfa82d6fc1eba93bd808e9febae Mon Sep 17 00:00:00 2001 From: Sandhya Mutha Naga Venkata Date: Mon, 15 Apr 2024 00:50:50 -0700 Subject: [PATCH 17/36] dsp: q6lsm: Check size of payload before access check size of payload before access in q6lsm_mmapcallback. Change-Id: I6a755ca4cf54078f0d00f38e303f1b1da29b244c Signed-off-by: Kumar Anurag Singh (cherry picked from commit bbe748c8dfa4de303462edaba96d4ce283c13bc7) Signed-off-by: Sandhya Mutha Naga Venkata --- dsp/q6lsm.c | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/dsp/q6lsm.c b/dsp/q6lsm.c index fdff509e594d..74fb34a5151c 100644 --- a/dsp/q6lsm.c +++ b/dsp/q6lsm.c @@ -1,15 +1,6 @@ /* * Copyright (c) 2013-2019, Linux Foundation. All rights reserved. - * - * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 and - * only version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * Copyright (c) 2023-2024 Qualcomm Innovation Center, Inc. All rights reserved. */ #include #include @@ -1823,6 +1814,12 @@ static int q6lsm_mmapcallback(struct apr_client_data *data, void *priv) return 0; } + if (data->payload_size < (2 * sizeof(uint32_t))) { + pr_err("%s: payload has invalid size[%d]\n", __func__, + data->payload_size); + return -EINVAL; + } + command = payload[0]; retcode = payload[1]; sid = (data->token >> 8) & 0x0F; From 7afa37f24bc49e6c2dde1f9e9a2c2a194e4d582d Mon Sep 17 00:00:00 2001 From: Sandhya Mutha Naga Venkata Date: Tue, 7 May 2024 11:31:09 +0530 Subject: [PATCH 18/36] dsp: q6lsm: Check size of payload before access check size of payload before access in q6lsm_mmapcallback. Change-Id: I03df98f7ce7bb74f463225f904a0f402cf3da75e Signed-off-by: Sandhya Mutha Naga Venkata (Source change-Id: I6a755ca4cf54078f0d00f38e303f1b1da29b244c) --- 4.0/dsp/q6lsm.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/4.0/dsp/q6lsm.c b/4.0/dsp/q6lsm.c index 058e8a8e8666..8644305381ef 100644 --- a/4.0/dsp/q6lsm.c +++ b/4.0/dsp/q6lsm.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2013-2019, Linux Foundation. All rights reserved. - * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2023-2024 Qualcomm Innovation Center, Inc. All rights reserved. */ #include #include @@ -1901,6 +1901,12 @@ static int q6lsm_mmapcallback(struct apr_client_data *data, void *priv) return 0; } + if (data->payload_size < (2 * sizeof(uint32_t))) { + pr_err("%s: payload has invalid size[%d]\n", __func__, + data->payload_size); + return -EINVAL; + } + command = payload[0]; retcode = payload[1]; sid = (data->token >> 8) & 0x0F; From 3b792504f135ac973f126498a8fb2075b7dfb567 Mon Sep 17 00:00:00 2001 From: imallik Date: Wed, 24 Apr 2024 15:15:32 +0530 Subject: [PATCH 19/36] defconfig: Disable SLUB_DEBUG SCHED_DEBUG and DEBUG_PREEMPT in perf build Disabled Debug SLUB, SCHED and PREEMPT drivers in perf build for MDM9607 target. Wlan Throughput is impacted if these debug drivers are not disabled. Change-Id: If02c0cd6735d1e97e3959b53ec166d0a00e1f3ad Signed-off-by: imallik --- arch/arm/configs/vendor/mdm9607-perf_defconfig | 3 +++ 1 file changed, 3 insertions(+) diff --git a/arch/arm/configs/vendor/mdm9607-perf_defconfig b/arch/arm/configs/vendor/mdm9607-perf_defconfig index fca23c73bdde..37353e4af346 100644 --- a/arch/arm/configs/vendor/mdm9607-perf_defconfig +++ b/arch/arm/configs/vendor/mdm9607-perf_defconfig @@ -11,6 +11,7 @@ CONFIG_BLK_DEV_INITRD=y CONFIG_CC_OPTIMIZE_FOR_SIZE=y CONFIG_KALLSYMS_ALL=y CONFIG_EMBEDDED=y +# CONFIG_SLUB_DEBUG is not set CONFIG_PROFILING=y CONFIG_MODULES=y CONFIG_MODULE_UNLOAD=y @@ -336,6 +337,8 @@ CONFIG_DEBUG_INFO=y CONFIG_MAGIC_SYSRQ=y CONFIG_PANIC_ON_RECURSIVE_FAULT=y CONFIG_PANIC_TIMEOUT=5 +# CONFIG_SCHED_DEBUG is not set +# CONFIG_DEBUG_PREEMPT is not set CONFIG_IPC_LOGGING=y CONFIG_CORESIGHT=y CONFIG_CORESIGHT_LINK_AND_SINK_TMC=y From d66d9e683dc6f0b7afa8d65c28089540ff2d155b Mon Sep 17 00:00:00 2001 From: spuligil Date: Tue, 7 May 2024 02:14:19 -0700 Subject: [PATCH 20/36] fw-api: CL 26614150 - update fw common interface files Change-Id: I60d89bd7f8bf7f4c135e97dfdfb687908e3fd61b CRs-Fixed: 2262693 --- fw/wmi_unified.h | 5 +++++ fw/wmi_version.h | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/fw/wmi_unified.h b/fw/wmi_unified.h index 01caa7ccc56d..8b31d9105e9b 100644 --- a/fw/wmi_unified.h +++ b/fw/wmi_unified.h @@ -9632,6 +9632,11 @@ typedef enum { */ WMI_PDEV_PARAM_SCAN_MODE, + /** configure datastall consecutive no ack interval (units = ms) */ + WMI_PDEV_PARAM_DSTALL_CONSECUTIVE_TX_NO_ACK_INTERVAL, + /** configure datastall consecutive no ack threshold */ + WMI_PDEV_PARAM_DSTALL_CONSECUTIVE_TX_NO_ACK_THRESHOLD, + } WMI_PDEV_PARAM; #define WMI_PDEV_ONLY_BSR_TRIG_IS_ENABLED(trig_type) WMI_GET_BITS(trig_type, 0, 1) diff --git a/fw/wmi_version.h b/fw/wmi_version.h index adf28bee1c98..de089895ae7a 100644 --- a/fw/wmi_version.h +++ b/fw/wmi_version.h @@ -37,7 +37,7 @@ #define __WMI_VER_MINOR_ 0 /** WMI revision number has to be incremented when there is a * change that may or may not break compatibility. */ -#define __WMI_REVISION_ 1481 +#define __WMI_REVISION_ 1482 /** The Version Namespace should not be normally changed. Only * host and firmware of the same WMI namespace will work From a5297b52fc13bf5a7b1e771b3f0fb8278655df25 Mon Sep 17 00:00:00 2001 From: Sandhya Mutha Naga Venkata Date: Wed, 1 May 2024 09:51:35 +0530 Subject: [PATCH 21/36] dsp: q6voice: Adds checks for an integer overflow there is no check for cvs_voc_pkt[2],when recieves 0xffffffff from ADSP which results in an integer overflow Fix is to address this. Change-Id: Ie935dd8823981ec260d77f5117f4ef0b0fc08f60 Signed-off-by: Ramireddy KrishnaKanth Reddy (cherry picked from commit 4524418cd14dce47e4ea7234618f919e28dbbe5a) Signed-off-by: Sandhya Mutha Naga Venkata --- dsp/q6voice.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/dsp/q6voice.c b/dsp/q6voice.c index 0089adbd5680..d9b444715f9e 100644 --- a/dsp/q6voice.c +++ b/dsp/q6voice.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* Copyright (c) 2012-2019, The Linux Foundation. All rights reserved. - * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2023-2024, Qualcomm Innovation Center, Inc. All rights reserved. */ #include #include @@ -7777,7 +7777,7 @@ static int32_t qdsp_cvs_callback(struct apr_client_data *data, void *priv) VSS_ISTREAM_EVT_OOB_NOTIFY_ENC_BUFFER_READY) { int ret = 0; u16 cvs_handle; - uint32_t *cvs_voc_pkt; + uint32_t *cvs_voc_pkt, tot_buf_sz; struct cvs_enc_buffer_consumed_cmd send_enc_buf_consumed_cmd; void *apr_cvs; @@ -7806,9 +7806,14 @@ static int32_t qdsp_cvs_callback(struct apr_client_data *data, void *priv) VSS_ISTREAM_EVT_OOB_NOTIFY_ENC_BUFFER_CONSUMED; cvs_voc_pkt = v->shmem_info.sh_buf.buf[1].data; + + if (__builtin_add_overflow(cvs_voc_pkt[2], 3 * sizeof(uint32_t), &tot_buf_sz)) { + pr_err("%s: integer overflow detected\n", __func__); + return -EINVAL; + } + if (cvs_voc_pkt != NULL && common.mvs_info.ul_cb != NULL) { - if (v->shmem_info.sh_buf.buf[1].size < - ((3 * sizeof(uint32_t)) + cvs_voc_pkt[2])) { + if (v->shmem_info.sh_buf.buf[1].size < tot_buf_sz) { pr_err("%s: invalid voc pkt size\n", __func__); return -EINVAL; } From 2445010977095c793e8bf7b114d6117372b97cdf Mon Sep 17 00:00:00 2001 From: Kaushal Hooda Date: Fri, 2 Jun 2023 20:21:06 +0530 Subject: [PATCH 22/36] rpmsg: bgcom: out of bound read from process_cmd When dereferencing "rx_data" as type "glink_bgcom_msg" , we didn't check if "rx_data" has enough room to hold that type. The "rx_size" is read from remote to master fifo and if received rx_size is less then "glink_bgcom_msg" then it could lead to heap out of bounds read. If received rx_size is less then the expected glink_bgcom_msg then return back as a bad message. Change-Id: Idde757ee70c7c88c22e4f036e6da0280e3b385d0 Signed-off-by: Kaushal Hooda --- drivers/rpmsg/qcom_glink_bgcom.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/drivers/rpmsg/qcom_glink_bgcom.c b/drivers/rpmsg/qcom_glink_bgcom.c index b25fa75d53b8..9987aaa3b14c 100644 --- a/drivers/rpmsg/qcom_glink_bgcom.c +++ b/drivers/rpmsg/qcom_glink_bgcom.c @@ -1864,7 +1864,7 @@ static void glink_bgcom_handle_rx_done(struct glink_bgcom *glink, mutex_unlock(&channel->intent_lock); } -static void glink_bgcom_process_cmd(struct glink_bgcom *glink, void *rx_data, +static int glink_bgcom_process_cmd(struct glink_bgcom *glink, void *rx_data, u32 rx_size) { struct glink_bgcom_msg *msg; @@ -1873,12 +1873,19 @@ static void glink_bgcom_process_cmd(struct glink_bgcom *glink, void *rx_data, unsigned int param3; unsigned int param4; unsigned int cmd; - int offset = 0; - int ret; + u32 offset = 0; + int ret = 0; u16 name_len; char *name; while (offset < rx_size) { + if (rx_size - offset < sizeof(struct glink_bgcom_msg)) { + ret = -EBADMSG; + GLINK_ERR(glink, "%s: Error %d process cmd\n", + __func__, ret); + return ret; + } + msg = (struct glink_bgcom_msg *)(rx_data + offset); offset += sizeof(*msg); @@ -1961,6 +1968,7 @@ static void glink_bgcom_process_cmd(struct glink_bgcom *glink, void *rx_data, break; } } + return ret; } /** From d1a8c671b39e3b40ef9f29d23186daf7164a59dd Mon Sep 17 00:00:00 2001 From: Jilai Wang Date: Mon, 5 Feb 2024 12:54:48 -0500 Subject: [PATCH 23/36] msm: npu v1: Fix OOB issue in IPC between driver and firmware We shoudn't trust the data from firmware, and need to validate all content before using them. Change-Id: I604f9c4b9d5fa8d2ace0583a84ebacfc5ae6b063 Signed-off-by: Jilai Wang --- drivers/media/platform/msm/npu/npu_common.h | 6 - drivers/media/platform/msm/npu/npu_debugfs.c | 265 +----------------- drivers/media/platform/msm/npu/npu_host_ipc.c | 48 +++- .../media/platform/msm/npu/npu_hw_access.c | 54 +--- .../media/platform/msm/npu/npu_hw_access.h | 3 - drivers/media/platform/msm/npu/npu_mgr.c | 62 +--- 6 files changed, 50 insertions(+), 388 deletions(-) diff --git a/drivers/media/platform/msm/npu/npu_common.h b/drivers/media/platform/msm/npu/npu_common.h index ee328717b837..b29d57b20399 100644 --- a/drivers/media/platform/msm/npu/npu_common.h +++ b/drivers/media/platform/msm/npu/npu_common.h @@ -102,12 +102,6 @@ struct npu_debugfs_ctx { struct dentry *root; uint32_t reg_off; uint32_t reg_cnt; - uint8_t *log_buf; - struct mutex log_lock; - uint32_t log_num_bytes_buffered; - uint32_t log_read_index; - uint32_t log_write_index; - uint32_t log_buf_size; }; struct npu_debugfs_reg_ctx { diff --git a/drivers/media/platform/msm/npu/npu_debugfs.c b/drivers/media/platform/msm/npu/npu_debugfs.c index fb1f62f64aa1..6157585ac48b 100644 --- a/drivers/media/platform/msm/npu/npu_debugfs.c +++ b/drivers/media/platform/msm/npu/npu_debugfs.c @@ -34,16 +34,6 @@ */ static int npu_debug_open(struct inode *inode, struct file *file); static int npu_debug_release(struct inode *inode, struct file *file); -static int npu_debug_reg_open(struct inode *inode, struct file *file); -static int npu_debug_reg_release(struct inode *inode, struct file *file); -static ssize_t npu_debug_reg_read(struct file *file, - char __user *user_buf, size_t count, loff_t *ppos); -static ssize_t npu_debug_off_write(struct file *file, - const char __user *user_buf, size_t count, loff_t *ppos); -static ssize_t npu_debug_off_read(struct file *file, - char __user *user_buf, size_t count, loff_t *ppos); -static ssize_t npu_debug_log_read(struct file *file, - char __user *user_buf, size_t count, loff_t *ppos); static ssize_t npu_debug_ctrl_write(struct file *file, const char __user *user_buf, size_t count, loff_t *ppos); @@ -51,27 +41,7 @@ static ssize_t npu_debug_ctrl_write(struct file *file, * Variables * ------------------------------------------------------------------------- */ -struct npu_device *g_npu_dev; - -static const struct file_operations npu_reg_fops = { - .open = npu_debug_reg_open, - .release = npu_debug_reg_release, - .read = npu_debug_reg_read, -}; - -static const struct file_operations npu_off_fops = { - .open = npu_debug_open, - .release = npu_debug_release, - .read = npu_debug_off_read, - .write = npu_debug_off_write, -}; - -static const struct file_operations npu_log_fops = { - .open = npu_debug_open, - .release = npu_debug_release, - .read = npu_debug_log_read, - .write = NULL, -}; +static struct npu_device *g_npu_dev; static const struct file_operations npu_ctrl_fops = { .open = npu_debug_open, @@ -97,207 +67,6 @@ static int npu_debug_release(struct inode *inode, struct file *file) return 0; } -static int npu_debug_reg_open(struct inode *inode, struct file *file) -{ - struct npu_debugfs_reg_ctx *reg_ctx; - - reg_ctx = kzalloc(sizeof(*reg_ctx), GFP_KERNEL); - if (!reg_ctx) - return -ENOMEM; - - /* non-seekable */ - file->f_mode &= ~(FMODE_LSEEK | FMODE_PREAD | FMODE_PWRITE); - reg_ctx->npu_dev = inode->i_private; - file->private_data = reg_ctx; - return 0; -} - -static int npu_debug_reg_release(struct inode *inode, struct file *file) -{ - struct npu_debugfs_reg_ctx *reg_ctx = file->private_data; - - kfree(reg_ctx->buf); - kfree(reg_ctx); - file->private_data = NULL; - return 0; -} - -/* ------------------------------------------------------------------------- - * Function Implementations - Reg Read/Write - * ------------------------------------------------------------------------- - */ -static ssize_t npu_debug_reg_read(struct file *file, - char __user *user_buf, size_t count, loff_t *ppos) -{ - struct npu_debugfs_reg_ctx *reg_ctx = file->private_data; - struct npu_device *npu_dev = reg_ctx->npu_dev; - struct npu_debugfs_ctx *debugfs; - size_t len; - - debugfs = &npu_dev->debugfs_ctx; - - if (debugfs->reg_cnt == 0) - return 0; - - if (!reg_ctx->buf) { - char dump_buf[64]; - char *ptr; - int cnt, tot, off; - - reg_ctx->buf_len = sizeof(dump_buf) * - DIV_ROUND_UP(debugfs->reg_cnt, ROW_BYTES); - reg_ctx->buf = kzalloc(reg_ctx->buf_len, GFP_KERNEL); - - if (!reg_ctx->buf) - return -ENOMEM; - - ptr = npu_dev->core_io.base + debugfs->reg_off; - tot = 0; - off = (int)debugfs->reg_off; - - if (npu_enable_core_power(npu_dev)) - return -EPERM; - - for (cnt = debugfs->reg_cnt * 4; cnt > 0; cnt -= ROW_BYTES) { - hex_dump_to_buffer(ptr, min(cnt, ROW_BYTES), - ROW_BYTES, GROUP_BYTES, dump_buf, - sizeof(dump_buf), false); - len = scnprintf(reg_ctx->buf + tot, - reg_ctx->buf_len - tot, "0x%08x: %s\n", - ((int) (unsigned long) ptr) - - ((int) (unsigned long) npu_dev->core_io.base), - dump_buf); - - ptr += ROW_BYTES; - tot += len; - if (tot >= reg_ctx->buf_len) - break; - } - npu_disable_core_power(npu_dev); - - reg_ctx->buf_len = tot; - } - - if (*ppos >= reg_ctx->buf_len) - return 0; /* done reading */ - - len = min(count, reg_ctx->buf_len - (size_t) *ppos); - pr_debug("read %zi %zi\n", count, reg_ctx->buf_len - (size_t) *ppos); - if (copy_to_user(user_buf, reg_ctx->buf + *ppos, len)) { - pr_err("failed to copy to user\n"); - return -EFAULT; - } - - *ppos += len; /* increase offset */ - return len; -} - -/* ------------------------------------------------------------------------- - * Function Implementations - Offset Read/Write - * ------------------------------------------------------------------------- - */ -static ssize_t npu_debug_off_write(struct file *file, - const char __user *user_buf, size_t count, loff_t *ppos) -{ - size_t off = 0; - uint32_t cnt, reg_cnt; - char buf[24]; - struct npu_device *npu_dev = file->private_data; - struct npu_debugfs_ctx *debugfs; - - pr_debug("npu_dev %pK %pK\n", npu_dev, g_npu_dev); - npu_dev = g_npu_dev; - debugfs = &npu_dev->debugfs_ctx; - - if (count >= sizeof(buf)) - return -EINVAL; - - if (copy_from_user(buf, user_buf, count)) - return -EFAULT; - - buf[count] = 0; /* end of string */ - - cnt = sscanf(buf, "%zx %x", &off, ®_cnt); - if (cnt == 1) - reg_cnt = DEFAULT_REG_DUMP_NUM; - pr_debug("reg off = %zx, %d cnt=%d\n", off, reg_cnt, cnt); - if (cnt >= 1) { - debugfs->reg_off = off; - debugfs->reg_cnt = reg_cnt; - } - - return count; -} - -static ssize_t npu_debug_off_read(struct file *file, - char __user *user_buf, size_t count, loff_t *ppos) -{ - size_t len; - char buf[64]; - struct npu_device *npu_dev = file->private_data; - struct npu_debugfs_ctx *debugfs; - - pr_debug("npu_dev %pK %pK\n", npu_dev, g_npu_dev); - npu_dev = g_npu_dev; - debugfs = &npu_dev->debugfs_ctx; - - if (*ppos) - return 0; /* the end */ - - len = scnprintf(buf, sizeof(buf), "offset=0x%08x cnt=%d\n", - debugfs->reg_off, debugfs->reg_cnt); - len = min(len, count); - - if (copy_to_user(user_buf, buf, len)) { - pr_err("failed to copy to user\n"); - return -EFAULT; - } - - *ppos += len; /* increase offset */ - return len; -} - -/* ------------------------------------------------------------------------- - * Function Implementations - DebugFS Log - * ------------------------------------------------------------------------- - */ -static ssize_t npu_debug_log_read(struct file *file, - char __user *user_buf, size_t count, loff_t *ppos) -{ - size_t len = 0; - struct npu_device *npu_dev = file->private_data; - struct npu_debugfs_ctx *debugfs; - - pr_debug("npu_dev %pK %pK\n", npu_dev, g_npu_dev); - npu_dev = g_npu_dev; - debugfs = &npu_dev->debugfs_ctx; - - /* mutex log lock */ - mutex_lock(&debugfs->log_lock); - - if (debugfs->log_num_bytes_buffered != 0) { - len = min(debugfs->log_num_bytes_buffered, - debugfs->log_buf_size - debugfs->log_read_index); - len = min(count, len); - if (copy_to_user(user_buf, (debugfs->log_buf + - debugfs->log_read_index), len)) { - pr_err("%s failed to copy to user\n", __func__); - mutex_unlock(&debugfs->log_lock); - return -EFAULT; - } - debugfs->log_read_index += len; - if (debugfs->log_read_index == debugfs->log_buf_size) - debugfs->log_read_index = 0; - - debugfs->log_num_bytes_buffered -= len; - *ppos += len; - } - - /* mutex log unlock */ - mutex_unlock(&debugfs->log_lock); - - return len; -} /* ------------------------------------------------------------------------- * Function Implementations - DebugFS Control @@ -381,24 +150,6 @@ int npu_debugfs_init(struct npu_device *npu_dev) return -ENODEV; } - if (!debugfs_create_file("reg", 0644, debugfs->root, - npu_dev, &npu_reg_fops)) { - pr_err("debugfs_create_file reg fail\n"); - goto err; - } - - if (!debugfs_create_file("off", 0644, debugfs->root, - npu_dev, &npu_off_fops)) { - pr_err("debugfs_create_file off fail\n"); - goto err; - } - - if (!debugfs_create_file("log", 0644, debugfs->root, - npu_dev, &npu_log_fops)) { - pr_err("debugfs_create_file log fail\n"); - goto err; - } - if (!debugfs_create_file("ctrl", 0644, debugfs->root, npu_dev, &npu_ctrl_fops)) { pr_err("debugfs_create_file ctrl fail\n"); @@ -435,14 +186,6 @@ int npu_debugfs_init(struct npu_device *npu_dev) goto err; } - debugfs->log_num_bytes_buffered = 0; - debugfs->log_read_index = 0; - debugfs->log_write_index = 0; - debugfs->log_buf_size = NPU_LOG_BUF_SIZE; - debugfs->log_buf = kzalloc(debugfs->log_buf_size, GFP_KERNEL); - if (!debugfs->log_buf) - goto err; - mutex_init(&debugfs->log_lock); return 0; @@ -455,12 +198,6 @@ void npu_debugfs_deinit(struct npu_device *npu_dev) { struct npu_debugfs_ctx *debugfs = &npu_dev->debugfs_ctx; - debugfs->log_num_bytes_buffered = 0; - debugfs->log_read_index = 0; - debugfs->log_write_index = 0; - debugfs->log_buf_size = 0; - kfree(debugfs->log_buf); - if (!IS_ERR_OR_NULL(debugfs->root)) { debugfs_remove_recursive(debugfs->root); debugfs->root = NULL; diff --git a/drivers/media/platform/msm/npu/npu_host_ipc.c b/drivers/media/platform/msm/npu/npu_host_ipc.c index c892e560d8ef..57e19c4a3f82 100644 --- a/drivers/media/platform/msm/npu/npu_host_ipc.c +++ b/drivers/media/platform/msm/npu/npu_host_ipc.c @@ -40,15 +40,16 @@ struct npu_queue_tuple { uint32_t size; uint32_t hdr; + uint32_t start_offset; }; -static const struct npu_queue_tuple npu_q_setup[6] = { - { 1024, IPC_QUEUE_CMD_HIGH_PRIORITY | TX_HDR_TYPE | RX_HDR_TYPE }, - { 4096, IPC_QUEUE_APPS_EXEC | TX_HDR_TYPE | RX_HDR_TYPE }, - { 4096, IPC_QUEUE_DSP_EXEC | TX_HDR_TYPE | RX_HDR_TYPE }, - { 4096, IPC_QUEUE_APPS_RSP | TX_HDR_TYPE | RX_HDR_TYPE }, - { 4096, IPC_QUEUE_DSP_RSP | TX_HDR_TYPE | RX_HDR_TYPE }, - { 1024, IPC_QUEUE_LOG | TX_HDR_TYPE | RX_HDR_TYPE }, +static struct npu_queue_tuple npu_q_setup[6] = { + { 1024, IPC_QUEUE_CMD_HIGH_PRIORITY | TX_HDR_TYPE | RX_HDR_TYPE, 0}, + { 4096, IPC_QUEUE_APPS_EXEC | TX_HDR_TYPE | RX_HDR_TYPE, 0}, + { 4096, IPC_QUEUE_DSP_EXEC | TX_HDR_TYPE | RX_HDR_TYPE, 0}, + { 4096, IPC_QUEUE_APPS_RSP | TX_HDR_TYPE | RX_HDR_TYPE, 0}, + { 4096, IPC_QUEUE_DSP_RSP | TX_HDR_TYPE | RX_HDR_TYPE, 0}, + { 1024, IPC_QUEUE_LOG | TX_HDR_TYPE | RX_HDR_TYPE, 0}, }; /* ------------------------------------------------------------------------- @@ -75,7 +76,7 @@ static int npu_host_ipc_init_hfi(struct npu_device *npu_dev) struct hfi_queue_tbl_header *q_tbl_hdr = NULL; struct hfi_queue_header *q_hdr_arr = NULL; struct hfi_queue_header *q_hdr = NULL; - void *q_tbl_addr = 0; + void *q_tbl_addr = NULL; uint32_t reg_val = 0; uint32_t q_idx = 0; uint32_t q_tbl_size = sizeof(struct hfi_queue_tbl_header) + @@ -118,6 +119,7 @@ static int npu_host_ipc_init_hfi(struct npu_device *npu_dev) /* queue is active */ q_hdr->qhdr_status = 0x01; q_hdr->qhdr_start_offset = cur_start_offset; + npu_q_setup[q_idx].start_offset = cur_start_offset; q_size = npu_q_setup[q_idx].size; q_hdr->qhdr_type = npu_q_setup[q_idx].hdr; /* in bytes */ @@ -219,6 +221,18 @@ static int ipc_queue_read(struct npu_device *npu_dev, /* Read the queue */ MEMR(npu_dev, (void *)((size_t)offset), (uint8_t *)&queue, HFI_QUEUE_HEADER_SIZE); + + if (queue.qhdr_type != npu_q_setup[target_que].hdr || + queue.qhdr_q_size != npu_q_setup[target_que].size || + queue.qhdr_read_idx >= queue.qhdr_q_size || + queue.qhdr_write_idx >= queue.qhdr_q_size || + queue.qhdr_start_offset != + npu_q_setup[target_que].start_offset) { + pr_err("Invalid Queue header\n"); + status = -EIO; + goto exit; + } + /* check if queue is empty */ if (queue.qhdr_read_idx == queue.qhdr_write_idx) { /* @@ -242,8 +256,10 @@ static int ipc_queue_read(struct npu_device *npu_dev, target_que, packet_size); - if (packet_size == 0) { - status = -EPERM; + if ((packet_size == 0) || + (packet_size > NPU_IPC_BUF_LENGTH)) { + pr_err("Invalid packet size %d\n", packet_size); + status = -EINVAL; goto exit; } new_read_idx = queue.qhdr_read_idx + packet_size; @@ -313,6 +329,18 @@ static int ipc_queue_write(struct npu_device *npu_dev, MEMR(npu_dev, (void *)((size_t)offset), (uint8_t *)&queue, HFI_QUEUE_HEADER_SIZE); + + if (queue.qhdr_type != npu_q_setup[target_que].hdr || + queue.qhdr_q_size != npu_q_setup[target_que].size || + queue.qhdr_read_idx >= queue.qhdr_q_size || + queue.qhdr_write_idx >= queue.qhdr_q_size || + queue.qhdr_start_offset != + npu_q_setup[target_que].start_offset) { + pr_err("Invalid Queue header\n"); + status = -EIO; + goto exit; + } + packet_size = (*(uint32_t *)packet); if (packet_size == 0) { /* assign failed status and return */ diff --git a/drivers/media/platform/msm/npu/npu_hw_access.c b/drivers/media/platform/msm/npu/npu_hw_access.c index 3356e3d6f15a..067ec0924838 100644 --- a/drivers/media/platform/msm/npu/npu_hw_access.c +++ b/drivers/media/platform/msm/npu/npu_hw_access.c @@ -110,7 +110,7 @@ void npu_mem_write(struct npu_device *npu_dev, void *dst, void *src, { size_t dst_off = (size_t)dst; uint32_t *src_ptr32 = (uint32_t *)src; - uint8_t *src_ptr8 = 0; + uint8_t *src_ptr8 = NULL; uint32_t i = 0; uint32_t num = 0; @@ -145,7 +145,7 @@ int32_t npu_mem_read(struct npu_device *npu_dev, void *src, void *dst, { size_t src_off = (size_t)src; uint32_t *out32 = (uint32_t *)dst; - uint8_t *out8 = 0; + uint8_t *out8 = NULL; uint32_t i = 0; uint32_t num = 0; @@ -374,7 +374,7 @@ void npu_mem_invalidate(struct npu_client *client, int buf_hdl) bool npu_mem_verify_addr(struct npu_client *client, uint64_t addr) { - struct npu_ion_buf *ion_buf = 0; + struct npu_ion_buf *ion_buf = NULL; struct list_head *pos = NULL; bool valid = false; @@ -394,7 +394,7 @@ bool npu_mem_verify_addr(struct npu_client *client, uint64_t addr) void npu_mem_unmap(struct npu_client *client, int buf_hdl, uint64_t addr) { struct npu_device *npu_dev = client->npu_dev; - struct npu_ion_buf *ion_buf = 0; + struct npu_ion_buf *ion_buf = NULL; /* clear entry and retrieve the corresponding buffer */ ion_buf = npu_get_npu_ion_buffer(client, buf_hdl); @@ -449,49 +449,3 @@ void subsystem_put_local(void *sub_system_handle) return subsystem_put(sub_system_handle); } -/* ------------------------------------------------------------------------- - * Functions - Log - * ------------------------------------------------------------------------- - */ -void npu_process_log_message(struct npu_device *npu_dev, uint32_t *message, - uint32_t size) -{ - struct npu_debugfs_ctx *debugfs = &npu_dev->debugfs_ctx; - - /* mutex log lock */ - mutex_lock(&debugfs->log_lock); - - if ((debugfs->log_num_bytes_buffered + size) > - debugfs->log_buf_size) { - /* No more space, invalidate it all and start over */ - debugfs->log_read_index = 0; - debugfs->log_write_index = size; - debugfs->log_num_bytes_buffered = size; - memcpy(debugfs->log_buf, message, size); - } else { - if ((debugfs->log_write_index + size) > - debugfs->log_buf_size) { - /* Wrap around case */ - uint8_t *src_addr = (uint8_t *)message; - uint8_t *dst_addr = 0; - uint32_t remaining_to_end = debugfs->log_buf_size - - debugfs->log_write_index + 1; - dst_addr = debugfs->log_buf + debugfs->log_write_index; - memcpy(dst_addr, src_addr, remaining_to_end); - src_addr = &(src_addr[remaining_to_end]); - dst_addr = debugfs->log_buf; - memcpy(dst_addr, src_addr, size-remaining_to_end); - debugfs->log_write_index = size-remaining_to_end; - } else { - memcpy((debugfs->log_buf + debugfs->log_write_index), - message, size); - debugfs->log_write_index += size; - if (debugfs->log_write_index == debugfs->log_buf_size) - debugfs->log_write_index = 0; - } - debugfs->log_num_bytes_buffered += size; - } - - /* mutex log unlock */ - mutex_unlock(&debugfs->log_lock); -} diff --git a/drivers/media/platform/msm/npu/npu_hw_access.h b/drivers/media/platform/msm/npu/npu_hw_access.h index 61457e1ca21c..3444d646c171 100644 --- a/drivers/media/platform/msm/npu/npu_hw_access.h +++ b/drivers/media/platform/msm/npu/npu_hw_access.h @@ -90,7 +90,4 @@ void npu_disable_sys_cache(struct npu_device *npu_dev); void *subsystem_get_local(char *sub_system); void subsystem_put_local(void *sub_system_handle); -void npu_process_log_message(struct npu_device *npu_dev, uint32_t *msg, - uint32_t size); - #endif /* _NPU_HW_ACCESS_H*/ diff --git a/drivers/media/platform/msm/npu/npu_mgr.c b/drivers/media/platform/msm/npu/npu_mgr.c index 9f8fa45d8a0d..61953ed2cb39 100644 --- a/drivers/media/platform/msm/npu/npu_mgr.c +++ b/drivers/media/platform/msm/npu/npu_mgr.c @@ -27,11 +27,6 @@ * Defines * ------------------------------------------------------------------------- */ -#define LOG_MSG_HEADER_SIZE 20 -#define LOG_MSG_START_MSG_INDEX 5 -#define LOG_MSG_TOTAL_SIZE_INDEX 0 -#define LOG_MSG_MSG_ID_INDEX 1 - #define NPU_FW_TIMEOUT_POLL_INTERVAL_MS 10 #define NPU_FW_TIMEOUT_MS 1000 @@ -55,9 +50,7 @@ static void free_network(struct npu_host_ctx *ctx, struct npu_client *client, static int network_get(struct npu_network *network); static int network_put(struct npu_network *network); static void app_msg_proc(struct npu_host_ctx *host_ctx, uint32_t *msg); -static void log_msg_proc(struct npu_device *npu_dev, uint32_t *msg); static void host_session_msg_hdlr(struct npu_device *npu_dev); -static void host_session_log_hdlr(struct npu_device *npu_dev); static int host_error_hdlr(struct npu_device *npu_dev, bool force); static int npu_send_network_cmd(struct npu_device *npu_dev, struct npu_network *network, void *cmd_ptr); @@ -396,7 +389,6 @@ static void host_irq_wq(struct work_struct *work) if (host_error_hdlr(npu_dev, false)) return; - host_session_log_hdlr(npu_dev); host_session_msg_hdlr(npu_dev); } @@ -773,6 +765,12 @@ static void app_msg_proc(struct npu_host_ctx *host_ctx, uint32_t *msg) } pr_debug("network id : %llu\n", network->id); + if (exe_rsp_pkt->header.size < sizeof(*exe_rsp_pkt)) { + pr_err("invalid packet header size, header.size: %d", + exe_rsp_pkt->header.size); + network_put(network); + break; + } stats_size = exe_rsp_pkt->header.size - sizeof(*exe_rsp_pkt); pr_debug("stats_size %d:%d\n", exe_rsp_pkt->header.size, stats_size); @@ -987,52 +985,6 @@ static void host_session_msg_hdlr(struct npu_device *npu_dev) kfree(msg); } -static void log_msg_proc(struct npu_device *npu_dev, uint32_t *msg) -{ - uint32_t msg_id; - uint32_t *log_msg; - uint32_t size; - - msg_id = msg[LOG_MSG_MSG_ID_INDEX]; - size = msg[LOG_MSG_TOTAL_SIZE_INDEX] - LOG_MSG_HEADER_SIZE; - - switch (msg_id) { - case NPU_IPC_MSG_EVENT_NOTIFY: - /* Process the message */ - log_msg = &(msg[LOG_MSG_START_MSG_INDEX]); - npu_process_log_message(npu_dev, log_msg, size); - break; - default: - pr_err("unsupported log response received %d\n", msg_id); - break; - } -} - -static void host_session_log_hdlr(struct npu_device *npu_dev) -{ - uint32_t *msg; - struct npu_host_ctx *host_ctx = &npu_dev->host_ctx; - - msg = kzalloc(sizeof(uint32_t) * NPU_IPC_BUF_LENGTH, GFP_KERNEL); - - if (!msg) - return; - - mutex_lock(&host_ctx->lock); - if (host_ctx->fw_state == FW_DISABLED) { - pr_warn("handle npu session msg when FW is disabled\n"); - goto skip_read_msg; - } - - while (npu_host_ipc_read_msg(npu_dev, IPC_QUEUE_LOG, msg) == 0) { - pr_debug("received from log queue\n"); - log_msg_proc(npu_dev, msg); - } - -skip_read_msg: - mutex_unlock(&host_ctx->lock); - kfree(msg); -} /* ------------------------------------------------------------------------- * Function Definitions - Functionality @@ -2097,7 +2049,7 @@ int32_t npu_host_set_perf_mode(struct npu_client *client, uint32_t network_hdl, ret = set_perf_mode(npu_dev); if (ret) - pr_err("set_perf_mode failed"); + pr_err("set_perf_mode failed\n"); if (network) network_put(network); From e89d6913454d69a84f9f53cf10c6faa5d4900e10 Mon Sep 17 00:00:00 2001 From: Jilai Wang Date: Mon, 5 Feb 2024 15:18:56 -0500 Subject: [PATCH 24/36] msm: npu v2: Fix OOB issue in IPC between driver and firmware We shoudn't trust the data from firmware, and need to validate all content before using them. Change-Id: I96e7a250d378ba7c99a28d0abdbe2ff34f1ede0d Signed-off-by: Jilai Wang --- .../media/platform/msm/npu_v2/npu_common.h | 6 -- .../media/platform/msm/npu_v2/npu_debugfs.c | 78 ------------------- .../media/platform/msm/npu_v2/npu_host_ipc.c | 40 ++++++++-- .../media/platform/msm/npu_v2/npu_hw_access.c | 47 ----------- .../media/platform/msm/npu_v2/npu_hw_access.h | 3 - drivers/media/platform/msm/npu_v2/npu_mgr.c | 64 +++------------ 6 files changed, 43 insertions(+), 195 deletions(-) diff --git a/drivers/media/platform/msm/npu_v2/npu_common.h b/drivers/media/platform/msm/npu_v2/npu_common.h index e5549eb02add..88d3208efc5a 100644 --- a/drivers/media/platform/msm/npu_v2/npu_common.h +++ b/drivers/media/platform/msm/npu_v2/npu_common.h @@ -116,12 +116,6 @@ struct npu_debugfs_ctx { struct dentry *root; uint32_t reg_off; uint32_t reg_cnt; - uint8_t *log_buf; - struct mutex log_lock; - uint32_t log_num_bytes_buffered; - uint32_t log_read_index; - uint32_t log_write_index; - uint32_t log_buf_size; }; struct npu_debugfs_reg_ctx { diff --git a/drivers/media/platform/msm/npu_v2/npu_debugfs.c b/drivers/media/platform/msm/npu_v2/npu_debugfs.c index 468cc6b751fb..cead168164a4 100644 --- a/drivers/media/platform/msm/npu_v2/npu_debugfs.c +++ b/drivers/media/platform/msm/npu_v2/npu_debugfs.c @@ -20,12 +20,6 @@ #include "npu_hw_access.h" #include "npu_common.h" -/* ------------------------------------------------------------------------- - * Defines - * ------------------------------------------------------------------------- - */ -#define NPU_LOG_BUF_SIZE 4096 - /* ------------------------------------------------------------------------- * Function Prototypes * ------------------------------------------------------------------------- @@ -40,8 +34,6 @@ static ssize_t npu_debug_off_write(struct file *file, const char __user *user_buf, size_t count, loff_t *ppos); static ssize_t npu_debug_off_read(struct file *file, char __user *user_buf, size_t count, loff_t *ppos); -static ssize_t npu_debug_log_read(struct file *file, - char __user *user_buf, size_t count, loff_t *ppos); static ssize_t npu_debug_ctrl_write(struct file *file, const char __user *user_buf, size_t count, loff_t *ppos); @@ -64,13 +56,6 @@ static const struct file_operations npu_off_fops = { .write = npu_debug_off_write, }; -static const struct file_operations npu_log_fops = { - .open = npu_debug_open, - .release = npu_debug_release, - .read = npu_debug_log_read, - .write = NULL, -}; - static const struct file_operations npu_ctrl_fops = { .open = npu_debug_open, .release = npu_debug_release, @@ -255,48 +240,6 @@ static ssize_t npu_debug_off_read(struct file *file, return len; } -/* ------------------------------------------------------------------------- - * Function Implementations - DebugFS Log - * ------------------------------------------------------------------------- - */ -static ssize_t npu_debug_log_read(struct file *file, - char __user *user_buf, size_t count, loff_t *ppos) -{ - size_t len = 0; - struct npu_device *npu_dev = file->private_data; - struct npu_debugfs_ctx *debugfs; - - NPU_DBG("npu_dev %pK %pK\n", npu_dev, g_npu_dev); - npu_dev = g_npu_dev; - debugfs = &npu_dev->debugfs_ctx; - - /* mutex log lock */ - mutex_lock(&debugfs->log_lock); - - if (debugfs->log_num_bytes_buffered != 0) { - len = min(debugfs->log_num_bytes_buffered, - debugfs->log_buf_size - debugfs->log_read_index); - len = min(count, len); - if (copy_to_user(user_buf, (debugfs->log_buf + - debugfs->log_read_index), len)) { - NPU_ERR("failed to copy to user\n"); - mutex_unlock(&debugfs->log_lock); - return -EFAULT; - } - debugfs->log_read_index += len; - if (debugfs->log_read_index == debugfs->log_buf_size) - debugfs->log_read_index = 0; - - debugfs->log_num_bytes_buffered -= len; - *ppos += len; - } - - /* mutex log unlock */ - mutex_unlock(&debugfs->log_lock); - - return len; -} - /* ------------------------------------------------------------------------- * Function Implementations - DebugFS Control * ------------------------------------------------------------------------- @@ -380,12 +323,6 @@ int npu_debugfs_init(struct npu_device *npu_dev) goto err; } - if (!debugfs_create_file("log", 0644, debugfs->root, - npu_dev, &npu_log_fops)) { - NPU_ERR("debugfs_create_file log fail\n"); - goto err; - } - if (!debugfs_create_file("ctrl", 0644, debugfs->root, npu_dev, &npu_ctrl_fops)) { NPU_ERR("debugfs_create_file ctrl fail\n"); @@ -428,15 +365,6 @@ int npu_debugfs_init(struct npu_device *npu_dev) goto err; } - debugfs->log_num_bytes_buffered = 0; - debugfs->log_read_index = 0; - debugfs->log_write_index = 0; - debugfs->log_buf_size = NPU_LOG_BUF_SIZE; - debugfs->log_buf = kzalloc(debugfs->log_buf_size, GFP_KERNEL); - if (!debugfs->log_buf) - goto err; - mutex_init(&debugfs->log_lock); - return 0; err: @@ -448,12 +376,6 @@ void npu_debugfs_deinit(struct npu_device *npu_dev) { struct npu_debugfs_ctx *debugfs = &npu_dev->debugfs_ctx; - debugfs->log_num_bytes_buffered = 0; - debugfs->log_read_index = 0; - debugfs->log_write_index = 0; - debugfs->log_buf_size = 0; - kfree(debugfs->log_buf); - if (!IS_ERR_OR_NULL(debugfs->root)) { debugfs_remove_recursive(debugfs->root); debugfs->root = NULL; diff --git a/drivers/media/platform/msm/npu_v2/npu_host_ipc.c b/drivers/media/platform/msm/npu_v2/npu_host_ipc.c index f557e28b2f84..6147ef74b23a 100644 --- a/drivers/media/platform/msm/npu_v2/npu_host_ipc.c +++ b/drivers/media/platform/msm/npu_v2/npu_host_ipc.c @@ -38,15 +38,16 @@ struct npu_queue_tuple { uint32_t size; uint32_t hdr; + uint32_t start_offset; }; -static const struct npu_queue_tuple npu_q_setup[6] = { - { 1024, IPC_QUEUE_CMD_HIGH_PRIORITY | TX_HDR_TYPE | RX_HDR_TYPE }, - { 4096, IPC_QUEUE_APPS_EXEC | TX_HDR_TYPE | RX_HDR_TYPE }, - { 4096, IPC_QUEUE_DSP_EXEC | TX_HDR_TYPE | RX_HDR_TYPE }, - { 4096, IPC_QUEUE_APPS_RSP | TX_HDR_TYPE | RX_HDR_TYPE }, - { 4096, IPC_QUEUE_DSP_RSP | TX_HDR_TYPE | RX_HDR_TYPE }, - { 1024, IPC_QUEUE_LOG | TX_HDR_TYPE | RX_HDR_TYPE }, +static struct npu_queue_tuple npu_q_setup[6] = { + { 1024, IPC_QUEUE_CMD_HIGH_PRIORITY | TX_HDR_TYPE | RX_HDR_TYPE, 0}, + { 4096, IPC_QUEUE_APPS_EXEC | TX_HDR_TYPE | RX_HDR_TYPE, 0}, + { 4096, IPC_QUEUE_DSP_EXEC | TX_HDR_TYPE | RX_HDR_TYPE, 0}, + { 4096, IPC_QUEUE_APPS_RSP | TX_HDR_TYPE | RX_HDR_TYPE, 0}, + { 4096, IPC_QUEUE_DSP_RSP | TX_HDR_TYPE | RX_HDR_TYPE, 0}, + { 1024, IPC_QUEUE_LOG | TX_HDR_TYPE | RX_HDR_TYPE, 0}, }; /* ------------------------------------------------------------------------- @@ -116,6 +117,7 @@ static int npu_host_ipc_init_hfi(struct npu_device *npu_dev) /* queue is active */ q_hdr->qhdr_status = 0x01; q_hdr->qhdr_start_offset = cur_start_offset; + npu_q_setup[q_idx].start_offset = cur_start_offset; q_size = npu_q_setup[q_idx].size; q_hdr->qhdr_type = npu_q_setup[q_idx].hdr; /* in bytes */ @@ -216,6 +218,18 @@ static int ipc_queue_read(struct npu_device *npu_dev, /* Read the queue */ MEMR(npu_dev, (void *)((size_t)offset), (uint8_t *)&queue, HFI_QUEUE_HEADER_SIZE); + + if (queue.qhdr_type != npu_q_setup[target_que].hdr || + queue.qhdr_q_size != npu_q_setup[target_que].size || + queue.qhdr_read_idx >= queue.qhdr_q_size || + queue.qhdr_write_idx >= queue.qhdr_q_size || + queue.qhdr_start_offset != + npu_q_setup[target_que].start_offset) { + NPU_ERR("Invalid Queue header\n"); + status = -EIO; + goto exit; + } + /* check if queue is empty */ if (queue.qhdr_read_idx == queue.qhdr_write_idx) { /* @@ -313,6 +327,18 @@ static int ipc_queue_write(struct npu_device *npu_dev, MEMR(npu_dev, (void *)((size_t)offset), (uint8_t *)&queue, HFI_QUEUE_HEADER_SIZE); + + if (queue.qhdr_type != npu_q_setup[target_que].hdr || + queue.qhdr_q_size != npu_q_setup[target_que].size || + queue.qhdr_read_idx >= queue.qhdr_q_size || + queue.qhdr_write_idx >= queue.qhdr_q_size || + queue.qhdr_start_offset != + npu_q_setup[target_que].start_offset) { + NPU_ERR("Invalid Queue header\n"); + status = -EIO; + goto exit; + } + packet_size = (*(uint32_t *)packet); if (packet_size == 0) { /* assign failed status and return */ diff --git a/drivers/media/platform/msm/npu_v2/npu_hw_access.c b/drivers/media/platform/msm/npu_v2/npu_hw_access.c index adef677a66cf..40e7765b8c9f 100644 --- a/drivers/media/platform/msm/npu_v2/npu_hw_access.c +++ b/drivers/media/platform/msm/npu_v2/npu_hw_access.c @@ -437,50 +437,3 @@ void subsystem_put_local(void *sub_system_handle) { return subsystem_put(sub_system_handle); } - -/* ------------------------------------------------------------------------- - * Functions - Log - * ------------------------------------------------------------------------- - */ -void npu_process_log_message(struct npu_device *npu_dev, uint32_t *message, - uint32_t size) -{ - struct npu_debugfs_ctx *debugfs = &npu_dev->debugfs_ctx; - - /* mutex log lock */ - mutex_lock(&debugfs->log_lock); - - if ((debugfs->log_num_bytes_buffered + size) > - debugfs->log_buf_size) { - /* No more space, invalidate it all and start over */ - debugfs->log_read_index = 0; - debugfs->log_write_index = size; - debugfs->log_num_bytes_buffered = size; - memcpy(debugfs->log_buf, message, size); - } else { - if ((debugfs->log_write_index + size) > - debugfs->log_buf_size) { - /* Wrap around case */ - uint8_t *src_addr = (uint8_t *)message; - uint8_t *dst_addr = NULL; - uint32_t remaining_to_end = debugfs->log_buf_size - - debugfs->log_write_index + 1; - dst_addr = debugfs->log_buf + debugfs->log_write_index; - memcpy(dst_addr, src_addr, remaining_to_end); - src_addr = &(src_addr[remaining_to_end]); - dst_addr = debugfs->log_buf; - memcpy(dst_addr, src_addr, size-remaining_to_end); - debugfs->log_write_index = size-remaining_to_end; - } else { - memcpy((debugfs->log_buf + debugfs->log_write_index), - message, size); - debugfs->log_write_index += size; - if (debugfs->log_write_index == debugfs->log_buf_size) - debugfs->log_write_index = 0; - } - debugfs->log_num_bytes_buffered += size; - } - - /* mutex log unlock */ - mutex_unlock(&debugfs->log_lock); -} diff --git a/drivers/media/platform/msm/npu_v2/npu_hw_access.h b/drivers/media/platform/msm/npu_v2/npu_hw_access.h index cb0c194401f5..2682624c82bb 100644 --- a/drivers/media/platform/msm/npu_v2/npu_hw_access.h +++ b/drivers/media/platform/msm/npu_v2/npu_hw_access.h @@ -98,7 +98,4 @@ void npu_disable_sys_cache(struct npu_device *npu_dev); void *subsystem_get_local(char *sub_system); void subsystem_put_local(void *sub_system_handle); -void npu_process_log_message(struct npu_device *npu_dev, uint32_t *msg, - uint32_t size); - #endif /* _NPU_HW_ACCESS_H*/ diff --git a/drivers/media/platform/msm/npu_v2/npu_mgr.c b/drivers/media/platform/msm/npu_v2/npu_mgr.c index 80fe69bec22b..40ee896dae96 100644 --- a/drivers/media/platform/msm/npu_v2/npu_mgr.c +++ b/drivers/media/platform/msm/npu_v2/npu_mgr.c @@ -24,15 +24,6 @@ #include #include -/* ------------------------------------------------------------------------- - * Defines - * ------------------------------------------------------------------------- - */ -#define LOG_MSG_HEADER_SIZE 20 -#define LOG_MSG_START_MSG_INDEX 5 -#define LOG_MSG_TOTAL_SIZE_INDEX 0 -#define LOG_MSG_MSG_ID_INDEX 1 - /* ------------------------------------------------------------------------- * File Scope Function Prototypes * ------------------------------------------------------------------------- @@ -58,9 +49,7 @@ static void free_network(struct npu_host_ctx *ctx, struct npu_client *client, static int network_get(struct npu_network *network); static int network_put(struct npu_network *network); static int app_msg_proc(struct npu_host_ctx *host_ctx, uint32_t *msg); -static void log_msg_proc(struct npu_device *npu_dev, uint32_t *msg); static void host_session_msg_hdlr(struct npu_device *npu_dev); -static void host_session_log_hdlr(struct npu_device *npu_dev); static int host_error_hdlr(struct npu_device *npu_dev, bool force); static int npu_send_network_cmd(struct npu_device *npu_dev, struct npu_network *network, void *cmd_ptr, @@ -1139,7 +1128,6 @@ static void npu_ipc_irq_work(struct work_struct *work) host_ctx = container_of(work, struct npu_host_ctx, ipc_irq_work); npu_dev = container_of(host_ctx, struct npu_device, host_ctx); - host_session_log_hdlr(npu_dev); host_session_msg_hdlr(npu_dev); } @@ -1671,6 +1659,12 @@ static int app_msg_proc(struct npu_host_ctx *host_ctx, uint32_t *msg) } NPU_DBG("network id : %lld\n", network->id); + if (exe_rsp_pkt->header.size < sizeof(*exe_rsp_pkt)) { + NPU_ERR("invalid packet header size, header.size: %d", + exe_rsp_pkt->header.size); + network_put(network); + break; + } stats_size = exe_rsp_pkt->header.size - sizeof(*exe_rsp_pkt); NPU_DBG("stats_size %d:%d\n", exe_rsp_pkt->header.size, stats_size); @@ -1912,47 +1906,6 @@ static void host_session_msg_hdlr(struct npu_device *npu_dev) mutex_unlock(&host_ctx->lock); } -static void log_msg_proc(struct npu_device *npu_dev, uint32_t *msg) -{ - uint32_t msg_id; - uint32_t *log_msg; - uint32_t size; - - msg_id = msg[LOG_MSG_MSG_ID_INDEX]; - size = msg[LOG_MSG_TOTAL_SIZE_INDEX] - LOG_MSG_HEADER_SIZE; - - switch (msg_id) { - case NPU_IPC_MSG_EVENT_NOTIFY: - /* Process the message */ - log_msg = &(msg[LOG_MSG_START_MSG_INDEX]); - npu_process_log_message(npu_dev, log_msg, size); - break; - default: - NPU_ERR("unsupported log response received %d\n", msg_id); - break; - } -} - -static void host_session_log_hdlr(struct npu_device *npu_dev) -{ - struct npu_host_ctx *host_ctx = &npu_dev->host_ctx; - - mutex_lock(&host_ctx->lock); - if (host_ctx->fw_state != FW_ENABLED) { - NPU_WARN("handle npu session msg when FW is disabled\n"); - goto skip_read_msg; - } - - while (npu_host_ipc_read_msg(npu_dev, IPC_QUEUE_LOG, - host_ctx->ipc_msg_buf) == 0) { - NPU_DBG("received from log queue\n"); - log_msg_proc(npu_dev, host_ctx->ipc_msg_buf); - } - -skip_read_msg: - mutex_unlock(&host_ctx->lock); -} - /* ------------------------------------------------------------------------- * Function Definitions - Functionality * ------------------------------------------------------------------------- @@ -2350,7 +2303,10 @@ int32_t npu_host_get_fw_property(struct npu_device *npu_dev, NPU_ERR("prop_id: %x\n", prop_from_fw->prop_id); NPU_ERR("network_hdl: %x\n", prop_from_fw->network_hdl); NPU_ERR("param_num: %x\n", prop_from_fw->num_of_params); - for (i = 0; i < prop_from_fw->num_of_params; i++) + num_of_params = min_t(uint32_t, + prop_from_fw->num_of_params, + (uint32_t)PROP_PARAM_MAX_SIZE); + for (i = 0; i < num_of_params; i++) NPU_ERR("%x\n", prop_from_fw->prop_param[i]); } From f3b2f5980b9da91842ee4432bfa1090fdc3f2156 Mon Sep 17 00:00:00 2001 From: Shaik Jabida Date: Mon, 3 Jun 2024 16:38:47 +0530 Subject: [PATCH 25/36] dsp: q6voice: Adds checks for an integer overflow there is no check for cvs_voc_pkt[2],when receives 0xffffffff from ADSP which results in an integer overflow Fix is to address this. Signed-off-by: Shaik Jabida (cherry picked from commit 4524418cd14dce47e4ea7234618f919e28dbbe5a) Change-Id: I2edaef7a22bf0e8d517b3269d004992a3ca35d4f --- 4.0/dsp/q6voice.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/4.0/dsp/q6voice.c b/4.0/dsp/q6voice.c index 46b70c626e78..5003b9945b0f 100644 --- a/4.0/dsp/q6voice.c +++ b/4.0/dsp/q6voice.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2012-2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2024 Qualcomm Innovation Center, Inc. All rights reserved. */ #include #include @@ -7905,7 +7906,7 @@ static int32_t qdsp_cvs_callback(struct apr_client_data *data, void *priv) VSS_ISTREAM_EVT_OOB_NOTIFY_ENC_BUFFER_READY) { int ret = 0; u16 cvs_handle; - uint32_t *cvs_voc_pkt; + uint32_t *cvs_voc_pkt, tot_buf_sz; struct cvs_enc_buffer_consumed_cmd send_enc_buf_consumed_cmd; void *apr_cvs; @@ -7934,9 +7935,14 @@ static int32_t qdsp_cvs_callback(struct apr_client_data *data, void *priv) VSS_ISTREAM_EVT_OOB_NOTIFY_ENC_BUFFER_CONSUMED; cvs_voc_pkt = v->shmem_info.sh_buf.buf[1].data; + + if (__builtin_add_overflow(cvs_voc_pkt[2], 3 * sizeof(uint32_t), &tot_buf_sz)) { + pr_err("%s: integer overflow detected\n", __func__); + return -EINVAL; + } + if (cvs_voc_pkt != NULL && common.mvs_info.ul_cb != NULL) { - if (v->shmem_info.sh_buf.buf[1].size < - ((3 * sizeof(uint32_t)) + cvs_voc_pkt[2])) { + if (v->shmem_info.sh_buf.buf[1].size < tot_buf_sz) { pr_err("%s: invalid voc pkt size\n", __func__); return -EINVAL; } From ddf319820397c37ee942cd193e31d1e286c93564 Mon Sep 17 00:00:00 2001 From: Santosh Sakore Date: Mon, 27 May 2024 17:09:48 +0530 Subject: [PATCH 26/36] msm: adsprpc: use-after-free (UAF) in global maps Currently, remote heap maps get added to the global list before the fastrpc_internal_mmap function completes the mapping. Meanwhile, the fastrpc_internal_munmap function accesses the map, starts unmapping, and frees the map before the fastrpc_internal_mmap function completes, resulting in a use-after-free (UAF) issue. Add the map to the list after the fastrpc_internal_mmap function completes the mapping. Change-Id: I72d24c7661244d1ff43454ce31dfc5e932090305 Acked-by: Abhishek Singh Signed-off-by: Santosh Sakore (cherry picked from commit c7125dffc507d30866cf2f895a7771e8417e1807) --- drivers/char/adsprpc.c | 88 +++++++++++++++++++----------------------- 1 file changed, 40 insertions(+), 48 deletions(-) diff --git a/drivers/char/adsprpc.c b/drivers/char/adsprpc.c index 3129fab9fdd6..75db24da2a7c 100644 --- a/drivers/char/adsprpc.c +++ b/drivers/char/adsprpc.c @@ -1,5 +1,6 @@ /* * Copyright (c) 2012-2021, The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2024, Qualcomm Innovation Center, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -607,64 +608,43 @@ static void fastrpc_remote_buf_list_free(struct fastrpc_file *fl) } while (free); } -static void fastrpc_mmap_add(struct fastrpc_mmap *map) +static void fastrpc_mmap_add_global(struct fastrpc_mmap *map) { - if (map->flags == ADSP_MMAP_HEAP_ADDR || - map->flags == ADSP_MMAP_REMOTE_HEAP_ADDR) { - struct fastrpc_apps *me = &gfa; + struct fastrpc_apps *me = &gfa; + unsigned long irq_flags = 0; - spin_lock(&me->hlock); - hlist_add_head(&map->hn, &me->maps); - spin_unlock(&me->hlock); - } else { - struct fastrpc_file *fl = map->fl; + spin_lock_irqsave(&me->hlock, irq_flags); + hlist_add_head(&map->hn, &me->maps); + spin_unlock_irqrestore(&me->hlock, irq_flags); +} - hlist_add_head(&map->hn, &fl->maps); - } +static void fastrpc_mmap_add(struct fastrpc_mmap *map) +{ + struct fastrpc_file *fl = map->fl; + + hlist_add_head(&map->hn, &fl->maps); } static int fastrpc_mmap_find(struct fastrpc_file *fl, int fd, uintptr_t va, size_t len, int mflags, int refs, struct fastrpc_mmap **ppmap) { - struct fastrpc_apps *me = &gfa; struct fastrpc_mmap *match = NULL, *map = NULL; struct hlist_node *n; if ((va + len) < va) return -EOVERFLOW; - if (mflags == ADSP_MMAP_HEAP_ADDR || - mflags == ADSP_MMAP_REMOTE_HEAP_ADDR) { - spin_lock(&me->hlock); - hlist_for_each_entry_safe(map, n, &me->maps, hn) { - if (va >= map->va && - va + len <= map->va + map->len && - map->fd == fd) { - if (refs) { - if (map->refs + 1 == INT_MAX) { - spin_unlock(&me->hlock); - return -ETOOMANYREFS; - } - map->refs++; - } - match = map; - break; - } - } - spin_unlock(&me->hlock); - } else { - hlist_for_each_entry_safe(map, n, &fl->maps, hn) { - if (va >= map->va && - va + len <= map->va + map->len && - map->fd == fd) { - if (refs) { - if (map->refs + 1 == INT_MAX) - return -ETOOMANYREFS; - map->refs++; - } - match = map; - break; + hlist_for_each_entry_safe(map, n, &fl->maps, hn) { + if (va >= map->va && + va + len <= map->va + map->len && + map->fd == fd) { + if (refs) { + if (map->refs + 1 == INT_MAX) + return -ETOOMANYREFS; + map->refs++; } + match = map; + break; } } if (match) { @@ -1013,8 +993,9 @@ static int fastrpc_mmap_create(struct fastrpc_file *fl, int fd, map->va = va; } map->len = len; - - fastrpc_mmap_add(map); + if ((mflags != ADSP_MMAP_HEAP_ADDR) && + (mflags != ADSP_MMAP_REMOTE_HEAP_ADDR)) + fastrpc_mmap_add(map); *ppmap = map; bail: @@ -2354,6 +2335,7 @@ static int fastrpc_init_process(struct fastrpc_file *fl, mutex_unlock(&fl->map_mutex); if (err) goto bail; + fastrpc_mmap_add_global(mem); phys = mem->phys; size = mem->size; if (me->channel[fl->cid].rhvm.vmid) { @@ -2802,8 +2784,11 @@ static int fastrpc_mmap_remove_ssr(struct fastrpc_file *fl, int locked) } } while (match); bail: - if (err && match) - fastrpc_mmap_add(match); + if (err && match) { + mutex_lock(&fl->map_mutex); + fastrpc_mmap_add_global(match); + mutex_unlock(&fl->map_mutex); + } return err; } @@ -2923,7 +2908,11 @@ static int fastrpc_internal_munmap(struct fastrpc_file *fl, bail: if (err && map) { mutex_lock(&fl->map_mutex); - fastrpc_mmap_add(map); + if ((map->flags == ADSP_MMAP_HEAP_ADDR) || + (map->flags == ADSP_MMAP_REMOTE_HEAP_ADDR)) + fastrpc_mmap_add_global(map); + else + fastrpc_mmap_add(map); mutex_unlock(&fl->map_mutex); } mutex_unlock(&fl->internal_map_mutex); @@ -3030,6 +3019,9 @@ static int fastrpc_internal_mmap(struct fastrpc_file *fl, if (err) goto bail; map->raddr = raddr; + if (ud->flags == ADSP_MMAP_HEAP_ADDR || + ud->flags == ADSP_MMAP_REMOTE_HEAP_ADDR) + fastrpc_mmap_add_global(map); } ud->vaddrout = raddr; bail: From 7369fd89f2fa7426c816bce87c0a3a63db223533 Mon Sep 17 00:00:00 2001 From: Tim Zimmermann Date: Tue, 25 Jun 2024 12:19:52 +0530 Subject: [PATCH 27/36] syscall: Increase bpf fake uname to 5.4.186 * https://android-review.googlesource.com/c/platform/packages/modules/Connectivity/+/3088785 Change-Id: Iaba91f5594cebd2e361b670fb866abb5c58c6707 --- kernel/sys.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kernel/sys.c b/kernel/sys.c index 0114527a3086..de93ecfef2bc 100644 --- a/kernel/sys.c +++ b/kernel/sys.c @@ -1198,7 +1198,7 @@ SYSCALL_DEFINE1(newuname, struct new_utsname __user *, name) if (!strncmp(current->comm, "bpfloader", 9) || !strncmp(current->comm, "netbpfload", 10) || !strncmp(current->comm, "netd", 4)) { - strcpy(tmp.release, "5.4.0"); + strcpy(tmp.release, "5.4.186"); pr_debug("fake uname: %s/%d release=%s\n", current->comm, current->pid, tmp.release); } From 4bebbbd3f2822e2396892f8b30a1b8ba6284a0ce Mon Sep 17 00:00:00 2001 From: Andrey Ignatov Date: Fri, 25 May 2018 08:55:23 -0700 Subject: [PATCH 28/36] bpf: Hooks for sys_sendmsg In addition to already existing BPF hooks for sys_bind and sys_connect, the patch provides new hooks for sys_sendmsg. It leverages existing BPF program type `BPF_PROG_TYPE_CGROUP_SOCK_ADDR` that provides access to socket itlself (properties like family, type, protocol) and user-passed `struct sockaddr *` so that BPF program can override destination IP and port for system calls such as sendto(2) or sendmsg(2) and/or assign source IP to the socket. The hooks are implemented as two new attach types: `BPF_CGROUP_UDP4_SENDMSG` and `BPF_CGROUP_UDP6_SENDMSG` for UDPv4 and UDPv6 correspondingly. UDPv4 and UDPv6 separate attach types for same reason as sys_bind and sys_connect hooks, i.e. to prevent reading from / writing to e.g. user_ip6 fields when user passes sockaddr_in since it'd be out-of-bound. The difference with already existing hooks is sys_sendmsg are implemented only for unconnected UDP. For TCP it doesn't make sense to change user-provided `struct sockaddr *` at sendto(2)/sendmsg(2) time since socket either was already connected and has source/destination set or wasn't connected and call to sendto(2)/sendmsg(2) would lead to ENOTCONN anyway. Connected UDP is already handled by sys_connect hooks that can override source/destination at connect time and use fast-path later, i.e. these hooks don't affect UDP fast-path. Rewriting source IP is implemented differently than that in sys_connect hooks. When sys_sendmsg is used with unconnected UDP it doesn't work to just bind socket to desired local IP address since source IP can be set on per-packet basis by using ancillary data (cmsg(3)). So no matter if socket is bound or not, source IP has to be rewritten on every call to sys_sendmsg. To do so two new fields are added to UAPI `struct bpf_sock_addr`; * `msg_src_ip4` to set source IPv4 for UDPv4; * `msg_src_ip6` to set source IPv6 for UDPv6. Change-Id: Icf5938b0b69ddfb1e99dc2abc90204f7c97f0473 Signed-off-by: Andrey Ignatov Acked-by: Alexei Starovoitov Acked-by: Martin KaFai Lau Signed-off-by: Daniel Borkmann --- include/linux/bpf-cgroup.h | 23 ++++++++++++++++------ include/linux/filter.h | 1 + include/uapi/linux/bpf.h | 8 ++++++++ kernel/bpf/cgroup.c | 11 ++++++++++- kernel/bpf/syscall.c | 8 ++++++++ net/core/filter.c | 39 ++++++++++++++++++++++++++++++++++++++ net/ipv4/udp.c | 20 +++++++++++++++++-- net/ipv6/udp.c | 24 +++++++++++++++++++++++ 8 files changed, 125 insertions(+), 9 deletions(-) diff --git a/include/linux/bpf-cgroup.h b/include/linux/bpf-cgroup.h index c1fa663acd5f..00c19b460f1d 100644 --- a/include/linux/bpf-cgroup.h +++ b/include/linux/bpf-cgroup.h @@ -66,7 +66,8 @@ int __cgroup_bpf_run_filter_sk(struct sock *sk, int __cgroup_bpf_run_filter_sock_addr(struct sock *sk, struct sockaddr *uaddr, - enum bpf_attach_type type); + enum bpf_attach_type type, + void *t_ctx); int __cgroup_bpf_run_filter_sock_ops(struct sock *sk, struct bpf_sock_ops_kern *sock_ops, @@ -117,16 +118,18 @@ int __cgroup_bpf_run_filter_sock_ops(struct sock *sk, ({ \ int __ret = 0; \ if (cgroup_bpf_enabled) \ - __ret = __cgroup_bpf_run_filter_sock_addr(sk, uaddr, type); \ + __ret = __cgroup_bpf_run_filter_sock_addr(sk, uaddr, type, \ + NULL); \ __ret; \ }) -#define BPF_CGROUP_RUN_SA_PROG_LOCK(sk, uaddr, type) \ +#define BPF_CGROUP_RUN_SA_PROG_LOCK(sk, uaddr, type, t_ctx) \ ({ \ int __ret = 0; \ if (cgroup_bpf_enabled) { \ lock_sock(sk); \ - __ret = __cgroup_bpf_run_filter_sock_addr(sk, uaddr, type); \ + __ret = __cgroup_bpf_run_filter_sock_addr(sk, uaddr, type, \ + t_ctx); \ release_sock(sk); \ } \ __ret; \ @@ -148,10 +151,16 @@ int __cgroup_bpf_run_filter_sock_ops(struct sock *sk, BPF_CGROUP_RUN_SA_PROG(sk, uaddr, BPF_CGROUP_INET6_CONNECT) #define BPF_CGROUP_RUN_PROG_INET4_CONNECT_LOCK(sk, uaddr) \ - BPF_CGROUP_RUN_SA_PROG_LOCK(sk, uaddr, BPF_CGROUP_INET4_CONNECT) + BPF_CGROUP_RUN_SA_PROG_LOCK(sk, uaddr, BPF_CGROUP_INET4_CONNECT, NULL) #define BPF_CGROUP_RUN_PROG_INET6_CONNECT_LOCK(sk, uaddr) \ - BPF_CGROUP_RUN_SA_PROG_LOCK(sk, uaddr, BPF_CGROUP_INET6_CONNECT) + BPF_CGROUP_RUN_SA_PROG_LOCK(sk, uaddr, BPF_CGROUP_INET6_CONNECT, NULL) + +#define BPF_CGROUP_RUN_PROG_UDP4_SENDMSG_LOCK(sk, uaddr, t_ctx) \ + BPF_CGROUP_RUN_SA_PROG_LOCK(sk, uaddr, BPF_CGROUP_UDP4_SENDMSG, t_ctx) + +#define BPF_CGROUP_RUN_PROG_UDP6_SENDMSG_LOCK(sk, uaddr, t_ctx) \ + BPF_CGROUP_RUN_SA_PROG_LOCK(sk, uaddr, BPF_CGROUP_UDP6_SENDMSG, t_ctx) #define BPF_CGROUP_RUN_PROG_SOCK_OPS(sock_ops) \ ({ \ @@ -183,6 +192,8 @@ static inline int cgroup_bpf_inherit(struct cgroup *cgrp) { return 0; } #define BPF_CGROUP_RUN_PROG_INET4_CONNECT_LOCK(sk, uaddr) ({ 0; }) #define BPF_CGROUP_RUN_PROG_INET6_CONNECT(sk, uaddr) ({ 0; }) #define BPF_CGROUP_RUN_PROG_INET6_CONNECT_LOCK(sk, uaddr) ({ 0; }) +#define BPF_CGROUP_RUN_PROG_UDP4_SENDMSG_LOCK(sk, uaddr, t_ctx) ({ 0; }) +#define BPF_CGROUP_RUN_PROG_UDP6_SENDMSG_LOCK(sk, uaddr, t_ctx) ({ 0; }) #define BPF_CGROUP_RUN_PROG_SOCK_OPS(sock_ops) ({ 0; }) #endif /* CONFIG_CGROUP_BPF */ diff --git a/include/linux/filter.h b/include/linux/filter.h index e473895d41e0..d9072ff4ee48 100644 --- a/include/linux/filter.h +++ b/include/linux/filter.h @@ -1051,6 +1051,7 @@ struct bpf_sock_addr_kern { * only two (src and dst) are available at convert_ctx_access time */ u64 tmp_reg; + void *t_ctx; /* Attach type specific context. */ }; struct bpf_sock_ops_kern { diff --git a/include/uapi/linux/bpf.h b/include/uapi/linux/bpf.h index e5d541bab379..f9623c6368c2 100644 --- a/include/uapi/linux/bpf.h +++ b/include/uapi/linux/bpf.h @@ -149,6 +149,8 @@ enum bpf_attach_type { BPF_CGROUP_INET6_CONNECT, BPF_CGROUP_INET4_POST_BIND, BPF_CGROUP_INET6_POST_BIND, + BPF_CGROUP_UDP4_SENDMSG, + BPF_CGROUP_UDP6_SENDMSG, __MAX_BPF_ATTACH_TYPE }; @@ -1039,6 +1041,12 @@ struct bpf_sock_addr { __u32 family; /* Allows 4-byte read, but no write */ __u32 type; /* Allows 4-byte read, but no write */ __u32 protocol; /* Allows 4-byte read, but no write */ + __u32 msg_src_ip4; /* Allows 1,2,4-byte read an 4-byte write. + * Stored in network byte order. + */ + __u32 msg_src_ip6[4]; /* Allows 1,2,4-byte read an 4-byte write. + * Stored in network byte order. + */ }; /* User bpf_sock_ops struct to access socket values and specify request ops diff --git a/kernel/bpf/cgroup.c b/kernel/bpf/cgroup.c index 36a4f3efa43e..5f976ec57065 100644 --- a/kernel/bpf/cgroup.c +++ b/kernel/bpf/cgroup.c @@ -501,6 +501,7 @@ EXPORT_SYMBOL(__cgroup_bpf_run_filter_sk); * @sk: sock struct that will use sockaddr * @uaddr: sockaddr struct provided by user * @type: The type of program to be exectuted + * @t_ctx: Pointer to attach type specific context * * socket is expected to be of type INET or INET6. * @@ -509,12 +510,15 @@ EXPORT_SYMBOL(__cgroup_bpf_run_filter_sk); */ int __cgroup_bpf_run_filter_sock_addr(struct sock *sk, struct sockaddr *uaddr, - enum bpf_attach_type type) + enum bpf_attach_type type, + void *t_ctx) { struct bpf_sock_addr_kern ctx = { .sk = sk, .uaddr = uaddr, + .t_ctx = t_ctx, }; + struct sockaddr_storage unspec; struct cgroup *cgrp; int ret; @@ -524,6 +528,11 @@ int __cgroup_bpf_run_filter_sock_addr(struct sock *sk, if (sk->sk_family != AF_INET && sk->sk_family != AF_INET6) return 0; + if (!ctx.uaddr) { + memset(&unspec, 0, sizeof(unspec)); + ctx.uaddr = (struct sockaddr *)&unspec; + } + cgrp = sock_cgroup_ptr(&sk->sk_cgrp_data); ret = BPF_PROG_RUN_ARRAY(cgrp->bpf.effective[type], &ctx, BPF_PROG_RUN); diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c index f782d496ded1..6e9217448a68 100644 --- a/kernel/bpf/syscall.c +++ b/kernel/bpf/syscall.c @@ -1207,6 +1207,8 @@ bpf_prog_load_check_attach_type(enum bpf_prog_type prog_type, case BPF_CGROUP_INET6_BIND: case BPF_CGROUP_INET4_CONNECT: case BPF_CGROUP_INET6_CONNECT: + case BPF_CGROUP_UDP4_SENDMSG: + case BPF_CGROUP_UDP6_SENDMSG: return 0; default: return -EINVAL; @@ -1452,6 +1454,8 @@ static int bpf_prog_attach(const union bpf_attr *attr) case BPF_CGROUP_INET6_BIND: case BPF_CGROUP_INET4_CONNECT: case BPF_CGROUP_INET6_CONNECT: + case BPF_CGROUP_UDP4_SENDMSG: + case BPF_CGROUP_UDP6_SENDMSG: ptype = BPF_PROG_TYPE_CGROUP_SOCK_ADDR; break; case BPF_CGROUP_SOCK_OPS: @@ -1517,6 +1521,8 @@ static int bpf_prog_detach(const union bpf_attr *attr) case BPF_CGROUP_INET6_BIND: case BPF_CGROUP_INET4_CONNECT: case BPF_CGROUP_INET6_CONNECT: + case BPF_CGROUP_UDP4_SENDMSG: + case BPF_CGROUP_UDP6_SENDMSG: ptype = BPF_PROG_TYPE_CGROUP_SOCK_ADDR; break; case BPF_CGROUP_SOCK_OPS: @@ -1569,6 +1575,8 @@ static int bpf_prog_query(const union bpf_attr *attr, case BPF_CGROUP_INET6_POST_BIND: case BPF_CGROUP_INET4_CONNECT: case BPF_CGROUP_INET6_CONNECT: + case BPF_CGROUP_UDP4_SENDMSG: + case BPF_CGROUP_UDP6_SENDMSG: case BPF_CGROUP_SOCK_OPS: break; default: diff --git a/net/core/filter.c b/net/core/filter.c index e8a8d1fb4fb4..d51028cf5ea2 100644 --- a/net/core/filter.c +++ b/net/core/filter.c @@ -3894,6 +3894,7 @@ static bool sock_addr_is_valid_access(int off, int size, switch (prog->expected_attach_type) { case BPF_CGROUP_INET4_BIND: case BPF_CGROUP_INET4_CONNECT: + case BPF_CGROUP_UDP4_SENDMSG: break; default: return false; @@ -3903,6 +3904,24 @@ static bool sock_addr_is_valid_access(int off, int size, switch (prog->expected_attach_type) { case BPF_CGROUP_INET6_BIND: case BPF_CGROUP_INET6_CONNECT: + case BPF_CGROUP_UDP6_SENDMSG: + break; + default: + return false; + } + break; + case bpf_ctx_range(struct bpf_sock_addr, msg_src_ip4): + switch (prog->expected_attach_type) { + case BPF_CGROUP_UDP4_SENDMSG: + break; + default: + return false; + } + break; + case bpf_ctx_range_till(struct bpf_sock_addr, msg_src_ip6[0], + msg_src_ip6[3]): + switch (prog->expected_attach_type) { + case BPF_CGROUP_UDP6_SENDMSG: break; default: return false; @@ -3913,6 +3932,9 @@ static bool sock_addr_is_valid_access(int off, int size, switch (off) { case bpf_ctx_range(struct bpf_sock_addr, user_ip4): case bpf_ctx_range_till(struct bpf_sock_addr, user_ip6[0], user_ip6[3]): + case bpf_ctx_range(struct bpf_sock_addr, msg_src_ip4): + case bpf_ctx_range_till(struct bpf_sock_addr, msg_src_ip6[0], + msg_src_ip6[3]): /* Only narrow read access allowed for now. */ if (type == BPF_READ) { bpf_ctx_record_field_size(info, size_default); @@ -4588,6 +4610,23 @@ static u32 sock_addr_convert_ctx_access(enum bpf_access_type type, *insn++ = BPF_ALU32_IMM(BPF_RSH, si->dst_reg, SK_FL_PROTO_SHIFT); break; + + case offsetof(struct bpf_sock_addr, msg_src_ip4): + /* Treat t_ctx as struct in_addr for msg_src_ip4. */ + SOCK_ADDR_LOAD_OR_STORE_NESTED_FIELD_SIZE_OFF( + struct bpf_sock_addr_kern, struct in_addr, t_ctx, + s_addr, BPF_SIZE(si->code), 0, tmp_reg); + break; + + case bpf_ctx_range_till(struct bpf_sock_addr, msg_src_ip6[0], + msg_src_ip6[3]): + off = si->off; + off -= offsetof(struct bpf_sock_addr, msg_src_ip6[0]); + /* Treat t_ctx as struct in6_addr for msg_src_ip6. */ + SOCK_ADDR_LOAD_OR_STORE_NESTED_FIELD_SIZE_OFF( + struct bpf_sock_addr_kern, struct in6_addr, t_ctx, + s6_addr32[0], BPF_SIZE(si->code), off, tmp_reg); + break; } return insn - insn_buf; diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c index dc14d96e3af3..58efff7b3c9c 100644 --- a/net/ipv4/udp.c +++ b/net/ipv4/udp.c @@ -929,6 +929,7 @@ int udp_sendmsg(struct sock *sk, struct msghdr *msg, size_t len) { struct inet_sock *inet = inet_sk(sk); struct udp_sock *up = udp_sk(sk); + DECLARE_SOCKADDR(struct sockaddr_in *, usin, msg->msg_name); struct flowi4 fl4_stack; struct flowi4 *fl4; int ulen = len; @@ -983,8 +984,7 @@ int udp_sendmsg(struct sock *sk, struct msghdr *msg, size_t len) /* * Get and verify the address. */ - if (msg->msg_name) { - DECLARE_SOCKADDR(struct sockaddr_in *, usin, msg->msg_name); + if (usin) { if (msg->msg_namelen < sizeof(*usin)) return -EINVAL; if (usin->sin_family != AF_INET) { @@ -1038,6 +1038,22 @@ int udp_sendmsg(struct sock *sk, struct msghdr *msg, size_t len) rcu_read_unlock(); } + if (cgroup_bpf_enabled && !connected) { + err = BPF_CGROUP_RUN_PROG_UDP4_SENDMSG_LOCK(sk, + (struct sockaddr *)usin, &ipc.addr); + if (err) + goto out_free; + if (usin) { + if (usin->sin_port == 0) { + /* BPF program set invalid port. Reject it. */ + err = -EINVAL; + goto out_free; + } + daddr = usin->sin_addr.s_addr; + dport = usin->sin_port; + } + } + saddr = ipc.addr; ipc.addr = faddr = daddr; diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c index c519adff6244..4836492bac01 100644 --- a/net/ipv6/udp.c +++ b/net/ipv6/udp.c @@ -1386,6 +1386,29 @@ int udpv6_sendmsg(struct sock *sk, struct msghdr *msg, size_t len) fl6.saddr = np->saddr; fl6.fl6_sport = inet->inet_sport; + if (cgroup_bpf_enabled && !connected) { + err = BPF_CGROUP_RUN_PROG_UDP6_SENDMSG_LOCK(sk, + (struct sockaddr *)sin6, &fl6.saddr); + if (err) + goto out_no_dst; + if (sin6) { + if (ipv6_addr_v4mapped(&sin6->sin6_addr)) { + /* BPF program rewrote IPv6-only by IPv4-mapped + * IPv6. It's currently unsupported. + */ + err = -ENOTSUPP; + goto out_no_dst; + } + if (sin6->sin6_port == 0) { + /* BPF program set invalid port. Reject it. */ + err = -EINVAL; + goto out_no_dst; + } + fl6.fl6_dport = sin6->sin6_port; + fl6.daddr = sin6->sin6_addr; + } + } + final_p = fl6_update_dst(&fl6, opt, &final); if (final_p) connected = 0; @@ -1482,6 +1505,7 @@ int udpv6_sendmsg(struct sock *sk, struct msghdr *msg, size_t len) out: dst_release(dst); +out_no_dst: fl6_sock_release(flowlabel); txopt_put(opt_to_free); if (!err) From 4ef6a1987ccce358ab50ad6be714f94535c10bc0 Mon Sep 17 00:00:00 2001 From: Alexei Starovoitov Date: Mon, 2 Oct 2017 22:50:23 -0700 Subject: [PATCH 29/36] BACKPORT: bpf: enforce return code for cgroup-bpf programs with addition of tnum logic the verifier got smart enough and we can enforce return codes at program load time. For now do so for cgroup-bpf program types. Change-Id: Iae3a46c3d38810e47cbf4ec23356abae03ded736 Signed-off-by: Alexei Starovoitov Acked-by: Daniel Borkmann Signed-off-by: David S. Miller --- kernel/bpf/verifier.c | 40 ++++++++++++ tools/testing/selftests/bpf/test_verifier.c | 72 +++++++++++++++++++++ 2 files changed, 112 insertions(+) diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c index 83868b94be98..3d99789e02ae 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c @@ -3618,6 +3618,43 @@ static int check_ld_abs(struct bpf_verifier_env *env, struct bpf_insn *insn) return 0; } +static int check_return_code(struct bpf_verifier_env *env) +{ + struct bpf_reg_state *reg; + struct tnum range = tnum_range(0, 1); + + switch (env->prog->type) { + case BPF_PROG_TYPE_CGROUP_SKB: + case BPF_PROG_TYPE_CGROUP_SOCK: + case BPF_PROG_TYPE_SOCK_OPS: + break; + default: + return 0; + } + + reg = &env->cur_state->regs[BPF_REG_0]; + if (reg->type != SCALAR_VALUE) { + verbose("At program exit the register R0 is not a known value (%s)\n", + reg_type_str[reg->type]); + return -EINVAL; + } + + if (!tnum_in(range, reg->var_off)) { + verbose("At program exit the register R0 "); + if (!tnum_is_unknown(reg->var_off)) { + char tn_buf[48]; + + tnum_strn(tn_buf, sizeof(tn_buf), reg->var_off); + verbose("has value %s", tn_buf); + } else { + verbose("has unknown scalar value"); + } + verbose(" should have been 0 or 1\n"); + return -EINVAL; + } + return 0; +} + /* non-recursive DFS pseudo code * 1 procedure DFS-iterative(G,v): * 2 label v as discovered @@ -4460,6 +4497,9 @@ static int do_check(struct bpf_verifier_env *env) return -EACCES; } + err = check_return_code(env); + if (err) + return err; process_bpf_exit: err = pop_stack(env, &env->prev_insn_idx, &env->insn_idx); if (err < 0) { diff --git a/tools/testing/selftests/bpf/test_verifier.c b/tools/testing/selftests/bpf/test_verifier.c index f7757f7f6d2b..f2e9b37a4463 100644 --- a/tools/testing/selftests/bpf/test_verifier.c +++ b/tools/testing/selftests/bpf/test_verifier.c @@ -8046,6 +8046,78 @@ static struct bpf_test tests[] = { .result = REJECT, .errstr = "variable ctx access var_off=(0x0; 0x4)", }, + { + "bpf_exit with invalid return code. test1", + .insns = { + BPF_LDX_MEM(BPF_W, BPF_REG_0, BPF_REG_1, 0), + BPF_EXIT_INSN(), + }, + .errstr = "R0 has value (0x0; 0xffffffff)", + .result = REJECT, + .prog_type = BPF_PROG_TYPE_CGROUP_SOCK, + }, + { + "bpf_exit with invalid return code. test2", + .insns = { + BPF_LDX_MEM(BPF_W, BPF_REG_0, BPF_REG_1, 0), + BPF_ALU64_IMM(BPF_AND, BPF_REG_0, 1), + BPF_EXIT_INSN(), + }, + .result = ACCEPT, + .prog_type = BPF_PROG_TYPE_CGROUP_SOCK, + }, + { + "bpf_exit with invalid return code. test3", + .insns = { + BPF_LDX_MEM(BPF_W, BPF_REG_0, BPF_REG_1, 0), + BPF_ALU64_IMM(BPF_AND, BPF_REG_0, 3), + BPF_EXIT_INSN(), + }, + .errstr = "R0 has value (0x0; 0x3)", + .result = REJECT, + .prog_type = BPF_PROG_TYPE_CGROUP_SOCK, + }, + { + "bpf_exit with invalid return code. test4", + .insns = { + BPF_MOV64_IMM(BPF_REG_0, 1), + BPF_EXIT_INSN(), + }, + .result = ACCEPT, + .prog_type = BPF_PROG_TYPE_CGROUP_SOCK, + }, + { + "bpf_exit with invalid return code. test5", + .insns = { + BPF_MOV64_IMM(BPF_REG_0, 2), + BPF_EXIT_INSN(), + }, + .errstr = "R0 has value (0x2; 0x0)", + .result = REJECT, + .prog_type = BPF_PROG_TYPE_CGROUP_SOCK, + }, + { + "bpf_exit with invalid return code. test6", + .insns = { + BPF_MOV64_REG(BPF_REG_0, BPF_REG_1), + BPF_EXIT_INSN(), + }, + .errstr = "R0 is not a known value (ctx)", + .result = REJECT, + .prog_type = BPF_PROG_TYPE_CGROUP_SOCK, + }, + { + "bpf_exit with invalid return code. test7", + .insns = { + BPF_LDX_MEM(BPF_W, BPF_REG_0, BPF_REG_1, 0), + BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1, 4), + BPF_ALU64_REG(BPF_MUL, BPF_REG_0, BPF_REG_2), + BPF_EXIT_INSN(), + }, + .errstr = "R0 has unknown scalar value", + .result = REJECT, + .prog_type = BPF_PROG_TYPE_CGROUP_SOCK, + }, }; static int probe_filter_length(const struct bpf_insn *fp) From 568cd496530e66245c77dc6f2083fa1c3fac9e83 Mon Sep 17 00:00:00 2001 From: Daniel Borkmann Date: Fri, 7 Jun 2019 01:48:57 +0200 Subject: [PATCH 30/36] BACKPORT: bpf: fix unconnected udp hooks Intention of cgroup bind/connect/sendmsg BPF hooks is to act transparently to applications as also stated in original motivation in 7828f20e3779 ("Merge branch 'bpf-cgroup-bind-connect'"). When recently integrating the latter two hooks into Cilium to enable host based load-balancing with Kubernetes, I ran into the issue that pods couldn't start up as DNS got broken. Kubernetes typically sets up DNS as a service and is thus subject to load-balancing. Upon further debugging, it turns out that the cgroupv2 sendmsg BPF hooks API is currently insufficient and thus not usable as-is for standard applications shipped with most distros. To break down the issue we ran into with a simple example: # cat /etc/resolv.conf nameserver 147.75.207.207 nameserver 147.75.207.208 For the purpose of a simple test, we set up above IPs as service IPs and transparently redirect traffic to a different DNS backend server for that node: # cilium service list ID Frontend Backend 1 147.75.207.207:53 1 => 8.8.8.8:53 2 147.75.207.208:53 1 => 8.8.8.8:53 The attached BPF program is basically selecting one of the backends if the service IP/port matches on the cgroup hook. DNS breaks here, because the hooks are not transparent enough to applications which have built-in msg_name address checks: # nslookup 1.1.1.1 ;; reply from unexpected source: 8.8.8.8#53, expected 147.75.207.207#53 ;; reply from unexpected source: 8.8.8.8#53, expected 147.75.207.208#53 ;; reply from unexpected source: 8.8.8.8#53, expected 147.75.207.207#53 [...] ;; connection timed out; no servers could be reached # dig 1.1.1.1 ;; reply from unexpected source: 8.8.8.8#53, expected 147.75.207.207#53 ;; reply from unexpected source: 8.8.8.8#53, expected 147.75.207.208#53 ;; reply from unexpected source: 8.8.8.8#53, expected 147.75.207.207#53 [...] ; <<>> DiG 9.11.3-1ubuntu1.7-Ubuntu <<>> 1.1.1.1 ;; global options: +cmd ;; connection timed out; no servers could be reached For comparison, if none of the service IPs is used, and we tell nslookup to use 8.8.8.8 directly it works just fine, of course: # nslookup 1.1.1.1 8.8.8.8 1.1.1.1.in-addr.arpa name = one.one.one.one. In order to fix this and thus act more transparent to the application, this needs reverse translation on recvmsg() side. A minimal fix for this API is to add similar recvmsg() hooks behind the BPF cgroups static key such that the program can track state and replace the current sockaddr_in{,6} with the original service IP. From BPF side, this basically tracks the service tuple plus socket cookie in an LRU map where the reverse NAT can then be retrieved via map value as one example. Side-note: the BPF cgroups static key should be converted to a per-hook static key in future. Same example after this fix: # cilium service list ID Frontend Backend 1 147.75.207.207:53 1 => 8.8.8.8:53 2 147.75.207.208:53 1 => 8.8.8.8:53 Lookups work fine now: # nslookup 1.1.1.1 1.1.1.1.in-addr.arpa name = one.one.one.one. Authoritative answers can be found from: # dig 1.1.1.1 ; <<>> DiG 9.11.3-1ubuntu1.7-Ubuntu <<>> 1.1.1.1 ;; global options: +cmd ;; Got answer: ;; ->>HEADER<<- opcode: QUERY, status: NXDOMAIN, id: 51550 ;; flags: qr rd ra ad; QUERY: 1, ANSWER: 0, AUTHORITY: 1, ADDITIONAL: 1 ;; OPT PSEUDOSECTION: ; EDNS: version: 0, flags:; udp: 512 ;; QUESTION SECTION: ;1.1.1.1. IN A ;; AUTHORITY SECTION: . 23426 IN SOA a.root-servers.net. nstld.verisign-grs.com. 2019052001 1800 900 604800 86400 ;; Query time: 17 msec ;; SERVER: 147.75.207.207#53(147.75.207.207) ;; WHEN: Tue May 21 12:59:38 UTC 2019 ;; MSG SIZE rcvd: 111 And from an actual packet level it shows that we're using the back end server when talking via 147.75.207.20{7,8} front end: # tcpdump -i any udp [...] 12:59:52.698732 IP foo.42011 > google-public-dns-a.google.com.domain: 18803+ PTR? 1.1.1.1.in-addr.arpa. (38) 12:59:52.698735 IP foo.42011 > google-public-dns-a.google.com.domain: 18803+ PTR? 1.1.1.1.in-addr.arpa. (38) 12:59:52.701208 IP google-public-dns-a.google.com.domain > foo.42011: 18803 1/0/0 PTR one.one.one.one. (67) 12:59:52.701208 IP google-public-dns-a.google.com.domain > foo.42011: 18803 1/0/0 PTR one.one.one.one. (67) [...] In order to be flexible and to have same semantics as in sendmsg BPF programs, we only allow return codes in [1,1] range. In the sendmsg case the program is called if msg->msg_name is present which can be the case in both, connected and unconnected UDP. The former only relies on the sockaddr_in{,6} passed via connect(2) if passed msg->msg_name was NULL. Therefore, on recvmsg side, we act in similar way to call into the BPF program whenever a non-NULL msg->msg_name was passed independent of sk->sk_state being TCP_ESTABLISHED or not. Note that for TCP case, the msg->msg_name is ignored in the regular recvmsg path and therefore not relevant. For the case of ip{,v6}_recv_error() paths, picked up via MSG_ERRQUEUE, the hook is not called. This is intentional as it aligns with the same semantics as in case of TCP cgroup BPF hooks right now. This might be better addressed in future through a different bpf_attach_type such that this case can be distinguished from the regular recvmsg paths, for example. Fixes: 1cedee13d25a ("bpf: Hooks for sys_sendmsg") Change-Id: If2bab00efe5f37a591083fe2676e76f35f8cecc3 Signed-off-by: Daniel Borkmann Acked-by: Andrey Ignatov Acked-by: Martin KaFai Lau Acked-by: Martynas Pumputis Signed-off-by: Alexei Starovoitov --- include/linux/bpf-cgroup.h | 8 ++++++++ include/uapi/linux/bpf.h | 2 ++ kernel/bpf/syscall.c | 8 ++++++++ kernel/bpf/verifier.c | 11 ++++++++--- net/core/filter.c | 2 ++ net/ipv4/udp.c | 4 ++++ net/ipv6/udp.c | 4 ++++ 7 files changed, 36 insertions(+), 3 deletions(-) diff --git a/include/linux/bpf-cgroup.h b/include/linux/bpf-cgroup.h index 00c19b460f1d..2c68257be261 100644 --- a/include/linux/bpf-cgroup.h +++ b/include/linux/bpf-cgroup.h @@ -162,6 +162,12 @@ int __cgroup_bpf_run_filter_sock_ops(struct sock *sk, #define BPF_CGROUP_RUN_PROG_UDP6_SENDMSG_LOCK(sk, uaddr, t_ctx) \ BPF_CGROUP_RUN_SA_PROG_LOCK(sk, uaddr, BPF_CGROUP_UDP6_SENDMSG, t_ctx) +#define BPF_CGROUP_RUN_PROG_UDP4_RECVMSG_LOCK(sk, uaddr) \ + BPF_CGROUP_RUN_SA_PROG_LOCK(sk, uaddr, BPF_CGROUP_UDP4_RECVMSG, NULL) + +#define BPF_CGROUP_RUN_PROG_UDP6_RECVMSG_LOCK(sk, uaddr) \ + BPF_CGROUP_RUN_SA_PROG_LOCK(sk, uaddr, BPF_CGROUP_UDP6_RECVMSG, NULL) + #define BPF_CGROUP_RUN_PROG_SOCK_OPS(sock_ops) \ ({ \ int __ret = 0; \ @@ -194,6 +200,8 @@ static inline int cgroup_bpf_inherit(struct cgroup *cgrp) { return 0; } #define BPF_CGROUP_RUN_PROG_INET6_CONNECT_LOCK(sk, uaddr) ({ 0; }) #define BPF_CGROUP_RUN_PROG_UDP4_SENDMSG_LOCK(sk, uaddr, t_ctx) ({ 0; }) #define BPF_CGROUP_RUN_PROG_UDP6_SENDMSG_LOCK(sk, uaddr, t_ctx) ({ 0; }) +#define BPF_CGROUP_RUN_PROG_UDP4_RECVMSG_LOCK(sk, uaddr) ({ 0; }) +#define BPF_CGROUP_RUN_PROG_UDP6_RECVMSG_LOCK(sk, uaddr) ({ 0; }) #define BPF_CGROUP_RUN_PROG_SOCK_OPS(sock_ops) ({ 0; }) #endif /* CONFIG_CGROUP_BPF */ diff --git a/include/uapi/linux/bpf.h b/include/uapi/linux/bpf.h index f9623c6368c2..bf3fa85f500c 100644 --- a/include/uapi/linux/bpf.h +++ b/include/uapi/linux/bpf.h @@ -151,6 +151,8 @@ enum bpf_attach_type { BPF_CGROUP_INET6_POST_BIND, BPF_CGROUP_UDP4_SENDMSG, BPF_CGROUP_UDP6_SENDMSG, + BPF_CGROUP_UDP4_RECVMSG = 19, + BPF_CGROUP_UDP6_RECVMSG = 20, __MAX_BPF_ATTACH_TYPE }; diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c index 6e9217448a68..fdf89ccfbccf 100644 --- a/kernel/bpf/syscall.c +++ b/kernel/bpf/syscall.c @@ -1209,6 +1209,8 @@ bpf_prog_load_check_attach_type(enum bpf_prog_type prog_type, case BPF_CGROUP_INET6_CONNECT: case BPF_CGROUP_UDP4_SENDMSG: case BPF_CGROUP_UDP6_SENDMSG: + case BPF_CGROUP_UDP4_RECVMSG: + case BPF_CGROUP_UDP6_RECVMSG: return 0; default: return -EINVAL; @@ -1456,6 +1458,8 @@ static int bpf_prog_attach(const union bpf_attr *attr) case BPF_CGROUP_INET6_CONNECT: case BPF_CGROUP_UDP4_SENDMSG: case BPF_CGROUP_UDP6_SENDMSG: + case BPF_CGROUP_UDP4_RECVMSG: + case BPF_CGROUP_UDP6_RECVMSG: ptype = BPF_PROG_TYPE_CGROUP_SOCK_ADDR; break; case BPF_CGROUP_SOCK_OPS: @@ -1523,6 +1527,8 @@ static int bpf_prog_detach(const union bpf_attr *attr) case BPF_CGROUP_INET6_CONNECT: case BPF_CGROUP_UDP4_SENDMSG: case BPF_CGROUP_UDP6_SENDMSG: + case BPF_CGROUP_UDP4_RECVMSG: + case BPF_CGROUP_UDP6_RECVMSG: ptype = BPF_PROG_TYPE_CGROUP_SOCK_ADDR; break; case BPF_CGROUP_SOCK_OPS: @@ -1577,6 +1583,8 @@ static int bpf_prog_query(const union bpf_attr *attr, case BPF_CGROUP_INET6_CONNECT: case BPF_CGROUP_UDP4_SENDMSG: case BPF_CGROUP_UDP6_SENDMSG: + case BPF_CGROUP_UDP4_RECVMSG: + case BPF_CGROUP_UDP6_RECVMSG: case BPF_CGROUP_SOCK_OPS: break; default: diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c index 3d99789e02ae..bdb778aba6de 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c @@ -3624,6 +3624,10 @@ static int check_return_code(struct bpf_verifier_env *env) struct tnum range = tnum_range(0, 1); switch (env->prog->type) { + case BPF_PROG_TYPE_CGROUP_SOCK_ADDR: + if (env->prog->expected_attach_type == BPF_CGROUP_UDP4_RECVMSG || + env->prog->expected_attach_type == BPF_CGROUP_UDP6_RECVMSG) + range = tnum_range(1, 1); case BPF_PROG_TYPE_CGROUP_SKB: case BPF_PROG_TYPE_CGROUP_SOCK: case BPF_PROG_TYPE_SOCK_OPS: @@ -3640,16 +3644,17 @@ static int check_return_code(struct bpf_verifier_env *env) } if (!tnum_in(range, reg->var_off)) { + char tn_buf[48]; + verbose("At program exit the register R0 "); if (!tnum_is_unknown(reg->var_off)) { - char tn_buf[48]; - tnum_strn(tn_buf, sizeof(tn_buf), reg->var_off); verbose("has value %s", tn_buf); } else { verbose("has unknown scalar value"); } - verbose(" should have been 0 or 1\n"); + tnum_strn(tn_buf, sizeof(tn_buf), range); + verbose(" should have been in %s\n", tn_buf); return -EINVAL; } return 0; diff --git a/net/core/filter.c b/net/core/filter.c index d51028cf5ea2..0a80d0d1fe36 100644 --- a/net/core/filter.c +++ b/net/core/filter.c @@ -3895,6 +3895,7 @@ static bool sock_addr_is_valid_access(int off, int size, case BPF_CGROUP_INET4_BIND: case BPF_CGROUP_INET4_CONNECT: case BPF_CGROUP_UDP4_SENDMSG: + case BPF_CGROUP_UDP4_RECVMSG: break; default: return false; @@ -3905,6 +3906,7 @@ static bool sock_addr_is_valid_access(int off, int size, case BPF_CGROUP_INET6_BIND: case BPF_CGROUP_INET6_CONNECT: case BPF_CGROUP_UDP6_SENDMSG: + case BPF_CGROUP_UDP6_RECVMSG: break; default: return false; diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c index 58efff7b3c9c..d67d7e913c91 100644 --- a/net/ipv4/udp.c +++ b/net/ipv4/udp.c @@ -1748,6 +1748,10 @@ int udp_recvmsg(struct sock *sk, struct msghdr *msg, size_t len, int noblock, sin->sin_addr.s_addr = ip_hdr(skb)->saddr; memset(sin->sin_zero, 0, sizeof(sin->sin_zero)); *addr_len = sizeof(*sin); + + if (cgroup_bpf_enabled) + BPF_CGROUP_RUN_PROG_UDP4_RECVMSG_LOCK(sk, + (struct sockaddr *)sin); } if (udp_sk(sk)->gro_enabled) diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c index 4836492bac01..f0405d98444d 100644 --- a/net/ipv6/udp.c +++ b/net/ipv6/udp.c @@ -460,6 +460,10 @@ int udpv6_recvmsg(struct sock *sk, struct msghdr *msg, size_t len, inet6_iif(skb)); } *addr_len = sizeof(*sin6); + + if (cgroup_bpf_enabled) + BPF_CGROUP_RUN_PROG_UDP6_RECVMSG_LOCK(sk, + (struct sockaddr *)sin6); } if (udp_sk(sk)->gro_enabled) From e75a8f9479325bff7f768cddce1cb9e90669809c Mon Sep 17 00:00:00 2001 From: Tim Zimmermann Date: Sat, 20 Jul 2024 11:18:16 +0200 Subject: [PATCH 31/36] syscall: Only fake uname on very first call of netbpfload * The bpf programs actually still support older kernels, we just need to bypass the very first check for kernel version Change-Id: I4264782ee63efb26b95abd94774938d5456200a3 --- kernel/sys.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/kernel/sys.c b/kernel/sys.c index de93ecfef2bc..d1424baf85b5 100644 --- a/kernel/sys.c +++ b/kernel/sys.c @@ -1188,6 +1188,7 @@ static int override_release(char __user *release, size_t len) extern bool is_legacy_ebpf; +static uint64_t netbpfload_pid = 0; SYSCALL_DEFINE1(newuname, struct new_utsname __user *, name) { struct new_utsname tmp; @@ -1195,9 +1196,9 @@ SYSCALL_DEFINE1(newuname, struct new_utsname __user *, name) down_read(&uts_sem); memcpy(&tmp, utsname(), sizeof(tmp)); if (!is_legacy_ebpf) { - if (!strncmp(current->comm, "bpfloader", 9) || - !strncmp(current->comm, "netbpfload", 10) || - !strncmp(current->comm, "netd", 4)) { + if (!strncmp(current->comm, "netbpfload", 10) && + current->pid != netbpfload_pid) { + netbpfload_pid = current->pid; strcpy(tmp.release, "5.4.186"); pr_debug("fake uname: %s/%d release=%s\n", current->comm, current->pid, tmp.release); From b6f7d6240569b59d2352a65ba3fdbb390560ad42 Mon Sep 17 00:00:00 2001 From: Tim Zimmermann Date: Sat, 20 Jul 2024 11:19:35 +0200 Subject: [PATCH 32/36] syscall: Increase fake uname to 6.6.40 Change-Id: I77a8c5cd0e74eff97ae9b6b7e37812e2972cb3c8 --- kernel/sys.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kernel/sys.c b/kernel/sys.c index d1424baf85b5..fb41d5b0b443 100644 --- a/kernel/sys.c +++ b/kernel/sys.c @@ -1199,7 +1199,7 @@ SYSCALL_DEFINE1(newuname, struct new_utsname __user *, name) if (!strncmp(current->comm, "netbpfload", 10) && current->pid != netbpfload_pid) { netbpfload_pid = current->pid; - strcpy(tmp.release, "5.4.186"); + strcpy(tmp.release, "6.6.40"); pr_debug("fake uname: %s/%d release=%s\n", current->comm, current->pid, tmp.release); } From 403d92876b8a12a99405cd3e6e2963d8c349a5d5 Mon Sep 17 00:00:00 2001 From: Brian Geffon Date: Wed, 1 Apr 2020 21:09:17 -0700 Subject: [PATCH 33/36] BACKPORT: mm/mremap: add MREMAP_DONTUNMAP to mremap() When remapping an anonymous, private mapping, if MREMAP_DONTUNMAP is set, the source mapping will not be removed. The remap operation will be performed as it would have been normally by moving over the page tables to the new mapping. The old vma will have any locked flags cleared, have no pagetables, and any userfaultfds that were watching that range will continue watching it. For a mapping that is shared or not anonymous, MREMAP_DONTUNMAP will cause the mremap() call to fail. Because MREMAP_DONTUNMAP always results in moving a VMA you MUST use the MREMAP_MAYMOVE flag, it's not possible to resize a VMA while also moving with MREMAP_DONTUNMAP so old_len must always be equal to the new_len otherwise it will return -EINVAL. We hope to use this in Chrome OS where with userfaultfd we could write an anonymous mapping to disk without having to STOP the process or worry about VMA permission changes. This feature also has a use case in Android, Lokesh Gidra has said that "As part of using userfaultfd for GC, We'll have to move the physical pages of the java heap to a separate location. For this purpose mremap will be used. Without the MREMAP_DONTUNMAP flag, when I mremap the java heap, its virtual mapping will be removed as well. Therefore, we'll require performing mmap immediately after. This is not only time consuming but also opens a time window where a native thread may call mmap and reserve the java heap's address range for its own usage. This flag solves the problem." [bgeffon@google.com: v6] Link: http://lkml.kernel.org/r/20200218173221.237674-1-bgeffon@google.com [bgeffon@google.com: v7] Link: http://lkml.kernel.org/r/20200221174248.244748-1-bgeffon@google.com Signed-off-by: Brian Geffon Signed-off-by: Andrew Morton Tested-by: Lokesh Gidra Reviewed-by: Minchan Kim Acked-by: Kirill A. Shutemov Acked-by: Vlastimil Babka Cc: "Michael S . Tsirkin" Cc: Arnd Bergmann Cc: Andy Lutomirski Cc: Will Deacon Cc: Andrea Arcangeli Cc: Sonny Rao Cc: Minchan Kim Cc: Joel Fernandes Cc: Yu Zhao Cc: Jesse Barnes Cc: Nathan Chancellor Cc: Florian Weimer Link: http://lkml.kernel.org/r/20200207201856.46070-1-bgeffon@google.com Signed-off-by: Linus Torvalds (cherry picked from commit e346b3813067d4b17383f975f197a9aa28a3b077) Bug: 176847609 Signed-off-by: Kalesh Singh Change-Id: I8474cd9f032de02fa1764c49c63d368ac15346da --- include/uapi/linux/mman.h | 5 ++- mm/mremap.c | 90 ++++++++++++++++++++++++++++++--------- 2 files changed, 72 insertions(+), 23 deletions(-) diff --git a/include/uapi/linux/mman.h b/include/uapi/linux/mman.h index d0f515d53299..78b2660beae2 100644 --- a/include/uapi/linux/mman.h +++ b/include/uapi/linux/mman.h @@ -5,8 +5,9 @@ #include #include -#define MREMAP_MAYMOVE 1 -#define MREMAP_FIXED 2 +#define MREMAP_MAYMOVE 1 +#define MREMAP_FIXED 2 +#define MREMAP_DONTUNMAP 4 #define OVERCOMMIT_GUESS 0 #define OVERCOMMIT_ALWAYS 1 diff --git a/mm/mremap.c b/mm/mremap.c index 663a97d1072e..786353aa2786 100644 --- a/mm/mremap.c +++ b/mm/mremap.c @@ -469,8 +469,8 @@ unsigned long move_page_tables(struct vm_area_struct *vma, static unsigned long move_vma(struct vm_area_struct *vma, unsigned long old_addr, unsigned long old_len, unsigned long new_len, unsigned long new_addr, - bool *locked, struct vm_userfaultfd_ctx *uf, - struct list_head *uf_unmap) + bool *locked, unsigned long flags, + struct vm_userfaultfd_ctx *uf, struct list_head *uf_unmap) { struct mm_struct *mm = vma->vm_mm; struct vm_area_struct *new_vma; @@ -559,11 +559,32 @@ static unsigned long move_vma(struct vm_area_struct *vma, if (unlikely(vma->vm_flags & VM_PFNMAP)) untrack_pfn_moved(vma); + if (unlikely(!err && (flags & MREMAP_DONTUNMAP))) { + if (vm_flags & VM_ACCOUNT) { + /* Always put back VM_ACCOUNT since we won't unmap */ + vma->vm_flags |= VM_ACCOUNT; + + vm_acct_memory(vma_pages(new_vma)); + } + + /* We always clear VM_LOCKED[ONFAULT] on the old vma */ + vma->vm_flags &= VM_LOCKED_CLEAR_MASK; + + /* Because we won't unmap we don't need to touch locked_vm */ + goto out; + } + if (do_munmap(mm, old_addr, old_len, uf_unmap) < 0) { /* OOM: unable to split vma, just get accounts right */ vm_unacct_memory(excess >> PAGE_SHIFT); excess = 0; } + + if (vm_flags & VM_LOCKED) { + mm->locked_vm += new_len >> PAGE_SHIFT; + *locked = true; + } +out: mm->hiwater_vm = hiwater_vm; /* Restore VM_ACCOUNT if one or two pieces of vma left */ @@ -573,16 +594,12 @@ static unsigned long move_vma(struct vm_area_struct *vma, vma->vm_next->vm_flags |= VM_ACCOUNT; } - if (vm_flags & VM_LOCKED) { - mm->locked_vm += new_len >> PAGE_SHIFT; - *locked = true; - } - return new_addr; } static struct vm_area_struct *vma_to_resize(unsigned long addr, - unsigned long old_len, unsigned long new_len, unsigned long *p) + unsigned long old_len, unsigned long new_len, unsigned long flags, + unsigned long *p) { struct mm_struct *mm = current->mm; struct vm_area_struct *vma = find_vma(mm, addr); @@ -604,6 +621,10 @@ static struct vm_area_struct *vma_to_resize(unsigned long addr, return ERR_PTR(-EINVAL); } + if (flags & MREMAP_DONTUNMAP && (!vma_is_anonymous(vma) || + vma->vm_flags & VM_SHARED)) + return ERR_PTR(-EINVAL); + if (is_vm_hugetlb_page(vma)) return ERR_PTR(-EINVAL); @@ -648,7 +669,7 @@ static struct vm_area_struct *vma_to_resize(unsigned long addr, static unsigned long mremap_to(unsigned long addr, unsigned long old_len, unsigned long new_addr, unsigned long new_len, bool *locked, - struct vm_userfaultfd_ctx *uf, + unsigned long flags, struct vm_userfaultfd_ctx *uf, struct list_head *uf_unmap_early, struct list_head *uf_unmap) { @@ -656,7 +677,7 @@ static unsigned long mremap_to(unsigned long addr, unsigned long old_len, struct vm_area_struct *vma; unsigned long ret = -EINVAL; unsigned long charged = 0; - unsigned long map_flags; + unsigned long map_flags = 0; if (offset_in_page(new_addr)) goto out; @@ -668,9 +689,11 @@ static unsigned long mremap_to(unsigned long addr, unsigned long old_len, if (addr + old_len > new_addr && new_addr + new_len > addr) goto out; - ret = do_munmap(mm, new_addr, new_len, uf_unmap_early); - if (ret) - goto out; + if (flags & MREMAP_FIXED) { + ret = do_munmap(mm, new_addr, new_len, uf_unmap_early); + if (ret) + goto out; + } if (old_len >= new_len) { ret = do_munmap(mm, addr+new_len, old_len - new_len, uf_unmap); @@ -679,13 +702,22 @@ static unsigned long mremap_to(unsigned long addr, unsigned long old_len, old_len = new_len; } - vma = vma_to_resize(addr, old_len, new_len, &charged); + vma = vma_to_resize(addr, old_len, new_len, flags, &charged); if (IS_ERR(vma)) { ret = PTR_ERR(vma); goto out; } - map_flags = MAP_FIXED; + /* MREMAP_DONTUNMAP expands by old_len since old_len == new_len */ + if (flags & MREMAP_DONTUNMAP && + !may_expand_vm(mm, vma->vm_flags, old_len >> PAGE_SHIFT)) { + ret = -ENOMEM; + goto out; + } + + if (flags & MREMAP_FIXED) + map_flags |= MAP_FIXED; + if (vma->vm_flags & VM_MAYSHARE) map_flags |= MAP_SHARED; @@ -695,10 +727,16 @@ static unsigned long mremap_to(unsigned long addr, unsigned long old_len, if (offset_in_page(ret)) goto out1; - ret = move_vma(vma, addr, old_len, new_len, new_addr, locked, uf, + /* We got a new mapping */ + if (!(flags & MREMAP_FIXED)) + new_addr = ret; + + ret = move_vma(vma, addr, old_len, new_len, new_addr, locked, flags, uf, uf_unmap); + if (!(offset_in_page(ret))) goto out; + out1: vm_unacct_memory(charged); @@ -741,12 +779,21 @@ SYSCALL_DEFINE5(mremap, unsigned long, addr, unsigned long, old_len, addr = untagged_addr(addr); - if (flags & ~(MREMAP_FIXED | MREMAP_MAYMOVE)) + if (flags & ~(MREMAP_FIXED | MREMAP_MAYMOVE | MREMAP_DONTUNMAP)) return ret; if (flags & MREMAP_FIXED && !(flags & MREMAP_MAYMOVE)) return ret; + /* + * MREMAP_DONTUNMAP is always a move and it does not allow resizing + * in the process. + */ + if (flags & MREMAP_DONTUNMAP && + (!(flags & MREMAP_MAYMOVE) || old_len != new_len)) + return ret; + + if (offset_in_page(addr)) return ret; @@ -764,9 +811,10 @@ SYSCALL_DEFINE5(mremap, unsigned long, addr, unsigned long, old_len, if (down_write_killable(¤t->mm->mmap_sem)) return -EINTR; - if (flags & MREMAP_FIXED) { + if (flags & (MREMAP_FIXED | MREMAP_DONTUNMAP)) { ret = mremap_to(addr, old_len, new_addr, new_len, - &locked, &uf, &uf_unmap_early, &uf_unmap); + &locked, flags, &uf, &uf_unmap_early, + &uf_unmap); goto out; } @@ -786,7 +834,7 @@ SYSCALL_DEFINE5(mremap, unsigned long, addr, unsigned long, old_len, /* * Ok, we need to grow.. */ - vma = vma_to_resize(addr, old_len, new_len, &charged); + vma = vma_to_resize(addr, old_len, new_len, flags, &charged); if (IS_ERR(vma)) { ret = PTR_ERR(vma); goto out; @@ -836,7 +884,7 @@ SYSCALL_DEFINE5(mremap, unsigned long, addr, unsigned long, old_len, } ret = move_vma(vma, addr, old_len, new_len, new_addr, - &locked, &uf, &uf_unmap); + &locked, flags, &uf, &uf_unmap); } out: if (offset_in_page(ret)) { From 9f5a38d078298c2f935b060ada0d0f137cfdc941 Mon Sep 17 00:00:00 2001 From: Brian Geffon Date: Fri, 17 Apr 2020 10:25:56 -0700 Subject: [PATCH 34/36] UPSTREAM: mm: Fix MREMAP_DONTUNMAP accounting on VMA merge When remapping a mapping where a portion of a VMA is remapped into another portion of the VMA it can cause the VMA to become split. During the copy_vma operation the VMA can actually be remerged if it's an anonymous VMA whose pages have not yet been faulted. This isn't normally a problem because at the end of the remap the original portion is unmapped causing it to become split again. However, MREMAP_DONTUNMAP leaves that original portion in place which means that the VMA which was split and then remerged is not actually split at the end of the mremap. This patch fixes a bug where we don't detect that the VMAs got remerged and we end up putting back VM_ACCOUNT on the next mapping which is completely unreleated. When that next mapping is unmapped it results in incorrectly unaccounting for the memory which was never accounted, and eventually we will underflow on the memory comittment. There is also another issue which is similar, we're currently accouting for the number of pages in the new_vma but that's wrong. We need to account for the length of the remap operation as that's all that is being added. If there was a mapping already at that location its comittment would have been adjusted as part of the munmap at the start of the mremap. A really simple repro can be seen in: https://gist.github.com/bgaff/e101ce99da7d9a8c60acc641d07f312c Fixes: e346b3813067 ("mm/mremap: add MREMAP_DONTUNMAP to mremap()") Reported-by: syzbot Signed-off-by: Brian Geffon Signed-off-by: Linus Torvalds (cherry picked from commit dadbd85f2afc8ccd1dd1f0131781c740c91edd96) Bug: 176847609 Signed-off-by: Kalesh Singh Change-Id: I823b63d110825c306dab6929fca9408f8bf79ff0 --- mm/mremap.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/mm/mremap.c b/mm/mremap.c index 786353aa2786..75098b6c4817 100644 --- a/mm/mremap.c +++ b/mm/mremap.c @@ -564,9 +564,20 @@ static unsigned long move_vma(struct vm_area_struct *vma, /* Always put back VM_ACCOUNT since we won't unmap */ vma->vm_flags |= VM_ACCOUNT; - vm_acct_memory(vma_pages(new_vma)); + vm_acct_memory(new_len >> PAGE_SHIFT); } + /* + * VMAs can actually be merged back together in copy_vma + * calling merge_vma. This can happen with anonymous vmas + * which have not yet been faulted, so if we were to consider + * this VMA split we'll end up adding VM_ACCOUNT on the + * next VMA, which is completely unrelated if this VMA + * was re-merged. + */ + if (split && new_vma == vma) + split = 0; + /* We always clear VM_LOCKED[ONFAULT] on the old vma */ vma->vm_flags &= VM_LOCKED_CLEAR_MASK; From f3eee542d3d7251a8c78e4036fb552a3fdc028ad Mon Sep 17 00:00:00 2001 From: Brian Geffon Date: Wed, 13 May 2020 17:50:44 -0700 Subject: [PATCH 35/36] UPSTREAM: userfaultfd: fix remap event with MREMAP_DONTUNMAP A user is not required to set a new address when using MREMAP_DONTUNMAP as it can be used without MREMAP_FIXED. When doing so the remap event will use new_addr which may not have been set and we didn't propagate it back other then in the return value of remap_to. Because ret is always the new address it's probably more correct to use it rather than new_addr on the remap_event_complete call, and it resolves this bug. Fixes: e346b3813067d4b ("mm/mremap: add MREMAP_DONTUNMAP to mremap()") Reported-by: Randy Dunlap Signed-off-by: Brian Geffon Signed-off-by: Andrew Morton Cc: Lokesh Gidra Cc: Minchan Kim Cc: Kirill A. Shutemov Cc: Vlastimil Babka Cc: "Michael S . Tsirkin" Cc: Andrea Arcangeli Cc: Sonny Rao Cc: Joel Fernandes Link: http://lkml.kernel.org/r/20200506172158.218366-1-bgeffon@google.com Signed-off-by: Linus Torvalds (cherry picked from commit d1564926066115fb47ca06b2b9d23ed506ca9608) Bug: 176847609 Signed-off-by: Kalesh Singh Change-Id: I7a20139ee14a2c9124b74310d7c0324c11009087 --- mm/mremap.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mm/mremap.c b/mm/mremap.c index 75098b6c4817..f7a90ebd028a 100644 --- a/mm/mremap.c +++ b/mm/mremap.c @@ -906,7 +906,7 @@ SYSCALL_DEFINE5(mremap, unsigned long, addr, unsigned long, old_len, if (locked && new_len > old_len) mm_populate(new_addr + old_len, new_len - old_len); userfaultfd_unmap_complete(mm, &uf_unmap_early); - mremap_userfaultfd_complete(&uf, addr, new_addr, old_len); + mremap_userfaultfd_complete(&uf, addr, ret, old_len); userfaultfd_unmap_complete(mm, &uf_unmap); return ret; } From 8eb826aea144355c823195a22e615c254585c93e Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Tue, 14 Apr 2020 09:04:53 -0300 Subject: [PATCH 36/36] UPSTREAM: tools headers UAPI: Sync linux/mman.h with the kernel To get the changes in: e346b3813067 ("mm/mremap: add MREMAP_DONTUNMAP to mremap()") Add that to 'perf trace's mremap 'flags' decoder. This silences this perf build warning: Warning: Kernel ABI header at 'tools/include/uapi/linux/mman.h' differs from latest version at 'include/uapi/linux/mman.h' diff -u tools/include/uapi/linux/mman.h include/uapi/linux/mman.h Cc: Adrian Hunter Cc: Jiri Olsa Cc: Namhyung Kim Cc: Brian Geffon Signed-off-by: Arnaldo Carvalho de Melo (cherry picked from commit f60b3878f47311a61fe2d4c5ef77c52e31554c52) Bug: 176847609 Signed-off-by: Kalesh Singh Change-Id: Iab7117411cf9c4c32356da2b3de598a0df299a7c --- tools/include/uapi/linux/mman.h | 5 +++-- tools/perf/trace/beauty/mmap.c | 1 + 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/tools/include/uapi/linux/mman.h b/tools/include/uapi/linux/mman.h index bfd5938fede6..467dcfcba58b 100644 --- a/tools/include/uapi/linux/mman.h +++ b/tools/include/uapi/linux/mman.h @@ -5,8 +5,9 @@ #include #include -#define MREMAP_MAYMOVE 1 -#define MREMAP_FIXED 2 +#define MREMAP_MAYMOVE 1 +#define MREMAP_FIXED 2 +#define MREMAP_DONTUNMAP 4 #define OVERCOMMIT_GUESS 0 #define OVERCOMMIT_ALWAYS 1 diff --git a/tools/perf/trace/beauty/mmap.c b/tools/perf/trace/beauty/mmap.c index 51f1cea406f5..91b88fd9617c 100644 --- a/tools/perf/trace/beauty/mmap.c +++ b/tools/perf/trace/beauty/mmap.c @@ -85,6 +85,7 @@ static size_t syscall_arg__scnprintf_mremap_flags(char *bf, size_t size, P_MREMAP_FLAG(MAYMOVE); P_MREMAP_FLAG(FIXED); + P_MREMAP_FLAG(DONTUNMAP); #undef P_MREMAP_FLAG if (flags)