Import of kernel-6.12.0-211.50.1.el10_2
This commit is contained in:
parent
e9d74aef89
commit
1e9e3942c3
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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 */
|
||||
|
||||
@ -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 */
|
||||
|
||||
@ -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");
|
||||
}
|
||||
|
||||
@ -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");
|
||||
}
|
||||
|
||||
|
||||
@ -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:
|
||||
|
||||
@ -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_ */
|
||||
|
||||
@ -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 */
|
||||
|
||||
@ -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 */
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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) {
|
||||
|
||||
@ -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) {
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -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;
|
||||
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -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));
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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 */
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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),
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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 '-' */
|
||||
|
||||
@ -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),
|
||||
|
||||
@ -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),
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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);
|
||||
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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) &&
|
||||
|
||||
@ -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);
|
||||
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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);
|
||||
|
||||
|
||||
@ -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 */
|
||||
};
|
||||
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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),
|
||||
|
||||
@ -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();
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -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);
|
||||
|
||||
|
||||
@ -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 \
|
||||
|
||||
@ -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]
|
||||
|
||||
@ -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
874
redhat/scripts/kmap.py
Executable 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()
|
||||
@ -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)
|
||||
|
||||
@ -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
|
||||
|
||||
2
uki.sbat
2
uki.sbat
@ -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
|
||||
|
||||
Loading…
Reference in New Issue
Block a user