Import of kernel-6.12.0-211.50.1.el10_2

This commit is contained in:
almalinux-bot-kernel 2026-09-06 04:15:47 +00:00
parent e9d74aef89
commit 1e9e3942c3
70 changed files with 1556 additions and 187 deletions

View File

@ -12,7 +12,7 @@ RHEL_MINOR = 2
#
# Use this spot to avoid future merge conflicts.
# Do not trim this comment.
RHEL_RELEASE = 211.49.1
RHEL_RELEASE = 211.50.1
#
# RHEL_REBASE_NUM

View File

@ -140,7 +140,6 @@ config S390
select ARCH_WANT_LD_ORPHAN_WARN
select BUILDTIME_TABLE_SORT
select CLONE_BACKWARDS2
select DCACHE_WORD_ACCESS if !KMSAN
select DYNAMIC_FTRACE if FUNCTION_TRACER
select FUNCTION_ALIGNMENT_8B if CC_IS_GCC
select FUNCTION_ALIGNMENT_16B if !CC_IS_GCC

View File

@ -13,7 +13,6 @@
#define EX_TYPE_UA_LOAD_MEM 4
#define EX_TYPE_UA_LOAD_REG 5
#define EX_TYPE_UA_LOAD_REGPAIR 6
#define EX_TYPE_ZEROPAD 7
#define EX_DATA_REG_ERR_SHIFT 0
#define EX_DATA_REG_ERR GENMASK(3, 0)
@ -81,7 +80,4 @@
#define EX_TABLE_UA_LOAD_REGPAIR(_fault, _target, _regerr, _regzero) \
__EX_TABLE(__ex_table, _fault, _target, EX_TYPE_UA_LOAD_REGPAIR, _regerr, _regzero, 0)
#define EX_TABLE_ZEROPAD(_fault, _target, _regdata, _regaddr) \
__EX_TABLE(__ex_table, _fault, _target, EX_TYPE_ZEROPAD, _regdata, _regaddr, 0)
#endif /* __ASM_EXTABLE_H */

View File

@ -4,7 +4,6 @@
#include <linux/bitops.h>
#include <linux/wordpart.h>
#include <asm/asm-extable.h>
#include <asm/bitsperlong.h>
struct word_at_a_time {
@ -41,25 +40,4 @@ static inline unsigned long zero_bytemask(unsigned long data)
return ~1UL << data;
}
/*
* Load an unaligned word from kernel space.
*
* In the (very unlikely) case of the word being a page-crosser
* and the next page not being mapped, take the exception and
* return zeroes in the non-existing part.
*/
static inline unsigned long load_unaligned_zeropad(const void *addr)
{
unsigned long data;
asm volatile(
"0: lg %[data],0(%[addr])\n"
"1: nopr %%r7\n"
EX_TABLE_ZEROPAD(0b, 1b, %[data], %[addr])
EX_TABLE_ZEROPAD(1b, 1b, %[data], %[addr])
: [data] "=d" (data)
: [addr] "a" (addr), "m" (*(unsigned long *)addr));
return data;
}
#endif /* _ASM_WORD_AT_A_TIME_H */

View File

@ -61,22 +61,6 @@ static bool ex_handler_ua_load_reg(const struct exception_table_entry *ex,
return true;
}
static bool ex_handler_zeropad(const struct exception_table_entry *ex, struct pt_regs *regs)
{
unsigned int reg_addr = FIELD_GET(EX_DATA_REG_ADDR, ex->data);
unsigned int reg_data = FIELD_GET(EX_DATA_REG_ERR, ex->data);
unsigned long data, addr, offset;
addr = regs->gprs[reg_addr];
offset = addr & (sizeof(unsigned long) - 1);
addr &= ~(sizeof(unsigned long) - 1);
data = *(unsigned long *)addr;
data <<= BITS_PER_BYTE * offset;
regs->gprs[reg_data] = data;
regs->psw.addr = extable_fixup(ex);
return true;
}
bool fixup_exception(struct pt_regs *regs)
{
const struct exception_table_entry *ex;
@ -97,8 +81,6 @@ bool fixup_exception(struct pt_regs *regs)
return ex_handler_ua_load_reg(ex, false, regs);
case EX_TYPE_UA_LOAD_REGPAIR:
return ex_handler_ua_load_reg(ex, true, regs);
case EX_TYPE_ZEROPAD:
return ex_handler_zeropad(ex, regs);
}
panic("invalid exception table entry");
}

View File

@ -62,7 +62,7 @@ int __pfault_init(void)
"0: nopr %%r7\n"
EX_TABLE(0b, 0b)
: [rc] "+d" (rc)
: [refbk] "a" (&pfault_init_refbk), "m" (pfault_init_refbk)
: [refbk] "a" (virt_to_phys(&pfault_init_refbk)), "m" (pfault_init_refbk)
: "cc");
return rc;
}
@ -84,7 +84,7 @@ void __pfault_fini(void)
"0: nopr %%r7\n"
EX_TABLE(0b, 0b)
:
: [refbk] "a" (&pfault_fini_refbk), "m" (pfault_fini_refbk)
: [refbk] "a" (virt_to_phys(&pfault_fini_refbk)), "m" (pfault_fini_refbk)
: "cc");
}

View File

@ -935,6 +935,8 @@ SYM_CODE_START(paranoid_entry)
IBRS_ENTER save_reg=%r15
UNTRAIN_RET_FROM_CALL
HANDLE_INTR_SAFERET 8(%rsp)
RET
SYM_CODE_END(paranoid_entry)
@ -1037,6 +1039,11 @@ SYM_CODE_START(error_entry)
movl %ecx, %eax /* zero extend */
cmpq %rax, RIP+8(%rsp)
je .Lbstep_iret
VALIDATE_UNRET_END
HANDLE_INTR_SAFERET 8(%rsp)
cmpq $.Lgs_change, RIP+8(%rsp)
jne .Lerror_entry_done_lfence
@ -1055,7 +1062,6 @@ SYM_CODE_START(error_entry)
FENCE_SWAPGS_KERNEL_ENTRY
CALL_DEPTH_ACCOUNT
leaq 8(%rsp), %rax /* return pt_regs pointer */
VALIDATE_UNRET_END
RET
.Lbstep_iret:

View File

@ -12,6 +12,7 @@
#include <asm/msr-index.h>
#include <asm/unwind_hints.h>
#include <asm/percpu.h>
#include <asm/ptrace-abi.h>
#include <asm/current.h>
/*
@ -177,6 +178,50 @@
add $(BITS_PER_LONG/8), %_ASM_SP; \
lfence;
/*
* Helper for detecting if an interrupt occurred at an unsafe location within
* Safe-RET. If Safe-RET is interrupted after the CALL or LEA the RSB may get
* poisoned by the interrupt handler.
*
* The Safe-RET sequence is:
*
* CALL
* LEA 8(%RSP), %RSP
* RET
*
* The two CMPs below check whether RIP points to after the CALL or after the
* LEA.
*
* The LFENCE below is to address this particular speculation case:
*
* 1. Userspace runs and poisons the BTB around the safe-RET routine
*
* 2. Userspace triggers some kind of exception
*
* 3. Kernel executes error_entry() and mis-speculates the branch into thinking
* it actually came from kernel space
*
* 4. The kernel then further mis-speculates that the exception occurred due
* to an interrupted safe-RET
*
* 5. The handle_interrupted_saferet() routine speculatively executes and
* speculatively does a safe-RET. But this is unsafe since it was never
* untrained.
*
* The LFENCE fixes this by ensuring step 5 is never reached speculatively.
* Note that this LFENCE only occurs if safe-RET was actually interrupted (so
* it's outside of the normal path).
*/
#define __HANDLE_INTR_SAFERET(name, pt_regs) \
cmpq $(name), RIP+pt_regs; \
jb 1f; \
cmpq $(name)+5, RIP+pt_regs; \
ja 1f; \
lfence; \
leaq pt_regs, %rdi; \
call handle_interrupted_saferet; \
1:
#ifdef __ASSEMBLY__
/*
@ -295,6 +340,14 @@
#define UNTRAIN_RET_FROM_CALL \
__UNTRAIN_RET X86_FEATURE_ENTRY_IBPB, __stringify(RESET_CALL_DEPTH_FROM_CALL)
.macro HANDLE_INTR_SAFERET pt_regs
#ifdef CONFIG_MITIGATION_SRSO
ALTERNATIVE_2 "", \
__stringify(__HANDLE_INTR_SAFERET(srso_safe_ret, \pt_regs)), X86_FEATURE_SRSO, \
__stringify(__HANDLE_INTR_SAFERET(srso_alias_safe_ret, \pt_regs)), X86_FEATURE_SRSO_ALIAS
#endif
.endm
.macro CALL_DEPTH_ACCOUNT
#ifdef CONFIG_MITIGATION_CALL_DEPTH_TRACKING
@ -618,6 +671,11 @@ static __always_inline void x86_idle_clear_cpu_buffers(void)
x86_clear_cpu_buffers();
}
struct pt_regs;
void srso_safe_ret(void);
void srso_alias_safe_ret(void);
void handle_interrupted_saferet(struct pt_regs *regs);
#endif /* __ASSEMBLY__ */
#endif /* _ASM_X86_NOSPEC_BRANCH_H_ */

View File

@ -3794,3 +3794,42 @@ void __warn_thunk(void)
{
WARN_ONCE(1, "Unpatched return thunk in use. This should not happen!\n");
}
#ifdef CONFIG_MITIGATION_SRSO
/*
* Called during exception/interrupt entry if interrupted during the
* safe-RET sequence. The safe-RET sequence consists of 3 instructions:
*
* CALL
* LEA 8(%RSP), %RSP
* RET
*
* An interrupt after the CALL or after the LEA could potentially lead
* to branch predictor poisoning and results in the sequence not being
* able to be safely resumed.
*
* Therefore, modify the regs state as if the remaining part of the
* safe-RET sequence executed so the interrupt returns back to the
* desired return target, instead of the to the safe-RET sequence.
*/
void noinstr handle_interrupted_saferet(struct pt_regs *regs)
{
unsigned long rip = regs->ip;
if (rip == (unsigned long) srso_safe_ret ||
rip == (unsigned long) srso_alias_safe_ret) {
/* Modify stack pointer as if LEA executed: */
regs->sp += 8;
}
/*
* Adjust registers as if RET executed:
*
* 1. Read the return address off the stack and into rIP:
*/
regs->ip = *(unsigned long *)(regs->sp);
/* 2. Pop rIP off the stack: */
regs->sp += 8;
}
#endif /* CONFIG_MITIGATION_SRSO */

View File

@ -168,10 +168,24 @@ __EXPORT_THUNK(srso_alias_untrain_ret)
.pushsection .text..__x86.rethunk_safe
SYM_CODE_START_NOALIGN(srso_alias_safe_ret)
/*
* Tell objtool that those are not function pointers referenced by
* __HANDLE_INTR_SAFERET(). Below too.
*/
ANNOTATE_NOENDBR
/*
* Safe-RET sequence. If you need to change it, adjust
* handle_interrupted_saferet() too.
*/
lea 8(%_ASM_SP), %_ASM_SP
UNWIND_HINT_FUNC
ANNOTATE_NOENDBR
ANNOTATE_UNRET_SAFE
ret
/* End of Safe-RET sequence */
int3
SYM_FUNC_END(srso_alias_safe_ret)
@ -206,8 +220,14 @@ SYM_CODE_START_LOCAL_NOALIGN(srso_untrain_ret)
* the stack.
*/
SYM_INNER_LABEL(srso_safe_ret, SYM_L_GLOBAL)
/*
* Safe-RET sequence. If you need to change it, adjust
* handle_interrupted_saferet() too.
*/
lea 8(%_ASM_SP), %_ASM_SP
ret
/* End of Safe-RET sequence */
int3
int3
/* end of movabs */

View File

@ -3180,7 +3180,6 @@ CONFIG_INTERCONNECT=y
#
# File systems
#
CONFIG_DCACHE_WORD_ACCESS=y
# CONFIG_VALIDATE_FS_PARSER is not set
CONFIG_FS_IOMAP=y
CONFIG_FS_STACK=y

View File

@ -1326,7 +1326,6 @@ CONFIG_INTERCONNECT=y
#
# File systems
#
CONFIG_DCACHE_WORD_ACCESS=y
# CONFIG_VALIDATE_FS_PARSER is not set
CONFIG_FS_IOMAP=y
# CONFIG_EXT2_FS is not set

View File

@ -3204,7 +3204,6 @@ CONFIG_INTERCONNECT=y
#
# File systems
#
CONFIG_DCACHE_WORD_ACCESS=y
# CONFIG_VALIDATE_FS_PARSER is not set
CONFIG_FS_IOMAP=y
CONFIG_FS_STACK=y

View File

