From: Sasha Levin Date: Sat, 27 Jun 2026 16:34:59 +0000 (-0400) Subject: Fixes for all trees X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=1fd4549d389c95bfd3c27a17d8f662c889c0c8bc;p=thirdparty%2Fkernel%2Fstable-queue.git Fixes for all trees Signed-off-by: Sasha Levin --- diff --git a/queue-5.10/crypto-qat-remove-unused-character-device-and-ioctls.patch b/queue-5.10/crypto-qat-remove-unused-character-device-and-ioctls.patch new file mode 100644 index 0000000000..12efc936ff --- /dev/null +++ b/queue-5.10/crypto-qat-remove-unused-character-device-and-ioctls.patch @@ -0,0 +1,714 @@ +From 60c2837711ad6d3be46b410456ba365861aa29a0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 25 Jun 2026 22:25:11 -0400 +Subject: crypto: qat - remove unused character device and IOCTLs + +From: Giovanni Cabiddu + +[ Upstream commit d237230728c567297f2f98b425d63156ab2ed17f ] + +The QAT driver exposes a character device (qat_adf_ctl) with IOCTLs +for device configuration, start, stop, status query and enumeration. +These IOCTLs are not part of any public uAPI header and have no known +in-tree or out-of-tree users. Device lifecycle is already managed via +sysfs. + +The ioctl interface also increases the attack surface and is the +subject of a number of bug reports. + +Remove the character device, the IOCTL definitions, and the related +data structures (adf_dev_status_info, adf_user_cfg_key_val, +adf_user_cfg_section, adf_user_cfg_ctl_data). Drop the now-unused +adf_cfg_user.h header and strip adf_ctl_drv.c down to the minimal +module_init/module_exit hooks for workqueue, AER, and crypto/compression +algorithm registration. + +Clean up leftover dead code that was only reachable from the removed +IOCTL paths: adf_cfg_del_all(), adf_devmgr_verify_id(), +adf_devmgr_get_num_dev(), adf_devmgr_get_dev_by_id(), +adf_get_vf_real_id() and the unused ADF_CFG macros. + +Additionally, drop the entry associated to QAT IOCTLs in +ioctl-number.rst. + +Cc: stable@vger.kernel.org +Fixes: d8cba25d2c68 ("crypto: qat - Intel(R) QAT driver framework") +Reported-by: Zhi Wang +Reported-by: Bin Yu +Reported-by: MingYu Wang +Closes: https://lore.kernel.org/all/61d6d499.ab89.19b9b7f3186.Coremail.wangzhi_xd@stu.xidian.edu.cn/ +Link: https://lore.kernel.org/all/20260508034841.256794-1-w15303746062@163.com/ +Link: https://lore.kernel.org/all/20260508023542.256299-1-w15303746062@163.com/ +Link: https://lore.kernel.org/all/20260504025120.98242-1-w15303746062@163.com/ +Signed-off-by: Giovanni Cabiddu +Reviewed-by: Ahsan Atta +Signed-off-by: Herbert Xu +Signed-off-by: Sasha Levin +--- + .../userspace-api/ioctl/ioctl-number.rst | 1 - + .../crypto/qat/qat_common/adf_cfg_common.h | 32 -- + drivers/crypto/qat/qat_common/adf_cfg_user.h | 38 -- + .../crypto/qat/qat_common/adf_common_drv.h | 3 - + drivers/crypto/qat/qat_common/adf_ctl_drv.c | 409 +----------------- + drivers/crypto/qat/qat_common/adf_dev_mgr.c | 70 --- + 6 files changed, 3 insertions(+), 550 deletions(-) + delete mode 100644 drivers/crypto/qat/qat_common/adf_cfg_user.h + +diff --git a/Documentation/userspace-api/ioctl/ioctl-number.rst b/Documentation/userspace-api/ioctl/ioctl-number.rst +index aa8d0cf534a3d6..7c6e78f4eba07e 100644 +--- a/Documentation/userspace-api/ioctl/ioctl-number.rst ++++ b/Documentation/userspace-api/ioctl/ioctl-number.rst +@@ -215,7 +215,6 @@ Code Seq# Include File Comments + + 'a' all linux/atm*.h, linux/sonet.h ATM on linux + +-'a' 00-0F drivers/crypto/qat/qat_common/adf_cfg_common.h conflict! qat driver + 'b' 00-FF conflict! bit3 vme host bridge + + 'c' all linux/cm4000_cs.h conflict! +diff --git a/drivers/crypto/qat/qat_common/adf_cfg_common.h b/drivers/crypto/qat/qat_common/adf_cfg_common.h +index 1ef46ccfba47b1..cf0d29cc58e87f 100644 +--- a/drivers/crypto/qat/qat_common/adf_cfg_common.h ++++ b/drivers/crypto/qat/qat_common/adf_cfg_common.h +@@ -4,18 +4,11 @@ + #define ADF_CFG_COMMON_H_ + + #include +-#include + + #define ADF_CFG_MAX_STR_LEN 64 + #define ADF_CFG_MAX_KEY_LEN_IN_BYTES ADF_CFG_MAX_STR_LEN + #define ADF_CFG_MAX_VAL_LEN_IN_BYTES ADF_CFG_MAX_STR_LEN + #define ADF_CFG_MAX_SECTION_LEN_IN_BYTES ADF_CFG_MAX_STR_LEN +-#define ADF_CFG_BASE_DEC 10 +-#define ADF_CFG_BASE_HEX 16 +-#define ADF_CFG_ALL_DEVICES 0xFE +-#define ADF_CFG_NO_DEVICE 0xFF +-#define ADF_CFG_AFFINITY_WHATEVER 0xFF +-#define MAX_DEVICE_NAME_SIZE 32 + #define ADF_MAX_DEVICES (32 * 32) + #define ADF_DEVS_ARRAY_SIZE BITS_TO_LONGS(ADF_MAX_DEVICES) + +@@ -34,29 +27,4 @@ enum adf_device_type { + DEV_C3XXX, + DEV_C3XXXVF + }; +- +-struct adf_dev_status_info { +- enum adf_device_type type; +- __u32 accel_id; +- __u32 instance_id; +- __u8 num_ae; +- __u8 num_accel; +- __u8 num_logical_accel; +- __u8 banks_per_accel; +- __u8 state; +- __u8 bus; +- __u8 dev; +- __u8 fun; +- char name[MAX_DEVICE_NAME_SIZE]; +-}; +- +-#define ADF_CTL_IOC_MAGIC 'a' +-#define IOCTL_CONFIG_SYS_RESOURCE_PARAMETERS _IOW(ADF_CTL_IOC_MAGIC, 0, \ +- struct adf_user_cfg_ctl_data) +-#define IOCTL_STOP_ACCEL_DEV _IOW(ADF_CTL_IOC_MAGIC, 1, \ +- struct adf_user_cfg_ctl_data) +-#define IOCTL_START_ACCEL_DEV _IOW(ADF_CTL_IOC_MAGIC, 2, \ +- struct adf_user_cfg_ctl_data) +-#define IOCTL_STATUS_ACCEL_DEV _IOW(ADF_CTL_IOC_MAGIC, 3, __u32) +-#define IOCTL_GET_NUM_DEVICES _IOW(ADF_CTL_IOC_MAGIC, 4, __s32) + #endif +diff --git a/drivers/crypto/qat/qat_common/adf_cfg_user.h b/drivers/crypto/qat/qat_common/adf_cfg_user.h +deleted file mode 100644 +index 421f4fb8b4dd2f..00000000000000 +--- a/drivers/crypto/qat/qat_common/adf_cfg_user.h ++++ /dev/null +@@ -1,38 +0,0 @@ +-/* SPDX-License-Identifier: (BSD-3-Clause OR GPL-2.0-only) */ +-/* Copyright(c) 2014 - 2020 Intel Corporation */ +-#ifndef ADF_CFG_USER_H_ +-#define ADF_CFG_USER_H_ +- +-#include "adf_cfg_common.h" +-#include "adf_cfg_strings.h" +- +-struct adf_user_cfg_key_val { +- char key[ADF_CFG_MAX_KEY_LEN_IN_BYTES]; +- char val[ADF_CFG_MAX_VAL_LEN_IN_BYTES]; +- union { +- struct adf_user_cfg_key_val *next; +- __u64 padding3; +- }; +- enum adf_cfg_val_type type; +-} __packed; +- +-struct adf_user_cfg_section { +- char name[ADF_CFG_MAX_SECTION_LEN_IN_BYTES]; +- union { +- struct adf_user_cfg_key_val *params; +- __u64 padding1; +- }; +- union { +- struct adf_user_cfg_section *next; +- __u64 padding3; +- }; +-} __packed; +- +-struct adf_user_cfg_ctl_data { +- union { +- struct adf_user_cfg_section *config_section; +- __u64 padding; +- }; +- __u8 device_id; +-} __packed; +-#endif +diff --git a/drivers/crypto/qat/qat_common/adf_common_drv.h b/drivers/crypto/qat/qat_common/adf_common_drv.h +index 469e06c93fafeb..e84b1ca844032a 100644 +--- a/drivers/crypto/qat/qat_common/adf_common_drv.h ++++ b/drivers/crypto/qat/qat_common/adf_common_drv.h +@@ -79,11 +79,8 @@ int adf_devmgr_add_dev(struct adf_accel_dev *accel_dev, + void adf_devmgr_rm_dev(struct adf_accel_dev *accel_dev, + struct adf_accel_dev *pf); + struct list_head *adf_devmgr_get_head(void); +-struct adf_accel_dev *adf_devmgr_get_dev_by_id(u32 id); + struct adf_accel_dev *adf_devmgr_get_first(void); + struct adf_accel_dev *adf_devmgr_pci_to_accel_dev(struct pci_dev *pci_dev); +-int adf_devmgr_verify_id(u32 id); +-void adf_devmgr_get_num_dev(u32 *num); + int adf_devmgr_in_reset(struct adf_accel_dev *accel_dev); + int adf_dev_started(struct adf_accel_dev *accel_dev); + int adf_dev_restarting_notify(struct adf_accel_dev *accel_dev); +diff --git a/drivers/crypto/qat/qat_common/adf_ctl_drv.c b/drivers/crypto/qat/qat_common/adf_ctl_drv.c +index 543ffe00de67b2..ba220f5d35a66b 100644 +--- a/drivers/crypto/qat/qat_common/adf_ctl_drv.c ++++ b/drivers/crypto/qat/qat_common/adf_ctl_drv.c +@@ -1,412 +1,14 @@ + // SPDX-License-Identifier: (BSD-3-Clause OR GPL-2.0-only) + /* Copyright(c) 2014 - 2020 Intel Corporation */ ++ ++#include ++#include + #include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include + +-#include "adf_accel_devices.h" + #include "adf_common_drv.h" +-#include "adf_cfg.h" +-#include "adf_cfg_common.h" +-#include "adf_cfg_user.h" +- +-#define DEVICE_NAME "qat_adf_ctl" +- +-static DEFINE_MUTEX(adf_ctl_lock); +-static long adf_ctl_ioctl(struct file *fp, unsigned int cmd, unsigned long arg); +- +-static const struct file_operations adf_ctl_ops = { +- .owner = THIS_MODULE, +- .unlocked_ioctl = adf_ctl_ioctl, +- .compat_ioctl = compat_ptr_ioctl, +-}; +- +-struct adf_ctl_drv_info { +- unsigned int major; +- struct cdev drv_cdev; +- struct class *drv_class; +-}; +- +-static struct adf_ctl_drv_info adf_ctl_drv; +- +-static void adf_chr_drv_destroy(void) +-{ +- device_destroy(adf_ctl_drv.drv_class, MKDEV(adf_ctl_drv.major, 0)); +- cdev_del(&adf_ctl_drv.drv_cdev); +- class_destroy(adf_ctl_drv.drv_class); +- unregister_chrdev_region(MKDEV(adf_ctl_drv.major, 0), 1); +-} +- +-static int adf_chr_drv_create(void) +-{ +- dev_t dev_id; +- struct device *drv_device; +- +- if (alloc_chrdev_region(&dev_id, 0, 1, DEVICE_NAME)) { +- pr_err("QAT: unable to allocate chrdev region\n"); +- return -EFAULT; +- } +- +- adf_ctl_drv.drv_class = class_create(THIS_MODULE, DEVICE_NAME); +- if (IS_ERR(adf_ctl_drv.drv_class)) { +- pr_err("QAT: class_create failed for adf_ctl\n"); +- goto err_chrdev_unreg; +- } +- adf_ctl_drv.major = MAJOR(dev_id); +- cdev_init(&adf_ctl_drv.drv_cdev, &adf_ctl_ops); +- if (cdev_add(&adf_ctl_drv.drv_cdev, dev_id, 1)) { +- pr_err("QAT: cdev add failed\n"); +- goto err_class_destr; +- } +- +- drv_device = device_create(adf_ctl_drv.drv_class, NULL, +- MKDEV(adf_ctl_drv.major, 0), +- NULL, DEVICE_NAME); +- if (IS_ERR(drv_device)) { +- pr_err("QAT: failed to create device\n"); +- goto err_cdev_del; +- } +- return 0; +-err_cdev_del: +- cdev_del(&adf_ctl_drv.drv_cdev); +-err_class_destr: +- class_destroy(adf_ctl_drv.drv_class); +-err_chrdev_unreg: +- unregister_chrdev_region(dev_id, 1); +- return -EFAULT; +-} +- +-static struct adf_user_cfg_ctl_data *adf_ctl_alloc_resources(unsigned long arg) +-{ +- struct adf_user_cfg_ctl_data *cfg_data; +- +- cfg_data = memdup_user((void __user *)arg, sizeof(*cfg_data)); +- if (IS_ERR(cfg_data)) +- pr_err("QAT: failed to copy from user cfg_data.\n"); +- return cfg_data; +-} +- +-static int adf_add_key_value_data(struct adf_accel_dev *accel_dev, +- const char *section, +- const struct adf_user_cfg_key_val *key_val) +-{ +- if (key_val->type == ADF_HEX) { +- long *ptr = (long *)key_val->val; +- long val = *ptr; +- +- if (adf_cfg_add_key_value_param(accel_dev, section, +- key_val->key, (void *)val, +- key_val->type)) { +- dev_err(&GET_DEV(accel_dev), +- "failed to add hex keyvalue.\n"); +- return -EFAULT; +- } +- } else { +- if (adf_cfg_add_key_value_param(accel_dev, section, +- key_val->key, key_val->val, +- key_val->type)) { +- dev_err(&GET_DEV(accel_dev), +- "failed to add keyvalue.\n"); +- return -EFAULT; +- } +- } +- return 0; +-} +- +-static int adf_copy_key_value_data(struct adf_accel_dev *accel_dev, +- struct adf_user_cfg_ctl_data *ctl_data) +-{ +- struct adf_user_cfg_key_val key_val; +- struct adf_user_cfg_key_val *params_head; +- struct adf_user_cfg_section section, *section_head; +- +- section_head = ctl_data->config_section; +- +- while (section_head) { +- if (copy_from_user(§ion, (void __user *)section_head, +- sizeof(*section_head))) { +- dev_err(&GET_DEV(accel_dev), +- "failed to copy section info\n"); +- goto out_err; +- } +- +- if (adf_cfg_section_add(accel_dev, section.name)) { +- dev_err(&GET_DEV(accel_dev), +- "failed to add section.\n"); +- goto out_err; +- } +- +- params_head = section.params; +- +- while (params_head) { +- if (copy_from_user(&key_val, (void __user *)params_head, +- sizeof(key_val))) { +- dev_err(&GET_DEV(accel_dev), +- "Failed to copy keyvalue.\n"); +- goto out_err; +- } +- if (adf_add_key_value_data(accel_dev, section.name, +- &key_val)) { +- goto out_err; +- } +- params_head = key_val.next; +- } +- section_head = section.next; +- } +- return 0; +-out_err: +- adf_cfg_del_all(accel_dev); +- return -EFAULT; +-} +- +-static int adf_ctl_ioctl_dev_config(struct file *fp, unsigned int cmd, +- unsigned long arg) +-{ +- struct adf_user_cfg_ctl_data *ctl_data; +- struct adf_accel_dev *accel_dev; +- int ret = 0; +- +- ctl_data = adf_ctl_alloc_resources(arg); +- if (IS_ERR(ctl_data)) +- return PTR_ERR(ctl_data); +- +- accel_dev = adf_devmgr_get_dev_by_id(ctl_data->device_id); +- if (!accel_dev) { +- ret = -EFAULT; +- goto out; +- } +- +- if (adf_dev_started(accel_dev)) { +- ret = -EFAULT; +- goto out; +- } +- +- if (adf_copy_key_value_data(accel_dev, ctl_data)) { +- ret = -EFAULT; +- goto out; +- } +- set_bit(ADF_STATUS_CONFIGURED, &accel_dev->status); +-out: +- kfree(ctl_data); +- return ret; +-} +- +-static int adf_ctl_is_device_in_use(int id) +-{ +- struct adf_accel_dev *dev; +- +- list_for_each_entry(dev, adf_devmgr_get_head(), list) { +- if (id == dev->accel_id || id == ADF_CFG_ALL_DEVICES) { +- if (adf_devmgr_in_reset(dev) || adf_dev_in_use(dev)) { +- dev_info(&GET_DEV(dev), +- "device qat_dev%d is busy\n", +- dev->accel_id); +- return -EBUSY; +- } +- } +- } +- return 0; +-} +- +-static void adf_ctl_stop_devices(u32 id) +-{ +- struct adf_accel_dev *accel_dev; +- +- list_for_each_entry(accel_dev, adf_devmgr_get_head(), list) { +- if (id == accel_dev->accel_id || id == ADF_CFG_ALL_DEVICES) { +- if (!adf_dev_started(accel_dev)) +- continue; +- +- /* First stop all VFs */ +- if (!accel_dev->is_vf) +- continue; +- +- adf_dev_stop(accel_dev); +- adf_dev_shutdown(accel_dev); +- } +- } +- +- list_for_each_entry(accel_dev, adf_devmgr_get_head(), list) { +- if (id == accel_dev->accel_id || id == ADF_CFG_ALL_DEVICES) { +- if (!adf_dev_started(accel_dev)) +- continue; +- +- adf_dev_stop(accel_dev); +- adf_dev_shutdown(accel_dev); +- } +- } +-} +- +-static int adf_ctl_ioctl_dev_stop(struct file *fp, unsigned int cmd, +- unsigned long arg) +-{ +- int ret; +- struct adf_user_cfg_ctl_data *ctl_data; +- +- ctl_data = adf_ctl_alloc_resources(arg); +- if (IS_ERR(ctl_data)) +- return PTR_ERR(ctl_data); +- +- if (adf_devmgr_verify_id(ctl_data->device_id)) { +- pr_err("QAT: Device %d not found\n", ctl_data->device_id); +- ret = -ENODEV; +- goto out; +- } +- +- ret = adf_ctl_is_device_in_use(ctl_data->device_id); +- if (ret) +- goto out; +- +- if (ctl_data->device_id == ADF_CFG_ALL_DEVICES) +- pr_info("QAT: Stopping all acceleration devices.\n"); +- else +- pr_info("QAT: Stopping acceleration device qat_dev%d.\n", +- ctl_data->device_id); +- +- adf_ctl_stop_devices(ctl_data->device_id); +- +-out: +- kfree(ctl_data); +- return ret; +-} +- +-static int adf_ctl_ioctl_dev_start(struct file *fp, unsigned int cmd, +- unsigned long arg) +-{ +- int ret; +- struct adf_user_cfg_ctl_data *ctl_data; +- struct adf_accel_dev *accel_dev; +- +- ctl_data = adf_ctl_alloc_resources(arg); +- if (IS_ERR(ctl_data)) +- return PTR_ERR(ctl_data); +- +- ret = -ENODEV; +- accel_dev = adf_devmgr_get_dev_by_id(ctl_data->device_id); +- if (!accel_dev) +- goto out; +- +- if (!adf_dev_started(accel_dev)) { +- dev_info(&GET_DEV(accel_dev), +- "Starting acceleration device qat_dev%d.\n", +- ctl_data->device_id); +- ret = adf_dev_init(accel_dev); +- if (!ret) +- ret = adf_dev_start(accel_dev); +- } else { +- dev_info(&GET_DEV(accel_dev), +- "Acceleration device qat_dev%d already started.\n", +- ctl_data->device_id); +- } +- if (ret) { +- dev_err(&GET_DEV(accel_dev), "Failed to start qat_dev%d\n", +- ctl_data->device_id); +- adf_dev_stop(accel_dev); +- adf_dev_shutdown(accel_dev); +- } +-out: +- kfree(ctl_data); +- return ret; +-} +- +-static int adf_ctl_ioctl_get_num_devices(struct file *fp, unsigned int cmd, +- unsigned long arg) +-{ +- u32 num_devices = 0; +- +- adf_devmgr_get_num_dev(&num_devices); +- if (copy_to_user((void __user *)arg, &num_devices, sizeof(num_devices))) +- return -EFAULT; +- +- return 0; +-} +- +-static int adf_ctl_ioctl_get_status(struct file *fp, unsigned int cmd, +- unsigned long arg) +-{ +- struct adf_hw_device_data *hw_data; +- struct adf_dev_status_info dev_info; +- struct adf_accel_dev *accel_dev; +- +- if (copy_from_user(&dev_info, (void __user *)arg, +- sizeof(struct adf_dev_status_info))) { +- pr_err("QAT: failed to copy from user.\n"); +- return -EFAULT; +- } +- +- accel_dev = adf_devmgr_get_dev_by_id(dev_info.accel_id); +- if (!accel_dev) +- return -ENODEV; +- +- hw_data = accel_dev->hw_device; +- dev_info.state = adf_dev_started(accel_dev) ? DEV_UP : DEV_DOWN; +- dev_info.num_ae = hw_data->get_num_aes(hw_data); +- dev_info.num_accel = hw_data->get_num_accels(hw_data); +- dev_info.num_logical_accel = hw_data->num_logical_accel; +- dev_info.banks_per_accel = hw_data->num_banks +- / hw_data->num_logical_accel; +- strlcpy(dev_info.name, hw_data->dev_class->name, sizeof(dev_info.name)); +- dev_info.instance_id = hw_data->instance_id; +- dev_info.type = hw_data->dev_class->type; +- dev_info.bus = accel_to_pci_dev(accel_dev)->bus->number; +- dev_info.dev = PCI_SLOT(accel_to_pci_dev(accel_dev)->devfn); +- dev_info.fun = PCI_FUNC(accel_to_pci_dev(accel_dev)->devfn); +- +- if (copy_to_user((void __user *)arg, &dev_info, +- sizeof(struct adf_dev_status_info))) { +- dev_err(&GET_DEV(accel_dev), "failed to copy status.\n"); +- return -EFAULT; +- } +- return 0; +-} +- +-static long adf_ctl_ioctl(struct file *fp, unsigned int cmd, unsigned long arg) +-{ +- int ret; +- +- if (mutex_lock_interruptible(&adf_ctl_lock)) +- return -EFAULT; +- +- switch (cmd) { +- case IOCTL_CONFIG_SYS_RESOURCE_PARAMETERS: +- ret = adf_ctl_ioctl_dev_config(fp, cmd, arg); +- break; +- +- case IOCTL_STOP_ACCEL_DEV: +- ret = adf_ctl_ioctl_dev_stop(fp, cmd, arg); +- break; +- +- case IOCTL_START_ACCEL_DEV: +- ret = adf_ctl_ioctl_dev_start(fp, cmd, arg); +- break; +- +- case IOCTL_GET_NUM_DEVICES: +- ret = adf_ctl_ioctl_get_num_devices(fp, cmd, arg); +- break; +- +- case IOCTL_STATUS_ACCEL_DEV: +- ret = adf_ctl_ioctl_get_status(fp, cmd, arg); +- break; +- default: +- pr_err("QAT: Invalid ioctl\n"); +- ret = -EFAULT; +- break; +- } +- mutex_unlock(&adf_ctl_lock); +- return ret; +-} + + static int __init adf_register_ctl_device_driver(void) + { +- if (adf_chr_drv_create()) +- goto err_chr_dev; +- + if (adf_init_aer()) + goto err_aer; + +@@ -428,21 +30,16 @@ static int __init adf_register_ctl_device_driver(void) + err_pf_wq: + adf_exit_aer(); + err_aer: +- adf_chr_drv_destroy(); +-err_chr_dev: +- mutex_destroy(&adf_ctl_lock); + return -EFAULT; + } + + static void __exit adf_unregister_ctl_device_driver(void) + { +- adf_chr_drv_destroy(); + adf_exit_aer(); + adf_exit_vf_wq(); + adf_exit_pf_wq(); + qat_crypto_unregister(); + adf_clean_vf_map(false); +- mutex_destroy(&adf_ctl_lock); + } + + module_init(adf_register_ctl_device_driver); +diff --git a/drivers/crypto/qat/qat_common/adf_dev_mgr.c b/drivers/crypto/qat/qat_common/adf_dev_mgr.c +index 92ec035576dfd8..9c4dd70865b3b8 100644 +--- a/drivers/crypto/qat/qat_common/adf_dev_mgr.c ++++ b/drivers/crypto/qat/qat_common/adf_dev_mgr.c +@@ -45,19 +45,6 @@ static struct vf_id_map *adf_find_vf(u32 bdf) + return NULL; + } + +-static int adf_get_vf_real_id(u32 fake) +-{ +- struct list_head *itr; +- +- list_for_each(itr, &vfs_table) { +- struct vf_id_map *ptr = +- list_entry(itr, struct vf_id_map, list); +- if (ptr->fake_id == fake) +- return ptr->id; +- } +- return -1; +-} +- + /** + * adf_clean_vf_map() - Cleans VF id mapings + * +@@ -311,63 +298,6 @@ struct adf_accel_dev *adf_devmgr_pci_to_accel_dev(struct pci_dev *pci_dev) + } + EXPORT_SYMBOL_GPL(adf_devmgr_pci_to_accel_dev); + +-struct adf_accel_dev *adf_devmgr_get_dev_by_id(u32 id) +-{ +- struct list_head *itr; +- int real_id; +- +- mutex_lock(&table_lock); +- real_id = adf_get_vf_real_id(id); +- if (real_id < 0) +- goto unlock; +- +- id = real_id; +- +- list_for_each(itr, &accel_table) { +- struct adf_accel_dev *ptr = +- list_entry(itr, struct adf_accel_dev, list); +- if (ptr->accel_id == id) { +- mutex_unlock(&table_lock); +- return ptr; +- } +- } +-unlock: +- mutex_unlock(&table_lock); +- return NULL; +-} +- +-int adf_devmgr_verify_id(u32 id) +-{ +- if (id == ADF_CFG_ALL_DEVICES) +- return 0; +- +- if (adf_devmgr_get_dev_by_id(id)) +- return 0; +- +- return -ENODEV; +-} +- +-static int adf_get_num_dettached_vfs(void) +-{ +- struct list_head *itr; +- int vfs = 0; +- +- mutex_lock(&table_lock); +- list_for_each(itr, &vfs_table) { +- struct vf_id_map *ptr = +- list_entry(itr, struct vf_id_map, list); +- if (ptr->bdf != ~0 && !ptr->attached) +- vfs++; +- } +- mutex_unlock(&table_lock); +- return vfs; +-} +- +-void adf_devmgr_get_num_dev(u32 *num) +-{ +- *num = num_devices - adf_get_num_dettached_vfs(); +-} +- + /** + * adf_dev_in_use() - Check whether accel_dev is currently in use + * @accel_dev: Pointer to acceleration device. +-- +2.53.0 + diff --git a/queue-5.10/crypto-qat-replace-kzalloc-copy_from_user-with-memdu.patch b/queue-5.10/crypto-qat-replace-kzalloc-copy_from_user-with-memdu.patch new file mode 100644 index 0000000000..161f52e4e1 --- /dev/null +++ b/queue-5.10/crypto-qat-replace-kzalloc-copy_from_user-with-memdu.patch @@ -0,0 +1,55 @@ +From f78d14b0942ca53f27ec203d4e6a8ea2de8b444f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 25 Jun 2026 22:25:09 -0400 +Subject: crypto: qat - Replace kzalloc() + copy_from_user() with memdup_user() + +From: Thorsten Blum + +[ Upstream commit 1e26339703e2afd397037defa798682b2b93dcc0 ] + +Replace kzalloc() followed by copy_from_user() with memdup_user() to +improve and simplify adf_ctl_alloc_resources(). memdup_user() returns +either -ENOMEM or -EFAULT (instead of -EIO) if an error occurs. + +Remove the unnecessary device id initialization, since memdup_user() +(like copy_from_user()) immediately overwrites it. + +No functional changes intended other than returning the more idiomatic +error code -EFAULT. + +Signed-off-by: Thorsten Blum +Signed-off-by: Herbert Xu +Stable-dep-of: d237230728c5 ("crypto: qat - remove unused character device and IOCTLs") +Signed-off-by: Sasha Levin +--- + drivers/crypto/qat/qat_common/adf_ctl_drv.c | 13 +++---------- + 1 file changed, 3 insertions(+), 10 deletions(-) + +diff --git a/drivers/crypto/qat/qat_common/adf_ctl_drv.c b/drivers/crypto/qat/qat_common/adf_ctl_drv.c +index eb9b3be9d8ebed..cd2ab4e9c7c4e6 100644 +--- a/drivers/crypto/qat/qat_common/adf_ctl_drv.c ++++ b/drivers/crypto/qat/qat_common/adf_ctl_drv.c +@@ -87,17 +87,10 @@ static int adf_ctl_alloc_resources(struct adf_user_cfg_ctl_data **ctl_data, + { + struct adf_user_cfg_ctl_data *cfg_data; + +- cfg_data = kzalloc(sizeof(*cfg_data), GFP_KERNEL); +- if (!cfg_data) +- return -ENOMEM; +- +- /* Initialize device id to NO DEVICE as 0 is a valid device id */ +- cfg_data->device_id = ADF_CFG_NO_DEVICE; +- +- if (copy_from_user(cfg_data, (void __user *)arg, sizeof(*cfg_data))) { ++ cfg_data = memdup_user((void __user *)arg, sizeof(*cfg_data)); ++ if (IS_ERR(cfg_data)) { + pr_err("QAT: failed to copy from user cfg_data.\n"); +- kfree(cfg_data); +- return -EIO; ++ return PTR_ERR(cfg_data); + } + + *ctl_data = cfg_data; +-- +2.53.0 + diff --git a/queue-5.10/crypto-qat-return-pointer-directly-in-adf_ctl_alloc_.patch b/queue-5.10/crypto-qat-return-pointer-directly-in-adf_ctl_alloc_.patch new file mode 100644 index 0000000000..8976571670 --- /dev/null +++ b/queue-5.10/crypto-qat-return-pointer-directly-in-adf_ctl_alloc_.patch @@ -0,0 +1,127 @@ +From a3b092562a8386936b56858839419c847a2369a0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 25 Jun 2026 22:25:10 -0400 +Subject: crypto: qat - Return pointer directly in adf_ctl_alloc_resources +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Herbert Xu + +[ Upstream commit 5ce9891ea928208a915411ce8227f8c3e37e5ad9 ] + +Returning values through arguments is confusing and that has +upset the compiler with the recent change to memdup_user: + +../drivers/crypto/intel/qat/qat_common/adf_ctl_drv.c: In function ‘adf_ctl_ioctl’: +../drivers/crypto/intel/qat/qat_common/adf_ctl_drv.c:308:26: warning: ‘ctl_data’ may be used uninitialized [-Wmaybe-uninitialized] + 308 | ctl_data->device_id); + | ^~ +../drivers/crypto/intel/qat/qat_common/adf_ctl_drv.c:294:39: note: ‘ctl_data’ was declared here + 294 | struct adf_user_cfg_ctl_data *ctl_data; + | ^~~~~~~~ +In function ‘adf_ctl_ioctl_dev_stop’, + inlined from ‘adf_ctl_ioctl’ at ../drivers/crypto/intel/qat/qat_common/adf_ctl_drv.c:386:9: +../drivers/crypto/intel/qat/qat_common/adf_ctl_drv.c:273:48: warning: ‘ctl_data’ may be used uninitialized [-Wmaybe-uninitialized] + 273 | ret = adf_ctl_is_device_in_use(ctl_data->device_id); + | ~~~~~~~~^~~~~~~~~~~ +../drivers/crypto/intel/qat/qat_common/adf_ctl_drv.c: In function ‘adf_ctl_ioctl’: +../drivers/crypto/intel/qat/qat_common/adf_ctl_drv.c:261:39: note: ‘ctl_data’ was declared here + 261 | struct adf_user_cfg_ctl_data *ctl_data; + | ^~~~~~~~ +In function ‘adf_ctl_ioctl_dev_config’, + inlined from ‘adf_ctl_ioctl’ at ../drivers/crypto/intel/qat/qat_common/adf_ctl_drv.c:382:9: +../drivers/crypto/intel/qat/qat_common/adf_ctl_drv.c:192:54: warning: ‘ctl_data’ may be used uninitialized [-Wmaybe-uninitialized] + 192 | accel_dev = adf_devmgr_get_dev_by_id(ctl_data->device_id); + | ~~~~~~~~^~~~~~~~~~~ +../drivers/crypto/intel/qat/qat_common/adf_ctl_drv.c: In function ‘adf_ctl_ioctl’: +../drivers/crypto/intel/qat/qat_common/adf_ctl_drv.c:185:39: note: ‘ctl_data’ was declared here + 185 | struct adf_user_cfg_ctl_data *ctl_data; + | ^~~~~~~~ + +Fix this by returning the pointer directly. + +Signed-off-by: Herbert Xu +Reviewed-by: Thorsten Blum +Acked-by: Giovanni Cabiddu +Signed-off-by: Herbert Xu +Stable-dep-of: d237230728c5 ("crypto: qat - remove unused character device and IOCTLs") +Signed-off-by: Sasha Levin +--- + drivers/crypto/qat/qat_common/adf_ctl_drv.c | 31 +++++++++------------ + 1 file changed, 13 insertions(+), 18 deletions(-) + +diff --git a/drivers/crypto/qat/qat_common/adf_ctl_drv.c b/drivers/crypto/qat/qat_common/adf_ctl_drv.c +index cd2ab4e9c7c4e6..543ffe00de67b2 100644 +--- a/drivers/crypto/qat/qat_common/adf_ctl_drv.c ++++ b/drivers/crypto/qat/qat_common/adf_ctl_drv.c +@@ -82,19 +82,14 @@ static int adf_chr_drv_create(void) + return -EFAULT; + } + +-static int adf_ctl_alloc_resources(struct adf_user_cfg_ctl_data **ctl_data, +- unsigned long arg) ++static struct adf_user_cfg_ctl_data *adf_ctl_alloc_resources(unsigned long arg) + { + struct adf_user_cfg_ctl_data *cfg_data; + + cfg_data = memdup_user((void __user *)arg, sizeof(*cfg_data)); +- if (IS_ERR(cfg_data)) { ++ if (IS_ERR(cfg_data)) + pr_err("QAT: failed to copy from user cfg_data.\n"); +- return PTR_ERR(cfg_data); +- } +- +- *ctl_data = cfg_data; +- return 0; ++ return cfg_data; + } + + static int adf_add_key_value_data(struct adf_accel_dev *accel_dev, +@@ -173,13 +168,13 @@ static int adf_copy_key_value_data(struct adf_accel_dev *accel_dev, + static int adf_ctl_ioctl_dev_config(struct file *fp, unsigned int cmd, + unsigned long arg) + { +- int ret; + struct adf_user_cfg_ctl_data *ctl_data; + struct adf_accel_dev *accel_dev; ++ int ret = 0; + +- ret = adf_ctl_alloc_resources(&ctl_data, arg); +- if (ret) +- return ret; ++ ctl_data = adf_ctl_alloc_resources(arg); ++ if (IS_ERR(ctl_data)) ++ return PTR_ERR(ctl_data); + + accel_dev = adf_devmgr_get_dev_by_id(ctl_data->device_id); + if (!accel_dev) { +@@ -254,9 +249,9 @@ static int adf_ctl_ioctl_dev_stop(struct file *fp, unsigned int cmd, + int ret; + struct adf_user_cfg_ctl_data *ctl_data; + +- ret = adf_ctl_alloc_resources(&ctl_data, arg); +- if (ret) +- return ret; ++ ctl_data = adf_ctl_alloc_resources(arg); ++ if (IS_ERR(ctl_data)) ++ return PTR_ERR(ctl_data); + + if (adf_devmgr_verify_id(ctl_data->device_id)) { + pr_err("QAT: Device %d not found\n", ctl_data->device_id); +@@ -288,9 +283,9 @@ static int adf_ctl_ioctl_dev_start(struct file *fp, unsigned int cmd, + struct adf_user_cfg_ctl_data *ctl_data; + struct adf_accel_dev *accel_dev; + +- ret = adf_ctl_alloc_resources(&ctl_data, arg); +- if (ret) +- return ret; ++ ctl_data = adf_ctl_alloc_resources(arg); ++ if (IS_ERR(ctl_data)) ++ return PTR_ERR(ctl_data); + + ret = -ENODEV; + accel_dev = adf_devmgr_get_dev_by_id(ctl_data->device_id); +-- +2.53.0 + diff --git a/queue-5.10/documentation-ioctl-number-extend-include-file-colum.patch b/queue-5.10/documentation-ioctl-number-extend-include-file-colum.patch new file mode 100644 index 0000000000..ef98a4af14 --- /dev/null +++ b/queue-5.10/documentation-ioctl-number-extend-include-file-colum.patch @@ -0,0 +1,545 @@ +From 420193744e29115f4cf8624d6934291537ccb4e6 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 25 Jun 2026 22:25:08 -0400 +Subject: Documentation: ioctl-number: Extend "Include File" column width + +From: Bagas Sanjaya + +[ Upstream commit 15afd5def819e4df2a29cef6fcfa6ae7ba167c0f ] + +Extend width of "Include File" column to fit full path to +papr-physical-attestation.h in later commit. + +Reviewed-by: Haren Myneni +Signed-off-by: Bagas Sanjaya +Acked-by: Madhavan Srinivasan +Signed-off-by: Jonathan Corbet +Link: https://lore.kernel.org/r/20250714015711.14525-3-bagasdotme@gmail.com +Stable-dep-of: d237230728c5 ("crypto: qat - remove unused character device and IOCTLs") +Signed-off-by: Sasha Levin +--- + .../userspace-api/ioctl/ioctl-number.rst | 428 +++++++++--------- + 1 file changed, 214 insertions(+), 214 deletions(-) + +diff --git a/Documentation/userspace-api/ioctl/ioctl-number.rst b/Documentation/userspace-api/ioctl/ioctl-number.rst +index a7373d4e3984cf..aa8d0cf534a3d6 100644 +--- a/Documentation/userspace-api/ioctl/ioctl-number.rst ++++ b/Documentation/userspace-api/ioctl/ioctl-number.rst +@@ -66,17 +66,17 @@ This table lists ioctls visible from user land for Linux/x86. It contains + most drivers up to 2.6.31, but I know I am missing some. There has been + no attempt to list non-X86 architectures or ioctls from drivers/staging/. + +-==== ===== ======================================================= ================================================================ +-Code Seq# Include File Comments ++==== ===== ========================================================= ================================================================ ++Code Seq# Include File Comments + (hex) +-==== ===== ======================================================= ================================================================ +-0x00 00-1F linux/fs.h conflict! +-0x00 00-1F scsi/scsi_ioctl.h conflict! +-0x00 00-1F linux/fb.h conflict! +-0x00 00-1F linux/wavefront.h conflict! ++==== ===== ========================================================= ================================================================ ++0x00 00-1F linux/fs.h conflict! ++0x00 00-1F scsi/scsi_ioctl.h conflict! ++0x00 00-1F linux/fb.h conflict! ++0x00 00-1F linux/wavefront.h conflict! + 0x02 all linux/fd.h + 0x03 all linux/hdreg.h +-0x04 D2-DC linux/umsdos_fs.h Dead since 2.6.11, but don't reuse these. ++0x04 D2-DC linux/umsdos_fs.h Dead since 2.6.11, but don't reuse these. + 0x06 all linux/lp.h + 0x09 all linux/raid/md_u.h + 0x10 00-0F drivers/char/s390/vmcp.h +@@ -84,282 +84,282 @@ Code Seq# Include File Comments + 0x10 20-2F arch/s390/include/uapi/asm/hypfs.h + 0x12 all linux/fs.h + linux/blkpg.h +-0x1b all InfiniBand Subsystem +- ++0x1b all InfiniBand Subsystem ++ + 0x20 all drivers/cdrom/cm206.h + 0x22 all scsi/sg.h + '!' 00-1F uapi/linux/seccomp.h +-'#' 00-3F IEEE 1394 Subsystem +- Block for the entire subsystem ++'#' 00-3F IEEE 1394 Subsystem ++ Block for the entire subsystem + '$' 00-0F linux/perf_counter.h, linux/perf_event.h +-'%' 00-0F include/uapi/linux/stm.h System Trace Module subsystem +- ++'%' 00-0F include/uapi/linux/stm.h System Trace Module subsystem ++ + '&' 00-07 drivers/firewire/nosy-user.h +-'1' 00-1F linux/timepps.h PPS kit from Ulrich Windl +- ++'1' 00-1F linux/timepps.h PPS kit from Ulrich Windl ++ + '2' 01-04 linux/i2o.h +-'3' 00-0F drivers/s390/char/raw3270.h conflict! +-'3' 00-1F linux/suspend_ioctls.h, conflict! ++'3' 00-0F drivers/s390/char/raw3270.h conflict! ++'3' 00-1F linux/suspend_ioctls.h, conflict! + kernel/power/user.c +-'8' all SNP8023 advanced NIC card +- ++'8' all SNP8023 advanced NIC card ++ + ';' 64-7F linux/vfio.h +-'@' 00-0F linux/radeonfb.h conflict! +-'@' 00-0F drivers/video/aty/aty128fb.c conflict! +-'A' 00-1F linux/apm_bios.h conflict! +-'A' 00-0F linux/agpgart.h, conflict! ++'@' 00-0F linux/radeonfb.h conflict! ++'@' 00-0F drivers/video/aty/aty128fb.c conflict! ++'A' 00-1F linux/apm_bios.h conflict! ++'A' 00-0F linux/agpgart.h, conflict! + drivers/char/agp/compat_ioctl.h +-'A' 00-7F sound/asound.h conflict! +-'B' 00-1F linux/cciss_ioctl.h conflict! +-'B' 00-0F include/linux/pmu.h conflict! +-'B' C0-FF advanced bbus +-'C' all linux/soundcard.h conflict! +-'C' 01-2F linux/capi.h conflict! +-'C' F0-FF drivers/net/wan/cosa.h conflict! ++'A' 00-7F sound/asound.h conflict! ++'B' 00-1F linux/cciss_ioctl.h conflict! ++'B' 00-0F include/linux/pmu.h conflict! ++'B' C0-FF advanced bbus ++'C' all linux/soundcard.h conflict! ++'C' 01-2F linux/capi.h conflict! ++'C' F0-FF drivers/net/wan/cosa.h conflict! + 'D' all arch/s390/include/asm/dasd.h + 'D' 40-5F drivers/scsi/dpt/dtpi_ioctl.h + 'D' 05 drivers/scsi/pmcraid.h +-'E' all linux/input.h conflict! +-'E' 00-0F xen/evtchn.h conflict! +-'F' all linux/fb.h conflict! +-'F' 01-02 drivers/scsi/pmcraid.h conflict! +-'F' 20 drivers/video/fsl-diu-fb.h conflict! +-'F' 20 drivers/video/intelfb/intelfb.h conflict! +-'F' 20 linux/ivtvfb.h conflict! +-'F' 20 linux/matroxfb.h conflict! +-'F' 20 drivers/video/aty/atyfb_base.c conflict! +-'F' 00-0F video/da8xx-fb.h conflict! +-'F' 80-8F linux/arcfb.h conflict! +-'F' DD video/sstfb.h conflict! +-'G' 00-3F drivers/misc/sgi-gru/grulib.h conflict! +-'H' 00-7F linux/hiddev.h conflict! +-'H' 00-0F linux/hidraw.h conflict! +-'H' 01 linux/mei.h conflict! +-'H' 02 linux/mei.h conflict! +-'H' 03 linux/mei.h conflict! +-'H' 00-0F sound/asound.h conflict! +-'H' 20-40 sound/asound_fm.h conflict! +-'H' 80-8F sound/sfnt_info.h conflict! +-'H' 10-8F sound/emu10k1.h conflict! +-'H' 10-1F sound/sb16_csp.h conflict! +-'H' 10-1F sound/hda_hwdep.h conflict! +-'H' 40-4F sound/hdspm.h conflict! +-'H' 40-4F sound/hdsp.h conflict! ++'E' all linux/input.h conflict! ++'E' 00-0F xen/evtchn.h conflict! ++'F' all linux/fb.h conflict! ++'F' 01-02 drivers/scsi/pmcraid.h conflict! ++'F' 20 drivers/video/fsl-diu-fb.h conflict! ++'F' 20 drivers/video/intelfb/intelfb.h conflict! ++'F' 20 linux/ivtvfb.h conflict! ++'F' 20 linux/matroxfb.h conflict! ++'F' 20 drivers/video/aty/atyfb_base.c conflict! ++'F' 00-0F video/da8xx-fb.h conflict! ++'F' 80-8F linux/arcfb.h conflict! ++'F' DD video/sstfb.h conflict! ++'G' 00-3F drivers/misc/sgi-gru/grulib.h conflict! ++'H' 00-7F linux/hiddev.h conflict! ++'H' 00-0F linux/hidraw.h conflict! ++'H' 01 linux/mei.h conflict! ++'H' 02 linux/mei.h conflict! ++'H' 03 linux/mei.h conflict! ++'H' 00-0F sound/asound.h conflict! ++'H' 20-40 sound/asound_fm.h conflict! ++'H' 80-8F sound/sfnt_info.h conflict! ++'H' 10-8F sound/emu10k1.h conflict! ++'H' 10-1F sound/sb16_csp.h conflict! ++'H' 10-1F sound/hda_hwdep.h conflict! ++'H' 40-4F sound/hdspm.h conflict! ++'H' 40-4F sound/hdsp.h conflict! + 'H' 90 sound/usb/usx2y/usb_stream.h +-'H' 00-0F uapi/misc/habanalabs.h conflict! ++'H' 00-0F uapi/misc/habanalabs.h conflict! + 'H' A0 uapi/linux/usb/cdc-wdm.h +-'H' C0-F0 net/bluetooth/hci.h conflict! +-'H' C0-DF net/bluetooth/hidp/hidp.h conflict! +-'H' C0-DF net/bluetooth/cmtp/cmtp.h conflict! +-'H' C0-DF net/bluetooth/bnep/bnep.h conflict! +-'H' F1 linux/hid-roccat.h ++'H' C0-F0 net/bluetooth/hci.h conflict! ++'H' C0-DF net/bluetooth/hidp/hidp.h conflict! ++'H' C0-DF net/bluetooth/cmtp/cmtp.h conflict! ++'H' C0-DF net/bluetooth/bnep/bnep.h conflict! ++'H' F1 linux/hid-roccat.h + 'H' F8-FA sound/firewire.h +-'I' all linux/isdn.h conflict! +-'I' 00-0F drivers/isdn/divert/isdn_divert.h conflict! +-'I' 40-4F linux/mISDNif.h conflict! ++'I' all linux/isdn.h conflict! ++'I' 00-0F drivers/isdn/divert/isdn_divert.h conflict! ++'I' 40-4F linux/mISDNif.h conflict! + 'J' 00-1F drivers/scsi/gdth_ioctl.h + 'K' all linux/kd.h +-'L' 00-1F linux/loop.h conflict! +-'L' 10-1F drivers/scsi/mpt3sas/mpt3sas_ctl.h conflict! ++'L' 00-1F linux/loop.h conflict! ++'L' 10-1F drivers/scsi/mpt3sas/mpt3sas_ctl.h conflict! + 'L' 20-2F linux/lightnvm.h +-'L' E0-FF linux/ppdd.h encrypted disk device driver +- +-'M' all linux/soundcard.h conflict! +-'M' 01-16 mtd/mtd-abi.h conflict! ++'L' E0-FF linux/ppdd.h encrypted disk device driver ++ ++'M' all linux/soundcard.h conflict! ++'M' 01-16 mtd/mtd-abi.h conflict! + and drivers/mtd/mtdchar.c + 'M' 01-03 drivers/scsi/megaraid/megaraid_sas.h +-'M' 00-0F drivers/video/fsl-diu-fb.h conflict! ++'M' 00-0F drivers/video/fsl-diu-fb.h conflict! + 'N' 00-1F drivers/usb/scanner.h + 'N' 40-7F drivers/block/nvme.c +-'O' 00-06 mtd/ubi-user.h UBI +-'P' all linux/soundcard.h conflict! +-'P' 60-6F sound/sscape_ioctl.h conflict! +-'P' 00-0F drivers/usb/class/usblp.c conflict! +-'P' 01-09 drivers/misc/pci_endpoint_test.c conflict! ++'O' 00-06 mtd/ubi-user.h UBI ++'P' all linux/soundcard.h conflict! ++'P' 60-6F sound/sscape_ioctl.h conflict! ++'P' 00-0F drivers/usb/class/usblp.c conflict! ++'P' 01-09 drivers/misc/pci_endpoint_test.c conflict! + 'Q' all linux/soundcard.h +-'R' 00-1F linux/random.h conflict! +-'R' 01 linux/rfkill.h conflict! ++'R' 00-1F linux/random.h conflict! ++'R' 01 linux/rfkill.h conflict! + 'R' C0-DF net/bluetooth/rfcomm.h +-'S' all linux/cdrom.h conflict! +-'S' 80-81 scsi/scsi_ioctl.h conflict! +-'S' 82-FF scsi/scsi.h conflict! +-'S' 00-7F sound/asequencer.h conflict! +-'T' all linux/soundcard.h conflict! +-'T' 00-AF sound/asound.h conflict! +-'T' all arch/x86/include/asm/ioctls.h conflict! +-'T' C0-DF linux/if_tun.h conflict! +-'U' all sound/asound.h conflict! +-'U' 00-CF linux/uinput.h conflict! ++'S' all linux/cdrom.h conflict! ++'S' 80-81 scsi/scsi_ioctl.h conflict! ++'S' 82-FF scsi/scsi.h conflict! ++'S' 00-7F sound/asequencer.h conflict! ++'T' all linux/soundcard.h conflict! ++'T' 00-AF sound/asound.h conflict! ++'T' all arch/x86/include/asm/ioctls.h conflict! ++'T' C0-DF linux/if_tun.h conflict! ++'U' all sound/asound.h conflict! ++'U' 00-CF linux/uinput.h conflict! + 'U' 00-EF linux/usbdevice_fs.h + 'U' C0-CF drivers/bluetooth/hci_uart.h +-'V' all linux/vt.h conflict! +-'V' all linux/videodev2.h conflict! +-'V' C0 linux/ivtvfb.h conflict! +-'V' C0 linux/ivtv.h conflict! +-'V' C0 media/davinci/vpfe_capture.h conflict! +-'V' C0 media/si4713.h conflict! +-'W' 00-1F linux/watchdog.h conflict! +-'W' 00-1F linux/wanrouter.h conflict! (pre 3.9) +-'W' 00-3F sound/asound.h conflict! ++'V' all linux/vt.h conflict! ++'V' all linux/videodev2.h conflict! ++'V' C0 linux/ivtvfb.h conflict! ++'V' C0 linux/ivtv.h conflict! ++'V' C0 media/davinci/vpfe_capture.h conflict! ++'V' C0 media/si4713.h conflict! ++'W' 00-1F linux/watchdog.h conflict! ++'W' 00-1F linux/wanrouter.h conflict! (pre 3.9) ++'W' 00-3F sound/asound.h conflict! + 'W' 40-5F drivers/pci/switch/switchtec.c + 'W' 60-61 linux/watch_queue.h +-'X' all fs/xfs/xfs_fs.h, conflict! ++'X' all fs/xfs/xfs_fs.h, conflict! + fs/xfs/linux-2.6/xfs_ioctl32.h, + include/linux/falloc.h, + linux/fs.h, +-'X' all fs/ocfs2/ocfs_fs.h conflict! +-'X' 01 linux/pktcdvd.h conflict! ++'X' all fs/ocfs2/ocfs_fs.h conflict! ++'X' 01 linux/pktcdvd.h conflict! + 'Y' all linux/cyclades.h + 'Z' 14-15 drivers/message/fusion/mptctl.h +-'[' 00-3F linux/usb/tmc.h USB Test and Measurement Devices +- +-'a' all linux/atm*.h, linux/sonet.h ATM on linux +- +-'a' 00-0F drivers/crypto/qat/qat_common/adf_cfg_common.h conflict! qat driver +-'b' 00-FF conflict! bit3 vme host bridge +- +-'c' all linux/cm4000_cs.h conflict! +-'c' 00-7F linux/comstats.h conflict! +-'c' 00-7F linux/coda.h conflict! +-'c' 00-1F linux/chio.h conflict! +-'c' 80-9F arch/s390/include/asm/chsc.h conflict! ++'[' 00-3F linux/usb/tmc.h USB Test and Measurement Devices ++ ++'a' all linux/atm*.h, linux/sonet.h ATM on linux ++ ++'a' 00-0F drivers/crypto/qat/qat_common/adf_cfg_common.h conflict! qat driver ++'b' 00-FF conflict! bit3 vme host bridge ++ ++'c' all linux/cm4000_cs.h conflict! ++'c' 00-7F linux/comstats.h conflict! ++'c' 00-7F linux/coda.h conflict! ++'c' 00-1F linux/chio.h conflict! ++'c' 80-9F arch/s390/include/asm/chsc.h conflict! + 'c' A0-AF arch/x86/include/asm/msr.h conflict! +-'d' 00-FF linux/char/drm/drm.h conflict! +-'d' 02-40 pcmcia/ds.h conflict! ++'d' 00-FF linux/char/drm/drm.h conflict! ++'d' 02-40 pcmcia/ds.h conflict! + 'd' F0-FF linux/digi1.h +-'e' all linux/digi1.h conflict! +-'f' 00-1F linux/ext2_fs.h conflict! +-'f' 00-1F linux/ext3_fs.h conflict! +-'f' 00-0F fs/jfs/jfs_dinode.h conflict! +-'f' 00-0F fs/ext4/ext4.h conflict! +-'f' 00-0F linux/fs.h conflict! +-'f' 00-0F fs/ocfs2/ocfs2_fs.h conflict! ++'e' all linux/digi1.h conflict! ++'f' 00-1F linux/ext2_fs.h conflict! ++'f' 00-1F linux/ext3_fs.h conflict! ++'f' 00-0F fs/jfs/jfs_dinode.h conflict! ++'f' 00-0F fs/ext4/ext4.h conflict! ++'f' 00-0F linux/fs.h conflict! ++'f' 00-0F fs/ocfs2/ocfs2_fs.h conflict! + 'f' 13-27 linux/fscrypt.h + 'f' 81-8F linux/fsverity.h + 'g' 00-0F linux/usb/gadgetfs.h + 'g' 20-2F linux/usb/g_printer.h +-'h' 00-7F conflict! Charon filesystem +- +-'h' 00-1F linux/hpet.h conflict! ++'h' 00-7F conflict! Charon filesystem ++ ++'h' 00-1F linux/hpet.h conflict! + 'h' 80-8F fs/hfsplus/ioctl.c +-'i' 00-3F linux/i2o-dev.h conflict! +-'i' 0B-1F linux/ipmi.h conflict! ++'i' 00-3F linux/i2o-dev.h conflict! ++'i' 0B-1F linux/ipmi.h conflict! + 'i' 80-8F linux/i8k.h + 'j' 00-3F linux/joystick.h +-'k' 00-0F linux/spi/spidev.h conflict! +-'k' 00-05 video/kyro.h conflict! +-'k' 10-17 linux/hsi/hsi_char.h HSI character device +-'l' 00-3F linux/tcfs_fs.h transparent cryptographic file system +- +-'l' 40-7F linux/udf_fs_i.h in development: +- +-'m' 00-09 linux/mmtimer.h conflict! +-'m' all linux/mtio.h conflict! +-'m' all linux/soundcard.h conflict! +-'m' all linux/synclink.h conflict! +-'m' 00-19 drivers/message/fusion/mptctl.h conflict! +-'m' 00 drivers/scsi/megaraid/megaraid_ioctl.h conflict! ++'k' 00-0F linux/spi/spidev.h conflict! ++'k' 00-05 video/kyro.h conflict! ++'k' 10-17 linux/hsi/hsi_char.h HSI character device ++'l' 00-3F linux/tcfs_fs.h transparent cryptographic file system ++ ++'l' 40-7F linux/udf_fs_i.h in development: ++ ++'m' 00-09 linux/mmtimer.h conflict! ++'m' all linux/mtio.h conflict! ++'m' all linux/soundcard.h conflict! ++'m' all linux/synclink.h conflict! ++'m' 00-19 drivers/message/fusion/mptctl.h conflict! ++'m' 00 drivers/scsi/megaraid/megaraid_ioctl.h conflict! + 'n' 00-7F linux/ncp_fs.h and fs/ncpfs/ioctl.c +-'n' 80-8F uapi/linux/nilfs2_api.h NILFS2 +-'n' E0-FF linux/matroxfb.h matroxfb +-'o' 00-1F fs/ocfs2/ocfs2_fs.h OCFS2 +-'o' 00-03 mtd/ubi-user.h conflict! (OCFS2 and UBI overlaps) +-'o' 40-41 mtd/ubi-user.h UBI +-'o' 01-A1 `linux/dvb/*.h` DVB +-'p' 00-0F linux/phantom.h conflict! (OpenHaptics needs this) +-'p' 00-1F linux/rtc.h conflict! ++'n' 80-8F uapi/linux/nilfs2_api.h NILFS2 ++'n' E0-FF linux/matroxfb.h matroxfb ++'o' 00-1F fs/ocfs2/ocfs2_fs.h OCFS2 ++'o' 00-03 mtd/ubi-user.h conflict! (OCFS2 and UBI overlaps) ++'o' 40-41 mtd/ubi-user.h UBI ++'o' 01-A1 `linux/dvb/*.h` DVB ++'p' 00-0F linux/phantom.h conflict! (OpenHaptics needs this) ++'p' 00-1F linux/rtc.h conflict! + 'p' 40-7F linux/nvram.h +-'p' 80-9F linux/ppdev.h user-space parport +- +-'p' A1-A5 linux/pps.h LinuxPPS +- ++'p' 80-9F linux/ppdev.h user-space parport ++ ++'p' A1-A5 linux/pps.h LinuxPPS ++ + 'q' 00-1F linux/serio.h +-'q' 80-FF linux/telephony.h Internet PhoneJACK, Internet LineJACK +- linux/ixjuser.h ++'q' 80-FF linux/telephony.h Internet PhoneJACK, Internet LineJACK ++ linux/ixjuser.h + 'r' 00-1F linux/msdos_fs.h and fs/fat/dir.c + 's' all linux/cdk.h + 't' 00-7F linux/ppp-ioctl.h + 't' 80-8F linux/isdn_ppp.h +-'t' 90-91 linux/toshiba.h toshiba and toshiba_acpi SMM +-'u' 00-1F linux/smb_fs.h gone +-'u' 20-3F linux/uvcvideo.h USB video class host driver +-'u' 40-4f linux/udmabuf.h userspace dma-buf misc device +-'v' 00-1F linux/ext2_fs.h conflict! +-'v' 00-1F linux/fs.h conflict! +-'v' 00-0F linux/sonypi.h conflict! +-'v' 00-0F media/v4l2-subdev.h conflict! +-'v' 20-27 arch/powerpc/include/uapi/asm/vas-api.h VAS API +-'v' C0-FF linux/meye.h conflict! +-'w' all CERN SCI driver +-'y' 00-1F packet based user level communications +- +-'z' 00-3F CAN bus card conflict! +- +-'z' 40-7F CAN bus card conflict! +- +-'z' 10-4F drivers/s390/crypto/zcrypt_api.h conflict! ++'t' 90-91 linux/toshiba.h toshiba and toshiba_acpi SMM ++'u' 00-1F linux/smb_fs.h gone ++'u' 20-3F linux/uvcvideo.h USB video class host driver ++'u' 40-4f linux/udmabuf.h userspace dma-buf misc device ++'v' 00-1F linux/ext2_fs.h conflict! ++'v' 00-1F linux/fs.h conflict! ++'v' 00-0F linux/sonypi.h conflict! ++'v' 00-0F media/v4l2-subdev.h conflict! ++'v' 20-27 arch/powerpc/include/uapi/asm/vas-api.h VAS API ++'v' C0-FF linux/meye.h conflict! ++'w' all CERN SCI driver ++'y' 00-1F packet based user level communications ++ ++'z' 00-3F CAN bus card conflict! ++ ++'z' 40-7F CAN bus card conflict! ++ ++'z' 10-4F drivers/s390/crypto/zcrypt_api.h conflict! + '|' 00-7F linux/media.h + 0x80 00-1F linux/fb.h + 0x89 00-06 arch/x86/include/asm/sockios.h + 0x89 0B-DF linux/sockios.h +-0x89 E0-EF linux/sockios.h SIOCPROTOPRIVATE range +-0x89 F0-FF linux/sockios.h SIOCDEVPRIVATE range ++0x89 E0-EF linux/sockios.h SIOCPROTOPRIVATE range ++0x89 F0-FF linux/sockios.h SIOCDEVPRIVATE range + 0x8B all linux/wireless.h +-0x8C 00-3F WiNRADiO driver +- ++0x8C 00-3F WiNRADiO driver ++ + 0x90 00 drivers/cdrom/sbpcd.h + 0x92 00-0F drivers/usb/mon/mon_bin.c + 0x93 60-7F linux/auto_fs.h +-0x94 all fs/btrfs/ioctl.h Btrfs filesystem +- and linux/fs.h some lifted to vfs/generic +-0x97 00-7F fs/ceph/ioctl.h Ceph file system +-0x99 00-0F 537-Addinboard driver +- +-0xA0 all linux/sdp/sdp.h Industrial Device Project +- +-0xA1 0 linux/vtpm_proxy.h TPM Emulator Proxy Driver +-0xA3 80-8F Port ACL in development: +- ++0x94 all fs/btrfs/ioctl.h Btrfs filesystem ++ and linux/fs.h some lifted to vfs/generic ++0x97 00-7F fs/ceph/ioctl.h Ceph file system ++0x99 00-0F 537-Addinboard driver ++ ++0xA0 all linux/sdp/sdp.h Industrial Device Project ++ ++0xA1 0 linux/vtpm_proxy.h TPM Emulator Proxy Driver ++0xA3 80-8F Port ACL in development: ++ + 0xA3 90-9F linux/dtlk.h +-0xA4 00-1F uapi/linux/tee.h Generic TEE subsystem ++0xA4 00-1F uapi/linux/tee.h Generic TEE subsystem + 0xAA 00-3F linux/uapi/linux/userfaultfd.h + 0xAB 00-1F linux/nbd.h + 0xAC 00-1F linux/raw.h +-0xAD 00 Netfilter device in development: +- +-0xAE 00-1F linux/kvm.h Kernel-based Virtual Machine +- +-0xAE 40-FF linux/kvm.h Kernel-based Virtual Machine +- +-0xAE 20-3F linux/nitro_enclaves.h Nitro Enclaves +-0xAF 00-1F linux/fsl_hypervisor.h Freescale hypervisor +-0xB0 all RATIO devices in development: +- +-0xB1 00-1F PPPoX +- ++0xAD 00 Netfilter device in development: ++ ++0xAE 00-1F linux/kvm.h Kernel-based Virtual Machine ++ ++0xAE 40-FF linux/kvm.h Kernel-based Virtual Machine ++ ++0xAE 20-3F linux/nitro_enclaves.h Nitro Enclaves ++0xAF 00-1F linux/fsl_hypervisor.h Freescale hypervisor ++0xB0 all RATIO devices in development: ++ ++0xB1 00-1F PPPoX ++ + 0xB3 00 linux/mmc/ioctl.h +-0xB4 00-0F linux/gpio.h +-0xB5 00-0F uapi/linux/rpmsg.h ++0xB4 00-0F linux/gpio.h ++0xB5 00-0F uapi/linux/rpmsg.h + 0xB6 all linux/fpga-dfl.h +-0xB7 all uapi/linux/remoteproc_cdev.h ++0xB7 all uapi/linux/remoteproc_cdev.h + 0xC0 00-0F linux/usb/iowarrior.h + 0xCA 00-0F uapi/misc/cxl.h + 0xCA 10-2F uapi/misc/ocxl.h + 0xCA 80-BF uapi/scsi/cxlflash_ioctl.h +-0xCB 00-1F CBM serial IEC bus in development: +- +-0xCC 00-0F drivers/misc/ibmvmc.h pseries VMC driver ++0xCB 00-1F CBM serial IEC bus in development: ++ ++0xCC 00-0F drivers/misc/ibmvmc.h pseries VMC driver + 0xCD 01 linux/reiserfs_fs.h + 0xCF 02 fs/cifs/ioctl.c + 0xDB 00-0F drivers/char/mwave/mwavepub.h +-0xDD 00-3F ZFCP device driver see drivers/s390/scsi/ +- ++0xDD 00-3F ZFCP device driver see drivers/s390/scsi/ ++ + 0xE5 00-3F linux/fuse.h +-0xEC 00-01 drivers/platform/chrome/cros_ec_dev.h ChromeOS EC driver +-0xF3 00-3F drivers/usb/misc/sisusbvga/sisusb.h sisfb (in development) +- +-0xF6 all LTTng Linux Trace Toolkit Next Generation +- ++0xEC 00-01 drivers/platform/chrome/cros_ec_dev.h ChromeOS EC driver ++0xF3 00-3F drivers/usb/misc/sisusbvga/sisusb.h sisfb (in development) ++ ++0xF6 all LTTng Linux Trace Toolkit Next Generation ++ + 0xFD all linux/dm-ioctl.h + 0xFE all linux/isst_if.h +-==== ===== ======================================================= ================================================================ ++==== ===== ========================================================= ================================================================ +-- +2.53.0 + diff --git a/queue-5.10/net-sched-act_pedit-fix-action-bind-logic.patch b/queue-5.10/net-sched-act_pedit-fix-action-bind-logic.patch new file mode 100644 index 0000000000..5b2d612ce6 --- /dev/null +++ b/queue-5.10/net-sched-act_pedit-fix-action-bind-logic.patch @@ -0,0 +1,206 @@ +From c40ff0ac509e7e604a906b2406210c1fa3cd5bd1 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 27 Jun 2026 02:07:35 +0800 +Subject: net/sched: act_pedit: fix action bind logic + +From: Pedro Tammela + +[ Upstream commit e9e42292ea76a8358b0c02ffd530d78e133a1b73 ] + +The TC architecture allows filters and actions to be created independently. +In filters the user can reference action objects using: +tc action add action pedit ... index 1 +tc filter add ... action pedit index 1 + +In the current code for act_pedit this is broken as it checks netlink +attributes for create/update before actually checking if we are binding to an +existing action. + +tdc results: +1..69 +ok 1 319a - Add pedit action that mangles IP TTL +ok 2 7e67 - Replace pedit action with invalid goto chain +ok 3 377e - Add pedit action with RAW_OP offset u32 +ok 4 a0ca - Add pedit action with RAW_OP offset u32 (INVALID) +ok 5 dd8a - Add pedit action with RAW_OP offset u16 u16 +ok 6 53db - Add pedit action with RAW_OP offset u16 (INVALID) +ok 7 5c7e - Add pedit action with RAW_OP offset u8 add value +ok 8 2893 - Add pedit action with RAW_OP offset u8 quad +ok 9 3a07 - Add pedit action with RAW_OP offset u8-u16-u8 +ok 10 ab0f - Add pedit action with RAW_OP offset u16-u8-u8 +ok 11 9d12 - Add pedit action with RAW_OP offset u32 set u16 clear u8 invert +ok 12 ebfa - Add pedit action with RAW_OP offset overflow u32 (INVALID) +ok 13 f512 - Add pedit action with RAW_OP offset u16 at offmask shift set +ok 14 c2cb - Add pedit action with RAW_OP offset u32 retain value +ok 15 1762 - Add pedit action with RAW_OP offset u8 clear value +ok 16 bcee - Add pedit action with RAW_OP offset u8 retain value +ok 17 e89f - Add pedit action with RAW_OP offset u16 retain value +ok 18 c282 - Add pedit action with RAW_OP offset u32 clear value +ok 19 c422 - Add pedit action with RAW_OP offset u16 invert value +ok 20 d3d3 - Add pedit action with RAW_OP offset u32 invert value +ok 21 57e5 - Add pedit action with RAW_OP offset u8 preserve value +ok 22 99e0 - Add pedit action with RAW_OP offset u16 preserve value +ok 23 1892 - Add pedit action with RAW_OP offset u32 preserve value +ok 24 4b60 - Add pedit action with RAW_OP negative offset u16/u32 set value +ok 25 a5a7 - Add pedit action with LAYERED_OP eth set src +ok 26 86d4 - Add pedit action with LAYERED_OP eth set src & dst +ok 27 f8a9 - Add pedit action with LAYERED_OP eth set dst +ok 28 c715 - Add pedit action with LAYERED_OP eth set src (INVALID) +ok 29 8131 - Add pedit action with LAYERED_OP eth set dst (INVALID) +ok 30 ba22 - Add pedit action with LAYERED_OP eth type set/clear sequence +ok 31 dec4 - Add pedit action with LAYERED_OP eth set type (INVALID) +ok 32 ab06 - Add pedit action with LAYERED_OP eth add type +ok 33 918d - Add pedit action with LAYERED_OP eth invert src +ok 34 a8d4 - Add pedit action with LAYERED_OP eth invert dst +ok 35 ee13 - Add pedit action with LAYERED_OP eth invert type +ok 36 7588 - Add pedit action with LAYERED_OP ip set src +ok 37 0fa7 - Add pedit action with LAYERED_OP ip set dst +ok 38 5810 - Add pedit action with LAYERED_OP ip set src & dst +ok 39 1092 - Add pedit action with LAYERED_OP ip set ihl & dsfield +ok 40 02d8 - Add pedit action with LAYERED_OP ip set ttl & protocol +ok 41 3e2d - Add pedit action with LAYERED_OP ip set ttl (INVALID) +ok 42 31ae - Add pedit action with LAYERED_OP ip ttl clear/set +ok 43 486f - Add pedit action with LAYERED_OP ip set duplicate fields +ok 44 e790 - Add pedit action with LAYERED_OP ip set ce, df, mf, firstfrag, nofrag fields +ok 45 cc8a - Add pedit action with LAYERED_OP ip set tos +ok 46 7a17 - Add pedit action with LAYERED_OP ip set precedence +ok 47 c3b6 - Add pedit action with LAYERED_OP ip add tos +ok 48 43d3 - Add pedit action with LAYERED_OP ip add precedence +ok 49 438e - Add pedit action with LAYERED_OP ip clear tos +ok 50 6b1b - Add pedit action with LAYERED_OP ip clear precedence +ok 51 824a - Add pedit action with LAYERED_OP ip invert tos +ok 52 106f - Add pedit action with LAYERED_OP ip invert precedence +ok 53 6829 - Add pedit action with LAYERED_OP beyond ip set dport & sport +ok 54 afd8 - Add pedit action with LAYERED_OP beyond ip set icmp_type & icmp_code +ok 55 3143 - Add pedit action with LAYERED_OP beyond ip set dport (INVALID) +ok 56 815c - Add pedit action with LAYERED_OP ip6 set src +ok 57 4dae - Add pedit action with LAYERED_OP ip6 set dst +ok 58 fc1f - Add pedit action with LAYERED_OP ip6 set src & dst +ok 59 6d34 - Add pedit action with LAYERED_OP ip6 dst retain value (INVALID) +ok 60 94bb - Add pedit action with LAYERED_OP ip6 traffic_class +ok 61 6f5e - Add pedit action with LAYERED_OP ip6 flow_lbl +ok 62 6795 - Add pedit action with LAYERED_OP ip6 set payload_len, nexthdr, hoplimit +ok 63 1442 - Add pedit action with LAYERED_OP tcp set dport & sport +ok 64 b7ac - Add pedit action with LAYERED_OP tcp sport set (INVALID) +ok 65 cfcc - Add pedit action with LAYERED_OP tcp flags set +ok 66 3bc4 - Add pedit action with LAYERED_OP tcp set dport, sport & flags fields +ok 67 f1c8 - Add pedit action with LAYERED_OP udp set dport & sport +ok 68 d784 - Add pedit action with mixed RAW/LAYERED_OP #1 +ok 69 70ca - Add pedit action with mixed RAW/LAYERED_OP #2 + +Fixes: 71d0ed7079df ("net/act_pedit: Support using offset relative to the conventional network headers") +Fixes: f67169fef8db ("net/sched: act_pedit: fix WARN() in the traffic path") +Reviewed-by: Jamal Hadi Salim +Signed-off-by: Pedro Tammela +Reviewed-by: Simon Horman +Signed-off-by: David S. Miller +Signed-off-by: Wentao Guan +Signed-off-by: Sasha Levin +--- + net/sched/act_pedit.c | 58 +++++++++++++++++++++++-------------------- + 1 file changed, 31 insertions(+), 27 deletions(-) + +diff --git a/net/sched/act_pedit.c b/net/sched/act_pedit.c +index 0601deea04d725..fe9e826184c168 100644 +--- a/net/sched/act_pedit.c ++++ b/net/sched/act_pedit.c +@@ -182,26 +182,6 @@ static int tcf_pedit_init(struct net *net, struct nlattr *nla, + } + + parm = nla_data(pattr); +- if (!parm->nkeys) { +- NL_SET_ERR_MSG_MOD(extack, "Pedit requires keys to be passed"); +- return -EINVAL; +- } +- ksize = parm->nkeys * sizeof(struct tc_pedit_key); +- if (nla_len(pattr) < sizeof(*parm) + ksize) { +- NL_SET_ERR_MSG_ATTR(extack, pattr, "Length of TCA_PEDIT_PARMS or TCA_PEDIT_PARMS_EX pedit attribute is invalid"); +- return -EINVAL; +- } +- +- nparms = kzalloc(sizeof(*nparms), GFP_KERNEL); +- if (!nparms) +- return -ENOMEM; +- +- nparms->tcfp_keys_ex = +- tcf_pedit_keys_ex_parse(tb[TCA_PEDIT_KEYS_EX], parm->nkeys); +- if (IS_ERR(nparms->tcfp_keys_ex)) { +- ret = PTR_ERR(nparms->tcfp_keys_ex); +- goto out_free; +- } + + index = parm->index; + err = tcf_idr_check_alloc(tn, &index, a, bind); +@@ -210,25 +190,49 @@ static int tcf_pedit_init(struct net *net, struct nlattr *nla, + &act_pedit_ops, bind, flags); + if (ret) { + tcf_idr_cleanup(tn, index); +- goto out_free_ex; ++ return ret; + } + ret = ACT_P_CREATED; + } else if (err > 0) { + if (bind) +- goto out_free; ++ return 0; + if (!ovr) { + ret = -EEXIST; + goto out_release; + } + } else { +- ret = err; +- goto out_free_ex; ++ return err; ++ } ++ ++ if (!parm->nkeys) { ++ NL_SET_ERR_MSG_MOD(extack, "Pedit requires keys to be passed"); ++ ret = -EINVAL; ++ goto out_release; ++ } ++ ksize = parm->nkeys * sizeof(struct tc_pedit_key); ++ if (nla_len(pattr) < sizeof(*parm) + ksize) { ++ NL_SET_ERR_MSG_ATTR(extack, pattr, "Length of TCA_PEDIT_PARMS or TCA_PEDIT_PARMS_EX pedit attribute is invalid"); ++ ret = -EINVAL; ++ goto out_release; ++ } ++ ++ nparms = kzalloc(sizeof(*nparms), GFP_KERNEL); ++ if (!nparms) { ++ ret = -ENOMEM; ++ goto out_release; ++ } ++ ++ nparms->tcfp_keys_ex = ++ tcf_pedit_keys_ex_parse(tb[TCA_PEDIT_KEYS_EX], parm->nkeys); ++ if (IS_ERR(nparms->tcfp_keys_ex)) { ++ ret = PTR_ERR(nparms->tcfp_keys_ex); ++ goto out_free; + } + + err = tcf_action_check_ctrlact(parm->action, tp, &goto_ch, extack); + if (err < 0) { + ret = err; +- goto out_release; ++ goto out_free_ex; + } + + nparms->tcfp_flags = parm->flags; +@@ -280,12 +284,12 @@ static int tcf_pedit_init(struct net *net, struct nlattr *nla, + put_chain: + if (goto_ch) + tcf_chain_put_by_act(goto_ch); +-out_release: +- tcf_idr_release(*a, bind); + out_free_ex: + kfree(nparms->tcfp_keys_ex); + out_free: + kfree(nparms); ++out_release: ++ tcf_idr_release(*a, bind); + return ret; + } + +-- +2.53.0 + diff --git a/queue-5.10/series b/queue-5.10/series index 6c6d385f8a..e48b2b93a9 100644 --- a/queue-5.10/series +++ b/queue-5.10/series @@ -26,3 +26,8 @@ agp-amd64-fix-broken-error-propagation-in-agp_amd64_probe.patch regulator-core-fix-locking-in-regulator_resolve_supply-error-path.patch vc_screen-fix-null-ptr-deref-in-vcs_notifier-during-concurrent-vcs_write.patch media-vidtv-fix-null-pointer-dereference-in-vidtv_mux_push_si.patch +documentation-ioctl-number-extend-include-file-colum.patch +crypto-qat-replace-kzalloc-copy_from_user-with-memdu.patch +crypto-qat-return-pointer-directly-in-adf_ctl_alloc_.patch +crypto-qat-remove-unused-character-device-and-ioctls.patch +net-sched-act_pedit-fix-action-bind-logic.patch diff --git a/queue-5.15/kselftest-arm64-signal-skip-sve-signal-test-if-not-e.patch b/queue-5.15/kselftest-arm64-signal-skip-sve-signal-test-if-not-e.patch new file mode 100644 index 0000000000..d24f73a01e --- /dev/null +++ b/queue-5.15/kselftest-arm64-signal-skip-sve-signal-test-if-not-e.patch @@ -0,0 +1,49 @@ +From 841e923db3f66058241a83f7c2fb43ac2ebd91aa Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 27 Jun 2026 11:22:59 +0800 +Subject: kselftest/arm64: signal: Skip SVE signal test if not enough VLs + supported + +From: Yijia Wang + +[ Upstream commit 78c09c0f4df89fabdcfb3e5e53d3196cf67f64ef ] + +On platform where SVE is supported but there are less than 2 VLs available +the signal SVE change test should be skipped instead of failing. + +Reported-by: Andre Przywara +Tested-by: Andre Przywara +Cc: Mark Brown +Signed-off-by: Cristian Marussi +Reviewed-by: Mark Brown +Link: https://lore.kernel.org/r/20220524103149.2802-1-cristian.marussi@arm.com +Signed-off-by: Catalin Marinas +Signed-off-by: Yijia Wang +Signed-off-by: Sasha Levin +--- + .../arm64/signal/testcases/fake_sigreturn_sve_change_vl.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/tools/testing/selftests/arm64/signal/testcases/fake_sigreturn_sve_change_vl.c b/tools/testing/selftests/arm64/signal/testcases/fake_sigreturn_sve_change_vl.c +index bb50b5adbf10de..915821375b0a44 100644 +--- a/tools/testing/selftests/arm64/signal/testcases/fake_sigreturn_sve_change_vl.c ++++ b/tools/testing/selftests/arm64/signal/testcases/fake_sigreturn_sve_change_vl.c +@@ -6,6 +6,7 @@ + * supported and is expected to segfault. + */ + ++#include + #include + #include + #include +@@ -40,6 +41,7 @@ static bool sve_get_vls(struct tdescr *td) + /* We need at least two VLs */ + if (nvls < 2) { + fprintf(stderr, "Only %d VL supported\n", nvls); ++ td->result = KSFT_SKIP; + return false; + } + +-- +2.53.0 + diff --git a/queue-5.15/kvm-x86-fix-shadow-paging-use-after-free-due-to-unex.patch b/queue-5.15/kvm-x86-fix-shadow-paging-use-after-free-due-to-unex.patch new file mode 100644 index 0000000000..589f8850d3 --- /dev/null +++ b/queue-5.15/kvm-x86-fix-shadow-paging-use-after-free-due-to-unex.patch @@ -0,0 +1,153 @@ +From c5187da0baea9ce4ae374f34426c36ca619aa217 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 26 Jun 2026 19:46:17 +0200 +Subject: KVM: x86: Fix shadow paging use-after-free due to unexpected GFN + +From: Sean Christopherson + +commit 0cb2af2ea66ad8ff195c156ea690f11216285bdf upstream. + +The shadow MMU computes GFNs for direct shadow pages using sp->gfn plus +the SPTE index. This assumption breaks for shadow paging if the guest +page tables are modified between VM entries (similar to commit +aad885e77496, "KVM: x86/mmu: Drop/zap existing present SPTE even +when creating an MMIO SPTE", 2026-03-27). The flow is as follows: + +- a PDE is installed for a 2MB mapping, and a page in that area is + accessed. KVM creates a kvm_mmu_page consisting of 512 4KB pages; + the kvm_mmu_page is marked by FNAME(fetch) as direct-mapped because + the guest's mapping is a huge page (and thus contiguous). + +- the PDE mapping is changed from outside the guest. + +- the guest accesses another page in the same 2MB area. KVM installs + a new leaf SPTE and rmap entry; the SPTE uses the "correct" GFN + (i.e. based on the new mapping, as changed in the previous step) but + that GFN is outside of the [sp->gfn, sp->gfn + 511] range; therefore + the rmap entry cannot be found and removed when the kvm_mmu_page + is zapped. + +- the memslot that covers the first 2MB mapping is deleted, and the + kvm_mmu_page for the now-invalid GPA is zapped. However, rmap_remove() + only looks at the [sp->gfn, sp->gfn + 511] range established in step 1, + and fails to find the rmap entry that was recorded by step 3. + +- any operation that causes an rmap walk for the same page accessed + by step 3 then walks a stale rmap and dereferences a freed kvm_mmu_page. + This includes dirty logging or MMU notifier invalidations (e.g., from + MADV_DONTNEED). + +The underlying issue is that KVM's walking of shadow PTEs assumes that +if a SPTE is present when KVM wants to install a non-leaf SPTE, then the +existing kvm_mmu_page must be for the correct gfn. Because the only way +for the gfn to be wrong is if KVM messed up and failed to zap a SPTE... +which shouldn't happen, but *actually* only happens in response to a +guest write. + +That bug dates back literally forever, as even the first version of KVM +assumes that the GFN matches and walks into the "wrong" shadow page. +However, that was only an imprecision until 2032a93d66fa ("KVM: MMU: +Don't allocate gfns page for direct mmu pages") came along. + +Fix it by checking for a target gfn mismatch and zapping the existing +SPTE. That way the old SP and rmap entries are gone, KVM installs +the rmap in the right location, and everyone is happy. + +Fixes: 2032a93d66fa ("KVM: MMU: Don't allocate gfns page for direct mmu pages") +Fixes: 6aa8b732ca01 ("kvm: userspace interface") +Reported-by: Alexander Bulekov +Reported-by: Fred Griffoul +Cc: stable@vger.kernel.org +Signed-off-by: Sean Christopherson +Link: https://patch.msgid.link/20260503201029.106481-1-pbonzini@redhat.com/ +Signed-off-by: Paolo Bonzini +Signed-off-by: Sasha Levin +--- + arch/x86/kvm/mmu/mmu.c | 33 ++++++++++++++------------------- + arch/x86/kvm/mmu/spte.h | 5 +++++ + 2 files changed, 19 insertions(+), 19 deletions(-) + +diff --git a/arch/x86/kvm/mmu/mmu.c b/arch/x86/kvm/mmu/mmu.c +index d58be2e698f795..6c9656b8062e4e 100644 +--- a/arch/x86/kvm/mmu/mmu.c ++++ b/arch/x86/kvm/mmu/mmu.c +@@ -188,6 +188,8 @@ static struct percpu_counter kvm_total_used_mmu_pages; + static void mmu_spte_set(u64 *sptep, u64 spte); + static union kvm_mmu_page_role + kvm_mmu_calc_root_page_role(struct kvm_vcpu *vcpu); ++static int mmu_page_zap_pte(struct kvm *kvm, struct kvm_mmu_page *sp, ++ u64 *spte, struct list_head *invalid_list); + + struct kvm_mmu_role_regs { + const unsigned long cr0; +@@ -1179,18 +1181,6 @@ static void drop_spte(struct kvm *kvm, u64 *sptep) + rmap_remove(kvm, sptep); + } + +-static void drop_large_spte(struct kvm *kvm, u64 *sptep) +-{ +- struct kvm_mmu_page *sp; +- +- sp = sptep_to_sp(sptep); +- WARN_ON(sp->role.level == PG_LEVEL_4K); +- +- drop_spte(kvm, sptep); +- kvm_flush_remote_tlbs_with_address(kvm, sp->gfn, +- KVM_PAGES_PER_HPAGE(sp->role.level)); +-} +- + /* + * Write-protect on the specified @sptep, @pt_protect indicates whether + * spte write-protection is caused by protecting shadow page table. +@@ -2187,7 +2177,8 @@ static struct kvm_mmu_page *kvm_mmu_get_child_sp(struct kvm_vcpu *vcpu, + { + union kvm_mmu_page_role role; + +- if (is_shadow_present_pte(*sptep) && !is_large_pte(*sptep)) ++ if (is_shadow_present_pte(*sptep) && !is_large_pte(*sptep) && ++ spte_to_child_sp(*sptep) && spte_to_child_sp(*sptep)->gfn == gfn) + return ERR_PTR(-EEXIST); + + role = kvm_mmu_child_role(sptep, direct, access); +@@ -2265,12 +2256,16 @@ static void __link_shadow_page(struct kvm_vcpu *vcpu, + + BUILD_BUG_ON(VMX_EPT_WRITABLE_MASK != PT_WRITABLE_MASK); + +- /* +- * If an SPTE is present already, it must be a leaf and therefore +- * a large one. Drop it and flush the TLB before installing sp. +- */ +- if (is_shadow_present_pte(*sptep)) +- drop_large_spte(vcpu->kvm, sptep); ++ if (is_shadow_present_pte(*sptep)) { ++ struct kvm_mmu_page *parent_sp; ++ LIST_HEAD(invalid_list); ++ ++ parent_sp = sptep_to_sp(sptep); ++ WARN_ON_ONCE(parent_sp->role.level == PG_LEVEL_4K); ++ ++ mmu_page_zap_pte(vcpu->kvm, parent_sp, sptep, &invalid_list); ++ kvm_mmu_remote_flush_or_zap(vcpu->kvm, &invalid_list, true); ++ } + + spte = make_nonleaf_spte(sp->spt, sp_ad_disabled(sp)); + +diff --git a/arch/x86/kvm/mmu/spte.h b/arch/x86/kvm/mmu/spte.h +index 31d6456d8ac333..31d03d15415c01 100644 +--- a/arch/x86/kvm/mmu/spte.h ++++ b/arch/x86/kvm/mmu/spte.h +@@ -267,6 +267,11 @@ static inline bool is_executable_pte(u64 spte) + return (spte & (shadow_x_mask | shadow_nx_mask)) == shadow_x_mask; + } + ++static inline struct kvm_mmu_page *spte_to_child_sp(u64 spte) ++{ ++ return to_shadow_page(spte & PT64_BASE_ADDR_MASK); ++} ++ + static inline kvm_pfn_t spte_to_pfn(u64 pte) + { + return (pte & PT64_BASE_ADDR_MASK) >> PAGE_SHIFT; +-- +2.53.0 + diff --git a/queue-5.15/kvm-x86-fix-shadow-paging-use-after-free-due-to-unex.patch-23529 b/queue-5.15/kvm-x86-fix-shadow-paging-use-after-free-due-to-unex.patch-23529 new file mode 100644 index 0000000000..772f811e1b --- /dev/null +++ b/queue-5.15/kvm-x86-fix-shadow-paging-use-after-free-due-to-unex.patch-23529 @@ -0,0 +1,71 @@ +From 6d15eee7dcdbc7794d7e83bb36847eeeea7d4938 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 26 Jun 2026 19:46:18 +0200 +Subject: KVM: x86: Fix shadow paging use-after-free due to unexpected role + +From: Paolo Bonzini + +[ Upstream commit 81ccda30b4e83d8f5cc4fd50503c44e3a33abfeb ] + +Commit 0cb2af2ea66ad ("KVM: x86: Fix shadow paging use-after-free due +to unexpected GFN") fixed a shadow paging mismatch between stored and +computed GFNs; the bug could be triggered by changing a PDE mapping from +outside the guest, and then deleting a memslot. The rmap_remove() +call would miss entries created after the PDE change because the GFN +of the leaf SPTE does not match the GFN of the struct kvm_mmu_page. + +A similar hole however remains if the modified PDE points to a non-leaf +page. In this case the gfn can be made to match, but the role does not +match: the original large 2MB page creates a kvm_mmu_page with direct=1, +while the new 4KB needs a kvm_mmu_page with direct=0. However, +kvm_mmu_get_child_sp() does not compare the role, and therefore reuses +the page. + +The next step is installing a leaf (4KB) SPTE on the new path which +records an rmap entry under the gfn resolved by the walk. But when +that child is zapped its parent kvm_mmu_page has direct=1 and +kvm_mmu_page_get_gfn() computes the gfn for the 4KB page as +sp->gfn + index instead of using sp->shadowed_translation[] (or sp->gfns[] +in older kernels). It therefore fails to remove the recorded entry. + +When the memslot is dropped the shadow page is freed but the rmap +entry survives, as in the scenario that was already fixed. Code that +later walks that gfn (dirty logging, MMU notifier invalidation, and +so on) dereferences an sptep that lies in the freed page, causing the +use-after-free. + +Fixes: 2032a93d66fa ("KVM: MMU: Don't allocate gfns page for direct mmu pages") +Reported-by: Hyunwoo Kim +Signed-off-by: Paolo Bonzini +Signed-off-by: Sasha Levin +--- + arch/x86/kvm/mmu/mmu.c | 10 ++++++---- + 1 file changed, 6 insertions(+), 4 deletions(-) + +diff --git a/arch/x86/kvm/mmu/mmu.c b/arch/x86/kvm/mmu/mmu.c +index 6c9656b8062e4e..e9dbe3e7ec622f 100644 +--- a/arch/x86/kvm/mmu/mmu.c ++++ b/arch/x86/kvm/mmu/mmu.c +@@ -2175,13 +2175,15 @@ static struct kvm_mmu_page *kvm_mmu_get_child_sp(struct kvm_vcpu *vcpu, + u64 *sptep, gfn_t gfn, + bool direct, unsigned int access) + { +- union kvm_mmu_page_role role; ++ union kvm_mmu_page_role role = kvm_mmu_child_role(sptep, direct, access); + +- if (is_shadow_present_pte(*sptep) && !is_large_pte(*sptep) && +- spte_to_child_sp(*sptep) && spte_to_child_sp(*sptep)->gfn == gfn) ++ if (is_shadow_present_pte(*sptep) && ++ !is_large_pte(*sptep) && ++ spte_to_child_sp(*sptep) && ++ spte_to_child_sp(*sptep)->gfn == gfn && ++ spte_to_child_sp(*sptep)->role.word == role.word) + return ERR_PTR(-EEXIST); + +- role = kvm_mmu_child_role(sptep, direct, access); + return kvm_mmu_get_page(vcpu, gfn, role); + } + +-- +2.53.0 + diff --git a/queue-5.15/kvm-x86-mmu-always-pass-0-for-quadrant-when-gptes-ar.patch b/queue-5.15/kvm-x86-mmu-always-pass-0-for-quadrant-when-gptes-ar.patch new file mode 100644 index 0000000000..b3502dca3e --- /dev/null +++ b/queue-5.15/kvm-x86-mmu-always-pass-0-for-quadrant-when-gptes-ar.patch @@ -0,0 +1,79 @@ +From cd2b29b10c0f8055c823c5df970fb98e897f65b9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 26 Jun 2026 19:46:15 +0200 +Subject: KVM: x86/mmu: Always pass 0 for @quadrant when gptes are 8 bytes + +From: Paolo Bonzini + +commit 7f49777550e55a7d6832cbb0873f48f91c175b9c upstream. + +The quadrant is only used when gptes are 4 bytes, but +mmu_alloc_{direct,shadow}_roots() pass in a non-zero quadrant for PAE +page directories regardless. Make this less confusing by only passing in +a non-zero quadrant when it is actually necessary. + +Signed-off-by: David Matlack +Message-Id: <20220516232138.1783324-6-dmatlack@google.com> +Signed-off-by: Paolo Bonzini +Signed-off-by: Sasha Levin +--- + arch/x86/kvm/mmu/mmu.c | 20 ++++++++++++++------ + 1 file changed, 14 insertions(+), 6 deletions(-) + +diff --git a/arch/x86/kvm/mmu/mmu.c b/arch/x86/kvm/mmu/mmu.c +index 3a5ed967037765..dbc18d4cc572c1 100644 +--- a/arch/x86/kvm/mmu/mmu.c ++++ b/arch/x86/kvm/mmu/mmu.c +@@ -3444,9 +3444,10 @@ static hpa_t mmu_alloc_root(struct kvm_vcpu *vcpu, gfn_t gfn, int quadrant, + struct kvm_mmu_page *sp; + + role.level = level; ++ role.quadrant = quadrant; + +- if (!role.gpte_is_8_bytes) +- role.quadrant = quadrant; ++ WARN_ON_ONCE(quadrant && role.gpte_is_8_bytes); ++ WARN_ON_ONCE(role.direct && !role.gpte_is_8_bytes); + + sp = kvm_mmu_get_page(vcpu, gfn, role); + ++sp->root_count; +@@ -3482,7 +3483,7 @@ static int mmu_alloc_direct_roots(struct kvm_vcpu *vcpu) + for (i = 0; i < 4; ++i) { + WARN_ON_ONCE(IS_VALID_PAE_ROOT(mmu->pae_root[i])); + +- root = mmu_alloc_root(vcpu, i << (30 - PAGE_SHIFT), i, ++ root = mmu_alloc_root(vcpu, i << (30 - PAGE_SHIFT), 0, + PT32_ROOT_LEVEL); + mmu->pae_root[i] = root | PT_PRESENT_MASK | + shadow_me_mask; +@@ -3506,9 +3507,8 @@ static int mmu_alloc_shadow_roots(struct kvm_vcpu *vcpu) + struct kvm_mmu *mmu = vcpu->arch.mmu; + u64 pdptrs[4], pm_mask; + gfn_t root_gfn, root_pgd; ++ int quadrant, i, r; + hpa_t root; +- unsigned i; +- int r; + + root_pgd = mmu->get_guest_pgd(vcpu); + root_gfn = root_pgd >> PAGE_SHIFT; +@@ -3591,7 +3591,15 @@ static int mmu_alloc_shadow_roots(struct kvm_vcpu *vcpu) + root_gfn = pdptrs[i] >> PAGE_SHIFT; + } + +- root = mmu_alloc_root(vcpu, root_gfn, i, PT32_ROOT_LEVEL); ++ /* ++ * If shadowing 32-bit non-PAE page tables, each PAE page ++ * directory maps one quarter of the guest's non-PAE page ++ * directory. Othwerise each PAE page direct shadows one guest ++ * PAE page directory so that quadrant should be 0. ++ */ ++ quadrant = !mmu->mmu_role.base.gpte_is_8_bytes ? i : 0; ++ ++ root = mmu_alloc_root(vcpu, root_gfn, quadrant, PT32_ROOT_LEVEL); + mmu->pae_root[i] = root | pm_mask; + } + +-- +2.53.0 + diff --git a/queue-5.15/kvm-x86-mmu-derive-shadow-mmu-page-role-from-parent.patch b/queue-5.15/kvm-x86-mmu-derive-shadow-mmu-page-role-from-parent.patch new file mode 100644 index 0000000000..77edb26340 --- /dev/null +++ b/queue-5.15/kvm-x86-mmu-derive-shadow-mmu-page-role-from-parent.patch @@ -0,0 +1,240 @@ +From 3776b66e4f8c1d6c8b888792cf8a31987b316bd6 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 26 Jun 2026 19:46:14 +0200 +Subject: KVM: x86/mmu: Derive shadow MMU page role from parent + +From: Paolo Bonzini + +commit 2e65e842c57d72e9a573ba42bc2055b7f626ea1f upstream. + +Instead of computing the shadow page role from scratch for every new +page, derive most of the information from the parent shadow page. This +eliminates the dependency on the vCPU root role to allocate shadow page +tables, and reduces the number of parameters to kvm_mmu_get_page(). + +Preemptively split out the role calculation to a separate function for +use in a following commit. + +Note that when calculating the MMU root role, we can take +@role.passthrough, @role.direct, and @role.access directly from +@vcpu->arch.mmu->root_role. Only @role.level and @role.quadrant still +must be overridden for PAE page directories, when shadowing 32-bit +guest page tables with PAE page tables. + +No functional change intended. + +Reviewed-by: Peter Xu +Signed-off-by: David Matlack +Message-Id: <20220516232138.1783324-5-dmatlack@google.com> +Signed-off-by: Paolo Bonzini +Signed-off-by: Sasha Levin +--- + arch/x86/kvm/mmu/mmu.c | 99 ++++++++++++++++++++++------------ + arch/x86/kvm/mmu/paging_tmpl.h | 9 ++-- + 2 files changed, 71 insertions(+), 37 deletions(-) + +diff --git a/arch/x86/kvm/mmu/mmu.c b/arch/x86/kvm/mmu/mmu.c +index bd7650380ad9e7..3a5ed967037765 100644 +--- a/arch/x86/kvm/mmu/mmu.c ++++ b/arch/x86/kvm/mmu/mmu.c +@@ -2070,33 +2070,15 @@ static void clear_sp_write_flooding_count(u64 *spte) + __clear_sp_write_flooding_count(sptep_to_sp(spte)); + } + +-static struct kvm_mmu_page *kvm_mmu_get_page(struct kvm_vcpu *vcpu, +- gfn_t gfn, +- gva_t gaddr, +- unsigned level, +- bool direct, +- unsigned int access) ++static struct kvm_mmu_page *kvm_mmu_get_page(struct kvm_vcpu *vcpu, gfn_t gfn, ++ union kvm_mmu_page_role role) + { + bool direct_mmu = vcpu->arch.mmu->direct_map; +- union kvm_mmu_page_role role; + struct hlist_head *sp_list; +- unsigned quadrant; + struct kvm_mmu_page *sp; + int collisions = 0; + LIST_HEAD(invalid_list); + +- role = vcpu->arch.mmu->mmu_role.base; +- role.level = level; +- role.direct = direct; +- if (role.direct) +- role.gpte_is_8_bytes = true; +- role.access = access; +- if (!direct_mmu && vcpu->arch.mmu->root_level <= PT32_ROOT_LEVEL) { +- quadrant = gaddr >> (PAGE_SHIFT + (PT64_PT_BITS * level)); +- quadrant &= (1 << ((PT32_PT_BITS - PT64_PT_BITS) * level)) - 1; +- role.quadrant = quadrant; +- } +- + sp_list = &vcpu->kvm->arch.mmu_page_hash[kvm_page_table_hashfn(gfn)]; + for_each_valid_sp(vcpu->kvm, sp, sp_list) { + if (sp->gfn != gfn) { +@@ -2114,7 +2096,7 @@ static struct kvm_mmu_page *kvm_mmu_get_page(struct kvm_vcpu *vcpu, + * Unsync pages must not be left as is, because the new + * upper-level page will be write-protected. + */ +- if (level > PG_LEVEL_4K && sp->unsync) ++ if (role.level > PG_LEVEL_4K && sp->unsync) + kvm_mmu_prepare_zap_page(vcpu->kvm, sp, + &invalid_list); + continue; +@@ -2152,14 +2134,14 @@ static struct kvm_mmu_page *kvm_mmu_get_page(struct kvm_vcpu *vcpu, + + ++vcpu->kvm->stat.mmu_cache_miss; + +- sp = kvm_mmu_alloc_page(vcpu, direct); ++ sp = kvm_mmu_alloc_page(vcpu, role.direct); + + sp->gfn = gfn; + sp->role = role; + hlist_add_head(&sp->hash_link, sp_list); +- if (!direct) { ++ if (!role.direct) { + account_shadowed(vcpu->kvm, sp); +- if (level == PG_LEVEL_4K && rmap_write_protect(vcpu, gfn)) ++ if (role.level == PG_LEVEL_4K && rmap_write_protect(vcpu, gfn)) + kvm_flush_remote_tlbs_with_address(vcpu->kvm, gfn, 1); + } + trace_kvm_mmu_get_page(sp, true); +@@ -2171,6 +2153,54 @@ static struct kvm_mmu_page *kvm_mmu_get_page(struct kvm_vcpu *vcpu, + return sp; + } + ++static union kvm_mmu_page_role kvm_mmu_child_role(u64 *sptep, bool direct, unsigned int access) ++{ ++ struct kvm_mmu_page *parent_sp = sptep_to_sp(sptep); ++ union kvm_mmu_page_role role; ++ ++ role = parent_sp->role; ++ role.level--; ++ role.access = access; ++ role.direct = direct; ++ ++ /* ++ * If the guest has 4-byte PTEs then that means it's using 32-bit, ++ * 2-level, non-PAE paging. KVM shadows such guests with PAE paging ++ * (i.e. 8-byte PTEs). The difference in PTE size means that KVM must ++ * shadow each guest page table with multiple shadow page tables, which ++ * requires extra bookkeeping in the role. ++ * ++ * Specifically, to shadow the guest's page directory (which covers a ++ * 4GiB address space), KVM uses 4 PAE page directories, each mapping ++ * 1GiB of the address space. @role.quadrant encodes which quarter of ++ * the address space each maps. ++ * ++ * To shadow the guest's page tables (which each map a 4MiB region), KVM ++ * uses 2 PAE page tables, each mapping a 2MiB region. For these, ++ * @role.quadrant encodes which half of the region they map. ++ * ++ * Note, the 4 PAE page directories are pre-allocated and the quadrant ++ * assigned in mmu_alloc_root(). So only page tables need to be handled ++ * here. ++ */ ++ if (!role.gpte_is_8_bytes) { ++ WARN_ON_ONCE(role.level != PG_LEVEL_4K); ++ role.quadrant = (sptep - parent_sp->spt) % 2; ++ } ++ ++ return role; ++} ++ ++static struct kvm_mmu_page *kvm_mmu_get_child_sp(struct kvm_vcpu *vcpu, ++ u64 *sptep, gfn_t gfn, ++ bool direct, unsigned int access) ++{ ++ union kvm_mmu_page_role role; ++ ++ role = kvm_mmu_child_role(sptep, direct, access); ++ return kvm_mmu_get_page(vcpu, gfn, role); ++} ++ + static void shadow_walk_init_using_root(struct kvm_shadow_walk_iterator *iterator, + struct kvm_vcpu *vcpu, hpa_t root, + u64 addr) +@@ -3013,8 +3043,7 @@ static int __direct_map(struct kvm_vcpu *vcpu, gpa_t gpa, u32 error_code, + if (is_shadow_present_pte(*it.sptep)) + continue; + +- sp = kvm_mmu_get_page(vcpu, base_gfn, it.addr, +- it.level - 1, true, ACC_ALL); ++ sp = kvm_mmu_get_child_sp(vcpu, it.sptep, base_gfn, true, ACC_ALL); + + link_shadow_page(vcpu, it.sptep, sp); + if (is_tdp && huge_page_disallowed && +@@ -3408,13 +3437,18 @@ static int mmu_check_root(struct kvm_vcpu *vcpu, gfn_t root_gfn) + return ret; + } + +-static hpa_t mmu_alloc_root(struct kvm_vcpu *vcpu, gfn_t gfn, gva_t gva, ++static hpa_t mmu_alloc_root(struct kvm_vcpu *vcpu, gfn_t gfn, int quadrant, + u8 level) + { +- bool direct = vcpu->arch.mmu->mmu_role.base.direct; ++ union kvm_mmu_page_role role = vcpu->arch.mmu->mmu_role.base; + struct kvm_mmu_page *sp; + +- sp = kvm_mmu_get_page(vcpu, gfn, gva, level, direct, ACC_ALL); ++ role.level = level; ++ ++ if (!role.gpte_is_8_bytes) ++ role.quadrant = quadrant; ++ ++ sp = kvm_mmu_get_page(vcpu, gfn, role); + ++sp->root_count; + + return __pa(sp->spt); +@@ -3448,8 +3482,8 @@ static int mmu_alloc_direct_roots(struct kvm_vcpu *vcpu) + for (i = 0; i < 4; ++i) { + WARN_ON_ONCE(IS_VALID_PAE_ROOT(mmu->pae_root[i])); + +- root = mmu_alloc_root(vcpu, i << (30 - PAGE_SHIFT), +- i << 30, PT32_ROOT_LEVEL); ++ root = mmu_alloc_root(vcpu, i << (30 - PAGE_SHIFT), i, ++ PT32_ROOT_LEVEL); + mmu->pae_root[i] = root | PT_PRESENT_MASK | + shadow_me_mask; + } +@@ -3557,8 +3591,7 @@ static int mmu_alloc_shadow_roots(struct kvm_vcpu *vcpu) + root_gfn = pdptrs[i] >> PAGE_SHIFT; + } + +- root = mmu_alloc_root(vcpu, root_gfn, i << 30, +- PT32_ROOT_LEVEL); ++ root = mmu_alloc_root(vcpu, root_gfn, i, PT32_ROOT_LEVEL); + mmu->pae_root[i] = root | pm_mask; + } + +diff --git a/arch/x86/kvm/mmu/paging_tmpl.h b/arch/x86/kvm/mmu/paging_tmpl.h +index a1811f51eda925..cc70cbb3f261ba 100644 +--- a/arch/x86/kvm/mmu/paging_tmpl.h ++++ b/arch/x86/kvm/mmu/paging_tmpl.h +@@ -704,8 +704,9 @@ static int FNAME(fetch)(struct kvm_vcpu *vcpu, gpa_t addr, + if (!is_shadow_present_pte(*it.sptep)) { + table_gfn = gw->table_gfn[it.level - 2]; + access = gw->pt_access[it.level - 2]; +- sp = kvm_mmu_get_page(vcpu, table_gfn, addr, +- it.level-1, false, access); ++ sp = kvm_mmu_get_child_sp(vcpu, it.sptep, table_gfn, ++ false, access); ++ + /* + * We must synchronize the pagetable before linking it + * because the guest doesn't need to flush tlb when +@@ -763,8 +764,8 @@ static int FNAME(fetch)(struct kvm_vcpu *vcpu, gpa_t addr, + drop_large_spte(vcpu, it.sptep); + + if (!is_shadow_present_pte(*it.sptep)) { +- sp = kvm_mmu_get_page(vcpu, base_gfn, addr, +- it.level - 1, true, direct_access); ++ sp = kvm_mmu_get_child_sp(vcpu, it.sptep, base_gfn, ++ true, direct_access); + link_shadow_page(vcpu, it.sptep, sp); + if (huge_page_disallowed && req_level >= it.level) + account_huge_nx_page(vcpu->kvm, sp); +-- +2.53.0 + diff --git a/queue-5.15/kvm-x86-mmu-ensure-hugepage-is-in-by-slot-before-che.patch b/queue-5.15/kvm-x86-mmu-ensure-hugepage-is-in-by-slot-before-che.patch new file mode 100644 index 0000000000..5a3943c087 --- /dev/null +++ b/queue-5.15/kvm-x86-mmu-ensure-hugepage-is-in-by-slot-before-che.patch @@ -0,0 +1,137 @@ +From 53868487a36b1a092a7b7cdb98b5375fd4271ce4 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 26 Jun 2026 19:46:19 +0200 +Subject: KVM: x86/mmu: Ensure hugepage is in by slot before checking max + mapping level + +From: Sean Christopherson + +commit ef057cbf825e03b63f6edf5980f96abf3c53089d upstream. + +When recovering hugepages in the shadow MMU, verify that the base gfn of +the shadow page is actually contained within the target memslot, *before* +querying the max mapping level given the shadow page's gfn. Failure to +pre-check the validity of the gfn can lead to an out-of-bounds access to +the slot's lpage_info (which typically manifests as a host #PF because the +lpage_info is vmalloc'd) if the guest creates a hugepage mapping (in its +PTEs) that extends "below" the bounds of a memslot. + +When faulting in memory for a guest, and the size of the guest mapping is +greater than KVM's (current) max mapping, then KVM will create a "direct" +shadow page (direct in that there are no gPTEs to shadow, and so the target +gfn is a direct calculation given the base gfn of the shadow page). The +hugepage recovery flow looks for such direct shadow pages, as forcing 4KiB +mappings when dirty logging generates the guest > host mapping size case. +When the 4KiB restriction is lifted, then KVM can replace the shadow page +with a hugepage. + +But if KVM originally used a smaller mapping than the guest because the +range of memory covered by the guest hugepage exceeds the bounds of a +memslot, then KVM will link a direct shadow page with a gfn that is outside +the bounds of the memslot being used to fault in memory. The rmap entry +added for the leaf mapping is correct and within bounds, but the gfn of the +leaf SPTE's parent shadow page will be out of bounds. + + BUG: unable to handle page fault for address: ffffc90000806ffc + #PF: supervisor read access in kernel mode + #PF: error_code(0x0000) - not-present page + PGD 100000067 P4D 100000067 PUD 1002a7067 PMD 10612f067 PTE 0 + Oops: Oops: 0000 [#1] SMP + CPU: 13 UID: 1000 PID: 757 Comm: mmu_stress_test Not tainted 7.1.0-rc1-48ce1e26eace-x86_pir_to_irr_comments-vm #341 PREEMPT + Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS 0.0.0 02/06/2015 + RIP: 0010:kvm_mmu_max_mapping_level+0x79/0x2b0 [kvm] + Call Trace: + + kvm_mmu_recover_huge_pages+0x21b/0x320 [kvm] + kvm_set_memslot+0x1ee/0x590 [kvm] + kvm_set_memory_region.part.0+0x3a1/0x4d0 [kvm] + kvm_vm_ioctl+0x9bf/0x15d0 [kvm] + __x64_sys_ioctl+0x8a/0xd0 + do_syscall_64+0xb7/0xbb0 + entry_SYSCALL_64_after_hwframe+0x4b/0x53 + RIP: 0033:0x7f21c0f1a9bf + + +Don't bother pre-checking the bounds of the potential hugepage, i.e. don't +check that e.g. sp->gfn + KVM_PAGES_PER_HPAGE(sp->role.level + 1) is also +within the memslot, as the checks performed by kvm_mmu_max_mapping_level() +are a superset of the basic bounds checks. I.e. pre-checking the full +range would be a dubious micro-optimization. + +Fixes: 9eba50f8d7fc ("KVM: x86/mmu: Consult max mapping level when zapping collapsible SPTEs") +Cc: stable@vger.kernel.org +Cc: David Matlack +Cc: James Houghton +Cc: Alexander Bulekov +Cc: Fred Griffoul +Cc: Alexander Graf +Cc: David Woodhouse +Cc: Filippo Sironi +Cc: Ivan Orlov +Signed-off-by: Sean Christopherson +Signed-off-by: Paolo Bonzini +Signed-off-by: Sasha Levin +--- + arch/x86/kvm/mmu/mmu.c | 19 +++++++++++++------ + include/linux/kvm_host.h | 7 ++++++- + 2 files changed, 19 insertions(+), 7 deletions(-) + +diff --git a/arch/x86/kvm/mmu/mmu.c b/arch/x86/kvm/mmu/mmu.c +index e9dbe3e7ec622f..3b993fade5f712 100644 +--- a/arch/x86/kvm/mmu/mmu.c ++++ b/arch/x86/kvm/mmu/mmu.c +@@ -5883,13 +5883,20 @@ static bool kvm_mmu_zap_collapsible_spte(struct kvm *kvm, + pfn = spte_to_pfn(*sptep); + + /* +- * We cannot do huge page mapping for indirect shadow pages, +- * which are found on the last rmap (level = 1) when not using +- * tdp; such shadow pages are synced with the page table in +- * the guest, and the guest page table is using 4K page size +- * mapping if the indirect sp has level = 1. ++ * Direct shadow page can be replaced by a hugepage if the host ++ * mapping level allows it and the memslot maps all of the host ++ * hugepage. Note! If the memslot maps only part of the ++ * hugepage, sp->gfn may be below slot->base_gfn, and querying ++ * the max mapping level would cause an out-of-bounds lpage_info ++ * access. So the gfn bounds check *must* be done first. ++ * ++ * Indirect shadow pages are created when the guest page tables ++ * are using 4K pages. Since the host mapping is always ++ * constrained by the page size in the guest, indirect shadow ++ * pages are never collapsible. + */ +- if (sp->role.direct && !kvm_is_reserved_pfn(pfn) && ++ if (sp->role.direct && is_gfn_in_memslot(slot, sp->gfn) && ++ !kvm_is_reserved_pfn(pfn) && + sp->role.level < kvm_mmu_max_mapping_level(kvm, slot, sp->gfn, + pfn, PG_LEVEL_NUM)) { + pte_list_remove(kvm, rmap_head, sptep); +diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h +index ec12082e587df3..118a3905afb006 100644 +--- a/include/linux/kvm_host.h ++++ b/include/linux/kvm_host.h +@@ -1312,6 +1312,11 @@ int kvm_request_irq_source_id(struct kvm *kvm); + void kvm_free_irq_source_id(struct kvm *kvm, int irq_source_id); + bool kvm_arch_irqfd_allowed(struct kvm *kvm, struct kvm_irqfd *args); + ++static inline bool is_gfn_in_memslot(const struct kvm_memory_slot *slot, gfn_t gfn) ++{ ++ return gfn >= slot->base_gfn && gfn < slot->base_gfn + slot->npages; ++} ++ + /* + * Returns a pointer to the memslot at slot_index if it contains gfn. + * Otherwise returns NULL. +@@ -1332,7 +1337,7 @@ try_get_memslot(struct kvm_memslots *slots, int slot_index, gfn_t gfn) + slot_index = array_index_nospec(slot_index, slots->used_slots); + slot = &slots->memslots[slot_index]; + +- if (gfn >= slot->base_gfn && gfn < slot->base_gfn + slot->npages) ++ if (is_gfn_in_memslot(slot, gfn)) + return slot; + else + return NULL; +-- +2.53.0 + diff --git a/queue-5.15/kvm-x86-mmu-pull-call-to-drop_large_spte-into-__link.patch b/queue-5.15/kvm-x86-mmu-pull-call-to-drop_large_spte-into-__link.patch new file mode 100644 index 0000000000..920b801fcd --- /dev/null +++ b/queue-5.15/kvm-x86-mmu-pull-call-to-drop_large_spte-into-__link.patch @@ -0,0 +1,193 @@ +From bcc6397d244844807014d82fa65afa416d431f0b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 26 Jun 2026 19:46:16 +0200 +Subject: KVM: x86/mmu: pull call to drop_large_spte() into + __link_shadow_page() + +From: Paolo Bonzini + +commit 0cd8dc739833080aa0813cbd94d907a93e3a14c3 upstream. + +Before allocating a child shadow page table, all callers check +whether the parent already points to a huge page and, if so, they +drop that SPTE. This is done by drop_large_spte(). + +However, dropping the large SPTE is really only necessary before the +sp is installed. While the sp is returned by kvm_mmu_get_child_sp(), +installing it happens later in __link_shadow_page(). Move the call +there instead of having it in each and every caller. + +To ensure that the shadow page is not linked twice if it was present, +do _not_ opportunistically make kvm_mmu_get_child_sp() idempotent: +instead, return an error value if the shadow page already existed. +This is a bit more verbose, but clearer than NULL. + +Finally, now that the drop_large_spte() name is not taken anymore, +remove the two underscores in front of __drop_large_spte(). + +Reviewed-by: Sean Christopherson +Signed-off-by: Paolo Bonzini +Signed-off-by: Sasha Levin +--- + arch/x86/kvm/mmu/mmu.c | 49 +++++++++++++++++++--------------- + arch/x86/kvm/mmu/paging_tmpl.h | 29 +++++++++----------- + 2 files changed, 40 insertions(+), 38 deletions(-) + +diff --git a/arch/x86/kvm/mmu/mmu.c b/arch/x86/kvm/mmu/mmu.c +index dbc18d4cc572c1..d58be2e698f795 100644 +--- a/arch/x86/kvm/mmu/mmu.c ++++ b/arch/x86/kvm/mmu/mmu.c +@@ -1179,26 +1179,16 @@ static void drop_spte(struct kvm *kvm, u64 *sptep) + rmap_remove(kvm, sptep); + } + +- +-static bool __drop_large_spte(struct kvm *kvm, u64 *sptep) ++static void drop_large_spte(struct kvm *kvm, u64 *sptep) + { +- if (is_large_pte(*sptep)) { +- WARN_ON(sptep_to_sp(sptep)->role.level == PG_LEVEL_4K); +- drop_spte(kvm, sptep); +- return true; +- } +- +- return false; +-} ++ struct kvm_mmu_page *sp; + +-static void drop_large_spte(struct kvm_vcpu *vcpu, u64 *sptep) +-{ +- if (__drop_large_spte(vcpu->kvm, sptep)) { +- struct kvm_mmu_page *sp = sptep_to_sp(sptep); ++ sp = sptep_to_sp(sptep); ++ WARN_ON(sp->role.level == PG_LEVEL_4K); + +- kvm_flush_remote_tlbs_with_address(vcpu->kvm, sp->gfn, ++ drop_spte(kvm, sptep); ++ kvm_flush_remote_tlbs_with_address(kvm, sp->gfn, + KVM_PAGES_PER_HPAGE(sp->role.level)); +- } + } + + /* +@@ -2197,6 +2187,9 @@ static struct kvm_mmu_page *kvm_mmu_get_child_sp(struct kvm_vcpu *vcpu, + { + union kvm_mmu_page_role role; + ++ if (is_shadow_present_pte(*sptep) && !is_large_pte(*sptep)) ++ return ERR_PTR(-EEXIST); ++ + role = kvm_mmu_child_role(sptep, direct, access); + return kvm_mmu_get_page(vcpu, gfn, role); + } +@@ -2264,13 +2257,21 @@ static void shadow_walk_next(struct kvm_shadow_walk_iterator *iterator) + __shadow_walk_next(iterator, *iterator->sptep); + } + +-static void link_shadow_page(struct kvm_vcpu *vcpu, u64 *sptep, +- struct kvm_mmu_page *sp) ++static void __link_shadow_page(struct kvm_vcpu *vcpu, ++ struct kvm_mmu_memory_cache *cache, u64 *sptep, ++ struct kvm_mmu_page *sp) + { + u64 spte; + + BUILD_BUG_ON(VMX_EPT_WRITABLE_MASK != PT_WRITABLE_MASK); + ++ /* ++ * If an SPTE is present already, it must be a leaf and therefore ++ * a large one. Drop it and flush the TLB before installing sp. ++ */ ++ if (is_shadow_present_pte(*sptep)) ++ drop_large_spte(vcpu->kvm, sptep); ++ + spte = make_nonleaf_spte(sp->spt, sp_ad_disabled(sp)); + + mmu_spte_set(sptep, spte); +@@ -2281,6 +2282,12 @@ static void link_shadow_page(struct kvm_vcpu *vcpu, u64 *sptep, + mark_unsync(sptep); + } + ++static void link_shadow_page(struct kvm_vcpu *vcpu, u64 *sptep, ++ struct kvm_mmu_page *sp) ++{ ++ __link_shadow_page(vcpu, &vcpu->arch.mmu_pte_list_desc_cache, sptep, sp); ++} ++ + static void validate_direct_spte(struct kvm_vcpu *vcpu, u64 *sptep, + unsigned direct_access) + { +@@ -3039,11 +3046,9 @@ static int __direct_map(struct kvm_vcpu *vcpu, gpa_t gpa, u32 error_code, + if (it.level == level) + break; + +- drop_large_spte(vcpu, it.sptep); +- if (is_shadow_present_pte(*it.sptep)) +- continue; +- + sp = kvm_mmu_get_child_sp(vcpu, it.sptep, base_gfn, true, ACC_ALL); ++ if (sp == ERR_PTR(-EEXIST)) ++ continue; + + link_shadow_page(vcpu, it.sptep, sp); + if (is_tdp && huge_page_disallowed && +diff --git a/arch/x86/kvm/mmu/paging_tmpl.h b/arch/x86/kvm/mmu/paging_tmpl.h +index cc70cbb3f261ba..0f68f5afa642c8 100644 +--- a/arch/x86/kvm/mmu/paging_tmpl.h ++++ b/arch/x86/kvm/mmu/paging_tmpl.h +@@ -698,15 +698,13 @@ static int FNAME(fetch)(struct kvm_vcpu *vcpu, gpa_t addr, + gfn_t table_gfn; + + clear_sp_write_flooding_count(it.sptep); +- drop_large_spte(vcpu, it.sptep); + +- sp = NULL; +- if (!is_shadow_present_pte(*it.sptep)) { +- table_gfn = gw->table_gfn[it.level - 2]; +- access = gw->pt_access[it.level - 2]; +- sp = kvm_mmu_get_child_sp(vcpu, it.sptep, table_gfn, +- false, access); ++ table_gfn = gw->table_gfn[it.level - 2]; ++ access = gw->pt_access[it.level - 2]; ++ sp = kvm_mmu_get_child_sp(vcpu, it.sptep, table_gfn, ++ false, access); + ++ if (sp != ERR_PTR(-EEXIST)) { + /* + * We must synchronize the pagetable before linking it + * because the guest doesn't need to flush tlb when +@@ -735,7 +733,7 @@ static int FNAME(fetch)(struct kvm_vcpu *vcpu, gpa_t addr, + if (FNAME(gpte_changed)(vcpu, gw, it.level - 1)) + goto out_gpte_changed; + +- if (sp) ++ if (sp != ERR_PTR(-EEXIST)) + link_shadow_page(vcpu, it.sptep, sp); + } + +@@ -761,15 +759,14 @@ static int FNAME(fetch)(struct kvm_vcpu *vcpu, gpa_t addr, + + validate_direct_spte(vcpu, it.sptep, direct_access); + +- drop_large_spte(vcpu, it.sptep); ++ sp = kvm_mmu_get_child_sp(vcpu, it.sptep, base_gfn, ++ true, direct_access); ++ if (sp == ERR_PTR(-EEXIST)) ++ continue; + +- if (!is_shadow_present_pte(*it.sptep)) { +- sp = kvm_mmu_get_child_sp(vcpu, it.sptep, base_gfn, +- true, direct_access); +- link_shadow_page(vcpu, it.sptep, sp); +- if (huge_page_disallowed && req_level >= it.level) +- account_huge_nx_page(vcpu->kvm, sp); +- } ++ link_shadow_page(vcpu, it.sptep, sp); ++ if (huge_page_disallowed && req_level >= it.level) ++ account_huge_nx_page(vcpu->kvm, sp); + } + + ret = mmu_set_spte(vcpu, it.sptep, gw->pte_access, write_fault, +-- +2.53.0 + diff --git a/queue-5.15/kvm-x86-mmu-stop-passing-direct-to-mmu_alloc_root.patch b/queue-5.15/kvm-x86-mmu-stop-passing-direct-to-mmu_alloc_root.patch new file mode 100644 index 0000000000..ef4721eee6 --- /dev/null +++ b/queue-5.15/kvm-x86-mmu-stop-passing-direct-to-mmu_alloc_root.patch @@ -0,0 +1,76 @@ +From 18d012c4f2b01a72e0682e509dad85caf3248d11 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 26 Jun 2026 19:46:13 +0200 +Subject: KVM: x86/mmu: Stop passing "direct" to mmu_alloc_root() + +From: David Matlack + +commit 86938ab6925b8fe174ca6abf397e6ea9d3c054a4 upstream. + +The "direct" argument is vcpu->arch.mmu->root_role.direct, +because unlike non-root page tables, it's impossible to have +a direct root in an indirect MMU. So just use that. + +Suggested-by: Lai Jiangshan +Signed-off-by: David Matlack +Message-Id: <20220516232138.1783324-4-dmatlack@google.com> +Signed-off-by: Paolo Bonzini +Signed-off-by: Sasha Levin +--- + arch/x86/kvm/mmu/mmu.c | 11 ++++++----- + 1 file changed, 6 insertions(+), 5 deletions(-) + +diff --git a/arch/x86/kvm/mmu/mmu.c b/arch/x86/kvm/mmu/mmu.c +index c03c4341a87fd7..bd7650380ad9e7 100644 +--- a/arch/x86/kvm/mmu/mmu.c ++++ b/arch/x86/kvm/mmu/mmu.c +@@ -3409,8 +3409,9 @@ static int mmu_check_root(struct kvm_vcpu *vcpu, gfn_t root_gfn) + } + + static hpa_t mmu_alloc_root(struct kvm_vcpu *vcpu, gfn_t gfn, gva_t gva, +- u8 level, bool direct) ++ u8 level) + { ++ bool direct = vcpu->arch.mmu->mmu_role.base.direct; + struct kvm_mmu_page *sp; + + sp = kvm_mmu_get_page(vcpu, gfn, gva, level, direct, ACC_ALL); +@@ -3436,7 +3437,7 @@ static int mmu_alloc_direct_roots(struct kvm_vcpu *vcpu) + root = kvm_tdp_mmu_get_vcpu_root_hpa(vcpu); + mmu->root_hpa = root; + } else if (shadow_root_level >= PT64_ROOT_4LEVEL) { +- root = mmu_alloc_root(vcpu, 0, 0, shadow_root_level, true); ++ root = mmu_alloc_root(vcpu, 0, 0, shadow_root_level); + mmu->root_hpa = root; + } else if (shadow_root_level == PT32E_ROOT_LEVEL) { + if (WARN_ON_ONCE(!mmu->pae_root)) { +@@ -3448,7 +3449,7 @@ static int mmu_alloc_direct_roots(struct kvm_vcpu *vcpu) + WARN_ON_ONCE(IS_VALID_PAE_ROOT(mmu->pae_root[i])); + + root = mmu_alloc_root(vcpu, i << (30 - PAGE_SHIFT), +- i << 30, PT32_ROOT_LEVEL, true); ++ i << 30, PT32_ROOT_LEVEL); + mmu->pae_root[i] = root | PT_PRESENT_MASK | + shadow_me_mask; + } +@@ -3511,7 +3512,7 @@ static int mmu_alloc_shadow_roots(struct kvm_vcpu *vcpu) + */ + if (mmu->root_level >= PT64_ROOT_4LEVEL) { + root = mmu_alloc_root(vcpu, root_gfn, 0, +- mmu->shadow_root_level, false); ++ mmu->shadow_root_level); + mmu->root_hpa = root; + goto set_root_pgd; + } +@@ -3557,7 +3558,7 @@ static int mmu_alloc_shadow_roots(struct kvm_vcpu *vcpu) + } + + root = mmu_alloc_root(vcpu, root_gfn, i << 30, +- PT32_ROOT_LEVEL, false); ++ PT32_ROOT_LEVEL); + mmu->pae_root[i] = root | pm_mask; + } + +-- +2.53.0 + diff --git a/queue-5.15/kvm-x86-mmu-use-a-bool-for-direct.patch b/queue-5.15/kvm-x86-mmu-use-a-bool-for-direct.patch new file mode 100644 index 0000000000..37981229e5 --- /dev/null +++ b/queue-5.15/kvm-x86-mmu-use-a-bool-for-direct.patch @@ -0,0 +1,50 @@ +From 88a03cd0c1f9927e56dc6fd8cb5dc4c44b2666d8 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 26 Jun 2026 19:46:12 +0200 +Subject: KVM: x86/mmu: Use a bool for direct + +From: David Matlack + +commit 27a59d57f073f21f029df1517c2c0a1abea5b0ce upstream. + +The parameter "direct" can either be true or false, and all of the +callers pass in a bool variable or true/false literal, so just use the +type bool. + +No functional change intended. + +Reviewed-by: Lai Jiangshan +Reviewed-by: Sean Christopherson +Signed-off-by: David Matlack +Message-Id: <20220516232138.1783324-3-dmatlack@google.com> +Signed-off-by: Paolo Bonzini +Signed-off-by: Sasha Levin +--- + arch/x86/kvm/mmu/mmu.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/arch/x86/kvm/mmu/mmu.c b/arch/x86/kvm/mmu/mmu.c +index e4813964bfa07a..c03c4341a87fd7 100644 +--- a/arch/x86/kvm/mmu/mmu.c ++++ b/arch/x86/kvm/mmu/mmu.c +@@ -1737,7 +1737,7 @@ static void drop_parent_pte(struct kvm_mmu_page *sp, + mmu_spte_clear_no_track(parent_pte); + } + +-static struct kvm_mmu_page *kvm_mmu_alloc_page(struct kvm_vcpu *vcpu, int direct) ++static struct kvm_mmu_page *kvm_mmu_alloc_page(struct kvm_vcpu *vcpu, bool direct) + { + struct kvm_mmu_page *sp; + +@@ -2074,7 +2074,7 @@ static struct kvm_mmu_page *kvm_mmu_get_page(struct kvm_vcpu *vcpu, + gfn_t gfn, + gva_t gaddr, + unsigned level, +- int direct, ++ bool direct, + unsigned int access) + { + bool direct_mmu = vcpu->arch.mmu->direct_map; +-- +2.53.0 + diff --git a/queue-5.15/series b/queue-5.15/series index f3da244a4d..0f0db55aee 100644 --- a/queue-5.15/series +++ b/queue-5.15/series @@ -23,3 +23,12 @@ media-vidtv-fix-null-pointer-dereference-in-vidtv_mux_push_si.patch virtiofs-fix-uaf-on-submount-umount.patch revert-selftest-ptp-update-ptp-selftest-to-exercise-.patch revert-ptp-add-testptp-mask-test.patch +kvm-x86-mmu-use-a-bool-for-direct.patch +kvm-x86-mmu-stop-passing-direct-to-mmu_alloc_root.patch +kvm-x86-mmu-derive-shadow-mmu-page-role-from-parent.patch +kvm-x86-mmu-always-pass-0-for-quadrant-when-gptes-ar.patch +kvm-x86-mmu-pull-call-to-drop_large_spte-into-__link.patch +kvm-x86-fix-shadow-paging-use-after-free-due-to-unex.patch +kvm-x86-fix-shadow-paging-use-after-free-due-to-unex.patch-23529 +kvm-x86-mmu-ensure-hugepage-is-in-by-slot-before-che.patch +kselftest-arm64-signal-skip-sve-signal-test-if-not-e.patch diff --git a/queue-6.12/kvm-sev-ignore-mmio-requests-of-length-0.patch b/queue-6.12/kvm-sev-ignore-mmio-requests-of-length-0.patch new file mode 100644 index 0000000000..7c11570fde --- /dev/null +++ b/queue-6.12/kvm-sev-ignore-mmio-requests-of-length-0.patch @@ -0,0 +1,53 @@ +From a7260c5e57af3037cb73c10921723f4d3ca3a5d0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 26 Jun 2026 21:28:54 +0200 +Subject: KVM: SEV: Ignore MMIO requests of length '0' + +From: Sean Christopherson + +commit 1aa8a6dc7dac8b83234b53518311bf78231f4fa5 upstream. + +Explicitly ignore MMIO requests of length '0', so that setting up the +software scratch area (and other code) doesn't have to worry about +underflowing the length, and to allow for special casing '0' in the +future. + +Fixes: 8f423a80d299 ("KVM: SVM: Support MMIO for an SEV-ES guest") +Cc: stable@vger.kernel.org +Reviewed-by: Tom Lendacky +Signed-off-by: Sean Christopherson +Message-ID: <20260501202250.2115252-3-seanjc@google.com> +Signed-off-by: Paolo Bonzini +Signed-off-by: Jack Wang +Signed-off-by: Sasha Levin +--- + arch/x86/kvm/svm/sev.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/arch/x86/kvm/svm/sev.c b/arch/x86/kvm/svm/sev.c +index 115c59c86f448a..0a01971e33f0b7 100644 +--- a/arch/x86/kvm/svm/sev.c ++++ b/arch/x86/kvm/svm/sev.c +@@ -4347,6 +4347,9 @@ int sev_handle_vmgexit(struct kvm_vcpu *vcpu) + exit_code = kvm_ghcb_get_sw_exit_code(control); + switch (exit_code) { + case SVM_VMGEXIT_MMIO_READ: ++ if (!control->exit_info_2) ++ return 1; ++ + ret = setup_vmgexit_scratch(svm, true, control->exit_info_2); + if (ret) + break; +@@ -4357,6 +4360,9 @@ int sev_handle_vmgexit(struct kvm_vcpu *vcpu) + svm->sev_es.ghcb_sa); + break; + case SVM_VMGEXIT_MMIO_WRITE: ++ if (!control->exit_info_2) ++ return 1; ++ + ret = setup_vmgexit_scratch(svm, false, control->exit_info_2); + if (ret) + break; +-- +2.53.0 + diff --git a/queue-6.12/kvm-sev-ignore-port-i-o-requests-of-length-0.patch b/queue-6.12/kvm-sev-ignore-port-i-o-requests-of-length-0.patch new file mode 100644 index 0000000000..48dc71564c --- /dev/null +++ b/queue-6.12/kvm-sev-ignore-port-i-o-requests-of-length-0.patch @@ -0,0 +1,55 @@ +From 5e0c1f8fce4de31722a7f8a96fa4b3c5cf82a90b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 26 Jun 2026 21:28:56 +0200 +Subject: KVM: SEV: Ignore Port I/O requests of length '0' + +From: Sean Christopherson + +commit 3988bd2723de407ae90fa7a6f6029b4e60238c58 upstream. + +Explicitly ignore Port I/O requests of length '0' (or count '0'), so that +setting up the software scratch area (and other code) doesn't have to +worry about underflowing the length, and to allow for WARNing on trying +to configure the scratch area with len==0. + +Fixes: 291bd20d5d88 ("KVM: SVM: Add initial support for a VMGEXIT VMEXIT") +Cc: stable@vger.kernel.org +Reviewed-by: Tom Lendacky +Signed-off-by: Sean Christopherson +Message-ID: <20260501202250.2115252-5-seanjc@google.com> +Signed-off-by: Paolo Bonzini +Signed-off-by: Jack Wang +Signed-off-by: Sasha Levin +--- + arch/x86/kvm/svm/sev.c | 8 ++++++++ + 1 file changed, 8 insertions(+) + +diff --git a/arch/x86/kvm/svm/sev.c b/arch/x86/kvm/svm/sev.c +index 497a6e70513570..73e49317735173 100644 +--- a/arch/x86/kvm/svm/sev.c ++++ b/arch/x86/kvm/svm/sev.c +@@ -4459,6 +4459,11 @@ int sev_handle_vmgexit(struct kvm_vcpu *vcpu) + control->exit_info_1, control->exit_info_2); + ret = -EINVAL; + break; ++ case SVM_EXIT_IOIO: ++ if (!((control->exit_info_1 & SVM_IOIO_SIZE_MASK) >> SVM_IOIO_SIZE_SHIFT)) ++ return 1; ++ ++ fallthrough; + default: + ret = svm_invoke_exit_handler(vcpu, exit_code); + } +@@ -4479,6 +4484,9 @@ int sev_es_string_io(struct vcpu_svm *svm, int size, unsigned int port, int in) + if (unlikely(check_mul_overflow(count, size, &bytes))) + return -EINVAL; + ++ if (!bytes) ++ return 1; ++ + r = setup_vmgexit_scratch(svm, in, bytes); + if (r) + return r; +-- +2.53.0 + diff --git a/queue-6.12/kvm-sev-reject-mmio-requests-larger-than-8-bytes-wit.patch b/queue-6.12/kvm-sev-reject-mmio-requests-larger-than-8-bytes-wit.patch new file mode 100644 index 0000000000..648aeaf085 --- /dev/null +++ b/queue-6.12/kvm-sev-reject-mmio-requests-larger-than-8-bytes-wit.patch @@ -0,0 +1,62 @@ +From 3a4a2c93944cea17c985feb4c198417b5f324ff3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 26 Jun 2026 21:28:55 +0200 +Subject: KVM: SEV: Reject MMIO requests larger than 8 bytes with GHCB v2+ + +From: Sean Christopherson + +commit dcf1b2d4b0564a27e4ca7c654871aab4f9620046 upstream. + +When using GHCB v2+, reject MMIO requests that are larger than 8 bytes. +Per the GHCB spec: + + SW_EXITINFO2 must be less than or equal to 0x7fffffff for version 1 and + less than or equal to 0x8 for all other versions. + +Fixes: 4af663c2f64a ("KVM: SEV: Allow per-guest configuration of GHCB protocol version") +Cc: stable@vger.kernel.org +Reviewed-by: Tom Lendacky +Signed-off-by: Sean Christopherson +Message-ID: <20260501202250.2115252-4-seanjc@google.com> +Signed-off-by: Paolo Bonzini +Signed-off-by: Jack Wang +Signed-off-by: Sasha Levin +--- + arch/x86/kvm/svm/sev.c | 14 ++++++++++++++ + 1 file changed, 14 insertions(+) + +diff --git a/arch/x86/kvm/svm/sev.c b/arch/x86/kvm/svm/sev.c +index 0a01971e33f0b7..497a6e70513570 100644 +--- a/arch/x86/kvm/svm/sev.c ++++ b/arch/x86/kvm/svm/sev.c +@@ -4350,6 +4350,13 @@ int sev_handle_vmgexit(struct kvm_vcpu *vcpu) + if (!control->exit_info_2) + return 1; + ++ if (to_kvm_sev_info(vcpu->kvm)->ghcb_version >= 2 && ++ control->exit_info_2 > 8) { ++ ghcb_set_sw_exit_info_1(svm->sev_es.ghcb, 2); ++ ghcb_set_sw_exit_info_2(svm->sev_es.ghcb, GHCB_ERR_INVALID_INPUT); ++ return 1; ++ } ++ + ret = setup_vmgexit_scratch(svm, true, control->exit_info_2); + if (ret) + break; +@@ -4363,6 +4370,13 @@ int sev_handle_vmgexit(struct kvm_vcpu *vcpu) + if (!control->exit_info_2) + return 1; + ++ if (to_kvm_sev_info(vcpu->kvm)->ghcb_version >= 2 && ++ control->exit_info_2 > 8) { ++ ghcb_set_sw_exit_info_1(svm->sev_es.ghcb, 2); ++ ghcb_set_sw_exit_info_2(svm->sev_es.ghcb, GHCB_ERR_INVALID_INPUT); ++ return 1; ++ } ++ + ret = setup_vmgexit_scratch(svm, false, control->exit_info_2); + if (ret) + break; +-- +2.53.0 + diff --git a/queue-6.12/revert-pci-qcom-advertise-hotplug-slot-capability-wi.patch b/queue-6.12/revert-pci-qcom-advertise-hotplug-slot-capability-wi.patch new file mode 100644 index 0000000000..db16dfbefb --- /dev/null +++ b/queue-6.12/revert-pci-qcom-advertise-hotplug-slot-capability-wi.patch @@ -0,0 +1,79 @@ +From b1d26b5ab59e4ab1787d3aef80f98b753abf396d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 27 Jun 2026 10:53:51 -0400 +Subject: Revert "PCI: qcom: Advertise Hotplug Slot Capability with no Command + Completion support" + +This reverts commit 480c94d3affbc11b9e98ca223a9fa19d90b84fbb. + +Signed-off-by: Sasha Levin +--- + drivers/pci/controller/dwc/pcie-qcom.c | 17 ++++++----------- + 1 file changed, 6 insertions(+), 11 deletions(-) + +diff --git a/drivers/pci/controller/dwc/pcie-qcom.c b/drivers/pci/controller/dwc/pcie-qcom.c +index ae0f36e270baa1..5d27cd149f5120 100644 +--- a/drivers/pci/controller/dwc/pcie-qcom.c ++++ b/drivers/pci/controller/dwc/pcie-qcom.c +@@ -329,20 +329,15 @@ static void qcom_pcie_clear_aspm_l0s(struct dw_pcie *pci) + dw_pcie_dbi_ro_wr_dis(pci); + } + +-static void qcom_pcie_set_slot_nccs(struct dw_pcie *pci) ++static void qcom_pcie_clear_hpc(struct dw_pcie *pci) + { + u16 offset = dw_pcie_find_capability(pci, PCI_CAP_ID_EXP); + u32 val; + + dw_pcie_dbi_ro_wr_en(pci); + +- /* +- * Qcom PCIe Root Ports do not support generating command completion +- * notifications for the Hot-Plug commands. So set the NCCS field to +- * avoid waiting for the completions. +- */ + val = readl(pci->dbi_base + offset + PCI_EXP_SLTCAP); +- val |= PCI_EXP_SLTCAP_NCCS; ++ val &= ~PCI_EXP_SLTCAP_HPC; + writel(val, pci->dbi_base + offset + PCI_EXP_SLTCAP); + + dw_pcie_dbi_ro_wr_dis(pci); +@@ -537,7 +532,7 @@ static int qcom_pcie_post_init_2_1_0(struct qcom_pcie *pcie) + writel(CFG_BRIDGE_SB_INIT, + pci->dbi_base + AXI_MSTR_RESP_COMP_CTRL1); + +- qcom_pcie_set_slot_nccs(pcie->pci); ++ qcom_pcie_clear_hpc(pcie->pci); + + return 0; + } +@@ -617,7 +612,7 @@ static int qcom_pcie_post_init_1_0_0(struct qcom_pcie *pcie) + writel(val, pcie->parf + PARF_AXI_MSTR_WR_ADDR_HALT); + } + +- qcom_pcie_set_slot_nccs(pcie->pci); ++ qcom_pcie_clear_hpc(pcie->pci); + + return 0; + } +@@ -710,7 +705,7 @@ static int qcom_pcie_post_init_2_3_2(struct qcom_pcie *pcie) + val |= EN; + writel(val, pcie->parf + PARF_AXI_MSTR_WR_ADDR_HALT_V2); + +- qcom_pcie_set_slot_nccs(pcie->pci); ++ qcom_pcie_clear_hpc(pcie->pci); + + return 0; + } +@@ -1014,7 +1009,7 @@ static int qcom_pcie_post_init_2_7_0(struct qcom_pcie *pcie) + writel(WR_NO_SNOOP_OVERIDE_EN | RD_NO_SNOOP_OVERIDE_EN, + pcie->parf + PARF_NO_SNOOP_OVERIDE); + +- qcom_pcie_set_slot_nccs(pcie->pci); ++ qcom_pcie_clear_hpc(pcie->pci); + + return 0; + } +-- +2.53.0 + diff --git a/queue-6.12/series b/queue-6.12/series index cd1d4f3ab8..9200140766 100644 --- a/queue-6.12/series +++ b/queue-6.12/series @@ -92,3 +92,7 @@ media-vidtv-fix-null-pointer-dereference-in-vidtv_mux_push_si.patch virtiofs-fix-uaf-on-submount-umount.patch kvm-x86-fix-shadow-paging-use-after-free-due-to-unex.patch kvm-x86-mmu-ensure-hugepage-is-in-by-slot-before-che.patch +revert-pci-qcom-advertise-hotplug-slot-capability-wi.patch +kvm-sev-ignore-mmio-requests-of-length-0.patch +kvm-sev-reject-mmio-requests-larger-than-8-bytes-wit.patch +kvm-sev-ignore-port-i-o-requests-of-length-0.patch diff --git a/queue-6.18/lockd-fix-test-handling-when-not-all-permissions-are.patch b/queue-6.18/lockd-fix-test-handling-when-not-all-permissions-are.patch new file mode 100644 index 0000000000..01325cae47 --- /dev/null +++ b/queue-6.18/lockd-fix-test-handling-when-not-all-permissions-are.patch @@ -0,0 +1,254 @@ +From e05991356efd662f8a9fb480feea90862857424d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 26 Jun 2026 10:31:22 -0400 +Subject: lockd: fix TEST handling when not all permissions are available. + +From: NeilBrown + +[ Upstream commit 0b474240327cebeff08ad429e8ed3cfc6c8ee816 ] + +The F_GETLK fcntl can work with either read access or write access or +both. It can query F_RDLCK and F_WRLCK locks in either case. + +However lockd currently treats F_GETLK similar to F_SETLK in that read +access is required to query an F_RDLCK lock and write access is required +to query a F_WRLCK lock. + +This is wrong and can cause problems - e.g. when qemu accesses a +read-only (e.g. iso) filesystem image over NFS (though why it queries +if it can get a write lock - I don't know. But it does, and this works +with local filesystems). + +So we need TEST requests to be handled differently. To do this: + +- change nlm_do_fopen() to accept O_RDWR as a mode and in that case + succeed if either a O_RDONLY or O_WRONLY file can be opened. +- change nlm_lookup_file() to accept a mode argument from caller, + instead of deducing base on lock time, and pass that on to nlm_do_fopen() +- change nlm4svc_retrieve_args() and nlmsvc_retrieve_args() to detect + TEST requests and pass O_RDWR as a mode to nlm_lookup_file, passing + the same mode as before for other requests. Also set + lock->fl.c.flc_file to whichever file is available for TEST requests. +- change nlmsvc_testlock() to also not calculate the mode, but to use + whatever was stored in lock->fl.c.flc_file. + +This behaviour of lockd - requesting O_WRONLY access to TEST for +exclusive locks - has been present at least since git history began. +However it was hidden until recently because knfsd ignored the access +requested by lockd and required only READ access for all locking +requests (unless the underlying filesystem provided an f_op->open +function which checked access permissions). + +The commit mentioned in Fixes: below changed nfsd_permission() to NOT +override the access request for LOCK requests and this exposed the bug +that we are now fixing. + +Note that there is another issue that this patch does not address. +The flock(.., LOCK_EX) call is permitted on a read-only file descriptor. +Linux NFS maps this to NLM locking as whole-file byte-range locks. +nfsd will see this as though it were fcntl( F_SETLK (F_WRLCK)) and will +now require write access, which it might not be able to get. +It is not clear if this is a problem in practice, or what the best +solution might be. So no attempt is made to address it. + +Reported-by: Tj +Link: https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=1128861 +Fixes: 4cc9b9f2bf4d ("nfsd: refine and rename NFSD_MAY_LOCK") +Reviewed-by: Jeff Layton +Signed-off-by: NeilBrown +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/lockd/svc4proc.c | 13 ++++++++++--- + fs/lockd/svclock.c | 4 +--- + fs/lockd/svcproc.c | 15 ++++++++++++--- + fs/lockd/svcsubs.c | 35 +++++++++++++++++++++++++---------- + include/linux/lockd/lockd.h | 2 +- + 5 files changed, 49 insertions(+), 20 deletions(-) + +diff --git a/fs/lockd/svc4proc.c b/fs/lockd/svc4proc.c +index 4b6f18d977343d..75e020a8bfd072 100644 +--- a/fs/lockd/svc4proc.c ++++ b/fs/lockd/svc4proc.c +@@ -26,6 +26,8 @@ nlm4svc_retrieve_args(struct svc_rqst *rqstp, struct nlm_args *argp, + struct nlm_host *host = NULL; + struct nlm_file *file = NULL; + struct nlm_lock *lock = &argp->lock; ++ bool is_test = (rqstp->rq_proc == NLMPROC_TEST || ++ rqstp->rq_proc == NLMPROC_TEST_MSG); + __be32 error = 0; + + /* nfsd callbacks must have been installed for this procedure */ +@@ -46,15 +48,20 @@ nlm4svc_retrieve_args(struct svc_rqst *rqstp, struct nlm_args *argp, + if (filp != NULL) { + int mode = lock_to_openmode(&lock->fl); + ++ if (is_test) ++ mode = O_RDWR; ++ + lock->fl.c.flc_flags = FL_POSIX; + +- error = nlm_lookup_file(rqstp, &file, lock); ++ error = nlm_lookup_file(rqstp, &file, lock, mode); + if (error) + goto no_locks; + *filp = file; +- + /* Set up the missing parts of the file_lock structure */ +- lock->fl.c.flc_file = file->f_file[mode]; ++ if (is_test) ++ lock->fl.c.flc_file = nlmsvc_file_file(file); ++ else ++ lock->fl.c.flc_file = file->f_file[mode]; + lock->fl.c.flc_pid = current->tgid; + lock->fl.fl_start = (loff_t)lock->lock_start; + lock->fl.fl_end = lock->lock_len ? +diff --git a/fs/lockd/svclock.c b/fs/lockd/svclock.c +index d66e8285159996..c35ffa1b4b89d4 100644 +--- a/fs/lockd/svclock.c ++++ b/fs/lockd/svclock.c +@@ -611,7 +611,6 @@ nlmsvc_testlock(struct svc_rqst *rqstp, struct nlm_file *file, + struct nlm_lock *conflock) + { + int error; +- int mode; + __be32 ret; + + dprintk("lockd: nlmsvc_testlock(%s/%ld, ty=%d, %Ld-%Ld)\n", +@@ -626,14 +625,13 @@ nlmsvc_testlock(struct svc_rqst *rqstp, struct nlm_file *file, + goto out; + } + +- mode = lock_to_openmode(&lock->fl); + locks_init_lock(&conflock->fl); + /* vfs_test_lock only uses start, end, and owner, but tests flc_file */ + conflock->fl.c.flc_file = lock->fl.c.flc_file; + conflock->fl.fl_start = lock->fl.fl_start; + conflock->fl.fl_end = lock->fl.fl_end; + conflock->fl.c.flc_owner = lock->fl.c.flc_owner; +- error = vfs_test_lock(file->f_file[mode], &conflock->fl); ++ error = vfs_test_lock(lock->fl.c.flc_file, &conflock->fl); + if (error) { + /* We can't currently deal with deferred test requests */ + if (error == FILE_LOCK_DEFERRED) +diff --git a/fs/lockd/svcproc.c b/fs/lockd/svcproc.c +index 5817ef272332d9..d98e8d684376b7 100644 +--- a/fs/lockd/svcproc.c ++++ b/fs/lockd/svcproc.c +@@ -55,6 +55,8 @@ nlmsvc_retrieve_args(struct svc_rqst *rqstp, struct nlm_args *argp, + struct nlm_host *host = NULL; + struct nlm_file *file = NULL; + struct nlm_lock *lock = &argp->lock; ++ bool is_test = (rqstp->rq_proc == NLMPROC_TEST || ++ rqstp->rq_proc == NLMPROC_TEST_MSG); + int mode; + __be32 error = 0; + +@@ -70,15 +72,22 @@ nlmsvc_retrieve_args(struct svc_rqst *rqstp, struct nlm_args *argp, + + /* Obtain file pointer. Not used by FREE_ALL call. */ + if (filp != NULL) { +- error = cast_status(nlm_lookup_file(rqstp, &file, lock)); ++ mode = lock_to_openmode(&lock->fl); ++ ++ if (is_test) ++ mode = O_RDWR; ++ ++ error = cast_status(nlm_lookup_file(rqstp, &file, lock, mode)); + if (error != 0) + goto no_locks; + *filp = file; + + /* Set up the missing parts of the file_lock structure */ +- mode = lock_to_openmode(&lock->fl); + lock->fl.c.flc_flags = FL_POSIX; +- lock->fl.c.flc_file = file->f_file[mode]; ++ if (is_test) ++ lock->fl.c.flc_file = nlmsvc_file_file(file); ++ else ++ lock->fl.c.flc_file = file->f_file[mode]; + lock->fl.c.flc_pid = current->tgid; + lock->fl.fl_lmops = &nlmsvc_lock_operations; + nlmsvc_locks_init_private(&lock->fl, host, (pid_t)lock->svid); +diff --git a/fs/lockd/svcsubs.c b/fs/lockd/svcsubs.c +index 9103896164f688..7ea204eadfcace 100644 +--- a/fs/lockd/svcsubs.c ++++ b/fs/lockd/svcsubs.c +@@ -82,18 +82,35 @@ int lock_to_openmode(struct file_lock *lock) + * + * We have to make sure we have the right credential to open + * the file. ++ * ++ * mode can be O_RDONLY(0), O_WRONLY(1) or O_RDWR(2). The latter ++ * means success can be achieved with EITHER O_RDONLY or O_WRONLY. ++ * It does NOT mean both read and write are required. + */ + static __be32 nlm_do_fopen(struct svc_rqst *rqstp, + struct nlm_file *file, int mode) + { +- struct file **fp = &file->f_file[mode]; +- __be32 nfserr; ++ __be32 nfserr = nlm_lck_denied_nolocks; ++ __be32 deferred = 0; ++ struct file **fp; ++ int m; + +- if (*fp) +- return 0; +- nfserr = nlmsvc_ops->fopen(rqstp, &file->f_handle, fp, mode); +- if (nfserr) +- dprintk("lockd: open failed (error %d)\n", nfserr); ++ for (m = O_RDONLY ; m <= O_WRONLY ; m++) { ++ if (mode != O_RDWR && mode != m) ++ continue; ++ ++ fp = &file->f_file[m]; ++ if (*fp) ++ return 0; ++ nfserr = nlmsvc_ops->fopen(rqstp, &file->f_handle, fp, m); ++ if (!nfserr) ++ return 0; ++ if (nfserr == nlm_drop_reply) ++ deferred = nfserr; ++ } ++ if (deferred) ++ return deferred; ++ dprintk("lockd: open failed (error %d)\n", ntohl(nfserr)); + return nfserr; + } + +@@ -103,17 +120,15 @@ static __be32 nlm_do_fopen(struct svc_rqst *rqstp, + */ + __be32 + nlm_lookup_file(struct svc_rqst *rqstp, struct nlm_file **result, +- struct nlm_lock *lock) ++ struct nlm_lock *lock, int mode) + { + struct nlm_file *file; + unsigned int hash; + __be32 nfserr; +- int mode; + + nlm_debug_print_fh("nlm_lookup_file", &lock->fh); + + hash = file_hash(&lock->fh); +- mode = lock_to_openmode(&lock->fl); + + /* Lock file table */ + mutex_lock(&nlm_file_mutex); +diff --git a/include/linux/lockd/lockd.h b/include/linux/lockd/lockd.h +index c8f0f9458f2cc0..d9930fc43ca540 100644 +--- a/include/linux/lockd/lockd.h ++++ b/include/linux/lockd/lockd.h +@@ -293,7 +293,7 @@ void nlmsvc_locks_init_private(struct file_lock *, struct nlm_host *, pid_t); + * File handling for the server personality + */ + __be32 nlm_lookup_file(struct svc_rqst *, struct nlm_file **, +- struct nlm_lock *); ++ struct nlm_lock *, int); + void nlm_release_file(struct nlm_file *); + void nlmsvc_put_lockowner(struct nlm_lockowner *); + void nlmsvc_release_lockowner(struct nlm_lock *); +-- +2.53.0 + diff --git a/queue-6.18/revert-pci-qcom-advertise-hotplug-slot-capability-wi.patch b/queue-6.18/revert-pci-qcom-advertise-hotplug-slot-capability-wi.patch new file mode 100644 index 0000000000..7ea41c11c5 --- /dev/null +++ b/queue-6.18/revert-pci-qcom-advertise-hotplug-slot-capability-wi.patch @@ -0,0 +1,79 @@ +From 8a29c0407dd15336ee5619acadda00de8fc7071a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 27 Jun 2026 10:53:39 -0400 +Subject: Revert "PCI: qcom: Advertise Hotplug Slot Capability with no Command + Completion support" + +This reverts commit f176c47683bf6365e2f6d580d557fae49169a703. + +Signed-off-by: Sasha Levin +--- + drivers/pci/controller/dwc/pcie-qcom.c | 17 ++++++----------- + 1 file changed, 6 insertions(+), 11 deletions(-) + +diff --git a/drivers/pci/controller/dwc/pcie-qcom.c b/drivers/pci/controller/dwc/pcie-qcom.c +index 43555ad9e5dcf5..789cc0e3c10da9 100644 +--- a/drivers/pci/controller/dwc/pcie-qcom.c ++++ b/drivers/pci/controller/dwc/pcie-qcom.c +@@ -341,20 +341,15 @@ static void qcom_pcie_clear_aspm_l0s(struct dw_pcie *pci) + dw_pcie_dbi_ro_wr_dis(pci); + } + +-static void qcom_pcie_set_slot_nccs(struct dw_pcie *pci) ++static void qcom_pcie_clear_hpc(struct dw_pcie *pci) + { + u16 offset = dw_pcie_find_capability(pci, PCI_CAP_ID_EXP); + u32 val; + + dw_pcie_dbi_ro_wr_en(pci); + +- /* +- * Qcom PCIe Root Ports do not support generating command completion +- * notifications for the Hot-Plug commands. So set the NCCS field to +- * avoid waiting for the completions. +- */ + val = readl(pci->dbi_base + offset + PCI_EXP_SLTCAP); +- val |= PCI_EXP_SLTCAP_NCCS; ++ val &= ~PCI_EXP_SLTCAP_HPC; + writel(val, pci->dbi_base + offset + PCI_EXP_SLTCAP); + + dw_pcie_dbi_ro_wr_dis(pci); +@@ -554,7 +549,7 @@ static int qcom_pcie_post_init_2_1_0(struct qcom_pcie *pcie) + writel(CFG_BRIDGE_SB_INIT, + pci->dbi_base + AXI_MSTR_RESP_COMP_CTRL1); + +- qcom_pcie_set_slot_nccs(pcie->pci); ++ qcom_pcie_clear_hpc(pcie->pci); + + return 0; + } +@@ -634,7 +629,7 @@ static int qcom_pcie_post_init_1_0_0(struct qcom_pcie *pcie) + writel(val, pcie->parf + PARF_AXI_MSTR_WR_ADDR_HALT); + } + +- qcom_pcie_set_slot_nccs(pcie->pci); ++ qcom_pcie_clear_hpc(pcie->pci); + + return 0; + } +@@ -727,7 +722,7 @@ static int qcom_pcie_post_init_2_3_2(struct qcom_pcie *pcie) + val |= EN; + writel(val, pcie->parf + PARF_AXI_MSTR_WR_ADDR_HALT_V2); + +- qcom_pcie_set_slot_nccs(pcie->pci); ++ qcom_pcie_clear_hpc(pcie->pci); + + return 0; + } +@@ -1033,7 +1028,7 @@ static int qcom_pcie_post_init_2_7_0(struct qcom_pcie *pcie) + writel(WR_NO_SNOOP_OVERRIDE_EN | RD_NO_SNOOP_OVERRIDE_EN, + pcie->parf + PARF_NO_SNOOP_OVERRIDE); + +- qcom_pcie_set_slot_nccs(pcie->pci); ++ qcom_pcie_clear_hpc(pcie->pci); + + return 0; + } +-- +2.53.0 + diff --git a/queue-6.18/series b/queue-6.18/series index d00f57e334..ad2d2ee538 100644 --- a/queue-6.18/series +++ b/queue-6.18/series @@ -1,3 +1,5 @@ kvm-x86-fix-shadow-paging-use-after-free-due-to-unex.patch lsm-add-backing_file-lsm-hooks.patch selinux-fix-overlayfs-mmap-and-mprotect-access-check.patch +revert-pci-qcom-advertise-hotplug-slot-capability-wi.patch +lockd-fix-test-handling-when-not-all-permissions-are.patch diff --git a/queue-6.6/bluetooth-btmtk-accept-too-short-wmt-func_ctrl-event.patch b/queue-6.6/bluetooth-btmtk-accept-too-short-wmt-func_ctrl-event.patch new file mode 100644 index 0000000000..df6aee4cd8 --- /dev/null +++ b/queue-6.6/bluetooth-btmtk-accept-too-short-wmt-func_ctrl-event.patch @@ -0,0 +1,50 @@ +From a78ebf762f6dc914ac28c8da87656d4c424a9308 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 24 Apr 2026 22:24:29 +0300 +Subject: Bluetooth: btmtk: accept too short WMT FUNC_CTRL events + +From: Pauli Virtanen + +[ Upstream commit e3ac0d9f1a205f33a43fba3b79ef74d2f604c78b ] + +MT7925 (USB ID 0e8d:e025) on fw version 20260106153314 sends WMT +FUNC_CTRL events that are missing the status field. + +Prior to commit 006b9943b982 ("Bluetooth: btmtk: validate WMT event SKB +length before struct access") the status was read from out-of-bounds of +SKB data, which usually would result to success with +BTMTK_WMT_ON_UNDONE, although I don't know the intent here. The bounds +check added in that commit returns with error instead, producing +"Bluetooth: hci0: Failed to send wmt func ctrl (-22)" and makes the +device unusable. + +Fix the regression by interpreting too short packet as status +BTMTK_WMT_ON_UNDONE, which makes the device work normally again. + +Fixes: 634a4408c061 ("Bluetooth: btmtk: validate WMT event SKB length before struct access") +Signed-off-by: Pauli Virtanen +Tested-by: Mikhail Gavrilov # MT7922 (0489:e0e2) +Signed-off-by: Luiz Augusto von Dentz +Signed-off-by: Sasha Levin +--- + drivers/bluetooth/btmtk.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/bluetooth/btmtk.c b/drivers/bluetooth/btmtk.c +index 5c6f4d4b2e7f0c..582915f9a8d700 100644 +--- a/drivers/bluetooth/btmtk.c ++++ b/drivers/bluetooth/btmtk.c +@@ -679,8 +679,8 @@ int btmtk_usb_hci_wmt_sync(struct hci_dev *hdev, + case BTMTK_WMT_FUNC_CTRL: + if (!skb_pull_data(data->evt_skb, + sizeof(wmt_evt_funcc->status))) { +- err = -EINVAL; +- goto err_free_skb; ++ status = BTMTK_WMT_ON_UNDONE; ++ break; + } + + wmt_evt_funcc = (struct btmtk_hci_wmt_evt_funcc *)wmt_evt; +-- +2.53.0 + diff --git a/queue-6.6/bluetooth-btmtk-validate-wmt-event-skb-length-before.patch b/queue-6.6/bluetooth-btmtk-validate-wmt-event-skb-length-before.patch new file mode 100644 index 0000000000..6617f8e76e --- /dev/null +++ b/queue-6.6/bluetooth-btmtk-validate-wmt-event-skb-length-before.patch @@ -0,0 +1,63 @@ +From 42ef3948ea9c63f31e5ef989f2df198010b03ba0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 21 Apr 2026 11:14:54 +0000 +Subject: Bluetooth: btmtk: validate WMT event SKB length before struct access + +From: Tristan Madani + +[ Upstream commit 634a4408c0615c523cf7531790f4f14a422b9206 ] + +btmtk_usb_hci_wmt_sync() casts the WMT event response SKB data to +struct btmtk_hci_wmt_evt (7 bytes) and struct btmtk_hci_wmt_evt_funcc +(9 bytes) without first checking that the SKB contains enough data. +A short firmware response causes out-of-bounds reads from SKB tailroom. + +Use skb_pull_data() to validate and advance past the base WMT event +header. For the FUNC_CTRL case, pull the additional status field bytes +before accessing them. + +Fixes: d019930b0049 ("Bluetooth: btmtk: move btusb_mtk_hci_wmt_sync to btmtk.c") +Cc: stable@vger.kernel.org +Signed-off-by: Tristan Madani +Signed-off-by: Luiz Augusto von Dentz +Signed-off-by: Sasha Levin +--- + drivers/bluetooth/btmtk.c | 15 +++++++++++++-- + 1 file changed, 13 insertions(+), 2 deletions(-) + +diff --git a/drivers/bluetooth/btmtk.c b/drivers/bluetooth/btmtk.c +index ad8753dda826bb..5c6f4d4b2e7f0c 100644 +--- a/drivers/bluetooth/btmtk.c ++++ b/drivers/bluetooth/btmtk.c +@@ -655,8 +655,13 @@ int btmtk_usb_hci_wmt_sync(struct hci_dev *hdev, + if (data->evt_skb == NULL) + goto err_free_wc; + +- /* Parse and handle the return WMT event */ +- wmt_evt = (struct btmtk_hci_wmt_evt *)data->evt_skb->data; ++ wmt_evt = skb_pull_data(data->evt_skb, sizeof(*wmt_evt)); ++ if (!wmt_evt) { ++ bt_dev_err(hdev, "WMT event too short (%u bytes)", ++ data->evt_skb->len); ++ err = -EINVAL; ++ goto err_free_skb; ++ } + if (wmt_evt->whdr.op != hdr->op) { + bt_dev_err(hdev, "Wrong op received %d expected %d", + wmt_evt->whdr.op, hdr->op); +@@ -672,6 +677,12 @@ int btmtk_usb_hci_wmt_sync(struct hci_dev *hdev, + status = BTMTK_WMT_PATCH_DONE; + break; + case BTMTK_WMT_FUNC_CTRL: ++ if (!skb_pull_data(data->evt_skb, ++ sizeof(wmt_evt_funcc->status))) { ++ err = -EINVAL; ++ goto err_free_skb; ++ } ++ + wmt_evt_funcc = (struct btmtk_hci_wmt_evt_funcc *)wmt_evt; + if (be16_to_cpu(wmt_evt_funcc->status) == 0x404) + status = BTMTK_WMT_ON_DONE; +-- +2.53.0 + diff --git a/queue-6.6/series b/queue-6.6/series index c79d3bee68..bf52f3ae0a 100644 --- a/queue-6.6/series +++ b/queue-6.6/series @@ -83,3 +83,5 @@ eventpoll-fix-ep_remove-struct-eventpoll-struct-file.patch kvm-x86-fix-shadow-paging-use-after-free-due-to-unex.patch kvm-x86-mmu-ensure-hugepage-is-in-by-slot-before-che.patch revert-ptp-add-testptp-mask-test.patch +bluetooth-btmtk-validate-wmt-event-skb-length-before.patch +bluetooth-btmtk-accept-too-short-wmt-func_ctrl-event.patch