Merge 2be86a8c57 ("Merge tag 'hwmon-for-v7.1-rc5' of git://git.kernel.org/pub/scm/linux/kernel/git/groeck/linux-staging") into android-mainline

Steps on the way to v7.1-rc5

Change-Id: If3e7b89bb02eea9f0da965fc3fb9e9a50e80b939
Signed-off-by: Carlos Llamas <cmllamas@google.com>
This commit is contained in:
Carlos Llamas authored and android-test-infra-autosubmit@system.gserviceaccount.com committed 2026-06-01 09:13:09 -07:00
commit d0fd6f5393
56 files changed
+772 -293

No files matched your search

+2 -1
View File
@@ -18955,7 +18955,8 @@ F: drivers/hid/hid-nintendo*
NIOS2 ARCHITECTURE
M: Dinh Nguyen <dinguyen@kernel.org>
S: Maintained
M: Simon Schuster <schuster.simon@siemens-energy.com>
S: Supported
T: git git://git.kernel.org/pub/scm/linux/kernel/git/dinguyen/linux.git
F: arch/nios2/
+3 -1
View File
@@ -30,6 +30,8 @@ static inline unsigned long efi_get_kimg_min_align(void)
return SZ_2M;
}
#define EFI_KIMG_PREFERRED_ADDRESS PHYSADDR(VMLINUX_LOAD_ADDRESS)
unsigned long efi_get_kimg_kaslr_address(void);
#define EFI_KIMG_PREFERRED_ADDRESS efi_get_kimg_kaslr_address()
#endif /* _ASM_LOONGARCH_EFI_H */
+6
View File
@@ -4,6 +4,12 @@
#ifdef CONFIG_PARAVIRT
#include <linux/jump_label.h>
DECLARE_STATIC_KEY_FALSE(virt_preempt_key);
DECLARE_STATIC_KEY_FALSE(virt_spin_lock_key);
DECLARE_PER_CPU(struct kvm_steal_time, steal_time);
int __init pv_ipi_init(void);
int __init pv_time_init(void);
int __init pv_spinlock_init(void);
+1 -4
View File
@@ -3,12 +3,9 @@
#define _ASM_LOONGARCH_QSPINLOCK_H
#include <asm/kvm_para.h>
#include <linux/jump_label.h>
#include <asm/paravirt.h>
#ifdef CONFIG_PARAVIRT
DECLARE_STATIC_KEY_FALSE(virt_preempt_key);
DECLARE_STATIC_KEY_FALSE(virt_spin_lock_key);
DECLARE_PER_CPU(struct kvm_steal_time, steal_time);
#define virt_spin_lock virt_spin_lock
+8 -6
View File
@@ -60,16 +60,18 @@ NOKPROBE_SYMBOL(arch_prepare_kprobe);
/* Install breakpoint in text */
void arch_arm_kprobe(struct kprobe *p)
{
*p->addr = KPROBE_BP_INSN;
flush_insn_slot(p);
u32 insn = KPROBE_BP_INSN;
larch_insn_text_copy(p->addr, &insn, LOONGARCH_INSN_SIZE);
}
NOKPROBE_SYMBOL(arch_arm_kprobe);
/* Remove breakpoint from text */
void arch_disarm_kprobe(struct kprobe *p)
{
*p->addr = p->opcode;
flush_insn_slot(p);
u32 insn = p->opcode;
larch_insn_text_copy(p->addr, &insn, LOONGARCH_INSN_SIZE);
}
NOKPROBE_SYMBOL(arch_disarm_kprobe);
@@ -184,16 +186,16 @@ static bool reenter_kprobe(struct kprobe *p, struct pt_regs *regs,
struct kprobe_ctlblk *kcb)
{
switch (kcb->kprobe_status) {
case KPROBE_HIT_SS:
case KPROBE_HIT_SSDONE:
case KPROBE_HIT_ACTIVE:
kprobes_inc_nmissed_count(p);
setup_singlestep(p, regs, kcb, 1);
break;
case KPROBE_HIT_SS:
case KPROBE_REENTER:
pr_warn("Failed to recover from reentered kprobes.\n");
dump_kprobe(p);
WARN_ON_ONCE(1);
BUG();
break;
default:
WARN_ON(1);
+50
View File
@@ -134,11 +134,23 @@ early_param("nokaslr", nokaslr);
#define KASLR_DISABLED_MESSAGE "KASLR is disabled by %s in %s cmdline.\n"
/*
* Note: strictly-defined KASLR means the kernel's final runtime address
* has a random offset from the kernel's load address, which is implemented
* in relocate.c; broadly-defined KALSR means the kernel's final runtime
* address has a random offset from the kernel's link address (a.k.a.
* VMLINUX_LOAD_ADDRESS), which also include the efistlub implementation,
* kexec_file implementation and QEMU direct kernel boot. kaslr_disabled()
* return true only means strictly-defined KASLR is disabled.
*/
static inline __init bool kaslr_disabled(void)
{
char *str;
const char *builtin_cmdline = CONFIG_CMDLINE;
if (kaslr_offset())
return true; /* KASLR is performed during early boot. */
str = strstr(builtin_cmdline, "nokaslr");
if (str == builtin_cmdline || (str > builtin_cmdline && *(str - 1) == ' ')) {
pr_info(KASLR_DISABLED_MESSAGE, "\'nokaslr\'", "built-in");
@@ -210,14 +222,52 @@ static inline void __init *determine_relocation_address(void)
return RELOCATED_KASLR(destination);
}
static unsigned long __init determine_initrd_address(unsigned long *size)
{
unsigned long start = 0;
unsigned long key_length;
char *p, *endp, *key = "initrd=";
key_length = strlen(key);
p = strstr(boot_command_line, key);
if (!p) {
key = "initrdmem=";
key_length = strlen(key);
p = strstr(boot_command_line, key);
}
if (p == boot_command_line || (p > boot_command_line && *(p - 1) == ' ')) {
p += key_length;
start = memparse(p, &endp);
if (*endp == ',')
*size = memparse(endp + 1, NULL);
}
return start;
}
static inline int __init relocation_addr_valid(void *location_new)
{
unsigned long kernel_start, kernel_size;
unsigned long initrd_start, initrd_size = 0;
if ((unsigned long)location_new & 0x00000ffff)
return 0; /* Inappropriately aligned new location */
if ((unsigned long)location_new < (unsigned long)_end)
return 0; /* New location overlaps original kernel */
initrd_start = determine_initrd_address(&initrd_size);
if (initrd_start && initrd_size) {
kernel_start = PHYSADDR(location_new);
kernel_size = (unsigned long)_end - (unsigned long)_text;
if (kernel_start < (initrd_start + initrd_size) &&
initrd_start < (kernel_start + kernel_size))
return 0; /* initrd/initramfs overlaps kernel */
}
return 1;
}
#endif
-4
View File
@@ -123,11 +123,7 @@ void arch_remove_memory(u64 start, u64 size, struct vmem_altmap *altmap)
{
unsigned long start_pfn = start >> PAGE_SHIFT;
unsigned long nr_pages = size >> PAGE_SHIFT;
struct page *page = pfn_to_page(start_pfn);
/* With altmap the first mapped page is offset from @start */
if (altmap)
page += vmem_altmap_offset(altmap);
__remove_pages(start_pfn, nr_pages, altmap);
}
#endif
+2
View File
@@ -12,4 +12,6 @@
#define __ALIGN .align 4
#define __ALIGN_STR ".align 4"
#define _THIS_IP_ ({ unsigned long __ip; asm volatile("nextpc %0" : "=r" (__ip)); __ip; })
#endif
+15 -1
View File
@@ -606,6 +606,12 @@ static void platform_device_release(struct device *dev)
kfree(pa);
}
static void platform_device_release_full(struct device *dev)
{
device_remove_software_node(dev);
platform_device_release(dev);
}
/**
* platform_device_alloc - create a platform device
* @name: base name of the device we're adding
@@ -848,7 +854,13 @@ struct platform_device *platform_device_register_full(const struct platform_devi
int ret;
struct platform_device *pdev;
if (pdevinfo->swnode && pdevinfo->properties)
/*
* Only one software node per device is allowed. Make sure we don't
* accept or create two.
*/
if ((pdevinfo->swnode && pdevinfo->properties) ||
(pdevinfo->swnode && is_software_node(pdevinfo->fwnode)) ||
(pdevinfo->properties && is_software_node(pdevinfo->fwnode)))
return ERR_PTR(-EINVAL);
pdev = platform_device_alloc(pdevinfo->name, pdevinfo->id);
@@ -878,6 +890,8 @@ struct platform_device *platform_device_register_full(const struct platform_devi
ret = device_add_software_node(&pdev->dev, pdevinfo->swnode);
if (ret)
goto err;
pdev->dev.release = platform_device_release_full;
} else if (pdevinfo->properties) {
ret = device_create_managed_software_node(&pdev->dev,
pdevinfo->properties, NULL);
@@ -79,6 +79,10 @@ efi_status_t efi_parse_options(char const *cmdline)
efi_noinitrd = true;
} else if (IS_ENABLED(CONFIG_X86_64) && !strcmp(param, "no5lvl")) {
efi_no5lvl = true;
} else if (IS_ENABLED(CONFIG_LOONGARCH) &&
IS_ENABLED(CONFIG_HIBERNATION) &&
!strcmp(param, "resume") && val) {
efi_nokaslr = true; /* LoongArch can't KASLR for hibernation */
} else if (IS_ENABLED(CONFIG_ARCH_HAS_MEM_ENCRYPT) &&
!strcmp(param, "mem_encrypt") && val) {
if (parse_option_str(val, "on"))
+16
View File
@@ -23,6 +23,22 @@ void efi_cache_sync_image(unsigned long image_base, unsigned long alloc_size)
asm volatile ("ibar 0" ::: "memory");
}
unsigned long efi_get_kimg_kaslr_address(void)
{
unsigned int random_offset = 0;
#ifdef CONFIG_RANDOMIZE_BASE
if (!efi_nokaslr) {
efi_get_random_bytes(sizeof(random_offset), (u8 *)&random_offset);
random_offset ^= (random_get_entropy() << 16);
random_offset &= (CONFIG_RANDOMIZE_BASE_MAX_OFFSET - 1);
random_offset = ALIGN(random_offset + SZ_64K, SZ_64K);
}
#endif
return PHYSADDR(VMLINUX_LOAD_ADDRESS) + random_offset;
}
struct exit_boot_struct {
efi_memory_desc_t *runtime_map;
int runtime_entry_count;
+2 -2
View File
@@ -102,7 +102,7 @@ out_unlock:
}
static bool
purge(struct drm_gem_object *obj, struct ww_acquire_ctx *)
purge(struct drm_gem_object *obj, struct ww_acquire_ctx *unused)
{
if (!is_purgeable(to_msm_bo(obj)))
return false;
@@ -114,7 +114,7 @@ purge(struct drm_gem_object *obj, struct ww_acquire_ctx *)
}
static bool
evict(struct drm_gem_object *obj, struct ww_acquire_ctx *)
evict(struct drm_gem_object *obj, struct ww_acquire_ctx *unused)
{
if (is_unevictable(to_msm_bo(obj)))
return false;
+7 -13
View File
@@ -519,8 +519,8 @@ static int lenovo_ec_probe(struct platform_device *pdev)
if (!ec_data)
return -ENOMEM;
if (!request_region(IO_REGION_START, IO_REGION_LENGTH, "LNV-WKS")) {
pr_err(":request fail\n");
if (!devm_request_region(dev, IO_REGION_START, IO_REGION_LENGTH, "LNV-WKS")) {
dev_err(dev, "Failed to request I/O region\n");
return -EIO;
}
@@ -537,13 +537,11 @@ static int lenovo_ec_probe(struct platform_device *pdev)
outw_p(MCHP_SING_IDX, MCHP_EMI0_EC_ADDRESS);
mutex_unlock(&ec_data->mec_mutex);
if ((inb_p(MCHP_EMI0_EC_DATA_BYTE0) != 'M') &&
(inb_p(MCHP_EMI0_EC_DATA_BYTE1) != 'C') &&
(inb_p(MCHP_EMI0_EC_DATA_BYTE2) != 'H') &&
(inb_p(MCHP_EMI0_EC_DATA_BYTE3) != 'P')) {
release_region(IO_REGION_START, IO_REGION_LENGTH);
if ((inb_p(MCHP_EMI0_EC_DATA_BYTE0) != 'M') ||
(inb_p(MCHP_EMI0_EC_DATA_BYTE1) != 'C') ||
(inb_p(MCHP_EMI0_EC_DATA_BYTE2) != 'H') ||
(inb_p(MCHP_EMI0_EC_DATA_BYTE3) != 'P'))
return -ENODEV;
}
dmi_id = dmi_first_match(thinkstation_dmi_table);
@@ -577,7 +575,6 @@ static int lenovo_ec_probe(struct platform_device *pdev)
lenovo_ec_chip_info.info = lenovo_ec_hwmon_info_p8;
break;
default:
release_region(IO_REGION_START, IO_REGION_LENGTH);
return -ENODEV;
}
@@ -606,10 +603,8 @@ static int __init lenovo_ec_init(void)
platform_create_bundle(&lenovo_ec_sensors_platform_driver,
lenovo_ec_probe, NULL, 0, NULL, 0);
if (IS_ERR(lenovo_ec_sensors_platform_device)) {
release_region(IO_REGION_START, IO_REGION_LENGTH);
if (IS_ERR(lenovo_ec_sensors_platform_device))
return PTR_ERR(lenovo_ec_sensors_platform_device);
}
return 0;
}
@@ -617,7 +612,6 @@ module_init(lenovo_ec_init);
static void __exit lenovo_ec_exit(void)
{
release_region(IO_REGION_START, IO_REGION_LENGTH);
platform_device_unregister(lenovo_ec_sensors_platform_device);
platform_driver_unregister(&lenovo_ec_sensors_platform_driver);
}
+33 -13
View File
@@ -46,6 +46,7 @@
#define ADM1266_BLACKBOX_OFFSET 0
#define ADM1266_BLACKBOX_SIZE 64
#define ADM1266_BLACKBOX_MAX_RECORDS 32
#define ADM1266_PMBUS_BLOCK_MAX 255
@@ -60,7 +61,7 @@ struct adm1266_data {
u8 *dev_mem;
struct mutex buf_mutex;
u8 write_buf[ADM1266_PMBUS_BLOCK_MAX + 1] ____cacheline_aligned;
u8 read_buf[ADM1266_PMBUS_BLOCK_MAX + 1] ____cacheline_aligned;
u8 read_buf[ADM1266_PMBUS_BLOCK_MAX + 2] ____cacheline_aligned;
};
static const struct nvmem_cell_info adm1266_nvmem_cells[] = {
@@ -172,9 +173,13 @@ static int adm1266_gpio_get(struct gpio_chip *chip, unsigned int offset)
else
pmbus_cmd = ADM1266_PDIO_STATUS;
guard(pmbus_lock)(data->client);
ret = i2c_smbus_read_block_data(data->client, pmbus_cmd, read_buf);
if (ret < 0)
return ret;
if (ret < 2)
return -EIO;
pins_status = read_buf[0] + (read_buf[1] << 8);
if (offset < ADM1266_GPIO_NR)
@@ -192,9 +197,13 @@ static int adm1266_gpio_get_multiple(struct gpio_chip *chip, unsigned long *mask
unsigned int gpio_nr;
int ret;
guard(pmbus_lock)(data->client);
ret = i2c_smbus_read_block_data(data->client, ADM1266_GPIO_STATUS, read_buf);
if (ret < 0)
return ret;
if (ret < 2)
return -EIO;
status = read_buf[0] + (read_buf[1] << 8);
@@ -207,11 +216,12 @@ static int adm1266_gpio_get_multiple(struct gpio_chip *chip, unsigned long *mask
ret = i2c_smbus_read_block_data(data->client, ADM1266_PDIO_STATUS, read_buf);
if (ret < 0)
return ret;
if (ret < 2)
return -EIO;
status = read_buf[0] + (read_buf[1] << 8);
*bits = 0;
for_each_set_bit_from(gpio_nr, mask, ADM1266_GPIO_NR + ADM1266_PDIO_STATUS) {
for_each_set_bit_from(gpio_nr, mask, ADM1266_GPIO_NR + ADM1266_PDIO_NR) {
if (test_bit(gpio_nr - ADM1266_GPIO_NR, &status))
set_bit(gpio_nr, bits);
}
@@ -230,6 +240,8 @@ static void adm1266_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip)
int ret;
int i;
guard(pmbus_lock)(data->client);
for (i = 0; i < ADM1266_GPIO_NR; i++) {
write_cmd = adm1266_gpio_mapping[i][1];
ret = adm1266_pmbus_block_xfer(data, ADM1266_GPIO_CONFIG, 1, &write_cmd, read_buf);
@@ -290,8 +302,9 @@ static int adm1266_config_gpio(struct adm1266_data *data)
int i;
for (i = 0; i < ARRAY_SIZE(data->gpio_names); i++) {
gpio_name = devm_kasprintf(&data->client->dev, GFP_KERNEL, "adm1266-%x-%s",
data->client->addr, adm1266_names[i]);
gpio_name = devm_kasprintf(&data->client->dev, GFP_KERNEL, "adm1266-%d-%x-%s",
data->client->adapter->nr, data->client->addr,
adm1266_names[i]);
if (!gpio_name)
return -ENOMEM;
@@ -322,6 +335,7 @@ static int adm1266_state_read(struct seq_file *s, void *pdata)
struct i2c_client *client = to_i2c_client(dev);
int ret;
guard(pmbus_lock)(client);
ret = i2c_smbus_read_word_data(client, ADM1266_READ_STATE);
if (ret < 0)
return ret;
@@ -347,9 +361,10 @@ static void adm1266_init_debugfs(struct adm1266_data *data)
static int adm1266_nvmem_read_blackbox(struct adm1266_data *data, u8 *read_buff)
{
u8 record[ADM1266_PMBUS_BLOCK_MAX];
int record_count;
char index;
u8 buf[5];
u8 buf[I2C_SMBUS_BLOCK_MAX];
int ret;
ret = i2c_smbus_read_block_data(data->client, ADM1266_BLACKBOX_INFO, buf);
@@ -360,15 +375,18 @@ static int adm1266_nvmem_read_blackbox(struct adm1266_data *data, u8 *read_buff)
return -EIO;
record_count = buf[3];
if (record_count > ADM1266_BLACKBOX_MAX_RECORDS)
return -EIO;
for (index = 0; index < record_count; index++) {
ret = adm1266_pmbus_block_xfer(data, ADM1266_READ_BLACKBOX, 1, &index, read_buff);
ret = adm1266_pmbus_block_xfer(data, ADM1266_READ_BLACKBOX, 1, &index, record);
if (ret < 0)
return ret;
if (ret != ADM1266_BLACKBOX_SIZE)
return -EIO;
memcpy(read_buff, record, ADM1266_BLACKBOX_SIZE);
read_buff += ADM1266_BLACKBOX_SIZE;
}
@@ -383,6 +401,8 @@ static int adm1266_nvmem_read(void *priv, unsigned int offset, void *val, size_t
if (offset + bytes > data->nvmem_config.size)
return -EINVAL;
guard(pmbus_lock)(data->client);
if (offset == 0) {
memset(data->dev_mem, 0, data->nvmem_config.size);
@@ -432,7 +452,7 @@ static int adm1266_set_rtc(struct adm1266_data *data)
char write_buf[6];
int i;
kt = ktime_get_seconds();
kt = ktime_get_real_seconds();
memset(write_buf, 0, sizeof(write_buf));
@@ -462,20 +482,20 @@ static int adm1266_probe(struct i2c_client *client)
crc8_populate_msb(pmbus_crc_table, 0x7);
mutex_init(&data->buf_mutex);
ret = adm1266_config_gpio(data);
ret = adm1266_set_rtc(data);
if (ret < 0)
return ret;
ret = adm1266_set_rtc(data);
if (ret < 0)
ret = pmbus_do_probe(client, &data->info);
if (ret)
return ret;
ret = adm1266_config_nvmem(data);
if (ret < 0)
return ret;
ret = pmbus_do_probe(client, &data->info);
if (ret)
ret = adm1266_config_gpio(data);
if (ret < 0)
return ret;
adm1266_init_debugfs(data);
+9 -10
View File
@@ -589,25 +589,22 @@ static int tegra_i2c_mutex_lock(struct tegra_i2c_dev *i2c_dev)
return ret;
}
static int tegra_i2c_mutex_unlock(struct tegra_i2c_dev *i2c_dev)
static void tegra_i2c_mutex_unlock(struct tegra_i2c_dev *i2c_dev)
{
unsigned int reg = i2c_dev->hw->regs->sw_mutex;
u32 val, id;
if (!i2c_dev->hw->has_mutex)
return 0;
return;
val = readl(i2c_dev->base + reg);
id = FIELD_GET(I2C_SW_MUTEX_GRANT, val);
if (id && id != I2C_SW_MUTEX_ID_CCPLEX) {
dev_warn(i2c_dev->dev, "unable to unlock mutex, mutex is owned by: %u\n", id);
return -EPERM;
}
if (WARN(id && id != I2C_SW_MUTEX_ID_CCPLEX,
"unable to unlock mutex, mutex is owned by: %u\n", id))
return;
writel(0, i2c_dev->base + reg);
return 0;
}
static void tegra_i2c_mask_irq(struct tegra_i2c_dev *i2c_dev, u32 mask)
@@ -1666,8 +1663,10 @@ static int tegra_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[],
}
ret = tegra_i2c_mutex_lock(i2c_dev);
if (ret)
if (ret) {
pm_runtime_put(i2c_dev->dev);
return ret;
}
for (i = 0; i < num; i++) {
enum msg_end_type end_type = MSG_END_STOP;
@@ -1698,7 +1697,7 @@ static int tegra_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[],
break;
}
ret = tegra_i2c_mutex_unlock(i2c_dev);
tegra_i2c_mutex_unlock(i2c_dev);
pm_runtime_put(i2c_dev->dev);
return ret ?: i;
+1
View File
@@ -353,6 +353,7 @@ static s32 i2c_smbus_xfer_emulated(struct i2c_adapter *adapter, u16 addr,
&& size != I2C_SMBUS_I2C_BLOCK_DATA);
msgbuf0[0] = command;
msgbuf1[0] = 0;
switch (size) {
case I2C_SMBUS_QUICK:
msg[0].len = 0;
+87
View File
@@ -9,6 +9,7 @@
#include <linux/dma-resv.h>
#include "uverbs.h"
#include "core_priv.h"
#include "rdma_core.h"
MODULE_IMPORT_NS("DMA_BUF");
@@ -416,3 +417,89 @@ struct ib_device *rdma_udata_to_dev(struct ib_udata *udata)
}
EXPORT_SYMBOL(rdma_udata_to_dev);
#if IS_ENABLED(CONFIG_INFINIBAND_USER_ACCESS)
uverbs_api_ioctl_handler_fn uverbs_get_handler_fn(struct ib_udata *udata)
{
struct uverbs_attr_bundle *bundle =
rdma_udata_to_uverbs_attr_bundle(udata);
lockdep_assert_held(&bundle->ufile->device->disassociate_srcu);
return srcu_dereference(bundle->method_elm->handler,
&bundle->ufile->device->disassociate_srcu);
}
int _ib_copy_validate_udata_in(struct ib_udata *udata, void *req,
size_t kernel_size, size_t minimum_size)
{
int err;
if (udata->inlen < minimum_size) {
ibdev_dbg(
rdma_udata_to_dev(udata),
"System call driver input udata too small (%zu < %zu) for ioctl %ps called by %pSR\n",
udata->inlen, minimum_size,
uverbs_get_handler_fn(udata),
__builtin_return_address(0));
return -EINVAL;
}
err = copy_struct_from_user(req, kernel_size, udata->inbuf,
udata->inlen);
if (err) {
if (err == -E2BIG) {
ibdev_dbg(
rdma_udata_to_dev(udata),
"System call driver input udata not zero from %zu -> %zu for ioctl %ps called by %pSR\n",
minimum_size, udata->inlen,
uverbs_get_handler_fn(udata),
__builtin_return_address(0));
return -EOPNOTSUPP;
}
ibdev_dbg(
rdma_udata_to_dev(udata),
"System call driver input udata EFAULT for ioctl %ps called by %pSR\n",
uverbs_get_handler_fn(udata),
__builtin_return_address(0));
return err;
}
return 0;
}
EXPORT_SYMBOL(_ib_copy_validate_udata_in);
int _ib_copy_validate_udata_cm_fail(struct ib_udata *udata, u64 req_cm,
u64 valid_cm)
{
ibdev_dbg(
rdma_udata_to_dev(udata),
"System call driver input udata has unsupported comp_mask %llx & ~%llx = %llx for ioctl %ps called by %pSR\n",
req_cm, valid_cm, req_cm & ~valid_cm,
uverbs_get_handler_fn(udata), __builtin_return_address(0));
return -EOPNOTSUPP;
}
EXPORT_SYMBOL(_ib_copy_validate_udata_cm_fail);
int _ib_respond_udata(struct ib_udata *udata, const void *src, size_t len)
{
size_t copy_len;
/* 0 length copy_len is a NOP for copy_to_user() and doesn't fail. */
copy_len = min(len, udata->outlen);
if (copy_to_user(udata->outbuf, src, copy_len))
goto err_fault;
if (copy_len < udata->outlen) {
if (clear_user(udata->outbuf + copy_len,
udata->outlen - copy_len))
goto err_fault;
}
return 0;
err_fault:
ibdev_dbg(
rdma_udata_to_dev(udata),
"System call driver out udata has EFAULT (%zu into %zu) for ioctl %ps called by %pSR\n",
len, udata->outlen, uverbs_get_handler_fn(udata),
__builtin_return_address(0));
return -EFAULT;
}
EXPORT_SYMBOL(_ib_respond_udata);
#endif
+3
View File
@@ -51,6 +51,7 @@
* a controlled QKEY.
*/
static bool privileged_qkey;
static DEFINE_MUTEX(nldev_dellink_mutex);
typedef int (*res_fill_func_t)(struct sk_buff*, bool,
struct rdma_restrack_entry*, uint32_t);
@@ -1846,7 +1847,9 @@ static int nldev_dellink(struct sk_buff *skb, struct nlmsghdr *nlh,
* implicitly scoped to the driver supporting dynamic link deletion like RXE.
*/
if (device->link_ops && device->link_ops->dellink) {
mutex_lock(&nldev_dellink_mutex);
err = device->link_ops->dellink(device);
mutex_unlock(&nldev_dellink_mutex);
if (err)
return err;
}
+34
View File
@@ -229,6 +229,40 @@ int uverbs_dealloc_mw(struct ib_mw *mw);
void ib_uverbs_detach_umcast(struct ib_qp *qp,
struct ib_uqp_object *uobj);
struct bundle_alloc_head {
struct_group_tagged(bundle_alloc_head_hdr, hdr,
struct bundle_alloc_head *next;
);
u8 data[];
};
struct bundle_priv {
/* Must be first */
struct bundle_alloc_head_hdr alloc_head;
struct bundle_alloc_head *allocated_mem;
size_t internal_avail;
size_t internal_used;
struct radix_tree_root *radix;
void __rcu **radix_slots;
unsigned long radix_slots_len;
u32 method_key;
struct ib_uverbs_attr __user *user_attrs;
struct ib_uverbs_attr *uattrs;
DECLARE_BITMAP(uobj_finalize, UVERBS_API_ATTR_BKEY_LEN);
DECLARE_BITMAP(spec_finalize, UVERBS_API_ATTR_BKEY_LEN);
DECLARE_BITMAP(uobj_hw_obj_valid, UVERBS_API_ATTR_BKEY_LEN);
/*
* Must be last. bundle ends in a flex array which overlaps
* internal_buffer.
*/
struct uverbs_attr_bundle_hdr bundle;
u64 internal_buffer[32];
};
long ib_uverbs_ioctl(struct file *filp, unsigned int cmd, unsigned long arg);
struct ib_uverbs_flow_spec {
+14 -134
View File
@@ -35,54 +35,6 @@
#include "rdma_core.h"
#include "uverbs.h"
struct bundle_alloc_head {
struct_group_tagged(bundle_alloc_head_hdr, hdr,
struct bundle_alloc_head *next;
);
u8 data[];
};
struct bundle_priv {
/* Must be first */
struct bundle_alloc_head_hdr alloc_head;
struct bundle_alloc_head *allocated_mem;
size_t internal_avail;
size_t internal_used;
struct radix_tree_root *radix;
const struct uverbs_api_ioctl_method *method_elm;
void __rcu **radix_slots;
unsigned long radix_slots_len;
u32 method_key;
struct ib_uverbs_attr __user *user_attrs;
struct ib_uverbs_attr *uattrs;
DECLARE_BITMAP(uobj_finalize, UVERBS_API_ATTR_BKEY_LEN);
DECLARE_BITMAP(spec_finalize, UVERBS_API_ATTR_BKEY_LEN);
DECLARE_BITMAP(uobj_hw_obj_valid, UVERBS_API_ATTR_BKEY_LEN);
/*
* Must be last. bundle ends in a flex array which overlaps
* internal_buffer.
*/
struct uverbs_attr_bundle_hdr bundle;
u64 internal_buffer[32];
};
uverbs_api_ioctl_handler_fn uverbs_get_handler_fn(struct ib_udata *udata)
{
struct uverbs_attr_bundle *bundle =
rdma_udata_to_uverbs_attr_bundle(udata);
struct bundle_priv *pbundle =
container_of(&bundle->hdr, struct bundle_priv, bundle);
lockdep_assert_held(&bundle->ufile->device->disassociate_srcu);
return srcu_dereference(pbundle->method_elm->handler,
&bundle->ufile->device->disassociate_srcu);
}
/*
* Each method has an absolute minimum amount of memory it needs to allocate,
* precompute that amount and determine if the onstack memory can be used or
@@ -445,13 +397,13 @@ static int ib_uverbs_run_method(struct bundle_priv *pbundle,
struct uverbs_attr_bundle *bundle =
container_of(&pbundle->bundle, struct uverbs_attr_bundle, hdr);
size_t uattrs_size = array_size(sizeof(*pbundle->uattrs), num_attrs);
unsigned int destroy_bkey = pbundle->method_elm->destroy_bkey;
unsigned int destroy_bkey = bundle->method_elm->destroy_bkey;
unsigned int i;
int ret;
/* See uverbs_disassociate_api() */
handler = srcu_dereference(
pbundle->method_elm->handler,
bundle->method_elm->handler,
&pbundle->bundle.ufile->device->disassociate_srcu);
if (!handler)
return -EIO;
@@ -469,12 +421,12 @@ static int ib_uverbs_run_method(struct bundle_priv *pbundle,
}
/* User space did not provide all the mandatory attributes */
if (unlikely(!bitmap_subset(pbundle->method_elm->attr_mandatory,
if (unlikely(!bitmap_subset(bundle->method_elm->attr_mandatory,
pbundle->bundle.attr_present,
pbundle->method_elm->key_bitmap_len)))
bundle->method_elm->key_bitmap_len)))
return -EINVAL;
if (pbundle->method_elm->has_udata)
if (bundle->method_elm->has_udata)
uverbs_fill_udata(bundle, &pbundle->bundle.driver_udata,
UVERBS_ATTR_UHW_IN, UVERBS_ATTR_UHW_OUT);
else
@@ -499,7 +451,7 @@ static int ib_uverbs_run_method(struct bundle_priv *pbundle,
* assume that the driver wrote to its UHW_OUT and flag userspace
* appropriately.
*/
if (!ret && pbundle->method_elm->has_udata) {
if (!ret && bundle->method_elm->has_udata) {
const struct uverbs_attr *attr =
uverbs_attr_get(bundle, UVERBS_ATTR_UHW_OUT);
@@ -520,7 +472,7 @@ static int ib_uverbs_run_method(struct bundle_priv *pbundle,
static void bundle_destroy(struct bundle_priv *pbundle, bool commit)
{
unsigned int key_bitmap_len = pbundle->method_elm->key_bitmap_len;
unsigned int key_bitmap_len = pbundle->bundle.method_elm->key_bitmap_len;
struct uverbs_attr_bundle *bundle =
container_of(&pbundle->bundle, struct uverbs_attr_bundle, hdr);
struct bundle_alloc_head *memblock;
@@ -608,7 +560,7 @@ static int ib_uverbs_cmd_verbs(struct ib_uverbs_file *ufile,
}
/* Space for the pbundle->bundle.attrs flex array */
pbundle->method_elm = method_elm;
pbundle->bundle.method_elm = method_elm;
pbundle->method_key = attrs_iter.index;
pbundle->bundle.ufile = ufile;
pbundle->bundle.context = NULL; /* only valid if bundle has uobject */
@@ -617,10 +569,12 @@ static int ib_uverbs_cmd_verbs(struct ib_uverbs_file *ufile,
pbundle->radix_slots_len = radix_tree_chunk_size(&attrs_iter);
pbundle->user_attrs = user_attrs;
pbundle->internal_used = ALIGN(pbundle->method_elm->key_bitmap_len *
sizeof(*container_of(&pbundle->bundle,
struct uverbs_attr_bundle, hdr)->attrs),
sizeof(*pbundle->internal_buffer));
pbundle->internal_used = ALIGN(
pbundle->bundle.method_elm->key_bitmap_len *
sizeof(*container_of(&pbundle->bundle,
struct uverbs_attr_bundle, hdr)
->attrs),
sizeof(*pbundle->internal_buffer));
memset(pbundle->bundle.attr_present, 0,
sizeof(pbundle->bundle.attr_present));
memset(pbundle->uobj_finalize, 0, sizeof(pbundle->uobj_finalize));
@@ -860,77 +814,3 @@ void uverbs_finalize_uobj_create(const struct uverbs_attr_bundle *bundle,
pbundle->uobj_hw_obj_valid);
}
EXPORT_SYMBOL(uverbs_finalize_uobj_create);
int _ib_copy_validate_udata_in(struct ib_udata *udata, void *req,
size_t kernel_size, size_t minimum_size)
{
int err;
if (udata->inlen < minimum_size) {
ibdev_dbg(
rdma_udata_to_dev(udata),
"System call driver input udata too small (%zu < %zu) for ioctl %ps called by %pSR\n",
udata->inlen, minimum_size,
uverbs_get_handler_fn(udata),
__builtin_return_address(0));
return -EINVAL;
}
err = copy_struct_from_user(req, kernel_size, udata->inbuf,
udata->inlen);
if (err) {
if (err == -E2BIG) {
ibdev_dbg(
rdma_udata_to_dev(udata),
"System call driver input udata not zero from %zu -> %zu for ioctl %ps called by %pSR\n",
minimum_size, udata->inlen,
uverbs_get_handler_fn(udata),
__builtin_return_address(0));
return -EOPNOTSUPP;
}
ibdev_dbg(
rdma_udata_to_dev(udata),
"System call driver input udata EFAULT for ioctl %ps called by %pSR\n",
uverbs_get_handler_fn(udata),
__builtin_return_address(0));
return err;
}
return 0;
}
EXPORT_SYMBOL(_ib_copy_validate_udata_in);
int _ib_copy_validate_udata_cm_fail(struct ib_udata *udata, u64 req_cm,
u64 valid_cm)
{
ibdev_dbg(
rdma_udata_to_dev(udata),
"System call driver input udata has unsupported comp_mask %llx & ~%llx = %llx for ioctl %ps called by %pSR\n",
req_cm, valid_cm, req_cm & ~valid_cm,
uverbs_get_handler_fn(udata), __builtin_return_address(0));
return -EOPNOTSUPP;
}
EXPORT_SYMBOL(_ib_copy_validate_udata_cm_fail);
int _ib_respond_udata(struct ib_udata *udata, const void *src, size_t len)
{
size_t copy_len;
/* 0 length copy_len is a NOP for copy_to_user() and doesn't fail. */
copy_len = min(len, udata->outlen);
if (copy_to_user(udata->outbuf, src, copy_len))
goto err_fault;
if (copy_len < udata->outlen) {
if (clear_user(udata->outbuf + copy_len,
udata->outlen - copy_len))
goto err_fault;
}
return 0;
err_fault:
ibdev_dbg(
rdma_udata_to_dev(udata),
"System call driver out udata has EFAULT (%zu into %zu) for ioctl %ps called by %pSR\n",
len, udata->outlen, uverbs_get_handler_fn(udata),
__builtin_return_address(0));
return -EFAULT;
}
EXPORT_SYMBOL(_ib_respond_udata);
+1 -1
View File
@@ -4638,7 +4638,7 @@ int bnxt_re_alloc_ucontext(struct ib_ucontext *ctx, struct ib_udata *udata)
uctx->rdev = rdev;
uctx->shpg = (void *)__get_free_page(GFP_KERNEL);
uctx->shpg = (void *)get_zeroed_page(GFP_KERNEL);
if (!uctx->shpg) {
rc = -ENOMEM;
goto fail;
+1
View File
@@ -606,6 +606,7 @@ int mana_ib_query_port(struct ib_device *ibdev, u32 port,
if (mana_ib_is_rnic(dev)) {
props->gid_tbl_len = 16;
props->ip_gids = true;
props->max_msg_sz = SZ_16M;
if (port == 1)
props->port_cap_flags = IB_PORT_CM_SUP;
}
+15
View File
@@ -1081,6 +1081,21 @@ static int siw_get_hdr(struct siw_rx_stream *srx)
return -EAGAIN;
}
/*
* Peer-controlled mpa_len must not underflow srx->fpdu_part_rem
* in siw_tcp_rx_data(); a negative value flows as a signed copy
* length into siw_check_mem() and skb_copy_bits().
*/
if (unlikely(be16_to_cpu(c_hdr->mpa_len) + MPA_HDR_SIZE <
iwarp_pktinfo[opcode].hdr_len)) {
pr_warn_ratelimited("siw: short mpa_len %u for opcode %u (hdr_len %u)\n",
be16_to_cpu(c_hdr->mpa_len), opcode,
iwarp_pktinfo[opcode].hdr_len);
siw_init_terminate(rx_qp(srx), TERM_ERROR_LAYER_LLP,
LLP_ETYPE_MPA, LLP_ECODE_FPDU_START, 0);
return -EINVAL;
}
/*
* DDP/RDMAP header receive completed. Check if the current
* DDP segment starts a new RDMAP message or continues a previously
+1 -1
View File
@@ -295,8 +295,8 @@ remove_group:
put_kobj:
kobject_del(&srv_path->kobj);
destroy_root:
kobject_put(&srv_path->kobj);
rtrs_srv_destroy_once_sysfs_root_folders(srv_path);
kobject_put(&srv_path->kobj);
return err;
}
+3 -1
View File
@@ -1246,7 +1246,9 @@ static struct btrfs_inode *find_first_inode_to_shrink(struct btrfs_root *root,
write_unlock(&tree->lock);
next:
from = btrfs_ino(inode) + 1;
cond_resched_lock(&root->inodes.xa_lock);
xa_unlock(&root->inodes);
cond_resched();
xa_lock(&root->inodes);
}
xa_unlock(&root->inodes);
+8 -3
View File
@@ -633,7 +633,7 @@ again:
trans->transid);
btrfs_set_file_extent_num_bytes(leaf, fi,
end - other_start);
return 0;
goto mark_dirty;
}
}
@@ -661,7 +661,7 @@ again:
other_end - start);
btrfs_set_file_extent_offset(leaf, fi,
start - orig_offset);
return 0;
goto mark_dirty;
}
}
@@ -788,7 +788,12 @@ again:
}
}
return 0;
mark_dirty:
ret = btrfs_inode_set_file_extent_range(inode, start, end - start);
if (ret)
btrfs_abort_transaction(trans, ret);
return ret;
}
/*
+1
View File
@@ -155,6 +155,7 @@ enum {
BTRFS_FS_LOG_RECOVERING,
BTRFS_FS_OPEN,
BTRFS_FS_QUOTA_ENABLED,
BTRFS_FS_SQUOTA_ENABLING,
BTRFS_FS_UPDATE_UUID_TREE_GEN,
BTRFS_FS_CREATING_FREE_SPACE_TREE,
BTRFS_FS_BTREE_ERR,
+3 -1
View File
@@ -10699,7 +10699,9 @@ struct btrfs_inode *btrfs_find_first_inode(struct btrfs_root *root, u64 min_ino)
break;
from = btrfs_ino(inode) + 1;
cond_resched_lock(&root->inodes.xa_lock);
xa_unlock(&root->inodes);
cond_resched();
xa_lock(&root->inodes);
}
xa_unlock(&root->inodes);
+68 -33
View File
@@ -1107,7 +1107,13 @@ int btrfs_quota_enable(struct btrfs_fs_info *fs_info,
if (simple) {
fs_info->qgroup_flags |= BTRFS_QGROUP_STATUS_FLAG_SIMPLE_MODE;
btrfs_set_fs_incompat(fs_info, SIMPLE_QUOTA);
btrfs_set_qgroup_status_enable_gen(leaf, ptr, trans->transid);
/*
* Set the enable generation to the next transaction, as we cannot
* ensure that extents written during this transaction will see any
* state we have set here. So we should treat all extents of the
* transaction as coming in before squotas was enabled.
*/
btrfs_set_qgroup_status_enable_gen(leaf, ptr, trans->transid + 1);
} else {
fs_info->qgroup_flags |= BTRFS_QGROUP_STATUS_FLAG_INCONSISTENT;
}
@@ -1210,7 +1216,15 @@ out_add_root:
goto out_free_path;
}
fs_info->qgroup_enable_gen = trans->transid;
/*
* Set fs_info->qgroup_enable_gen and BTRFS_FS_SQUOTA_ENABLING
* under the transaction handle. We want to ensure that all extents in
* the next transaction definitely see them.
*/
if (simple) {
fs_info->qgroup_enable_gen = trans->transid + 1;
set_bit(BTRFS_FS_SQUOTA_ENABLING, &fs_info->flags);
}
mutex_unlock(&fs_info->qgroup_ioctl_lock);
/*
@@ -1224,9 +1238,15 @@ out_add_root:
*/
ret = btrfs_commit_transaction(trans);
trans = NULL;
mutex_lock(&fs_info->qgroup_ioctl_lock);
if (ret)
if (ret) {
if (simple) {
clear_bit(BTRFS_FS_SQUOTA_ENABLING, &fs_info->flags);
fs_info->qgroup_enable_gen = 0;
}
goto out_free_path;
}
/*
* Set quota enabled flag after committing the transaction, to avoid
@@ -1236,6 +1256,8 @@ out_add_root:
spin_lock(&fs_info->qgroup_lock);
fs_info->quota_root = quota_root;
set_bit(BTRFS_FS_QUOTA_ENABLED, &fs_info->flags);
if (simple)
clear_bit(BTRFS_FS_SQUOTA_ENABLING, &fs_info->flags);
spin_unlock(&fs_info->qgroup_lock);
/* Skip rescan for simple qgroups. */
@@ -1715,32 +1737,24 @@ out:
return ret;
}
static bool can_delete_parent_qgroup(struct btrfs_qgroup *qgroup)
static bool can_delete_parent_qgroup(struct btrfs_fs_info *fs_info, struct btrfs_qgroup *qgroup)
{
ASSERT(btrfs_qgroup_level(qgroup->qgroupid));
if (btrfs_qgroup_mode(fs_info) == BTRFS_QGROUP_MODE_SIMPLE)
squota_check_parent_usage(fs_info, qgroup);
return list_empty(&qgroup->members);
}
/*
* Return true if we can delete the squota qgroup and false otherwise.
*
* Rules for whether we can delete:
*
* A subvolume qgroup can be removed iff the subvolume is fully deleted, which
* is iff there is 0 usage in the qgroup.
*
* A higher level qgroup can be removed iff it has no members.
* Note: We audit its usage to warn on inconsitencies without blocking deletion.
* Because a shared extent can outlive its owning subvolume, we cannot delete a
* subvol squota qgroup until all of the extents it owns are gone, even if the
* subvolume itself has been deleted.
*/
static bool can_delete_squota_qgroup(struct btrfs_fs_info *fs_info, struct btrfs_qgroup *qgroup)
static bool can_delete_squota_subvol_qgroup(struct btrfs_fs_info *fs_info,
struct btrfs_qgroup *qgroup)
{
ASSERT(btrfs_qgroup_mode(fs_info) == BTRFS_QGROUP_MODE_SIMPLE);
if (btrfs_qgroup_level(qgroup->qgroupid) > 0) {
squota_check_parent_usage(fs_info, qgroup);
return can_delete_parent_qgroup(qgroup);
}
ASSERT(btrfs_qgroup_level(qgroup->qgroupid) == 0);
return !(qgroup->rfer || qgroup->excl || qgroup->rfer_cmpr || qgroup->excl_cmpr);
}
@@ -1754,14 +1768,11 @@ static int can_delete_qgroup(struct btrfs_fs_info *fs_info, struct btrfs_qgroup
{
struct btrfs_key key;
BTRFS_PATH_AUTO_FREE(path);
/* Since squotas cannot be inconsistent, they have special rules for deletion. */
if (btrfs_qgroup_mode(fs_info) == BTRFS_QGROUP_MODE_SIMPLE)
return can_delete_squota_qgroup(fs_info, qgroup);
int ret;
/* For higher level qgroup, we can only delete it if it has no child. */
if (btrfs_qgroup_level(qgroup->qgroupid))
return can_delete_parent_qgroup(qgroup);
return can_delete_parent_qgroup(fs_info, qgroup);
/*
* For level-0 qgroups, we can only delete it if it has no subvolume
@@ -1777,10 +1788,21 @@ static int can_delete_qgroup(struct btrfs_fs_info *fs_info, struct btrfs_qgroup
return -ENOMEM;
/*
* The @ret from btrfs_find_root() exactly matches our definition for
* the return value, thus can be returned directly.
* Any subvol qgroup, regardless of mode, cannot be deleted if the
* subvol still exists.
*/
return btrfs_find_root(fs_info->tree_root, &key, path, NULL, NULL);
ret = btrfs_find_root(fs_info->tree_root, &key, path, NULL, NULL);
/*
* btrfs_find_root returns <0 on error, 0 if found, and >0 if not,
* so the "found" and "error" cases match our desired return values.
*/
if (ret <= 0)
return ret;
/* Squotas require additional checks, even if the subvol is deleted. */
if (btrfs_qgroup_mode(fs_info) == BTRFS_QGROUP_MODE_SIMPLE)
return can_delete_squota_subvol_qgroup(fs_info, qgroup);
return 1;
}
int btrfs_remove_qgroup(struct btrfs_trans_handle *trans, u64 qgroupid)
@@ -4922,7 +4944,8 @@ int btrfs_record_squota_delta(struct btrfs_fs_info *fs_info,
u64 num_bytes = delta->num_bytes;
const int sign = (delta->is_inc ? 1 : -1);
if (btrfs_qgroup_mode(fs_info) != BTRFS_QGROUP_MODE_SIMPLE)
if (btrfs_qgroup_mode(fs_info) != BTRFS_QGROUP_MODE_SIMPLE &&
!test_bit(BTRFS_FS_SQUOTA_ENABLING, &fs_info->flags))
return 0;
if (!btrfs_is_fstree(root))
@@ -4934,8 +4957,9 @@ int btrfs_record_squota_delta(struct btrfs_fs_info *fs_info,
spin_lock(&fs_info->qgroup_lock);
qgroup = find_qgroup_rb(fs_info, root);
if (!qgroup) {
ret = -ENOENT;
if (WARN_ON_ONCE(!qgroup)) {
btrfs_warn(fs_info, "squota failed to find qgroup for root %llu", root);
ret = 0;
goto out;
}
@@ -4944,8 +4968,19 @@ int btrfs_record_squota_delta(struct btrfs_fs_info *fs_info,
list_for_each_entry(qg, &qgroup_list, iterator) {
struct btrfs_qgroup_list *glist;
qg->excl += num_bytes * sign;
qg->rfer += num_bytes * sign;
ASSERT(qg->excl == qg->rfer);
if (WARN_ON_ONCE(sign < 0 && qg->excl < num_bytes)) {
btrfs_warn(fs_info,
"squota underflow qg %hu/%llu excl %llu num_bytes %llu",
btrfs_qgroup_level(qg->qgroupid),
btrfs_qgroup_subvolid(qg->qgroupid),
qg->excl, num_bytes);
qg->excl = 0;
qg->rfer = 0;
} else {
qg->excl += num_bytes * sign;
qg->rfer += num_bytes * sign;
}
qgroup_dirty(fs_info, qg);
list_for_each_entry(glist, &qg->groups, next_group)
+13 -2
View File
@@ -3804,8 +3804,19 @@ err_out2:
ksmbd_debug(SMB, "Error response: %x\n", rsp->hdr.Status);
}
if (dh_info.reconnected)
ksmbd_put_durable_fd(dh_info.fp);
if (dh_info.reconnected) {
/*
* If reconnect succeeded, fp was republished in the
* session file table. On a later error, ksmbd_fd_put()
* above drops the session reference; drop the durable
* lookup reference through the same session-aware path so
* final close removes the volatile id before freeing fp.
*/
if (rc && fp == dh_info.fp)
ksmbd_fd_put(work, dh_info.fp);
else
ksmbd_put_durable_fd(dh_info.fp);
}
kfree(name);
kfree(lc);
+50 -16
View File
@@ -1096,6 +1096,40 @@ static int smb_append_inherited_ace(struct smb_ace **ace, int *nt_size,
return 0;
}
static int smb_validate_ntsd_sid(struct smb_ntsd *pntsd, size_t pntsd_size,
unsigned int sid_offset, struct smb_sid **sid,
size_t *sid_size)
{
size_t sid_end;
*sid = NULL;
*sid_size = 0;
if (!sid_offset)
return 0;
if (sid_offset < sizeof(struct smb_ntsd) ||
check_add_overflow(sid_offset, (size_t)CIFS_SID_BASE_SIZE,
&sid_end) ||
sid_end > pntsd_size)
return -EINVAL;
*sid = (struct smb_sid *)((char *)pntsd + sid_offset);
if ((*sid)->num_subauth > SID_MAX_SUB_AUTHORITIES)
return -EINVAL;
if (check_add_overflow((size_t)CIFS_SID_BASE_SIZE,
sizeof(__le32) * (size_t)(*sid)->num_subauth,
&sid_end))
return -EINVAL;
if (sid_offset > pntsd_size || sid_end > pntsd_size - sid_offset)
return -EINVAL;
*sid_size = sid_end;
return 0;
}
int smb_inherit_dacl(struct ksmbd_conn *conn,
const struct path *path,
unsigned int uid, unsigned int gid)
@@ -1108,28 +1142,28 @@ int smb_inherit_dacl(struct ksmbd_conn *conn,
struct dentry *parent = path->dentry->d_parent;
struct mnt_idmap *idmap = mnt_idmap(path->mnt);
int inherited_flags = 0, flags = 0, i, nt_size = 0, pdacl_size;
int rc = 0, pntsd_type, pntsd_size, acl_len, aces_size;
int rc = 0, pntsd_type, ppntsd_size, acl_len, aces_size;
unsigned int dacloffset;
size_t dacl_struct_end;
u16 num_aces, ace_cnt = 0;
char *aces_base;
bool is_dir = S_ISDIR(d_inode(path->dentry)->i_mode);
pntsd_size = ksmbd_vfs_get_sd_xattr(conn, idmap,
ppntsd_size = ksmbd_vfs_get_sd_xattr(conn, idmap,
parent, &parent_pntsd);
if (pntsd_size <= 0)
if (ppntsd_size <= 0)
return -ENOENT;
dacloffset = le32_to_cpu(parent_pntsd->dacloffset);
if (!dacloffset ||
check_add_overflow(dacloffset, sizeof(struct smb_acl), &dacl_struct_end) ||
dacl_struct_end > (size_t)pntsd_size) {
dacl_struct_end > (size_t)ppntsd_size) {
rc = -EINVAL;
goto free_parent_pntsd;
}
parent_pdacl = (struct smb_acl *)((char *)parent_pntsd + dacloffset);
acl_len = pntsd_size - dacloffset;
acl_len = ppntsd_size - dacloffset;
num_aces = le16_to_cpu(parent_pdacl->num_aces);
pntsd_type = le16_to_cpu(parent_pntsd->type);
pdacl_size = le16_to_cpu(parent_pdacl->size);
@@ -1243,19 +1277,19 @@ pass:
struct smb_ntsd *pntsd;
struct smb_acl *pdacl;
struct smb_sid *powner_sid = NULL, *pgroup_sid = NULL;
int powner_sid_size = 0, pgroup_sid_size = 0, pntsd_size;
size_t powner_sid_size = 0, pgroup_sid_size = 0, pntsd_size;
size_t pntsd_alloc_size;
if (parent_pntsd->osidoffset) {
powner_sid = (struct smb_sid *)((char *)parent_pntsd +
le32_to_cpu(parent_pntsd->osidoffset));
powner_sid_size = 1 + 1 + 6 + (powner_sid->num_subauth * 4);
}
if (parent_pntsd->gsidoffset) {
pgroup_sid = (struct smb_sid *)((char *)parent_pntsd +
le32_to_cpu(parent_pntsd->gsidoffset));
pgroup_sid_size = 1 + 1 + 6 + (pgroup_sid->num_subauth * 4);
}
rc = smb_validate_ntsd_sid(parent_pntsd, ppntsd_size,
le32_to_cpu(parent_pntsd->osidoffset),
&powner_sid, &powner_sid_size);
if (rc)
goto free_aces_base;
rc = smb_validate_ntsd_sid(parent_pntsd, ppntsd_size,
le32_to_cpu(parent_pntsd->gsidoffset),
&pgroup_sid, &pgroup_sid_size);
if (rc)
goto free_aces_base;
if (check_add_overflow(sizeof(struct smb_ntsd),
(size_t)powner_sid_size,
+12 -4
View File
@@ -211,7 +211,7 @@ int ksmbd_query_inode_status(struct dentry *dentry)
return ret;
down_read(&ci->m_lock);
if (ci->m_flags & (S_DEL_PENDING | S_DEL_ON_CLS))
if (ci->m_flags & S_DEL_PENDING)
ret = KSMBD_INODE_STATUS_PENDING_DELETE;
else
ret = KSMBD_INODE_STATUS_OK;
@@ -227,7 +227,7 @@ bool ksmbd_inode_pending_delete(struct ksmbd_file *fp)
int ret;
down_read(&ci->m_lock);
ret = (ci->m_flags & (S_DEL_PENDING | S_DEL_ON_CLS));
ret = (ci->m_flags & S_DEL_PENDING);
up_read(&ci->m_lock);
return ret;
@@ -395,12 +395,20 @@ static void __ksmbd_inode_close(struct ksmbd_file *fp)
}
}
down_write(&ci->m_lock);
/* Promote S_DEL_ON_CLS to S_DEL_PENDING when close */
if (ci->m_flags & S_DEL_ON_CLS) {
ci->m_flags &= ~S_DEL_ON_CLS;
ci->m_flags |= S_DEL_PENDING;
}
up_write(&ci->m_lock);
if (atomic_dec_and_test(&ci->m_count)) {
bool do_unlink = false;
down_write(&ci->m_lock);
if (ci->m_flags & (S_DEL_ON_CLS | S_DEL_PENDING)) {
ci->m_flags &= ~(S_DEL_ON_CLS | S_DEL_PENDING);
if (ci->m_flags & S_DEL_PENDING) {
ci->m_flags &= ~S_DEL_PENDING;
do_unlink = true;
}
up_write(&ci->m_lock);
+1 -1
View File
@@ -188,7 +188,7 @@ static int internal_create_group(struct kobject *kobj, int update,
kernfs_get(kn);
error = create_files(kn, kobj, uid, gid, grp, update);
if (error) {
if (grp->name)
if (grp->name && !update)
kernfs_remove(kn);
}
kernfs_put(kn);
+24 -10
View File
@@ -472,6 +472,7 @@ xfs_buf_find_insert(
/* The new buffer keeps the perag reference until it is freed. */
new_bp->b_pag = pag;
retry:
rcu_read_lock();
bp = rhashtable_lookup_get_insert_fast(&btp->bt_hash,
&new_bp->b_rhash_head, xfs_buf_hash_params);
@@ -480,8 +481,16 @@ xfs_buf_find_insert(
error = PTR_ERR(bp);
goto out_free_buf;
}
if (bp && lockref_get_not_dead(&bp->b_lockref)) {
/* found an existing buffer */
if (bp) {
/*
* If there is an existing buffer with a dead lockref, retry
* until the new buffer is added, or a usable buffer is found.
*/
if (!lockref_get_not_dead(&bp->b_lockref)) {
rcu_read_unlock();
cpu_relax();
goto retry;
}
rcu_read_unlock();
error = xfs_buf_find_lock(bp, flags);
if (error)
@@ -820,15 +829,20 @@ xfs_buf_destroy(
ASSERT(__lockref_is_dead(&bp->b_lockref));
ASSERT(!(bp->b_flags & _XBF_DELWRI_Q));
if (bp->b_pag)
xfs_perag_put(bp->b_pag);
xfs_buf_free(bp);
}
static inline void
xfs_buf_kill(
struct xfs_buf *bp)
{
lockref_mark_dead(&bp->b_lockref);
if (!xfs_buf_is_uncached(bp)) {
rhashtable_remove_fast(&bp->b_target->bt_hash,
&bp->b_rhash_head, xfs_buf_hash_params);
if (bp->b_pag)
xfs_perag_put(bp->b_pag);
}
xfs_buf_free(bp);
}
/*
@@ -851,7 +865,7 @@ xfs_buf_rele(
return;
kill:
lockref_mark_dead(&bp->b_lockref);
xfs_buf_kill(bp);
list_lru_del_obj(&bp->b_target->bt_lru, &bp->b_lru);
spin_unlock(&bp->b_lockref.lock);
@@ -1433,7 +1447,7 @@ xfs_buftarg_drain_rele(
return LRU_SKIP;
}
lockref_mark_dead(&bp->b_lockref);
xfs_buf_kill(bp);
list_lru_isolate_move(lru, item, dispose);
spin_unlock(&bp->b_lockref.lock);
return LRU_REMOVED;
@@ -1545,7 +1559,7 @@ xfs_buftarg_isolate(
return LRU_ROTATE;
}
lockref_mark_dead(&bp->b_lockref);
xfs_buf_kill(bp);
list_lru_isolate_move(lru, item, dispose);
spin_unlock(&bp->b_lockref.lock);
return LRU_REMOVED;
+7 -1
View File
@@ -2917,7 +2917,13 @@ int bpf_check_uarg_tail_zero(bpfptr_t uaddr, size_t expected_size,
int bpf_check(struct bpf_prog **fp, union bpf_attr *attr, bpfptr_t uattr, u32 uattr_size);
#ifndef CONFIG_BPF_JIT_ALWAYS_ON
void bpf_patch_call_args(struct bpf_insn *insn, u32 stack_depth);
int bpf_patch_call_args(struct bpf_insn *insn, u32 stack_depth);
s32 bpf_call_args_imm(s16 idx);
#else
static inline s32 bpf_call_args_imm(s16 idx)
{
return 0;
}
#endif
struct btf *bpf_get_btf_vmlinux(void);
+2
View File
@@ -729,6 +729,7 @@ struct bpf_subprog_info {
*/
s16 fastcall_stack_off;
bool has_tail_call: 1;
bool might_throw: 1;
bool tail_call_reachable: 1;
bool has_ld_abs: 1;
bool is_cb: 1;
@@ -1308,6 +1309,7 @@ void bpf_fmt_stack_mask(char *buf, ssize_t buf_sz, u64 stack_mask);
bool bpf_subprog_is_global(const struct bpf_verifier_env *env, int subprog);
int bpf_find_subprog(struct bpf_verifier_env *env, int off);
bool bpf_is_throw_kfunc(struct bpf_insn *insn);
int bpf_compute_const_regs(struct bpf_verifier_env *env);
int bpf_prune_dead_branches(struct bpf_verifier_env *env);
int bpf_check_cfg(struct bpf_verifier_env *env);
-3
View File
@@ -1151,9 +1151,6 @@ bool sk_filter_charge(struct sock *sk, struct sk_filter *fp);
void sk_filter_uncharge(struct sock *sk, struct sk_filter *fp);
u64 __bpf_call_base(u64 r1, u64 r2, u64 r3, u64 r4, u64 r5);
#define __bpf_call_base_args \
((u64 (*)(u64, u64, u64, u64, u64, const struct bpf_insn *)) \
(void *)__bpf_call_base)
struct bpf_prog *bpf_int_jit_compile(struct bpf_verifier_env *env, struct bpf_prog *prog);
void bpf_jit_compile(struct bpf_prog *prog);
+1
View File
@@ -208,6 +208,7 @@ struct fwnode_operations {
static inline void fwnode_init(struct fwnode_handle *fwnode,
const struct fwnode_operations *ops)
{
fwnode->secondary = NULL;
fwnode->ops = ops;
INIT_LIST_HEAD(&fwnode->consumers);
INIT_LIST_HEAD(&fwnode->suppliers);
+1
View File
@@ -635,6 +635,7 @@ struct uverbs_attr_bundle {
struct ib_uverbs_file *ufile;
struct ib_ucontext *context;
struct ib_uobject *uobject;
const struct uverbs_api_ioctl_method *method_elm;
DECLARE_BITMAP(attr_present, UVERBS_API_ATTR_BKEY_LEN);
);
struct uverbs_attr attrs[];
+1 -1
View File
@@ -827,7 +827,7 @@ const struct bpf_map_ops array_map_ops = {
};
const struct bpf_map_ops percpu_array_map_ops = {
.map_meta_equal = bpf_map_meta_equal,
.map_meta_equal = array_map_meta_equal,
.map_alloc_check = array_map_alloc_check,
.map_alloc = array_map_alloc,
.map_free = array_map_free,
+12 -1
View File
@@ -64,11 +64,19 @@ static void mark_subprog_might_sleep(struct bpf_verifier_env *env, int off)
subprog->might_sleep = true;
}
static void mark_subprog_might_throw(struct bpf_verifier_env *env, int off)
{
struct bpf_subprog_info *subprog;
subprog = bpf_find_containing_subprog(env, off);
subprog->might_throw = true;
}
/* 't' is an index of a call-site.
* 'w' is a callee entry point.
* Eventually this function would be called when env->cfg.insn_state[w] == EXPLORED.
* Rely on DFS traversal order and absence of recursive calls to guarantee that
* callee's change_pkt_data marks would be correct at that moment.
* callee's effect marks would be correct at that moment.
*/
static void merge_callee_effects(struct bpf_verifier_env *env, int t, int w)
{
@@ -78,6 +86,7 @@ static void merge_callee_effects(struct bpf_verifier_env *env, int t, int w)
callee = bpf_find_containing_subprog(env, w);
caller->changes_pkt_data |= callee->changes_pkt_data;
caller->might_sleep |= callee->might_sleep;
caller->might_throw |= callee->might_throw;
}
enum {
@@ -509,6 +518,8 @@ static int visit_insn(int t, struct bpf_verifier_env *env)
mark_subprog_might_sleep(env, t);
if (ret == 0 && bpf_is_kfunc_pkt_changing(&meta))
mark_subprog_changes_pkt_data(env, t);
if (ret == 0 && bpf_is_throw_kfunc(insn))
mark_subprog_might_throw(env, t);
}
return visit_func_call_insn(t, insns, env, insn->src_reg == BPF_PSEUDO_CALL);
+19 -8
View File
@@ -1771,6 +1771,9 @@ static u32 abs_s32(s32 x)
return x >= 0 ? (u32)x : -(u32)x;
}
static u64 (*interpreters_args[])(u64 r1, u64 r2, u64 r3, u64 r4, u64 r5,
const struct bpf_insn *insn);
/**
* ___bpf_prog_run - run eBPF program on a given context
* @regs: is the array of MAX_BPF_EXT_REG eBPF pseudo-registers
@@ -2077,10 +2080,9 @@ select_insn:
CONT;
JMP_CALL_ARGS:
BPF_R0 = (__bpf_call_base_args + insn->imm)(BPF_R1, BPF_R2,
BPF_R3, BPF_R4,
BPF_R5,
insn + insn->off + 1);
BPF_R0 = interpreters_args[insn->off](BPF_R1, BPF_R2, BPF_R3,
BPF_R4, BPF_R5,
insn + insn->imm + 1);
CONT;
JMP_TAIL_CALL: {
@@ -2394,13 +2396,22 @@ EVAL4(PROG_NAME_LIST, 416, 448, 480, 512)
#undef PROG_NAME_LIST
#ifdef CONFIG_BPF_SYSCALL
void bpf_patch_call_args(struct bpf_insn *insn, u32 stack_depth)
int bpf_patch_call_args(struct bpf_insn *insn, u32 stack_depth)
{
stack_depth = max_t(u32, stack_depth, 1);
insn->off = (s16) insn->imm;
insn->imm = interpreters_args[(round_up(stack_depth, 32) / 32) - 1] -
__bpf_call_base_args;
/* Prevent out-of-bounds read to interpreters_args */
if (stack_depth > MAX_BPF_STACK)
return -EINVAL;
insn->off = (round_up(stack_depth, 32) / 32) - 1;
insn->code = BPF_JMP | BPF_CALL_ARGS;
return 0;
}
s32 bpf_call_args_imm(s16 idx)
{
if (WARN_ON_ONCE(idx < 0 || idx >= ARRAY_SIZE(interpreters_args)))
return 0;
return BPF_CALL_IMM(interpreters_args[idx]);
}
#endif
#endif
+9 -4
View File
@@ -1250,9 +1250,9 @@ static int jit_subprogs(struct bpf_verifier_env *env)
}
if (!bpf_pseudo_call(insn))
continue;
insn->off = env->insn_aux_data[i].call_imm;
subprog = bpf_find_subprog(env, i + insn->off + 1);
insn->imm = subprog;
insn->imm = env->insn_aux_data[i].call_imm;
subprog = bpf_find_subprog(env, i + insn->imm + 1);
insn->off = subprog;
}
prog->jited = 1;
@@ -1416,7 +1416,12 @@ int bpf_fixup_call_args(struct bpf_verifier_env *env)
depth = get_callee_stack_depth(env, insn, i);
if (depth < 0)
return depth;
bpf_patch_call_args(insn, depth);
err = bpf_patch_call_args(insn, depth);
if (err) {
verbose(env, "stack depth %d exceeds interpreter stack depth limit\n",
depth);
return err;
}
}
err = 0;
#endif
+5
View File
@@ -4241,8 +4241,13 @@ __bpf_kfunc int bpf_verify_pkcs7_signature(struct bpf_dynptr *data_p,
data_len = __bpf_dynptr_size(data_ptr);
data = __bpf_dynptr_data(data_ptr, data_len);
if (!data)
return -EINVAL;
sig_len = __bpf_dynptr_size(sig_ptr);
sig = __bpf_dynptr_data(sig_ptr, sig_len);
if (!sig)
return -EINVAL;
return verify_pkcs7_signature(data, data_len, sig, sig_len,
trusted_keyring->key,
+26
View File
@@ -4921,6 +4921,29 @@ out:
return map;
}
static void prepare_dump_pseudo_call(struct bpf_insn *insn)
{
s32 call_off = insn->imm;
/*
* BPF_CALL_ARGS only exists for interpreter fallback.
* 1. For interpreter (BPF_CALL_ARGS): insn->off is the index of
* interpreters_args array, so here using bpf_call_args_imm()
* to get the real address offset.
* 2. For JIT (BPF_CALL): insn->off is the subprog id.
*/
if (insn->code == (BPF_JMP | BPF_CALL_ARGS))
insn->imm = bpf_call_args_imm(insn->off);
else
insn->imm = insn->off;
/* Avoid dumping a truncated and misleading pc-relative offset. */
if (call_off > S16_MAX || call_off < S16_MIN)
insn->off = 0;
else
insn->off = call_off;
}
static struct bpf_insn *bpf_insn_prepare_dump(const struct bpf_prog *prog,
const struct cred *f_cred)
{
@@ -4946,6 +4969,9 @@ static struct bpf_insn *bpf_insn_prepare_dump(const struct bpf_prog *prog,
}
if (code == (BPF_JMP | BPF_CALL) ||
code == (BPF_JMP | BPF_CALL_ARGS)) {
/* Restore the legacy xlated dump layout. */
if (insns[i].src_reg == BPF_PSEUDO_CALL)
prepare_dump_pseudo_call(&insns[i]);
if (code == (BPF_JMP | BPF_CALL_ARGS))
insns[i].code = BPF_JMP | BPF_CALL;
if (!bpf_dump_raw_ok(f_cred))
+21 -6
View File
@@ -442,7 +442,6 @@ static bool is_dynptr_ref_function(enum bpf_func_id func_id)
static bool is_sync_callback_calling_kfunc(u32 btf_id);
static bool is_async_callback_calling_kfunc(u32 btf_id);
static bool is_callback_calling_kfunc(u32 btf_id);
static bool is_bpf_throw_kfunc(struct bpf_insn *insn);
static bool is_bpf_wq_set_callback_kfunc(u32 btf_id);
static bool is_task_work_add_kfunc(u32 func_id);
@@ -5405,7 +5404,7 @@ continue_func:
if (bpf_pseudo_kfunc_call(insn + i) && !insn[i].off) {
bool err = false;
if (!is_bpf_throw_kfunc(insn + i))
if (!bpf_is_throw_kfunc(insn + i))
continue;
for (tmp = idx; tmp >= 0 && !err; tmp = dinfo[tmp].caller) {
if (subprog[tmp].is_cb) {
@@ -9499,6 +9498,9 @@ static int push_callback_call(struct bpf_verifier_env *env, struct bpf_insn *ins
return 0;
}
static int process_bpf_exit_full(struct bpf_verifier_env *env,
bool *do_print_state, bool exception_exit);
static int check_func_call(struct bpf_verifier_env *env, struct bpf_insn *insn,
int *insn_idx)
{
@@ -9552,6 +9554,17 @@ static int check_func_call(struct bpf_verifier_env *env, struct bpf_insn *insn,
caller->regs[BPF_REG_0].subreg_def = DEF_NOT_SUBREG;
}
if (env->subprog_info[subprog].might_throw) {
struct bpf_verifier_state *branch;
branch = push_stack(env, *insn_idx + 1, *insn_idx, false);
if (IS_ERR(branch)) {
verbose(env, "failed to push state for global subprog exception path\n");
return PTR_ERR(branch);
}
return process_bpf_exit_full(env, NULL, true);
}
/* continue with next insn after call */
return 0;
}
@@ -11263,7 +11276,11 @@ BTF_ID(func, bpf_task_work_schedule_resume)
BTF_ID(func, bpf_arena_alloc_pages)
BTF_ID(func, bpf_arena_free_pages)
BTF_ID(func, bpf_arena_reserve_pages)
#ifdef CONFIG_BPF_EVENTS
BTF_ID(func, bpf_session_is_return)
#else
BTF_ID_UNUSED
#endif
BTF_ID(func, bpf_stream_vprintk)
BTF_ID(func, bpf_stream_print_stack)
@@ -11778,7 +11795,7 @@ static bool is_async_callback_calling_kfunc(u32 btf_id)
is_task_work_add_kfunc(btf_id);
}
static bool is_bpf_throw_kfunc(struct bpf_insn *insn)
bool bpf_is_throw_kfunc(struct bpf_insn *insn)
{
return bpf_pseudo_kfunc_call(insn) && insn->off == 0 &&
insn->imm == special_kfunc_list[KF_bpf_throw];
@@ -12968,8 +12985,6 @@ static int check_special_kfunc(struct bpf_verifier_env *env, struct bpf_kfunc_ca
}
static int check_return_code(struct bpf_verifier_env *env, int regno, const char *reg_name);
static int process_bpf_exit_full(struct bpf_verifier_env *env,
bool *do_print_state, bool exception_exit);
static int check_kfunc_call(struct bpf_verifier_env *env, struct bpf_insn *insn,
int *insn_idx_p)
@@ -13350,7 +13365,7 @@ static int check_kfunc_call(struct bpf_verifier_env *env, struct bpf_insn *insn,
if (meta.func_id == special_kfunc_list[KF_bpf_session_cookie])
env->prog->call_session_cookie = true;
if (is_bpf_throw_kfunc(insn))
if (bpf_is_throw_kfunc(insn))
return process_bpf_exit_full(env, NULL, true);
return 0;
+1 -2
View File
@@ -592,13 +592,12 @@ static void emit_signature_match(struct bpf_gen *gen)
gen->hash_insn_offset[i] = gen->insn_cur - gen->insn_start;
emit2(gen, BPF_LD_IMM64_RAW_FULL(BPF_REG_3, 0, 0, 0, 0, 0));
off = -(gen->insn_cur - gen->insn_start - gen->cleanup_label) / 8 - 1;
off = -(gen->insn_cur - gen->insn_start - gen->cleanup_label) / 8 - 2;
if (is_simm16(off)) {
emit(gen, BPF_MOV64_IMM(BPF_REG_7, -EINVAL));
emit(gen, BPF_JMP_REG(BPF_JNE, BPF_REG_2, BPF_REG_3, off));
} else {
gen->error = -ERANGE;
emit(gen, BPF_JMP_IMM(BPF_JA, 0, 0, -1));
}
}
}
@@ -14,7 +14,7 @@ static struct {
const char *prog_name;
int expected_runtime_err;
} kfunc_dynptr_tests[] = {
{"dynptr_data_null", -EBADMSG},
{"dynptr_data_null", -EINVAL},
};
static bool kfunc_not_supported;
@@ -0,0 +1,57 @@
// SPDX-License-Identifier: GPL-2.0
#include <test_progs.h>
/*
* Test that replacing an inner percpu array map with one that has different
* max_entries is rejected. percpu_array_map_gen_lookup() inlines the
* template's index_mask, so allowing a smaller replacement would cause OOB.
*/
void test_percpu_array_inner_map(void)
{
LIBBPF_OPTS(bpf_map_create_opts, opts);
int outer_fd, tmpl_fd, good_fd, bad_fd, err;
int zero = 0;
/* Create template: percpu array with 8 entries */
tmpl_fd = bpf_map_create(BPF_MAP_TYPE_PERCPU_ARRAY, "tmpl",
sizeof(int), sizeof(long), 8, NULL);
if (!ASSERT_OK_FD(tmpl_fd, "create_tmpl"))
return;
/* Create outer array-of-maps using template */
opts.inner_map_fd = tmpl_fd;
outer_fd = bpf_map_create(BPF_MAP_TYPE_ARRAY_OF_MAPS, "outer",
sizeof(int), sizeof(int), 1, &opts);
if (!ASSERT_OK_FD(outer_fd, "create_outer"))
goto close_tmpl;
/* Insert template as initial inner map */
err = bpf_map_update_elem(outer_fd, &zero, &tmpl_fd, 0);
if (!ASSERT_OK(err, "insert_tmpl"))
goto close_outer;
/* Replacement with same max_entries should succeed */
good_fd = bpf_map_create(BPF_MAP_TYPE_PERCPU_ARRAY, "good",
sizeof(int), sizeof(long), 8, NULL);
if (!ASSERT_OK_FD(good_fd, "create_good"))
goto close_outer;
err = bpf_map_update_elem(outer_fd, &zero, &good_fd, 0);
ASSERT_OK(err, "replace_same_max_entries");
close(good_fd);
/* Replacement with fewer max_entries must fail */
bad_fd = bpf_map_create(BPF_MAP_TYPE_PERCPU_ARRAY, "bad",
sizeof(int), sizeof(long), 2, NULL);
if (!ASSERT_OK_FD(bad_fd, "create_bad"))
goto close_outer;
err = bpf_map_update_elem(outer_fd, &zero, &bad_fd, 0);
ASSERT_ERR(err, "replace_smaller_max_entries");
close(bad_fd);
close_outer:
close(outer_fd);
close_tmpl:
close(tmpl_fd);
}
@@ -22,6 +22,7 @@
#include "verifier_bswap.skel.h"
#include "verifier_btf_ctx_access.skel.h"
#include "verifier_btf_unreliable_prog.skel.h"
#include "verifier_call_large_imm.skel.h"
#include "verifier_cfg.skel.h"
#include "verifier_cgroup_inv_retcode.skel.h"
#include "verifier_cgroup_skb.skel.h"
@@ -170,6 +171,7 @@ void test_verifier_bpf_trap(void) { RUN(verifier_bpf_trap); }
void test_verifier_bswap(void) { RUN(verifier_bswap); }
void test_verifier_btf_ctx_access(void) { RUN(verifier_btf_ctx_access); }
void test_verifier_btf_unreliable_prog(void) { RUN(verifier_btf_unreliable_prog); }
void test_verifier_call_large_imm(void) { RUN(verifier_call_large_imm); }
void test_verifier_cfg(void) { RUN(verifier_cfg); }
void test_verifier_cgroup_inv_retcode(void) { RUN(verifier_cgroup_inv_retcode); }
void test_verifier_cgroup_skb(void) { RUN(verifier_cgroup_skb); }
@@ -208,6 +208,28 @@ int reject_with_reference(void *ctx)
return 0;
}
__noinline int global_subprog_may_throw(struct __sk_buff *ctx)
{
if (ctx->len)
bpf_throw(0);
return 0;
}
SEC("?tc")
__failure __msg("Unreleased reference")
int reject_global_subprog_throw_with_reference(struct __sk_buff *ctx)
{
struct foo *f;
f = bpf_obj_new(typeof(*f));
if (!f)
return 0;
if (ctx->protocol)
global_subprog_may_throw(ctx);
bpf_obj_drop(f);
return 0;
}
__noinline static int subprog_ref(struct __sk_buff *ctx)
{
struct foo *f;
@@ -0,0 +1,66 @@
// SPDX-License-Identifier: GPL-2.0
#include <linux/bpf.h>
#include <bpf/bpf_helpers.h>
#include "bpf_misc.h"
int call_happened = 0;
/*
* 32765 is the exact minimum number of padding instructions needed to
* trigger the verifier failure, because:
* 1. Counting the wrapper instructions around the padding block (one
* "r0=0" and two "exit" instructions), the actual jump distance
* evaluates to N + 3.
* 2. To overflow the s16 max bound (32767), we need N + 3 > 32767.
* Thus, N = 32765 is the exact minimum padding size required.
*/
static __attribute__((noinline)) void padding_subprog(void)
{
asm volatile (
"r0 = 0;"
".rept 32765;"
"r0 += 0;"
".endr;"
::: __clobber_all);
}
static __attribute__((noinline)) int target_subprog(void)
{
/* Use volatile variable here to prevent optimization. */
volatile int magic_ret = 3;
return magic_ret;
}
SEC("syscall")
__success __retval(3)
int call_large_imm_test(void *ctx)
{
/*
* Landing pad to handle call error on kernel without the fix,
* preventing kernel panic.
*/
asm volatile (
"r0 = 0;"
".rept 32768;"
"r0 += 0;"
".endr;"
::: __clobber_all);
/*
* The call_happened variable is 1 only when the call insn wrongly
* go back to the landing pad above.
*/
if (call_happened == 1) {
/* Use volatile variable here to prevent optimization. */
volatile int flag = -1;
return flag;
}
call_happened = 1;
padding_subprog();
return target_subprog();
}
char LICENSE[] SEC("license") = "GPL";
+4 -2
View File
@@ -8,6 +8,8 @@ RXE_NAME="rxe6"
PORT=4791
IP6_ADDR="2001:db8::1/64"
source "$(dirname "$0")/../kselftest/ktap_helpers.sh"
exec > /dev/null
# Cleanup function to run on exit (even on failure)
@@ -21,8 +23,8 @@ trap cleanup EXIT
# 1. Prerequisites check
for mod in tun veth rdma_rxe; do
if ! modinfo "$mod" >/dev/null 2>&1; then
echo "Error: Kernel module '$mod' not found."
exit 1
echo "SKIP: Kernel module '$mod' not found." >&2
exit $KSFT_SKIP
fi
done
@@ -8,6 +8,8 @@ IP_A="1.1.1.1"
IP_B="1.1.1.2"
PORT=4791
source "$(dirname "$0")/../kselftest/ktap_helpers.sh"
exec > /dev/null
# --- Cleanup Routine ---
@@ -27,6 +29,11 @@ if [[ $EUID -ne 0 ]]; then
exit 1
fi
if ! modinfo rdma_rxe >/dev/null 2>&1; then
echo "SKIP: Kernel module 'rdma_rxe' not found." >&2
exit $KSFT_SKIP
fi
modprobe rdma_rxe || { echo "Failed to load rdma_rxe"; exit 1; }
# --- Setup Network Topology ---
@@ -4,6 +4,8 @@
PORT=4791
MODS=("tun" "rdma_rxe")
source "$(dirname "$0")/../kselftest/ktap_helpers.sh"
exec > /dev/null
# --- Helper: Cleanup Routine ---
@@ -26,6 +28,10 @@ if [[ $EUID -ne 0 ]]; then
fi
for m in "${MODS[@]}"; do
if ! modinfo "$m" >/dev/null 2>&1; then
echo "SKIP: Kernel module '$m' not found." >&2
exit $KSFT_SKIP
fi
modprobe "$m" || { echo "Error: Failed to load $m"; exit 1; }
done
@@ -5,6 +5,8 @@ DEV_NAME="tun0"
RXE_NAME="rxe0"
RDMA_PORT=4791
source "$(dirname "$0")/../kselftest/ktap_helpers.sh"
exec > /dev/null
# --- Cleanup Routine ---
@@ -19,8 +21,8 @@ trap cleanup EXIT
# 1. Dependency Check
if ! modinfo rdma_rxe >/dev/null 2>&1; then
echo "Error: rdma_rxe module not found."
exit 1
echo "SKIP: rdma_rxe module not found." >&2
exit $KSFT_SKIP
fi
modprobe rdma_rxe