@ -1635,7 +1635,7 @@ static int zram_bvec_write_partial(struct zram *zram, struct bio_vec *bvec,
if (!page)
return -ENOMEM;
ret = zram_read_page(zram, page, index, bio);
ret = zram_read_page(zram, page, index, NULL);
if (!ret) {
memcpy_from_bvec(page_address(page) + offset, bvec);
ret = zram_write_page(zram, page, index);

View File

@ -472,6 +472,8 @@ struct adf_accel_dev {
struct {
/* protects VF2PF interrupts access */
spinlock_t vf2pf_ints_lock;
/* prevents VF2PF handling from racing with VF state teardown */
bool vf2pf_disabled;
/* vf_info is non-zero when SR-IOV is init'ed */
struct adf_accel_vf_info *vf_info;
} pf;

View File

@ -140,6 +140,8 @@ static void adf_device_reset_worker(struct work_struct *work)
queue_work(device_sriov_wq, &sriov_data.sriov_work);
if (wait_for_completion_timeout(&sriov_data.compl, wait_jiffies))
adf_pf2vf_notify_restarted(accel_dev);
else
cancel_work_sync(&sriov_data.sriov_work);
adf_dev_restarted_notify(accel_dev);
clear_bit(ADF_STATUS_RESTARTING, &accel_dev->status);

View File

@ -121,6 +121,7 @@ void qat_comp_alg_callback(void *resp);
int adf_isr_resource_alloc(struct adf_accel_dev *accel_dev);
void adf_isr_resource_free(struct adf_accel_dev *accel_dev);
void adf_isr_sync_ae_cluster(struct adf_accel_dev *accel_dev);
int adf_vf_isr_resource_alloc(struct adf_accel_dev *accel_dev);
void adf_vf_isr_resource_free(struct adf_accel_dev *accel_dev);
@ -194,6 +195,7 @@ int adf_sriov_configure(struct pci_dev *pdev, int numvfs);
void adf_disable_sriov(struct adf_accel_dev *accel_dev);
void adf_reenable_sriov(struct adf_accel_dev *accel_dev);
void adf_enable_vf2pf_interrupts(struct adf_accel_dev *accel_dev, u32 vf_mask);
void adf_enable_all_vf2pf_interrupts(struct adf_accel_dev *accel_dev, u32 num_vfs);
void adf_disable_all_vf2pf_interrupts(struct adf_accel_dev *accel_dev);
bool adf_recv_and_handle_pf2vf_msg(struct adf_accel_dev *accel_dev);
bool adf_recv_and_handle_vf2pf_msg(struct adf_accel_dev *accel_dev, u32 vf_nr);

View File

@ -62,6 +62,23 @@ void adf_enable_vf2pf_interrupts(struct adf_accel_dev *accel_dev, u32 vf_mask)
unsigned long flags;
spin_lock_irqsave(&accel_dev->pf.vf2pf_ints_lock, flags);
if (!READ_ONCE(accel_dev->pf.vf2pf_disabled))
GET_PFVF_OPS(accel_dev)->enable_vf2pf_interrupts(pmisc_addr, vf_mask);
spin_unlock_irqrestore(&accel_dev->pf.vf2pf_ints_lock, flags);
}
void adf_enable_all_vf2pf_interrupts(struct adf_accel_dev *accel_dev, u32 num_vfs)
{
void __iomem *pmisc_addr = adf_get_pmisc_base(accel_dev);
unsigned long flags;
u32 vf_mask;
vf_mask = BIT_ULL(num_vfs) - 1;
if (!vf_mask)
return;
spin_lock_irqsave(&accel_dev->pf.vf2pf_ints_lock, flags);
WRITE_ONCE(accel_dev->pf.vf2pf_disabled, false);
GET_PFVF_OPS(accel_dev)->enable_vf2pf_interrupts(pmisc_addr, vf_mask);
spin_unlock_irqrestore(&accel_dev->pf.vf2pf_ints_lock, flags);
}
@ -72,6 +89,7 @@ void adf_disable_all_vf2pf_interrupts(struct adf_accel_dev *accel_dev)
unsigned long flags;
spin_lock_irqsave(&accel_dev->pf.vf2pf_ints_lock, flags);
WRITE_ONCE(accel_dev->pf.vf2pf_disabled, true);
GET_PFVF_OPS(accel_dev)->disable_all_vf2pf_interrupts(pmisc_addr);
spin_unlock_irqrestore(&accel_dev->pf.vf2pf_ints_lock, flags);
}
@ -174,6 +192,27 @@ static irqreturn_t adf_msix_isr_ae(int irq, void *dev_ptr)
return IRQ_NONE;
}
void adf_isr_sync_ae_cluster(struct adf_accel_dev *accel_dev)
{
struct adf_accel_pci *pci_dev_info = &accel_dev->accel_pci_dev;
struct adf_hw_device_data *hw_data = GET_HW_DATA(accel_dev);
u32 num_entries = pci_dev_info->msix_entries.num_entries;
struct adf_irq *irqs = pci_dev_info->msix_entries.irqs;
u32 irq_idx;
int irq;
if (!test_bit(ADF_STATUS_IRQ_ALLOCATED, &accel_dev->status) || !irqs)
return;
irq_idx = num_entries > 1 ? hw_data->num_banks : 0;
if (irq_idx >= num_entries || !irqs[irq_idx].enabled)
return;
irq = pci_irq_vector(pci_dev_info->pci_dev, hw_data->num_banks);
if (irq > 0)
synchronize_irq(irq);
}
static void adf_free_irqs(struct adf_accel_dev *accel_dev)
{
struct adf_accel_pci *pci_dev_info = &accel_dev->accel_pci_dev;

View File

@ -26,6 +26,9 @@ static void adf_iov_send_resp(struct work_struct *work)
u32 vf_nr = vf_info->vf_nr;
bool ret;
if (READ_ONCE(accel_dev->pf.vf2pf_disabled))
goto out;
mutex_lock(&vf_info->pfvf_mig_lock);
ret = adf_recv_and_handle_vf2pf_msg(accel_dev, vf_nr);
if (ret)
@ -33,13 +36,18 @@ static void adf_iov_send_resp(struct work_struct *work)
adf_enable_vf2pf_interrupts(accel_dev, 1 << vf_nr);
mutex_unlock(&vf_info->pfvf_mig_lock);
out:
kfree(pf2vf_resp);
}
void adf_schedule_vf2pf_handler(struct adf_accel_vf_info *vf_info)
{
struct adf_accel_dev *accel_dev = vf_info->accel_dev;
struct adf_pf2vf_resp *pf2vf_resp;
if (READ_ONCE(accel_dev->pf.vf2pf_disabled))
return;
pf2vf_resp = kzalloc(sizeof(*pf2vf_resp), GFP_ATOMIC);
if (!pf2vf_resp)
return;
@ -49,6 +57,12 @@ void adf_schedule_vf2pf_handler(struct adf_accel_vf_info *vf_info)
queue_work(pf2vf_resp_wq, &pf2vf_resp->pf2vf_resp_work);
}
static void adf_flush_pf2vf_resp_wq(void)
{
if (pf2vf_resp_wq)
flush_workqueue(pf2vf_resp_wq);
}
static int adf_enable_sriov(struct adf_accel_dev *accel_dev)
{
struct pci_dev *pdev = accel_to_pci_dev(accel_dev);
@ -75,7 +89,7 @@ static int adf_enable_sriov(struct adf_accel_dev *accel_dev)
hw_data->configure_iov_threads(accel_dev, true);
/* Enable VF to PF interrupts for all VFs */
adf_enable_vf2pf_interrupts(accel_dev, BIT_ULL(totalvfs) - 1);
adf_enable_all_vf2pf_interrupts(accel_dev, totalvfs);
/*
* Due to the hardware design, when SR-IOV and the ring arbiter
@ -249,8 +263,10 @@ void adf_disable_sriov(struct adf_accel_dev *accel_dev)
adf_pf2vf_wait_for_restarting_complete(accel_dev);
pci_disable_sriov(accel_to_pci_dev(accel_dev));
/* Disable VF to PF interrupts */
/* Block VF2PF work and disable VF to PF interrupts */
adf_disable_all_vf2pf_interrupts(accel_dev);
adf_isr_sync_ae_cluster(accel_dev);
adf_flush_pf2vf_resp_wq();
/* Clear Valid bits in AE Thread to PCIe Function Mapping */
if (hw_data->configure_iov_threads)

View File

@ -1085,7 +1085,7 @@ static void qat_rsa_setkey_crt(struct qat_rsa_ctx *ctx, struct rsa_key *rsa_key)
ptr = rsa_key->p;
len = rsa_key->p_sz;
qat_rsa_drop_leading_zeros(&ptr, &len);
if (!len)
if (!len || len > half_key_sz)
goto err;
ctx->p = dma_alloc_coherent(dev, half_key_sz, &ctx->dma_p, GFP_KERNEL);
if (!ctx->p)
@ -1096,7 +1096,7 @@ static void qat_rsa_setkey_crt(struct qat_rsa_ctx *ctx, struct rsa_key *rsa_key)
ptr = rsa_key->q;
len = rsa_key->q_sz;
qat_rsa_drop_leading_zeros(&ptr, &len);
if (!len)
if (!len || len > half_key_sz)
goto free_p;
ctx->q = dma_alloc_coherent(dev, half_key_sz, &ctx->dma_q, GFP_KERNEL);
if (!ctx->q)
@ -1107,7 +1107,7 @@ static void qat_rsa_setkey_crt(struct qat_rsa_ctx *ctx, struct rsa_key *rsa_key)
ptr = rsa_key->dp;
len = rsa_key->dp_sz;
qat_rsa_drop_leading_zeros(&ptr, &len);
if (!len)
if (!len || len > half_key_sz)
goto free_q;
ctx->dp = dma_alloc_coherent(dev, half_key_sz, &ctx->dma_dp,
GFP_KERNEL);
@ -1119,7 +1119,7 @@ static void qat_rsa_setkey_crt(struct qat_rsa_ctx *ctx, struct rsa_key *rsa_key)
ptr = rsa_key->dq;
len = rsa_key->dq_sz;
qat_rsa_drop_leading_zeros(&ptr, &len);
if (!len)
if (!len || len > half_key_sz)
goto free_dp;
ctx->dq = dma_alloc_coherent(dev, half_key_sz, &ctx->dma_dq,
GFP_KERNEL);
@ -1131,7 +1131,7 @@ static void qat_rsa_setkey_crt(struct qat_rsa_ctx *ctx, struct rsa_key *rsa_key)
ptr = rsa_key->qinv;
len = rsa_key->qinv_sz;
qat_rsa_drop_leading_zeros(&ptr, &len);
if (!len)
if (!len || len > half_key_sz)
goto free_dq;
ctx->qinv = dma_alloc_coherent(dev, half_key_sz, &ctx->dma_qinv,
GFP_KERNEL);

View File

@ -233,7 +233,7 @@ static int rmi_f30_map_gpios(struct rmi_function *fn,
int button_count = min_t(u8, f30->gpioled_count, TRACKSTICK_RANGE_END);
f30->gpioled_key_map = devm_kcalloc(&fn->dev,
button_count,
f30->gpioled_count,
sizeof(f30->gpioled_key_map[0]),
GFP_KERNEL);
if (!f30->gpioled_key_map) {

View File

@ -132,7 +132,7 @@ static int rmi_f3a_map_gpios(struct rmi_function *fn, struct f3a_data *f3a,
int button_count = min_t(u8, f3a->gpio_count, TRACKSTICK_RANGE_END);
f3a->gpio_key_map = devm_kcalloc(&fn->dev,
button_count,
f3a->gpio_count,
sizeof(f3a->gpio_key_map[0]),
GFP_KERNEL);
if (!f3a->gpio_key_map) {

View File

@ -380,11 +380,12 @@ struct iommu_dev_data *search_dev_data(struct amd_iommu *iommu, u16 devid)
return NULL;
}
static int clone_alias(struct pci_dev *pdev, u16 alias, void *data)
static int clone_alias(struct pci_dev *pdev_origin, u16 alias, void *data)
{
struct dev_table_entry new;
struct amd_iommu *iommu;
struct iommu_dev_data *dev_data, *alias_data;
struct pci_dev *pdev = data;
u16 devid = pci_dev_id(pdev);
int ret = 0;
@ -431,9 +432,9 @@ static void clone_aliases(struct amd_iommu *iommu, struct device *dev)
* part of the PCI DMA aliases if it's bus differs
* from the original device.
*/
clone_alias(pdev, iommu->pci_seg->alias_table[pci_dev_id(pdev)], NULL);
clone_alias(pdev, iommu->pci_seg->alias_table[pci_dev_id(pdev)], pdev);
pci_for_each_dma_alias(pdev, clone_alias, NULL);
pci_for_each_dma_alias(pdev, clone_alias, pdev);
}
static void setup_aliases(struct amd_iommu *iommu, struct device *dev)

View File

@ -4481,9 +4481,13 @@ static int bond_close(struct net_device *bond_dev)
bond_work_cancel_all(bond);
bond->send_peer_notif = 0;
WRITE_ONCE(bond->recv_probe, NULL);
/* Wait for any in-flight RX handlers */
synchronize_net();
if (bond_is_lb(bond))
bond_alb_deinitialize(bond);
bond->recv_probe = NULL;
if (BOND_MODE(bond) == BOND_MODE_8023AD &&
bond->params.broadcast_neighbor)

View File

@ -266,6 +266,12 @@ static void mana_hwc_rx_event_handler(void *ctx, u32 gdma_rxq_id,
rq_base_addr = hwc_rxq->msg_buf->mem_info.dma_handle;
rx_req_idx = (sge->address - rq_base_addr) / hwc->max_req_msg_size;
if (rx_req_idx >= hwc_rxq->msg_buf->num_reqs) {
dev_err(hwc->dev, "HWC RX: wrong rx_req_idx=%llu, num_reqs=%u\n",
rx_req_idx, hwc_rxq->msg_buf->num_reqs);
return;
}
rx_req = &hwc_rxq->msg_buf->reqs[rx_req_idx];
resp = (struct gdma_resp_hdr *)rx_req->buf_va;

View File

@ -765,6 +765,9 @@ qede_tpa_rx_build_skb(struct qede_dev *edev,
struct sk_buff *skb;
skb = qede_build_skb(rxq, bd, len, pad);
if (unlikely(!skb))
return NULL;
bd->page_offset += rxq->rx_buf_seg_size;
if (bd->page_offset == PAGE_SIZE) {
@ -812,6 +815,8 @@ qede_rx_build_skb(struct qede_dev *edev,
}
skb = qede_build_skb(rxq, bd, len, pad);
if (unlikely(!skb))
return NULL;
if (unlikely(qede_realloc_rx_buffer(rxq, bd))) {
/* Incr page ref count to reuse on allocation failure so

View File

@ -166,6 +166,7 @@ static void nvmet_execute_disc_get_log_page(struct nvmet_req *req)
u64 offset = nvmet_get_log_page_offset(req->cmd);
size_t data_len = nvmet_get_log_page_len(req->cmd);
size_t alloc_len;
size_t copy_len;
struct nvmet_subsys_link *p;
struct nvmet_port *r;
u32 numrec = 0;
@ -242,7 +243,27 @@ static void nvmet_execute_disc_get_log_page(struct nvmet_req *req)
up_read(&nvmet_config_sem);
status = nvmet_copy_to_sgl(req, 0, buffer + offset, data_len);
/*
* Validate the host-supplied log page offset before copying out.
* Without this check, the host controls a 64-bit byte offset into
* a small kzalloc'd buffer: a value past the log page lets the
* subsequent memcpy read adjacent kernel heap, and a value aimed
* at unmapped kernel memory faults the in-kernel copy and crashes
* the target host. The Discovery controller is unauthenticated,
* so the bug is reachable from any reachable fabric peer.
*/
if (offset > alloc_len) {
req->error_loc =
offsetof(struct nvme_get_log_page_command, lpo);
status = NVME_SC_INVALID_FIELD | NVME_STATUS_DNR;
goto out_free_buffer;
}
copy_len = min_t(size_t, data_len, alloc_len - offset);
status = nvmet_copy_to_sgl(req, 0, buffer + offset, copy_len);
if (!status && copy_len < data_len)
status = nvmet_zero_sgl(req, copy_len, data_len - copy_len);
out_free_buffer:
kfree(buffer);
out:
nvmet_req_complete(req, status);

View File

@ -485,7 +485,31 @@ static void nvmet_auth_failure1(struct nvmet_req *req, void *d, int al)
u32 nvmet_auth_receive_data_len(struct nvmet_req *req)
{
return le32_to_cpu(req->cmd->auth_receive.al);
struct nvmet_ctrl *ctrl = req->sq->ctrl;
u32 al = le32_to_cpu(req->cmd->auth_receive.al);
u32 min_len;
/*
* Reject too-short al before kmalloc(al), since the SUCCESS1 and
* FAILURE1/default builders write fixed response headers into it.
*/
switch (req->sq->dhchap_step) {
case NVME_AUTH_DHCHAP_MESSAGE_CHALLENGE:
return al;
case NVME_AUTH_DHCHAP_MESSAGE_SUCCESS1:
min_len = sizeof(struct nvmf_auth_dhchap_success1_data);
if (req->sq->dhchap_c2)
min_len += nvme_auth_hmac_hash_len(ctrl->shash_id);
break;
default:
min_len = sizeof(struct nvmf_auth_dhchap_failure_data);
break;
}
if (al < min_len)
return 0;
return al;
}
void nvmet_execute_auth_receive(struct nvmet_req *req)

View File

@ -773,6 +773,12 @@ static int get_manuf_info(struct edgeport_serial *serial, u8 *buffer)
}
/* Read the descriptor data */
if (le16_to_cpu(rom_desc->Size) != sizeof(struct edge_ti_manuf_descriptor)) {
dev_err(dev, "unexpected Edge descriptor length: %u\n",
le16_to_cpu(rom_desc->Size));
status = -EINVAL;
goto exit;
}
status = read_rom(serial, start_address+sizeof(struct ti_i2c_desc),
le16_to_cpu(rom_desc->Size), buffer);
if (status)
@ -838,6 +844,11 @@ static int build_i2c_fw_hdr(u8 *header, const struct firmware *fw)
/* Pointer to fw_down memory image */
img_header = (struct ti_i2c_image_header *)&fw->data[4];
if (le16_to_cpu(img_header->Length) >
buffer_size - sizeof(struct ti_i2c_firmware_rec)) {
kfree(buffer);
return -EINVAL;
}
memcpy(buffer + sizeof(struct ti_i2c_firmware_rec),
&fw->data[4 + sizeof(struct ti_i2c_image_header)],
le16_to_cpu(img_header->Length));

View File

@ -79,7 +79,7 @@ static int mdsc_show(struct seq_file *s, void *p)
if (req->r_inode) {
seq_printf(s, " #%llx", ceph_ino(req->r_inode));
} else if (req->r_dentry) {
struct ceph_path_info path_info;
struct ceph_path_info path_info = {0};
path = ceph_mdsc_build_path(mdsc, req->r_dentry, &path_info, 0);
if (IS_ERR(path))
path = NULL;
@ -98,7 +98,7 @@ static int mdsc_show(struct seq_file *s, void *p)
}
if (req->r_old_dentry) {
struct ceph_path_info path_info;
struct ceph_path_info path_info = {0};
path = ceph_mdsc_build_path(mdsc, req->r_old_dentry, &path_info, 0);
if (IS_ERR(path))
path = NULL;

View File

@ -1355,7 +1355,7 @@ static int ceph_unlink(struct inode *dir, struct dentry *dentry)
if (!dn) {
try_async = false;
} else {
struct ceph_path_info path_info;
struct ceph_path_info path_info = {0};
path = ceph_mdsc_build_path(mdsc, dn, &path_info, 0);
if (IS_ERR(path)) {
try_async = false;

View File

@ -397,7 +397,7 @@ int ceph_open(struct inode *inode, struct file *file)
if (!dentry) {
do_sync = true;
} else {
struct ceph_path_info path_info;
struct ceph_path_info path_info = {0};
path = ceph_mdsc_build_path(mdsc, dentry, &path_info, 0);
if (IS_ERR(path)) {
do_sync = true;
@ -809,7 +809,7 @@ int ceph_atomic_open(struct inode *dir, struct dentry *dentry,
if (!dn) {
try_async = false;
} else {
struct ceph_path_info path_info;
struct ceph_path_info path_info = {0};
path = ceph_mdsc_build_path(mdsc, dn, &path_info, 0);
if (IS_ERR(path)) {
try_async = false;

View File

@ -2548,7 +2548,7 @@ int __ceph_setattr(struct mnt_idmap *idmap, struct inode *inode,
if (!dentry) {
do_sync = true;
} else {
struct ceph_path_info path_info;
struct ceph_path_info path_info = {0};
path = ceph_mdsc_build_path(mdsc, dentry, &path_info, 0);
if (IS_ERR(path)) {
do_sync = true;

View File

@ -2766,6 +2766,7 @@ retry:
if (ret < 0) {
dput(parent);
dput(cur);
__putname(path);
return ERR_PTR(ret);
}
@ -2775,6 +2776,7 @@ retry:
if (len < 0) {
dput(parent);
dput(cur);
__putname(path);
return ERR_PTR(len);
}
}
@ -2807,12 +2809,12 @@ retry:
if (pos < 0) {
/*
* A rename didn't occur, but somehow we didn't end up where
* we thought we would. Throw a warning and try again.
* The path is longer than PATH_MAX and this function
* cannot ever succeed. Creating paths that long is
* possible with Ceph, but Linux cannot use them.
*/
pr_warn_client(cl, "did not end path lookup where expected (pos = %d)\n",
pos);
goto retry;
__putname(path);
return ERR_PTR(-ENAMETOOLONG);
}
/* Initialize the output structure */

View File

@ -3319,6 +3319,8 @@ static int nfs_open_permission_mask(int openflags)
mask |= MAY_READ;
if ((openflags & O_ACCMODE) != O_RDONLY)
mask |= MAY_WRITE;
if (openflags & O_TRUNC)
mask |= MAY_WRITE;
}
return mask;

View File

@ -552,6 +552,10 @@ ff_layout_alloc_lseg(struct pnfs_layout_hdr *lh,
if (!p)
goto out_err_free;
fh_count = be32_to_cpup(p);
if (fh_count == 0) {
rc = -EINVAL;
goto out_err_free;
}
dss_info->fh_versions =
kcalloc(fh_count, sizeof(struct nfs_fh),

View File

@ -2217,11 +2217,11 @@ lookup_again:
dprintk("%s wait for layoutreturn\n", __func__);
lseg = ERR_PTR(pnfs_prepare_to_retry_layoutget(lo));
if (!IS_ERR(lseg)) {
pnfs_put_layout_hdr(lo);
dprintk("%s retrying\n", __func__);
trace_pnfs_update_layout(ino, pos, count, iomode, lo,
lseg,
PNFS_UPDATE_LAYOUT_RETRY);
pnfs_put_layout_hdr(lo);
goto lookup_again;
}
trace_pnfs_update_layout(ino, pos, count, iomode, lo, lseg,

View File

@ -1075,14 +1075,14 @@ nfs4_decode_mp_ds_addr(struct net *net, struct xdr_stream *xdr, gfp_t gfp_flags)
/* r_netid */
nlen = xdr_stream_decode_string_dup(xdr, &netid, XDR_MAX_NETOBJ,
gfp_flags);
if (unlikely(nlen < 0))
if (unlikely(nlen <= 0))
goto out_err;
/* r_addr: ip/ip6addr with port in dec octets - see RFC 5665 */
/* port is ".ABC.DEF", 8 chars max */
rlen = xdr_stream_decode_string_dup(xdr, &buf, INET6_ADDRSTRLEN +
IPV6_SCOPE_ID_LEN + 8, gfp_flags);
if (unlikely(rlen < 0))
if (unlikely(rlen <= 0))
goto out_free_netid;
/* replace port '.' with '-' */

View File

@ -131,10 +131,7 @@ static __be32 nfsacld_proc_setacl(struct svc_rqst *rqstp)
resp->status = fh_getattr(fh, &resp->stat);
out:
/* argp->acl_{access,default} may have been allocated in
nfssvc_decode_setaclargs. */
posix_acl_release(argp->acl_access);
posix_acl_release(argp->acl_default);
/* argp->acl_{access,default} are released in nfsaclsvc_release_setacl. */
return rpc_success;
out_drop_lock:
@ -310,6 +307,16 @@ static void nfsaclsvc_release_access(struct svc_rqst *rqstp)
fh_put(&resp->fh);
}
static void nfsaclsvc_release_setacl(struct svc_rqst *rqstp)
{
struct nfsd3_setaclargs *argp = rqstp->rq_argp;
struct nfsd_attrstat *resp = rqstp->rq_resp;
fh_put(&resp->fh);
posix_acl_release(argp->acl_access);
posix_acl_release(argp->acl_default);
}
#define ST 1 /* status*/
#define AT 21 /* attributes */
#define pAT (1+AT) /* post attributes - conditional */
@ -343,7 +350,7 @@ static const struct svc_procedure nfsd_acl_procedures2[5] = {
.pc_func = nfsacld_proc_setacl,
.pc_decode = nfsaclsvc_decode_setaclargs,
.pc_encode = nfssvc_encode_attrstatres,
.pc_release = nfssvc_release_attrstat,
.pc_release = nfsaclsvc_release_setacl,
.pc_argsize = sizeof(struct nfsd3_setaclargs),
.pc_argzero = sizeof(struct nfsd3_setaclargs),
.pc_ressize = sizeof(struct nfsd_attrstat),

View File

@ -118,10 +118,7 @@ out_drop_lock:
out_errno:
resp->status = nfserrno(error);
out:
/* argp->acl_{access,default} may have been allocated in
nfs3svc_decode_setaclargs. */
posix_acl_release(argp->acl_access);
posix_acl_release(argp->acl_default);
/* argp->acl_{access,default} are released in nfs3svc_release_setacl. */
return rpc_success;
}
@ -223,6 +220,16 @@ static void nfs3svc_release_getacl(struct svc_rqst *rqstp)
posix_acl_release(resp->acl_default);
}
static void nfs3svc_release_setacl(struct svc_rqst *rqstp)
{
struct nfsd3_setaclargs *argp = rqstp->rq_argp;
struct nfsd3_attrstat *resp = rqstp->rq_resp;
fh_put(&resp->fh);
posix_acl_release(argp->acl_access);
posix_acl_release(argp->acl_default);
}
#define ST 1 /* status*/
#define AT 21 /* attributes */
#define pAT (1+AT) /* post attributes - conditional */
@ -256,7 +263,7 @@ static const struct svc_procedure nfsd_acl_procedures3[3] = {
.pc_func = nfsd3_proc_setacl,
.pc_decode = nfs3svc_decode_setaclargs,
.pc_encode = nfs3svc_encode_setaclres,
.pc_release = nfs3svc_release_fhandle,
.pc_release = nfs3svc_release_setacl,
.pc_argsize = sizeof(struct nfsd3_setaclargs),
.pc_argzero = sizeof(struct nfsd3_setaclargs),
.pc_ressize = sizeof(struct nfsd3_attrstat),

View File

@ -256,9 +256,7 @@ nfsd4_alloc_layout_stateid(struct nfsd4_compound_state *cstate,
BUG_ON(!ls->ls_file);
if (nfsd4_layout_setlease(ls)) {
nfsd_file_put(ls->ls_file);
put_nfs4_file(fp);
kmem_cache_free(nfs4_layout_stateid_cache, ls);
nfs4_put_stid(stp);
return NULL;
}

View File

@ -6224,12 +6224,12 @@ nfsd4_add_rdaccess_to_wrdeleg(struct svc_rqst *rqstp, struct nfsd4_open *open,
return (false);
fp = stp->st_stid.sc_file;
spin_lock(&fp->fi_lock);
__nfs4_file_get_access(fp, NFS4_SHARE_ACCESS_READ);
if (!fp->fi_fds[O_RDONLY]) {
__nfs4_file_get_access(fp, NFS4_SHARE_ACCESS_READ);
fp->fi_fds[O_RDONLY] = nf;
fp->fi_rdeleg_file = nfsd_file_get(fp->fi_fds[O_RDONLY]);
nf = NULL;
}
fp->fi_rdeleg_file = nfsd_file_get(fp->fi_fds[O_RDONLY]);
spin_unlock(&fp->fi_lock);
if (nf)
nfsd_file_put(nf);

View File

@ -4093,6 +4093,8 @@ SMB2_change_notify(const unsigned int xid, struct cifs_tcon *tcon,
replay_again:
/* reinitialize for possible replay */
resp_buftype = CIFS_NO_BUFFER;
memset(&rsp_iov, 0, sizeof(rsp_iov));
flags = 0;
server = cifs_pick_channel(ses);

View File

@ -213,7 +213,9 @@ smb2_find_smb_sess_tcon_unlocked(struct cifs_ses *ses, __u32 tid)
list_for_each_entry(tcon, &ses->tcon_list, tcon_list) {
if (tcon->tid != tid)
continue;
spin_lock(&tcon->tc_lock);
++tcon->tc_count;
spin_unlock(&tcon->tc_lock);
trace_smb3_tcon_ref(tcon->debug_id, tcon->tc_count,
netfs_trace_tcon_ref_get_find_sess_tcon);
return tcon;

View File

@ -218,7 +218,10 @@ static inline bool vma_can_userfault(struct vm_area_struct *vma,
{
vm_flags &= __VM_UFFD_FLAGS;
if (vm_flags & VM_DROPPABLE)
if (vma->vm_flags & (VM_DROPPABLE | VM_SHADOW_STACK))
return false;
if (!is_vm_hugetlb_page(vma) && (vma->vm_flags & VM_SPECIAL))
return false;
if ((vm_flags & VM_UFFD_MINOR) &&

View File

@ -112,7 +112,8 @@ int sctp_transport_lookup_process(sctp_callback_t cb, struct net *net,
const union sctp_addr *paddr, void *p, int dif);
int sctp_transport_traverse_process(sctp_callback_t cb, sctp_callback_t cb_done,
struct net *net, int *pos, void *p);
int sctp_for_each_endpoint(int (*cb)(struct sctp_endpoint *, void *), void *p);
int sctp_for_each_endpoint(int (*cb)(struct sctp_endpoint *, void *),
struct net *net, int *pos, void *p);
int sctp_get_sctp_info(struct sock *sk, struct sctp_association *asoc,
struct sctp_info *info);

View File

@ -1,2 +1,2 @@
sbat,1,SBAT Version,sbat,1,https://github.com/rhboot/shim/blob/main/SBAT.md
kernel.almalinux,1,AlmaLinux,kernel-core,6.12.0-211.49.1.el10.x86_64,mailto:security@almalinux.org
kernel.almalinux,1,AlmaLinux,kernel-core,6.12.0-211.50.1.el10.x86_64,mailto:security@almalinux.org

View File

@ -79,10 +79,27 @@ void __sched rt_spin_unlock(spinlock_t *lock) __releases(RCU)
{
spin_release(&lock->dep_map, _RET_IP_);
migrate_enable();
rcu_read_unlock();
if (unlikely(!rt_mutex_cmpxchg_release(&lock->lock, current, NULL)))
rt_mutex_slowunlock(&lock->lock);
/*
* This must be last to prevent the following UAF:
*
* T1 T2
* spin_lock(&p->lock); rcu_read_lock();
* invalidate(p); p = rcu_dereference(ptr);
* rcu_assign_pointer(ptr, NULL); if (!p) return;
* spin_unlock(&p->lock); spin_lock(&p->lock);
* kfree_rcu(p); rcu_read_unlock();
* ....
* spin_unlock(&p->lock)
* rcu_read_unlock(); // Ends grace period
* rcu_do_batch()
* kfree(p);
* UAF -> rt_mutex_cmpxchg_release(&p->lock.lock...)
*/
rcu_read_unlock();
}
EXPORT_SYMBOL(rt_spin_unlock);
@ -262,17 +279,21 @@ void __sched rt_read_unlock(rwlock_t *rwlock) __releases(RCU)
{
rwlock_release(&rwlock->dep_map, _RET_IP_);
migrate_enable();
rcu_read_unlock();
rwbase_read_unlock(&rwlock->rwbase, TASK_RTLOCK_WAIT);
/* This must be last. See comment in rt_spin_unlock() */
rcu_read_unlock();
}
EXPORT_SYMBOL(rt_read_unlock);
void __sched rt_write_unlock(rwlock_t *rwlock) __releases(RCU)
{
rwlock_release(&rwlock->dep_map, _RET_IP_);
rcu_read_unlock();
migrate_enable();
rwbase_write_unlock(&rwlock->rwbase);
/* This must be last. See comment in rt_spin_unlock() */
rcu_read_unlock();
}
EXPORT_SYMBOL(rt_write_unlock);

View File

@ -749,6 +749,15 @@ static bool seccomp_is_const_allow(struct sock_fprog_kern *fprog,
if (WARN_ON_ONCE(!fprog))
return false;
/* Our single exception to filtering. */
#ifdef __NR_uretprobe
#ifdef SECCOMP_ARCH_COMPAT
if (sd->arch == SECCOMP_ARCH_NATIVE)
#endif
if (sd->nr == __NR_uretprobe)
return true;
#endif
for (pc = 0; pc < fprog->len; pc++) {
struct sock_filter *insn = &fprog->filter[pc];
u16 code = insn->code;
@ -1023,6 +1032,9 @@ static inline void seccomp_log(unsigned long syscall, long signr, u32 action,
*/
static const int mode1_syscalls[] = {
__NR_seccomp_read, __NR_seccomp_write, __NR_seccomp_exit, __NR_seccomp_sigreturn,
#ifdef __NR_uretprobe
__NR_uretprobe,
#endif
-1, /* negative terminated */
};

View File

@ -2778,7 +2778,9 @@ static void __split_huge_pmd_locked(struct vm_area_struct *vma, pmd_t *pmd,
if (!folio_test_referenced(folio) && pmd_young(old_pmd))
folio_set_referenced(folio);
folio_remove_rmap_pmd(folio, page, vma);
add_mm_counter(mm, mm_counter_file(folio), -HPAGE_PMD_NR);
folio_put(folio);
return;
}
add_mm_counter(mm, mm_counter_file(folio), -HPAGE_PMD_NR);
return;

View File

@ -2052,21 +2052,6 @@ out_unlock:
goto xa_unlocked;
}
if (!is_shmem) {
filemap_nr_thps_inc(mapping);
/*
* Paired with the fence in do_dentry_open() -> get_write_access()
* to ensure i_writecount is up to date and the update to nr_thps
* is visible. Ensures the page cache will be truncated if the
* file is opened writable.
*/
smp_mb();
if (inode_is_open_for_write(mapping->host)) {
result = SCAN_FAIL;
filemap_nr_thps_dec(mapping);
}
}
xa_locked:
xas_unlock_irq(&xas);
xa_unlocked:
@ -2078,6 +2063,32 @@ xa_unlocked:
*/
try_to_unmap_flush();
if (result == SCAN_SUCCEED && !is_shmem && !mapping_large_folio_support(mapping)) {
/*
* invalidate_lock as shared excludes against concurrent opens
* in do_dentry_open() truncating the page cache. This is
* particularly important if there are dirty folios in transit.
*/
filemap_invalidate_lock_shared(mapping);
filemap_nr_thps_inc(mapping);
/*
* Paired with the fence in do_dentry_open() -> get_write_access()
* to ensure i_writecount is up to date and the update to nr_thps
* is visible. Ensures the page cache will be truncated if the
* file is opened writable. If collapse looks to be successful,
* flush any dirty pages out the page cache. With the nr_thps
* incremented, there won't be any new writers (nor new dirties).
*/
smp_mb();
if (inode_is_open_for_write(mapping->host) || filemap_write_and_wait(mapping)) {
result = SCAN_FAIL;
filemap_nr_thps_dec(mapping);
filemap_invalidate_unlock_shared(mapping);
goto rollback;
}
filemap_invalidate_unlock_shared(mapping);
}
if (result == SCAN_SUCCEED && nr_none &&
!shmem_charge(mapping->host, nr_none))
result = SCAN_FAIL;

View File

@ -468,26 +468,29 @@ void memcg_reparent_list_lrus(struct mem_cgroup *memcg, struct mem_cgroup *paren
mutex_lock(&list_lrus_mutex);
list_for_each_entry(lru, &memcg_list_lrus, list) {
struct list_lru_memcg *mlru;
XA_STATE(xas, &lru->xa, memcg->kmemcg_id);
/*
* Lock the Xarray to ensure no on going list_lru_memcg
* allocation and further allocation will see css_is_dying().
* css_is_dying() check in memcg_list_lru_alloc() avoids
* allocating a new mlru since CSS_DYING is already set for this
* memcg a rcu grace period ago.
*/
xas_lock_irq(&xas);
mlru = xas_store(&xas, NULL);
xas_unlock_irq(&xas);
mlru = xa_load(&lru->xa, memcg->kmemcg_id);
if (!mlru)
continue;
/*
* With Xarray value set to NULL, holding the lru lock below
* prevents list_lru_{add,del,isolate} from touching the lru,
* safe to reparent.
* Reparent each per-node list and mark the child dead
* (LONG_MIN) before clearing xarray entry otherwise a
* concurrent list_lru_del() may corrupt the list if it arrives
* after xarray clear but before reparenting as
* lock_list_lru_of_memcg will acquire parent's lock while the
* item is still on child's list.
*/
for_each_node(i)
memcg_reparent_list_lru_one(lru, i, &mlru->node[i], parent);
xa_erase_irq(&lru->xa, memcg->kmemcg_id);
/*
* Here all list_lrus corresponding to the cgroup are guaranteed
* to remain empty, we can safely free this lru, any further

View File

@ -59,12 +59,14 @@ static inline int shrinker_unit_alloc(struct shrinker_info *new,
return 0;
}
void free_shrinker_info(struct mem_cgroup *memcg)
static void __free_shrinker_info(struct mem_cgroup *memcg)
{
struct mem_cgroup_per_node *pn;
struct shrinker_info *info;
int nid;
lockdep_assert_held(&shrinker_mutex);
for_each_node(nid) {
pn = memcg->nodeinfo[nid];
info = rcu_dereference_protected(pn->shrinker_info, true);
@ -74,6 +76,13 @@ void free_shrinker_info(struct mem_cgroup *memcg)
}
}
void free_shrinker_info(struct mem_cgroup *memcg)
{
mutex_lock(&shrinker_mutex);
__free_shrinker_info(memcg);
mutex_unlock(&shrinker_mutex);
}
int alloc_shrinker_info(struct mem_cgroup *memcg)
{
int nid, ret = 0;
@ -98,8 +107,8 @@ int alloc_shrinker_info(struct mem_cgroup *memcg)
return ret;
err:
__free_shrinker_info(memcg);
mutex_unlock(&shrinker_mutex);
free_shrinker_info(memcg);
return -ENOMEM;
}

View File

@ -186,10 +186,12 @@ int shrinker_debugfs_add(struct shrinker *shrinker)
}
shrinker->debugfs_entry = entry;
debugfs_create_file("count", 0440, entry, shrinker,
&shrinker_debugfs_count_fops);
debugfs_create_file("scan", 0220, entry, shrinker,
&shrinker_debugfs_scan_fops);
if (shrinker->count_objects)
debugfs_create_file("count", 0440, entry, shrinker,
&shrinker_debugfs_count_fops);
if (shrinker->scan_objects)
debugfs_create_file("scan", 0220, entry, shrinker,
&shrinker_debugfs_scan_fops);
return 0;
}

View File

@ -2292,10 +2292,11 @@ static int ip6erspan_changelink(struct net_device *dev, struct nlattr *tb[],
struct nlattr *data[],
struct netlink_ext_ack *extack)
{
struct ip6gre_net *ign = net_generic(dev_net(dev), ip6gre_net_id);
struct ip6_tnl *t = netdev_priv(dev);
struct __ip6_tnl_parm p;
struct ip6_tnl *t;
struct ip6gre_net *ign;
ign = net_generic(t->net, ip6gre_net_id);
t = ip6gre_changelink_common(dev, tb, data, &p, extack);
if (IS_ERR(t))
return PTR_ERR(t);

View File

@ -850,7 +850,7 @@ static int __ip6_tnl_rcv(struct ip6_tnl *tunnel, struct sk_buff *skb,
skb_reset_network_header(skb);
if (!pskb_inet_may_pull(skb)) {
if (skb_vlan_inet_prepare(skb, true)) {
DEV_STATS_INC(tunnel->dev, rx_length_errors);
DEV_STATS_INC(tunnel->dev, rx_errors);
goto drop;

View File

@ -1480,7 +1480,11 @@ ip_set_dump_done(struct netlink_callback *cb)
struct ip_set_net *inst =
(struct ip_set_net *)cb->args[IPSET_CB_NET];
ip_set_id_t index = (ip_set_id_t)cb->args[IPSET_CB_INDEX];
struct ip_set *set = ip_set_ref_netlink(inst, index);
struct ip_set *set;
rcu_read_lock();
set = ip_set_ref_netlink(inst, index);
rcu_read_unlock();
if (set->variant->uref)
set->variant->uref(set, cb, false);
@ -1685,7 +1689,9 @@ next_set:
release_refcount:
/* If there was an error or set is done, release set */
if (ret || !cb->args[IPSET_CB_ARG0]) {
rcu_read_lock();
set = ip_set_ref_netlink(inst, index);
rcu_read_unlock();
if (set->variant->uref)
set->variant->uref(set, cb, false);
pr_debug("release set %s\n", set->name);

View File

@ -9968,7 +9968,7 @@ static int nft_flowtable_event(unsigned long event, struct net_device *dev,
break;
case NETDEV_REGISTER:
/* NOP if not matching or already registered */
if (!match || (changename && ops))
if (!match || ops)
continue;
ops = kzalloc(sizeof(struct nf_hook_ops),

View File

@ -603,10 +603,10 @@ restart:
goto out;
}
}
}
if (cb->args[1]) {
cb->args[1] = 0;
goto restart;
if (cb->args[1]) {
cb->args[1] = 0;
goto restart;
}
}
out:
rcu_read_unlock();

View File

@ -344,7 +344,7 @@ static int nft_netdev_event(unsigned long event, struct net_device *dev,
break;
case NETDEV_REGISTER:
/* NOP if not matching or already registered */
if (!match || (changename && ops))
if (!match || ops)
continue;
ops = kmemdup(&basechain->ops,

View File

@ -92,6 +92,7 @@ static int inet_diag_msg_sctpladdrs_fill(struct sk_buff *skb,
if (!--addrcnt)
break;
}
WARN_ON_ONCE(addrcnt);
rcu_read_unlock();
return 0;
@ -372,42 +373,39 @@ static int sctp_ep_dump(struct sctp_endpoint *ep, void *p)
struct sk_buff *skb = commp->skb;
struct netlink_callback *cb = commp->cb;
const struct inet_diag_req_v2 *r = commp->r;
struct net *net = sock_net(skb->sk);
struct inet_sock *inet = inet_sk(sk);
int err = 0;
if (!net_eq(sock_net(sk), net))
lock_sock(sk);
if (ep->base.dead)
goto out;
if (cb->args[4] < cb->args[1])
goto next;
if (!(r->idiag_states & TCPF_LISTEN) && !list_empty(&ep->asocs))
goto next;
/* Skip eps with assocs if non-LISTEN states were requested, since
* they'll be dumped by sctp_sock_dump() during assoc traversal.
*/
if ((r->idiag_states & ~(TCPF_LISTEN | TCPF_CLOSE)) &&
!list_empty(&ep->asocs))
goto out;
if (r->sdiag_family != AF_UNSPEC &&
sk->sk_family != r->sdiag_family)
goto next;
goto out;
if (r->id.idiag_sport != inet->inet_sport &&
r->id.idiag_sport)
goto next;
goto out;
if (r->id.idiag_dport != inet->inet_dport &&
r->id.idiag_dport)
goto next;
if (inet_sctp_diag_fill(sk, NULL, skb, r,
sk_user_ns(NETLINK_CB(cb->skb).sk),
NETLINK_CB(cb->skb).portid,
cb->nlh->nlmsg_seq, NLM_F_MULTI,
cb->nlh, commp->net_admin) < 0) {
err = 2;
goto out;
}
next:
cb->args[4]++;
err = inet_sctp_diag_fill(sk, NULL, skb, r,
sk_user_ns(NETLINK_CB(cb->skb).sk),
NETLINK_CB(cb->skb).portid,
cb->nlh->nlmsg_seq, NLM_F_MULTI,
cb->nlh, commp->net_admin);
out:
release_sock(sk);
return err;
}
@ -478,41 +476,40 @@ static void sctp_diag_dump(struct sk_buff *skb, struct netlink_callback *cb,
.r = r,
.net_admin = netlink_net_capable(cb->skb, CAP_NET_ADMIN),
};
int pos = cb->args[2];
int pos;
/* eps hashtable dumps
* args:
* 0 : if it will traversal listen sock
* 1 : to record the sock pos of this time's traversal
* 4 : to work as a temporary variable to traversal list
*/
if (cb->args[0] == 0) {
if (!(idiag_states & TCPF_LISTEN))
goto skip;
if (sctp_for_each_endpoint(sctp_ep_dump, &commp))
goto done;
skip:
if (idiag_states & TCPF_LISTEN) {
pos = cb->args[1];
if (sctp_for_each_endpoint(sctp_ep_dump, net, &pos,
&commp)) {
cb->args[1] = pos;
return;
}
}
cb->args[0] = 1;
cb->args[1] = 0;
cb->args[4] = 0;
}
if (!(idiag_states & ~(TCPF_LISTEN | TCPF_CLOSE)))
return;
/* asocs by transport hashtable dump
* args:
* 1 : to record the assoc pos of this time's traversal
* 2 : to record the transport pos of this time's traversal
* 3 : to mark if we have dumped the ep info of the current asoc
* 4 : to work as a temporary variable to traversal list
* 5 : to save the sk we get from travelsing the tsp list.
* 4 : to track position within ep->asocs list in sctp_sock_dump()
*/
if (!(idiag_states & ~(TCPF_LISTEN | TCPF_CLOSE)))
goto done;
pos = cb->args[2];
sctp_transport_traverse_process(sctp_sock_filter, sctp_sock_dump,
net, &pos, &commp);
cb->args[2] = pos;
done:
cb->args[1] = cb->args[4];
cb->args[4] = 0;
}

View File

@ -5323,24 +5323,39 @@ struct sctp_transport *sctp_transport_get_idx(struct net *net,
}
int sctp_for_each_endpoint(int (*cb)(struct sctp_endpoint *, void *),
void *p) {
int err = 0;
int hash = 0;
struct sctp_endpoint *ep;
struct net *net, int *pos, void *p) {
int err, hash = 0, idx = 0, start;
struct sctp_hashbucket *head;
struct sctp_endpoint *ep;
for (head = sctp_ep_hashtable; hash < sctp_ep_hashsize;
hash++, head++) {
start = idx;
again:
read_lock_bh(&head->lock);
sctp_for_each_hentry(ep, &head->chain) {
err = cb(ep, p);
if (err)
if (sock_net(ep->base.sk) != net)
continue;
if (idx++ >= *pos) {
sctp_endpoint_hold(ep);
break;
}
}
read_unlock_bh(&head->lock);
if (ep) {
err = cb(ep, p);
sctp_endpoint_put(ep);
if (err)
return err;
(*pos)++;
idx = start;
goto again;
}
}
return err;
return 0;
}
EXPORT_SYMBOL_GPL(sctp_for_each_endpoint);

View File

@ -768,6 +768,7 @@ sources-rh: $(TARBALL) $(KABI_TARBALL) $(KABIDW_TARBALL) generate-testpatch-tmp
scripts/mod/mod-sign.sh \
scripts/uki_addons/uki_create_addons.py \
scripts/uki_addons/uki_addons.json \
scripts/kmap.py \
configs/flavors \
configs/generate_all_configs.sh \
configs/merge.py \

View File

@ -1,3 +1,49 @@
* Mon Aug 31 2026 CKI KWF Bot <cki-ci-bot+kwf-gitlab-com@redhat.com> [6.12.0-211.50.1.el10_2]
- redhat: add kmap.py tool and kernel-kmap-internal package (Rado Vrbovsky)
- nvmet-auth: reject short AUTH_RECEIVE buffers (CKI Backport Bot) [RHEL-244915] {CVE-2026-72130}
- locking/rt: Fix the incorrect RCU protection in rt_spin_unlock() (CKI Backport Bot) [RHEL-242861] {CVE-2026-72069}
- s390: Revert support for DCACHE_WORD_ACCESS (John J Coleman) [RHEL-188180]
- NFSv4: include MAY_WRITE in open permission mask for O_TRUNC (CKI Backport Bot) [RHEL-234051] {CVE-2026-64298}
- nfsd: release layout stid on setlease failure (Scott Mayhew) [RHEL-227794] {CVE-2026-53399}
- NFSv4/flexfiles: reject zero filehandle version count (CKI Backport Bot) [RHEL-229415] {CVE-2026-53392}
- NFSv4/pNFS: reject zero-length r_addr in nfs4_decode_mp_ds_addr (CKI Backport Bot) [RHEL-228036] {CVE-2026-53391}
- NFSD: fix nfs4_file access extra count in nfsd4_add_rdaccess_to_wrdeleg (CKI Backport Bot) [RHEL-227946] {CVE-2026-53026}
- pNFS: Fix use-after-free in pnfs_update_layout() (CKI Backport Bot) [RHEL-226322] {CVE-2026-63800}
- nfsd: fix posix_acl leak on SETACL decode failure (CKI Backport Bot) [RHEL-225522] {CVE-2026-53397}
- mm/khugepaged: write all dirty file folios when collapsing (Rafael Aquini) [RHEL-236329] {CVE-2026-68086}
- userfaultfd: prevent registration of special VMAs (Rafael Aquini) [RHEL-237862] {CVE-2026-68166}
- userfaultfd: correctly prevent registering VM_DROPPABLE regions (Rafael Aquini) [RHEL-237862] {CVE-2026-68166}
- crypto: qat - fix VF2PF work teardown race in adf_disable_sriov() (Vladislav Dronov) [RHEL-234477] {CVE-2026-64438}
- mm: shrinker: fix NULL pointer dereference in debugfs (Rafael Aquini) [RHEL-230833] {CVE-2026-64417}
- mm: shrinker: fix shrinker_info teardown race with expansion (Rafael Aquini) [RHEL-230833] {CVE-2026-64418}
- x86/bugs: Make Safe-RET robust against interrupt injection (Waiman Long) [RHEL-230475] {CVE-2026-68480}
- crypto: qat - validate RSA CRT component lengths (CKI Backport Bot) [RHEL-234546] {CVE-2026-64304}
- Input: synaptics-rmi4 - bound the F3A keymap to the GPIO count (CKI Backport Bot) [RHEL-231446] {CVE-2026-64277}
- mm/huge_memory: update file PMD counter before folio_put() (CKI Backport Bot) [RHEL-231228] {CVE-2026-53189}
- Input: synaptics-rmi4 - bound the F30 keymap to the GPIO/LED count (CKI Backport Bot) [RHEL-230263] {CVE-2026-64276}
- ALSA: virtio: Validate control metadata from the device (CKI Backport Bot) [RHEL-230142] {CVE-2026-64490}
- net: mana: validate rx_req_idx to prevent out-of-bounds array access (CKI Backport Bot) [RHEL-229231] {CVE-2026-64018}
- smb: client: protect tc_count increment in smb2_find_smb_sess_tcon_unlocked() (CKI Backport Bot) [RHEL-228550] {CVE-2026-64136}
- bonding: alb: fix UAF in rlb_arp_recv during bond up/down (CKI Backport Bot) [RHEL-225292] {CVE-2026-45970}
- netfilter: ipset: fix race between dump and ip_set_list resize (CKI Backport Bot) [RHEL-227657] {CVE-2026-64189}
- iommu/amd: Fix clone_alias() to use the original device's devid (CKI Backport Bot) [RHEL-227452] {CVE-2026-53053}
- smb: client: fix change notify replay double-free (CKI Backport Bot) [RHEL-226988] {CVE-2026-64384}
- mm/list_lru: drain before clearing xarray entry on reparent (Rafael Aquini) [RHEL-227399] {CVE-2026-53153}
- s390/pfault: Fix virtual vs physical address confusion (Ramesh Chhetri) [RHEL-222507]
- crypto: qat - cancel work on re-enable SR-IOV timeout (CKI Backport Bot) [RHEL-218627]
- nvmet: fix pre-auth out-of-bounds heap read in Discovery Get Log Page (CKI Backport Bot) [RHEL-219623] {CVE-2026-64320}
- sctp: hold socket lock when dumping endpoints in sctp_diag (CKI Backport Bot) [RHEL-212393]
- seccomp: passthrough uretprobe systemcall without filtering (Ricardo Robaina) [RHEL-210908] {CVE-2025-21834}
- qede: fix off-by-one in BD ring consumption on build_skb failure (CKI Backport Bot) [RHEL-193043]
- zram: fix use-after-free in zram_bvec_write_partial() (CKI Backport Bot) [RHEL-191442] {CVE-2026-53185}
- USB: serial: io_ti: fix heap overflow in build_i2c_fw_hdr() (Desnes Nunes) [RHEL-191042] {CVE-2026-53195}
- USB: serial: io_ti: fix heap overflow in get_manuf_info() (Desnes Nunes) [RHEL-191042] {CVE-2026-53196}
- ip6_tunnel: use skb_vlan_inet_prepare() in __ip6_tnl_rcv() (CKI Backport Bot) [RHEL-189631] {CVE-2026-23003}
- ip6_gre: Use cached t->net in ip6erspan_changelink(). (CKI Backport Bot) [RHEL-180136] {CVE-2026-46120}
- netfilter: nf_tables: Fix for duplicate device in netdev hooks (CKI Backport Bot) [RHEL-179761] {CVE-2026-43454}
- netfilter: nfnetlink_cthelper: fix OOB read in nfnl_cthelper_dump_table() (CKI Backport Bot) [RHEL-179744] {CVE-2026-43450}
Resolves: RHEL-179744, RHEL-179761, RHEL-180136, RHEL-188180, RHEL-189631, RHEL-191042, RHEL-191442, RHEL-193043, RHEL-210908, RHEL-212393, RHEL-218627, RHEL-219623, RHEL-222507, RHEL-225292, RHEL-225522, RHEL-226322, RHEL-226988, RHEL-227399, RHEL-227452, RHEL-227657, RHEL-227794, RHEL-227946, RHEL-228036, RHEL-228550, RHEL-229231, RHEL-229415, RHEL-230142, RHEL-230263, RHEL-230475, RHEL-230833, RHEL-231228, RHEL-231446, RHEL-234051, RHEL-234477, RHEL-234546, RHEL-236329, RHEL-237862, RHEL-242861, RHEL-244915
* Wed Aug 19 2026 CKI KWF Bot <cki-ci-bot+kwf-gitlab-com@redhat.com> [6.12.0-211.49.1.el10_2]
- udf: fix partition descriptor append bookkeeping (CKI Backport Bot) [RHEL-179570] {CVE-2026-45991}
- cifs: fix time_last_write stamp placement in setattr/truncate paths (Paulo Alcantara) [RHEL-235459]

View File

@ -250,6 +250,8 @@ Summary: The Linux kernel
%define with_ynl %{?_without_ynl: 0} %{?!_without_ynl: 1}
# kernel-debuginfo
%define with_debuginfo %{?_without_debuginfo: 0} %{?!_without_debuginfo: 1}
# kernel-kmap-internal: source-to-module mapping data (JSON)
%define with_kmap %{?_without_kmap: 0} %{?!_without_kmap: 1}
# kernel-abi-stablelists
%define with_kernel_abi_stablelists %{?_without_kernel_abi_stablelists: 0} %{?!_without_kernel_abi_stablelists: 1}
# internal samples and selftests
@ -631,6 +633,10 @@ Summary: The Linux kernel
%define _enable_debug_packages 0
%endif
%ifnarch x86_64 ppc64le s390x aarch64 riscv64
%define with_kmap 0
%endif
# Architectures we build tools/cpupower on
%if 0%{?fedora}
%define cpupowerarchs %{ix86} x86_64 ppc64le aarch64
@ -1103,6 +1109,9 @@ Source489: %{name}-x86_64-automotive-debug-rhel.config
# Sources for kernel-tools
Source2002: kvm_stat.logrotate
# Sources for kernel-kmap-internal
Source2100: kmap.py
# Some people enjoy building customized kernels from the dist-git in Fedora and
# use this to override configuration options. One day they may all use the
# source tree, but in the mean time we carry this to support the legacy workflow
@ -1377,6 +1386,27 @@ analysing the logical and timing behavior of Linux.
# with_tools
%endif
%if %{with_kmap} && %{with_base}
%package -n %{name}-kmap-internal
Summary: Kernel source-to-module mapping data and module list
Group: Development/System
BuildRequires: python3
%description -n %{name}-kmap-internal
The %{name}-kmap-internal package contains a JSON mapping file that describes
which C source files contributed to each kernel module and to the built-in
vmlinux image, and which RPM package each module is shipped in.
Files installed under /usr/share/%{name}-kmap-internal/:
kernel-map-<KVERREL>.json - unified mapping file for all kernel variants containing:
- variants: list of variant names (e.g., ["stock", "rt", "automotive"])
- source-map: source file mappings
- obj-src: maps kernel objects to source files with variant indices
- src-obj: maps source files to kernel objects with variant indices
- module-map: module to RPM mappings
- module-rpm: maps module names to RPM package names with variant indices
- rpm-modules: maps RPM package names to module names with variant indices
%endif
%if %{with_selftests}
%package selftests-internal
@ -2940,6 +2970,44 @@ BuildKernel() {
%endif
fi # $DoModules -eq 1
%if %{with_kmap} && %{with_base}
# Generate source-to-module mapping data using kmap.py.
# Must run before the next BuildKernel call issues make mrproper, which
# would wipe the .cmd files that kmap.py reads. Skip debug variants
# (same source mapping as the base kernel).
if [[ "$Variant" != *debug* ]]; then
_kmap_bdir=$(pwd)
_kmap_basedir=%{_builddir}/kmap-data
_kmap_merged=$_kmap_basedir/kernel-map.json
_kmap_variant=${Variant:-stock}
_kmap_listprefix=../kernel${Variant:+-${Variant}}
mkdir -p $_kmap_basedir
# Build kmap.py arguments; merge with existing data if present
_kmap_args="--directory $_kmap_bdir --outputdir $_kmap_basedir --rhel upstream --variant $_kmap_variant --time"
_kmap_args="$_kmap_args --vmlinux-rpm %{name}-core-%{KVERREL}.rpm"
if [ -f "$_kmap_merged" ]; then
_kmap_args="$_kmap_args --input kernel-map.json"
fi
# Add module list files for module-to-RPM mapping
for _kmap_type in modules-core modules modules-extra modules-internal; do
if [ -f "${_kmap_listprefix}-${_kmap_type}.list" ]; then
_kmap_rpm=%{name}-${_kmap_type}-%{KVERREL}.rpm
_kmap_args="$_kmap_args --module-list ${_kmap_rpm}:${_kmap_listprefix}-${_kmap_type}.list"
fi
done
%if 0%{!?fedora:1}
if [ -f "${_kmap_listprefix}-modules-partner.list" ]; then
_kmap_rpm=%{name}-modules-partner-%{KVERREL}.rpm
_kmap_args="$_kmap_args --module-list ${_kmap_rpm}:${_kmap_listprefix}-modules-partner.list"
fi
%endif
python3 %{SOURCE2100} $_kmap_args
fi
%endif
remove_depmod_files()
{
# remove files that will be auto generated by depmod at rpm -i time
@ -3829,6 +3897,14 @@ find -type f ! -executable -exec install -D -m644 {} %{buildroot}%{_libexecdir}/
popd
%endif
%if %{with_kmap} && %{with_base}
# Install kmap data files produced during %build.
_kmap_basedir=%{_builddir}/kmap-data
_kmap_destbase=$RPM_BUILD_ROOT%{_datadir}/%{name}-kmap-internal
mkdir -p $_kmap_destbase
install -m 644 $_kmap_basedir/kernel-map.json $_kmap_destbase/kernel-map-%{KVERREL}.json
%endif
###
### clean
###
@ -4320,6 +4396,13 @@ fi\
%{_libexecdir}/kselftests
%endif
%if %{with_kmap} && %{with_base}
%files -n %{name}-kmap-internal
%defattr(-,root,root)
%dir %{_datadir}/%{name}-kmap-internal
%{_datadir}/%{name}-kmap-internal/kernel-map-%{KVERREL}.json
%endif
# empty meta-package
%if %{with_up_base}
%ifnarch %nobuildarches noarch

874
redhat/scripts/kmap.py Executable file
View File

@ -0,0 +1,874 @@
#!/usr/bin/env python3
"""
kmap.py - Kernel Source-to-Binary Mapping Tool
DESCRIPTION
This tool parses Linux kernel build artifacts (.cmd files, archives) to
create a JSON mapping of which source files contribute to which kernel
binaries (modules and vmlinux). It supports merging data from multiple
kernel build variants (e.g., stock, debug, rt) into a single output
file using variant indices to track per-variant mappings.
Supported RHEL versions: 7, 8, 9, upstream
FEATURES
- Parses .cmd files generated by kbuild to extract compilation commands
- Supports C (gcc/clang) and Rust (rustc) source files
- Handles built-in objects via built-in.o.cmd (RHEL 7), built-in.a
(RHEL 8/9), or vmlinux.a (upstream)
- Merges multiple kernel variants into single output with variant indices
- Maps modules to their containing RPM packages
OUTPUT FORMAT
The output is a JSON file with the following structure:
{
"variants": ["stock", "rt", ...],
"source-map": {
"obj-src": {<object>: {<source>: [<variant_indices>]}},
"src-obj": {<source>: {<object>: [<variant_indices>]}}
},
"module-map": {
"module-rpm": {<module>: {<rpm_name>: [<variant_indices>]}},
"rpm-modules": {<rpm_name>: {<module>: [<variant_indices>]}}
}
}
PARSING THE OUTPUT
import json
with open('kernel-map.json') as f:
data = json.load(f)
variants = data['variants']
obj_src = data['source-map']['obj-src']
src_obj = data['source-map']['src-obj']
module_rpm = data['module-map']['module-rpm']
rpm_modules = data['module-map']['rpm-modules']
# Get sources for vmlinux in variant "stock" (index 0)
vmlinux_sources = [src for src, indices in obj_src['vmlinux'].items()
if 0 in indices]
# Find which object a source contributes to
fork_objects = [obj for obj, indices in src_obj['kernel/fork.c'].items()
if 0 in indices]
# Get RPM for a module
def get_rpm(module, variant_idx):
for rpm, indices in module_rpm.get(module, {}).items():
if variant_idx in indices:
return rpm
return None
USAGE
# Single variant
./kmap.py -d /build/stock -r upstream -v stock -o /output
# Merge multiple variants
./kmap.py -d /build/stock -r upstream -v stock -o /output
./kmap.py -d /build/debug -r upstream -v debug -o /output -i kernel-map.json
./kmap.py -d /build/rt -r upstream -v rt -o /output -i kernel-map.json
# With module-to-RPM mapping
./kmap.py -d /build -r upstream -v stock -o /output \\
--vmlinux-rpm kernel-core-5.14.0.rpm \\
--module-list kernel-modules-5.14.0.rpm:modules.list
CREDITS
Inspired by gen_compile_commands.py and Joe Lawrence.
Time measurement option added for Jan Stancek.
"""
import re
import os
import pathlib
import json
import argparse
import subprocess
import time
# =============================================================================
# Constants
# =============================================================================
VMLINUX = 'vmlinux'
KERNEL_PREFIX = 'kernel/'
# Supported compilers and linkers
COMPILERS = ('gcc', 'clang')
LINKER = 'ld'
RUST_COMPILER = 'rustc'
# =============================================================================
# Regex Patterns
#
# These patterns parse the kernel build .cmd files to extract:
# - What compiler/linker was used
# - What source files were compiled
# - What object files were linked
# =============================================================================
# Pattern for .ko.cmd files (module linking)
# Matches: cmd_path/to/module.ko := ld <params> -o <ko_name> <input_files>
# Note: upstream kernels use 'savedcmd_' prefix instead of 'cmd_'
_KO_CMD_PATTERN = (
r'^(saved)?cmd_[^ ]*\.ko\s*:=\s*ld\s+'
r'(?P<params>.*) -o (?P<ko_name>\S+) (?P<input_files>[^;]+?)\s*(?:;|$)'
)
# Pattern for .o.cmd files (object compilation)
# Matches multiple formats:
# - C/asm: cmd_*.o := gcc/clang <params> -o <output> <input>
# - Rust: cmd_*.o := rustc <params> --emit=obj=<output> <input.rs>
# - Rust source mapping: source_*.o := <file.rs>
_O_CMD_PATTERN = (
r'^(saved)?(?:cmd_|source_)[^ ]*\.o\s+:=\s+'
r'(?:'
r'(?P<prefix>(?:\S+=\S+\s+)*)?'
r'(?P<command>gcc|clang|ld|rustc)\s+'
r'(?P<params>.*?)'
r'(?:'
r'\s+-o\s+(?P<obj_out>\S+)\s+(?P<input_files>[^;]+?)'
r'|'
r'\s+--emit=obj=(?P<rust_obj_out>\S+).*?\s+(?P<rust_input_file>\S+\.rs)'
r')'
r'|'
r'(?P<source_file>\S+\.rs)'
r')\s*(?:;|$)'
)
ko_matcher = re.compile(_KO_CMD_PATTERN)
o_matcher = re.compile(_O_CMD_PATTERN)
# =============================================================================
# Utility Functions
# =============================================================================
def parse_args():
"""
Parse command line arguments
"""
parser = argparse.ArgumentParser(
prog='Kernel Build Mapper',
description='Scrape Linux Kernel .cmd files to map contribution '
'of individual source files to kernel binaries.',
)
parser.add_argument('-d', '--directory',
help='Directory with kernel build artifacts.',
default='',
type=str)
parser.add_argument('-o', '--outputdir',
help='Directory where to put generated files.',
default='',
type=str)
parser.add_argument('-p', '--prefix',
help='Name prefix to the generated files.',
default='',
type=str)
parser.add_argument('-r', '--rhel',
help='Specify to what version of RHEL artifacts belong (upstream for RHEL 10+/kernel-ark)',
choices=['7', '8', '9', 'upstream'],
required=True)
parser.add_argument('-m', '--no-modules',
help='*SKIP* collecting information about modules',
action='store_true')
parser.add_argument('-b', '--no-builtin',
help='*SKIP* collecting information about built-in',
action='store_true')
parser.add_argument('-t', '--time',
help='Print elapsed time at the end',
action='store_true')
parser.add_argument('-v', '--variant',
help='Name of this kernel variant (e.g., stock, debug, rt)',
required=True,
type=str)
parser.add_argument('-i', '--input',
help='Existing JSON file to merge with (from previous variant runs)',
default='',
type=str)
parser.add_argument('--module-list',
help='Module list in format <rpm-name>:<path> (can be specified multiple times)',
action='append',
default=[],
metavar='RPM:PATH')
parser.add_argument('--vmlinux-rpm',
help='RPM package name for vmlinux (e.g., "kernel-5.14.0.rpm")',
default='',
type=str)
return parser.parse_args()
def load_file(filename, build_dir=''):
"""
Load a text file and return non-empty lines as a list
"""
full_path = os.path.join(build_dir, filename)
try:
with open(full_path, 'rt', encoding='utf-8') as file:
return [line.rstrip() for line in file if line.rstrip()]
except FileNotFoundError:
print(f'File "{full_path}" not found.')
return []
def name_to_cmd(filename, suffix):
"""
Convert object filename to corresponding .cmd script filename
Example: kernel/fork.o -> kernel/.fork.o.cmd
"""
path, _ = os.path.splitext(filename)
dirname = os.path.dirname(path)
basename = os.path.basename(path)
return os.path.join(dirname, '.' + basename + suffix)
def strip_path_prefixes(path, build_dir):
"""
Normalize path by removing build directory prefix and other artifacts
"""
path = pathlib.Path(path)
if build_dir:
try:
return str(path.resolve().relative_to(pathlib.Path(build_dir).resolve()))
except ValueError:
pass
if path.is_absolute():
path = pathlib.Path(*path.parts[1:])
while path.parts and path.parts[0] == 'repos':
path = pathlib.Path(*path.parts[1:])
return str(path)
def is_external_source(path):
"""
Check if path should be excluded from source mapping
Filters out:
- Rust toolchain sources (not part of kernel source)
- Generated assembly files (e.g., initramfs_data.S)
"""
if 'rustlib' in path:
return True
if path.endswith('_data.S'):
return True
return False
def is_mod_file_reference(ld_input):
"""
Check if linker input is a .mod file reference (RHEL 9+ module linking)
In RHEL 9+, module linking uses @path/to/module.mod files that contain
the list of object files to link.
"""
files = ld_input.split()
return len(files) == 1 and files[0].startswith('@') and files[0].endswith('.mod')
# =============================================================================
# SourceMap Class
# =============================================================================
class SourceMap:
"""
Collects and manages kernel source-to-binary mappings.
This class parses kernel build artifacts (.cmd files, archives) to determine
which source files contribute to which kernel binaries (modules and vmlinux).
Data structures:
obj_to_src: {object_name: {source_file: [variant_indices]}}
src_to_obj: {source_file: {object_name: [variant_indices]}}
module_rpm: {module_name: {rpm_name: [variant_indices]}}
rpm_to_modules: {rpm_name: {module_name: [variant_indices]}}
Variant indices correspond to positions in the 'variants' list.
"""
# Dispatch table for RHEL-specific builtin collection methods
BUILTIN_COLLECTORS = {
'7': '_collect_builtin_rhel7',
'8': '_collect_builtin_archive',
'9': '_collect_builtin_archive',
'upstream': '_collect_builtin_vmlinux_archive',
}
def __init__(self, build_dir='', output_dir='', outprefix='', rhel='7', variant=''):
# Source mappings
self.obj_to_src = {}
self.src_to_obj = {}
# Module-to-RPM mappings
self.module_rpm = {}
self.rpm_to_modules = {}
# Configuration
self.build_dir = build_dir
self.output_dir = output_dir
self.outprefix = outprefix
self.rhel = rhel
# Module list
self.modlist = set()
# Variant tracking for multi-variant merging
self.variants = []
self.variant = variant
self.variant_idx = 0
# -------------------------------------------------------------------------
# Variant Management
# -------------------------------------------------------------------------
def load_existing(self, filename):
"""
Load existing merged data from previous variant runs
"""
if not filename:
return
full_path = os.path.join(self.output_dir, filename) if self.output_dir else filename
if not os.path.exists(full_path):
return
with open(full_path, 'rt', encoding='utf-8') as f:
data = json.load(f)
self.variants = data.get('variants', [])
module_map = data.get('module-map', {})
self.module_rpm = module_map.get('module-rpm', {})
self.rpm_to_modules = module_map.get('rpm-modules', {})
source_map = data.get('source-map', {})
self.obj_to_src = source_map.get('obj-src', {})
self.src_to_obj = source_map.get('src-obj', {})
def add_variant(self):
"""
Register current variant and store its index
"""
if self.variant in self.variants:
self.variant_idx = self.variants.index(self.variant)
else:
self.variant_idx = len(self.variants)
self.variants.append(self.variant)
# -------------------------------------------------------------------------
# Source Merging Helpers
# -------------------------------------------------------------------------
def _merge_sources(self, target, source):
"""
Merge source dict into target dict by combining variant index lists
"""
for src, indices in source.items():
if src not in target:
target[src] = []
for idx in indices:
if idx not in target[src]:
target[src].append(idx)
def _add_source(self, sources, source_path):
"""
Add a source file to the sources dict with current variant index
Returns True if source was added, False if filtered out
"""
source_path = os.path.normpath(source_path)
source_path = strip_path_prefixes(source_path, self.build_dir)
if is_external_source(source_path):
return False
sources[source_path] = [self.variant_idx]
return True
# -------------------------------------------------------------------------
# .cmd File Parsing
# -------------------------------------------------------------------------
def _parse_ko_cmd(self, ko_name):
"""
Parse .ko.cmd file to find the primary object file linked into the module
"""
ko_script = name_to_cmd(ko_name, '.ko.cmd')
lines = load_file(ko_script, build_dir=self.build_dir)
for line in lines:
result = ko_matcher.match(line)
if result:
input_files = result.group('input_files').split()
return input_files[0]
return None
def _parse_o_cmd(self, o_name, translate=True):
"""
Parse .o.cmd file to extract source files that contribute to the object
Handles:
- C/assembly compilation (gcc, clang)
- Linking (ld) - recursively parses linked objects
- Rust compilation (rustc)
- Rust source file mappings
Args:
o_name: Object file name or .cmd file path
translate: If True, convert object name to .cmd path (e.g., kernel/fork.o
becomes kernel/.fork.o.cmd). If False, use o_name as-is.
This parameter exists to handle different kbuild behaviors
across RHEL versions - some code paths may already have .cmd
paths while others have object names that need translation.
"""
sources = {}
o_script = name_to_cmd(o_name, '.o.cmd') if translate else o_name
lines = load_file(o_script, build_dir=self.build_dir)
for line in lines:
result = o_matcher.match(line)
if not result:
continue
command = result.group('command')
if command in COMPILERS:
self._handle_compiler(result, sources)
break
elif command == LINKER:
self._handle_linker(result, sources)
break
elif command == RUST_COMPILER:
self._handle_rustc(result, sources)
break
else:
self._handle_rust_source_mapping(result, sources)
break
return sources
def _handle_compiler(self, match_result, sources):
"""
Handle gcc/clang compilation - extract the input source file
"""
obj_input = match_result.group('input_files')
if obj_input:
self._add_source(sources, obj_input)
def _handle_linker(self, match_result, sources):
"""
Handle ld linking - recursively parse linked objects
"""
obj_input = match_result.group('input_files')
if not obj_input:
return
if is_mod_file_reference(obj_input):
self._merge_sources(sources, self._parse_mod_cmd(obj_input))
else:
for obj_file in obj_input.split():
self._merge_sources(sources, self._parse_o_cmd(obj_file))
def _handle_rustc(self, match_result, sources):
"""
Handle rustc compilation - extract the Rust source file
"""
rust_input = match_result.group('rust_input_file')
if rust_input:
self._add_source(sources, rust_input)
def _handle_rust_source_mapping(self, match_result, sources):
"""
Handle Rust source file mapping (source_*.o := *.rs)
"""
source_file = match_result.group('source_file')
if source_file and source_file.endswith('.rs'):
self._add_source(sources, source_file)
def _parse_mod_cmd(self, mod_name):
"""
Parse .mod file used by RHEL 9+ for linking modules
These files contain a list of object files to link into the module.
"""
sources = {}
mod_name = mod_name.strip('@')
lines = load_file(mod_name, build_dir=self.build_dir)
for line in lines:
self._merge_sources(sources, self._parse_o_cmd(line))
return sources
def _parse_a_cmd(self, a_name):
"""
Parse archive .cmd file (RHEL 7 built-in.o.cmd files)
"""
sources = {}
lines = load_file(a_name, build_dir=self.build_dir)
for line in lines:
result = o_matcher.match(line)
if not result:
continue
ar_input = result.group('input_files')
for filename in ar_input.rsplit():
if filename.endswith('.o'):
self._merge_sources(sources, self._parse_o_cmd(filename))
elif filename.endswith('.a'):
self._merge_sources(sources, self._parse_a_cmd(filename))
return sources
# -------------------------------------------------------------------------
# Module Collection
# -------------------------------------------------------------------------
def _load_module_list(self, modorder='modules.order'):
"""
Load modules.order file and normalize paths
RHEL 7, 8: modules.order has 'kernel/' prefix that needs to be stripped
RHEL 9, upstream: modules.order paths are used as-is
"""
lines = load_file(modorder, build_dir=self.build_dir)
if not lines:
print(f'Warning: modules.order is empty or not found')
self.modlist = set()
return
if self.rhel in ['9', 'upstream']:
self.modlist = set(lines)
else:
# RHEL 7, 8: strip fake 'kernel/' prefix added by kbuild
self.modlist = {
path[len(KERNEL_PREFIX):] if path.startswith(KERNEL_PREFIX) else path
for path in lines
}
def _parse_module_objects(self):
"""
Parse all module .cmd files and extract source mappings.
Note on RHEL version differences:
- RHEL 7/8/9: modules.order contains .ko paths (e.g., fs/exfat/exfat.ko)
- upstream: modules.order contains .o paths (e.g., fs/exfat/exfat.o)
The normalization below ensures consistent .ko keys in output regardless
of the modules.order format.
"""
for kobj in self.modlist:
# Normalize to .ko - upstream has .o paths in modules.order
if self.rhel == 'upstream' and kobj.endswith('.o'):
module_name = kobj[:-2] + '.ko'
else:
module_name = kobj
obj_name = self._parse_ko_cmd(module_name)
if obj_name is None:
print(f'Warning: Could not parse .ko.cmd for "{module_name}", skipping.')
continue
obj_source = self._parse_o_cmd(obj_name)
if module_name not in self.obj_to_src:
self.obj_to_src[module_name] = {}
self._merge_sources(self.obj_to_src[module_name], obj_source)
def collect_modules(self, no_modules=False, modorder='modules.order'):
"""
Collect source files for kernel modules
"""
if no_modules:
return
self._load_module_list(modorder)
self._parse_module_objects()
# -------------------------------------------------------------------------
# Builtin Collection (RHEL version-specific)
# -------------------------------------------------------------------------
def _collect_builtin_rhel7(self):
"""
Collect built-in objects for RHEL 7 using *built-in.o.cmd files
"""
pattern = '*built-in.o.cmd'
cmd_list = {
strip_path_prefixes(path, self.build_dir)
for path in pathlib.Path(self.build_dir).rglob(pattern)
}
for entry in cmd_list:
sources = self._parse_a_cmd(entry)
self._merge_sources(self.obj_to_src[VMLINUX], sources)
def _collect_builtin_archive(self):
"""
Collect built-in objects for RHEL 8/9 using *built-in.a archives
"""
pattern = '*built-in.a'
archive_list = {
strip_path_prefixes(path, self.build_dir)
for path in pathlib.Path(self.build_dir).rglob(pattern)
}
for entry in archive_list:
path = os.path.join(self.build_dir, entry)
objects = subprocess.check_output(['ar', 't', path]).decode().split()
for obj in objects:
obj_path = strip_path_prefixes(obj, build_dir=self.build_dir)
sources = self._parse_o_cmd(obj_path)
self._merge_sources(self.obj_to_src[VMLINUX], sources)
def _collect_builtin_vmlinux_archive(self):
"""
Collect built-in objects for upstream kernels using single vmlinux.a archive
"""
path = os.path.join(self.build_dir, 'vmlinux.a')
objects = subprocess.check_output(['ar', 't', path]).decode().split()
for obj in objects:
obj_path = strip_path_prefixes(obj, build_dir=self.build_dir)
sources = self._parse_o_cmd(obj_path)
self._merge_sources(self.obj_to_src[VMLINUX], sources)
def collect_builtin(self, no_builtin=False):
"""
Collect source files for vmlinux built-in objects
Uses RHEL version-specific collection method via dispatch table.
"""
if VMLINUX not in self.obj_to_src:
self.obj_to_src[VMLINUX] = {}
if no_builtin:
return
collector_name = self.BUILTIN_COLLECTORS.get(self.rhel, '_collect_builtin_archive')
collector = getattr(self, collector_name)
collector()
# -------------------------------------------------------------------------
# Module-to-RPM Mapping
# -------------------------------------------------------------------------
def _parse_module_list_file(self, filename, rpm_name):
"""
Parse a module list file and add entries to module_rpm mapping
Handles various formats:
- Absolute paths: /lib/modules/5.14.0/kernel/drivers/net/e1000.ko.xz
- Relative paths: kernel/drivers/net/e1000.ko
- Skips RPM spec directives (%dir, %defattr, etc.)
Args:
filename: Path to the module list file
rpm_name: Literal RPM package name (e.g., "kernel-modules-5.14.0.rpm")
"""
if not filename or not os.path.exists(filename):
return
with open(filename, 'rt', encoding='utf-8') as f:
for line in f:
line = line.strip()
# Skip empty lines, comments, and RPM spec directives
if not line or line.startswith('#') or line.startswith('%'):
continue
# Skip non-module files
if '.ko' not in line:
continue
# Extract module name from path
module = os.path.basename(line)
# Remove .ko and any compression suffix
module = re.sub(r'\.ko(\.[^.]+)?$', '', module)
if not module:
continue
if module not in self.module_rpm:
self.module_rpm[module] = {}
if rpm_name not in self.module_rpm[module]:
self.module_rpm[module][rpm_name] = []
if self.variant_idx not in self.module_rpm[module][rpm_name]:
self.module_rpm[module][rpm_name].append(self.variant_idx)
def collect_module_rpm(self, module_lists, vmlinux_rpm=''):
"""
Collect module-to-RPM name mappings from module list files
Args:
module_lists: List of "rpm_name:path" strings
vmlinux_rpm: RPM package name for vmlinux
"""
if not module_lists and not vmlinux_rpm:
return
# Add vmlinux to specified RPM
if vmlinux_rpm:
if VMLINUX not in self.module_rpm:
self.module_rpm[VMLINUX] = {}
if vmlinux_rpm not in self.module_rpm[VMLINUX]:
self.module_rpm[VMLINUX][vmlinux_rpm] = []
if self.variant_idx not in self.module_rpm[VMLINUX][vmlinux_rpm]:
self.module_rpm[VMLINUX][vmlinux_rpm].append(self.variant_idx)
# Process module list files
for entry in module_lists:
if ':' not in entry:
print(f'Warning: Invalid --module-list format "{entry}", expected RPM:PATH')
continue
rpm_name, path = entry.split(':', 1)
self._parse_module_list_file(path, rpm_name)
# -------------------------------------------------------------------------
# Output
# -------------------------------------------------------------------------
def _build_reverse_map(self):
"""
Create reverse mapping (source -> {obj: [indices]}) from obj_to_src
"""
for obj, sources in self.obj_to_src.items():
for source, indices in sources.items():
if source not in self.src_to_obj:
self.src_to_obj[source] = {}
if obj not in self.src_to_obj[source]:
self.src_to_obj[source][obj] = []
for idx in indices:
if idx not in self.src_to_obj[source][obj]:
self.src_to_obj[source][obj].append(idx)
def _build_rpm_reverse_map(self):
"""
Create reverse mapping (rpm -> {module: [indices]}) from module_rpm
"""
for module, rpms in self.module_rpm.items():
for rpm, indices in rpms.items():
if rpm not in self.rpm_to_modules:
self.rpm_to_modules[rpm] = {}
if module not in self.rpm_to_modules[rpm]:
self.rpm_to_modules[rpm][module] = []
for idx in indices:
if idx not in self.rpm_to_modules[rpm][module]:
self.rpm_to_modules[rpm][module].append(idx)
def save_data(self):
"""
Save collected data to JSON file
Output structure:
- variants: list of variant names
- source-map: source file mappings
- obj-src: object/module -> {source: [variant_indices]}
- src-obj: source -> {object/module: [variant_indices]}
- module-map: module to RPM mappings
- module-rpm: module name -> {rpm-name: [variant_indices]}
- rpm-modules: rpm-name -> {module name: [variant_indices]}
Variant indices correspond to positions in the 'variants' list.
"""
output = {
'variants': self.variants,
'source-map': {
'obj-src': self.obj_to_src,
'src-obj': self.src_to_obj
},
'module-map': {
'module-rpm': self.module_rpm,
'rpm-modules': self.rpm_to_modules
}
}
filename = self.outprefix + 'kernel-map.json'
with open(os.path.join(self.output_dir, filename), 'wt', encoding='utf-8') as f:
json.dump(output, f, indent=2, sort_keys=True)
# -------------------------------------------------------------------------
# Main Entry Point
# -------------------------------------------------------------------------
def collect_data(self, no_modules=False, no_builtin=False, modorder='modules.order',
input_file='', module_lists=None, vmlinux_rpm=''):
"""
Main entry point - collect all data and save to JSON
"""
self.load_existing(input_file)
self.add_variant()
self.collect_modules(no_modules, modorder)
self.collect_builtin(no_builtin)
self.collect_module_rpm(module_lists or [], vmlinux_rpm)
self._build_reverse_map()
self._build_rpm_reverse_map()
self.save_data()
# =============================================================================
# Main
# =============================================================================
def main():
"""
Main entry point
"""
args = parse_args()
start = time.monotonic()
source_map = SourceMap(
build_dir=args.directory,
output_dir=args.outputdir,
outprefix=args.prefix,
rhel=args.rhel,
variant=args.variant)
source_map.collect_data(
no_modules=args.no_modules,
no_builtin=args.no_builtin,
input_file=args.input,
module_lists=args.module_list,
vmlinux_rpm=args.vmlinux_rpm)
if args.time:
elapsed = time.monotonic() - start
minutes, seconds = divmod(int(elapsed), 60)
print(f'Elapsed time: {minutes:02d}:{seconds:02d}')
if __name__ == '__main__':
main()

View File

@ -18,6 +18,21 @@ static const snd_ctl_elem_type_t g_v2a_type_map[] = {
[VIRTIO_SND_CTL_TYPE_IEC958] = SNDRV_CTL_ELEM_TYPE_IEC958
};
/* Map for converting VirtIO types to maximum value counts. */
static const unsigned int g_v2a_count_map[] = {
[VIRTIO_SND_CTL_TYPE_BOOLEAN] =
ARRAY_SIZE(((struct virtio_snd_ctl_value *)0)->value.integer),
[VIRTIO_SND_CTL_TYPE_INTEGER] =
ARRAY_SIZE(((struct virtio_snd_ctl_value *)0)->value.integer),
[VIRTIO_SND_CTL_TYPE_INTEGER64] =
ARRAY_SIZE(((struct virtio_snd_ctl_value *)0)->value.integer64),
[VIRTIO_SND_CTL_TYPE_ENUMERATED] =
ARRAY_SIZE(((struct virtio_snd_ctl_value *)0)->value.enumerated),
[VIRTIO_SND_CTL_TYPE_BYTES] =
ARRAY_SIZE(((struct virtio_snd_ctl_value *)0)->value.bytes),
[VIRTIO_SND_CTL_TYPE_IEC958] = 1
};
/* Map for converting VirtIO access rights to ALSA access rights. */
static const unsigned int g_v2a_access_map[] = {
[VIRTIO_SND_CTL_ACCESS_READ] = SNDRV_CTL_ELEM_ACCESS_READ,
@ -36,6 +51,37 @@ static const unsigned int g_v2a_mask_map[] = {
[VIRTIO_SND_CTL_EVT_MASK_TLV] = SNDRV_CTL_EVENT_MASK_TLV
};
static int virtsnd_kctl_validate_info(struct virtio_snd *snd, u32 cid,
struct virtio_snd_ctl_info *kinfo)
{
struct virtio_device *vdev = snd->vdev;
unsigned int type = le32_to_cpu(kinfo->type);
unsigned int count = le32_to_cpu(kinfo->count);
if (type >= ARRAY_SIZE(g_v2a_type_map)) {
dev_err(&vdev->dev, "control #%u: unknown type %u\n",
cid, type);
return -EINVAL;
}
if (count > g_v2a_count_map[type] ||
(type == VIRTIO_SND_CTL_TYPE_IEC958 && count != 1)) {
dev_err(&vdev->dev, "control #%u: invalid count %u for type %u\n",
cid, count, type);
return -EINVAL;
}
if (type == VIRTIO_SND_CTL_TYPE_ENUMERATED &&
!le32_to_cpu(kinfo->value.enumerated.items)) {
dev_err(&vdev->dev,
"control #%u: no items for enumerated control\n",
cid);
return -EINVAL;
}
return 0;
}
/**
* virtsnd_kctl_info() - Returns information about the control.
* @kcontrol: ALSA control element.
@ -385,6 +431,10 @@ int virtsnd_kctl_parse_cfg(struct virtio_snd *snd)
struct virtio_snd_ctl_info *kinfo = &snd->kctl_infos[i];
unsigned int type = le32_to_cpu(kinfo->type);
rc = virtsnd_kctl_validate_info(snd, i, kinfo);
if (rc)
return rc;
if (type == VIRTIO_SND_CTL_TYPE_ENUMERATED) {
rc = virtsnd_kctl_get_enum_items(snd, i);
if (rc)

View File

@ -1,2 +1,2 @@
sbat,1,SBAT Version,sbat,1,https://github.com/rhboot/shim/blob/main/SBAT.md
kernel-uki-virt-addons.almalinux,1,AlmaLinux,kernel-uki-virt-addons,6.12.0-211.49.1.el10.x86_64,mailto:security@almalinux.org
kernel-uki-virt-addons.almalinux,1,AlmaLinux,kernel-uki-virt-addons,6.12.0-211.50.1.el10.x86_64,mailto:security@almalinux.org

View File

@ -1,2 +1,2 @@
sbat,1,SBAT Version,sbat,1,https://github.com/rhboot/shim/blob/main/SBAT.md
kernel-uki-virt.almalinux,1,AlmaLinux,kernel-uki-virt,6.12.0-211.49.1.el10.x86_64,mailto:security@almalinux.org
kernel-uki-virt.almalinux,1,AlmaLinux,kernel-uki-virt,6.12.0-211.50.1.el10.x86_64,mailto:security@almalinux.org