6.6.144-rc1 review
Subsystems (6)
Greg Kroah-Hartman
maintainerPATCH 1/175 fuse: limit FUSE_NOTIFY_RETRIEVE to uptodate folios
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jann Horn <[email protected]>
[ Upstream commit 4e3d1b2c48ca6c55f1e9ca7f8dccc76f120f276c ]
FUSE_NOTIFY_RETRIEVE must be limited to uptodate folios; !uptodate folios can contain uninitialized data.
Since FUSE_NOTIFY_RETRIEVE is intended to only return data that is already in the page cache and not wait for data from the FUSE daemon, treat !uptodate folios as if they weren't present.
This only has security impact on systems that don't enable automatic zero-initialization of all page allocations via CONFIG_INIT_ON_ALLOC_DEFAULT_ON or init_on_alloc=1.
--- fs/fuse/dev.c | 4 ++++ 1 file changed, 4 insertions(+)
fs/fuse/dev.c +4 -0
@@ -1722,6 +1722,10 @@ static int fuse_retrieve(struct fuse_mount *fm, struct inode *inode, page =find_get_page (mapping, index);if (!page)break ; +if (!PageUptodate (page)) { +put_page (page); +break ; + } this_num =min_t (unsigned, num,PAGE_SIZE - offset); ap->pages[ap->num_pages] = page;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 10/175 debugobjects: Do not fill_pool() if pi_blocked_on
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Helen Koike <[email protected]>
commit 5f41161059fd0f1bbf18c90f3180e38cc45a14eb upstream.
On RT enabled kernels, fill_pool() ends up calling rtlock_lock(), which asserts if current::pi_blocked_on is set, because a task can obviously only block on one lock as otherwise the priority inheritenace chain gets corrupted.
Prevent this by expanding the conditional to take current::pi_blocked_on into account.
--- lib/debugobjects.c | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-)
lib/debugobjects.c +14 -4
@@ -597,15 +597,25 @@ static struct debug_obj *lookup_object_or_alloc(void *addr, struct debug_bucketreturn NULL ; } +static inline bool debug_objects_is_pi_blocked_on (void ) +{ +#ifdef CONFIG_RT_MUTEXES +return current->pi_blocked_on !=NULL ; +#else +return false; +#endif +} +static void debug_objects_fill_pool (void ) {/* * On RT enabled kernels the pool refill must happen in preemptible -* context -- for !RT kernels we rely on the fact that spinlock_t and -* raw_spinlock_t are basically the same type and this lock-type -* inversion works just fine. +* context and not enqueued on an rt_mutex -- for !RT kernels we rely +* on the fact that spinlock_t and raw_spinlock_t are basically the +* same type and this lock-type inversion works just fine. */ -if (!IS_ENABLED (CONFIG_PREEMPT_RT ) ||preemptible () || system_state <SYSTEM_SCHEDULING ) { +if (!IS_ENABLED (CONFIG_PREEMPT_RT ) || system_state <SYSTEM_SCHEDULING || + (preemptible () && !debug_objects_is_pi_blocked_on ())) {/* * Annotate away the spinlock_t inside raw_spinlock_t warning * by temporarily raising the wait-type to LD_WAIT_CONFIG, matching
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 11/175 debugobjects: Dont call fill_pool() in early boot hardirq context
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Waiman Long <[email protected]>
commit 0d046ae106255cba5eb83b23f78ee93f3620247d upstream.
When booting a debug PREEMPT_RT kernel on an ARM64 system, a "inconsistent {HARDIRQ-ON-W} -> {IN-HARDIRQ-W} usage" lockdep warning message was reported to the console.
During early boot, interrupts are enabled before the scheduler is enabled. In this window (before SYSTEM_SCHEDULING is set) interrupts can fire and in the hard interrupt context handler attempt to fill the pool
This can lead to a deadlock when the interrupt occurred when the interrupt hits a region which holds a lock that is required to be taken in the allocation path.
Add a new can_fill_pool() helper and reorder the exception rule and forbid this scenario by excluding allocations from hard interrupt context.
--- lib/debugobjects.c | 44 ++++++++++++++++++++++++++++++++++++-------- 1 file changed, 36 insertions(+), 8 deletions(-)
lib/debugobjects.c +36 -8
@@ -606,20 +606,48 @@ static inline bool debug_objects_is_pi_blocked_on(void)#endif } -static void debug_objects_fill_pool (void ) +static inline bool can_fill_pool (void ) {/* -* On RT enabled kernels the pool refill must happen in preemptible -* context and not enqueued on an rt_mutex -- for !RT kernels we rely -* on the fact that spinlock_t and raw_spinlock_t are basically the -* same type and this lock-type inversion works just fine. +* On !RT enabled kernels there are no restrictions and spinlock_t and +* raw_spinlock_t are the same types. +*/ +if (!IS_ENABLED (CONFIG_PREEMPT_RT )) +return true; + +/* +* On RT enabled kernels, the task must not be blocked on a lock as +* that could corrupt the PI state when blocking on a lock in the +* allocation path. +*/ +if (debug_objects_is_pi_blocked_on ()) +return false; + +/* +* On RT enabled kernels the pool refill should happen in preemptible +* context. */ -if (!IS_ENABLED (CONFIG_PREEMPT_RT ) || system_state <SYSTEM_SCHEDULING || - (preemptible () && !debug_objects_is_pi_blocked_on ())) { +if (preemptible ()) +return true; + +/* +* Though during system boot before scheduling is set up, preemption is +* disabled and the pool can get exhausted. Before scheduling is active +* a task cannot be blocked on a sleeping lock, but it might hold a lock +* and if interrupted then hard interrupt context might run into a lock +* inversion. So exclude hard interrupt context from allocations before +* scheduling is active. +*/ +return system_state <SYSTEM_SCHEDULING && !in_hardirq (); +} + +static void debug_objects_fill_pool (void ) +{ +if (can_fill_pool ()) {/* * Annotate away the spinlock_t inside raw_spinlock_t warning * by temporarily raising the wait-type to LD_WAIT_CONFIG, matching -* the preemptible() condition above. +* the preemptible() condition in can_fill_pool(). */ static DEFINE_WAIT_OVERRIDE_MAP(fill_pool_map, LD_WAIT_CONFIG);lock_map_acquire_try (&fill_pool_map);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 12/175 ARM: group is_permission_fault() with is_translation_fault()
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Russell King (Oracle) <[email protected]>
commit dea20281ac88226615761c570c8ff7adc18e6ac2 upstream.
Group is_permission_fault() with is_translation_fault(), which is needed to use is_permission_fault() in __do_kernel_fault(). As this is static inline, there is no need for this to be under CONFIG_MMU.
--- arch/arm/mm/fault.c | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-)
arch/arm/mm/fault.c +13 -13
@@ -128,6 +128,19 @@ static inline bool is_translation_fault(unsigned int fsr)return false; } +static inline bool is_permission_fault (unsigned int fsr) +{ +int fs =fsr_fs (fsr); +#ifdef CONFIG_ARM_LPAE +if ((fs &FS_MMU_NOLL_MASK ) ==FS_PERM_NOLL ) +return true; +#else +if (fs ==FS_L1_PERM || fs ==FS_L2_PERM ) +return true; +#endif +return false; +} +static void die_kernel_fault (const char *msg,struct mm_struct *mm,unsigned long addr,unsigned int fsr,struct pt_regs *regs)
@@ -229,19 +242,6 @@ void do_bad_area(unsigned long addr, unsigned int fsr, struct pt_regs *regs)#define VM_FAULT_BADMAP ((__force vm_fault_t)0x010000)#define VM_FAULT_BADACCESS ((__force vm_fault_t)0x020000) -static inline bool is_permission_fault (unsigned int fsr) -{ -int fs =fsr_fs (fsr); -#ifdef CONFIG_ARM_LPAE -if ((fs &FS_MMU_NOLL_MASK ) ==FS_PERM_NOLL ) -return true; -#else -if (fs ==FS_L1_PERM || fs ==FS_L2_PERM ) -return true; -#endif -return false; -} -static int __kprobes do_page_fault (unsigned long addr,unsigned int fsr,struct pt_regs *regs) {
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 13/175 ARM: allow __do_kernel_fault() to report execution of memory faults
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Russell King (Oracle) <[email protected]>
commit 40b466db1dffb41f0529035c59c5739636d0e5b8 upstream
Allow __do_kernel_fault() to detect the execution of memory, so we can provide the same fault message as do_page_fault() would do. This is required when we split the kernel address fault handling from the main do_page_fault() code path.
--- arch/arm/mm/fault.c | 2 ++ 1 file changed, 2 insertions(+)
arch/arm/mm/fault.c +2 -0
@@ -176,6 +176,8 @@ __do_kernel_fault(struct mm_struct *mm, unsigned long addr, unsigned int fsr,*/ if (addr <PAGE_SIZE ) { msg ="NULL pointer dereference" ; + }else if (is_permission_fault (fsr) && fsr &FSR_LNX_PF ) { + msg ="execution of memory" ; }else {if (is_translation_fault (fsr) &&kfence_handle_page_fault (addr,is_write_fault (fsr), regs))
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 14/175 ARM: fix hash_name() fault
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Russell King (Oracle) <[email protected]>
commit 7733bc7d299d682f2723dc38fc7f370b9bf973e9 upstream.
Zizhi Wo reports:
"During the execution of hash_name()->load_unaligned_zeropad(), a
potential memory access beyond the PAGE boundary may occur. For example, when the filename length is near the PAGE_SIZE boundary. This triggers a page fault, which leads to a call to do_page_fault()->mmap_read_trylock(). If we can't acquire the lock, we have to fall back to the mmap_read_lock() path, which calls might_sleep(). This breaks RCU semantics because path lookup occurs under an RCU read-side critical section."
This is seen with CONFIG_DEBUG_ATOMIC_SLEEP=y and CONFIG_KFENCE=y.
Kernel addresses (with the exception of the vectors/kuser helper page) do not have VMAs associated with them. If the vectors/kuser helper page faults, then there are two possibilities:
1. if the fault happened while in kernel mode, then we're basically dead, because the CPU won't be able to vector through this page to handle the fault.
2. if the fault happened while in user mode, that means the page was protected from user access, and we want to fault anyway.
Thus, we can handle kernel addresses from any context entirely separately without going anywhere near the mmap lock. This gives us an entirely non-sleeping path for all kernel mode kernel address faults.
As we handle the kernel address faults before interrupts are enabled, this change has the side effect of improving the branch predictor hardening, but does not completely solve the issue.
--- arch/arm/mm/fault.c | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+)
arch/arm/mm/fault.c +35 -0
@@ -244,6 +244,35 @@ void do_bad_area(unsigned long addr, unsigned int fsr, struct pt_regs *regs)#define VM_FAULT_BADMAP ((__force vm_fault_t)0x010000)#define VM_FAULT_BADACCESS ((__force vm_fault_t)0x020000) +static int __kprobes +do_kernel_address_page_fault (struct mm_struct *mm,unsigned long addr, +unsigned int fsr,struct pt_regs *regs) +{ +if (user_mode (regs)) { +/* +* Fault from user mode for a kernel space address. User mode +* should not be faulting in kernel space, which includes the +* vector/khelper page. Send a SIGSEGV. +*/ +__do_user_fault (addr, fsr,SIGSEGV ,SEGV_MAPERR , regs); + }else { +/* +* Fault from kernel mode. Enable interrupts if they were +* enabled in the parent context. Section (upper page table) +* translation faults are handled via do_translation_fault(), +* so we will only get here for a non-present kernel space +* PTE or PTE permission fault. This may happen in exceptional +* circumstances and need the fixup tables to be walked. +*/ +if (interrupts_enabled (regs)) +local_irq_enable (); + +__do_kernel_fault (mm, addr, fsr, regs); + } + +return 0 ; +} +static int __kprobes do_page_fault (unsigned long addr,unsigned int fsr,struct pt_regs *regs) {
@@ -257,6 +286,12 @@ do_page_fault(unsigned long addr, unsigned int fsr, struct pt_regs *regs)if (kprobe_page_fault (regs, fsr))return 0 ; +/* +* Handle kernel addresses faults separately, which avoids touching +* the mmap lock from contexts that are not able to sleep. +*/ +if (addr >=TASK_SIZE ) +return do_kernel_address_page_fault (mm, addr, fsr, regs);/* Enable interrupts if they were enabled in the parent context. */ if (interrupts_enabled (regs))
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 15/175 ARM: fix branch predictor hardening
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Russell King (Oracle) <[email protected]>
commit fd2dee1c6e2256f726ba33fd3083a7be0efc80d3 upstream.
__do_user_fault() may be called with indeterminent interrupt enable state, which means we may be preemptive at this point. This causes problems when calling harden_branch_predictor(). For example, when called from a data abort, do_alignment_fault()->do_bad_area().
Move harden_branch_predictor() out of __do_user_fault() and into the calling contexts.
Moving it into do_kernel_address_page_fault(), we can be sure that interrupts will be disabled here.
Converting do_translation_fault() to use do_kernel_address_page_fault() rather than do_bad_area() means that we keep branch predictor handling for translation faults. Interrupts will also be disabled at this call site.
do_sect_fault() needs special handling, so detect user mode accesses to kernel-addresses, and add an explicit call to branch predictor hardening.
Finally, add branch predictor hardening to do_alignment() for the faulting case (user mode accessing kernel addresses) before interrupts are enabled.
This should cover all cases where harden_branch_predictor() is called, ensuring that it is always has interrupts disabled, also ensuring that it is called early in each call path.
--- arch/arm/mm/alignment.c | 4 ++++ arch/arm/mm/fault.c | 39 ++++++++++++++++++++++++++------------- 2 files changed, 30 insertions(+), 13 deletions(-)
arch/arm/mm/alignment.c +4 -0
@@ -22,6 +22,7 @@#include <asm/cp15.h> #include <asm/system_info.h> +#include <asm/system_misc.h> #include <asm/unaligned.h> #include <asm/opcodes.h>
@@ -809,6 +810,9 @@ do_alignment(unsigned long addr, unsigned int fsr, struct pt_regs *regs)int thumb2_32b =0 ;int fault; +if (addr >=TASK_SIZE &&user_mode (regs)) +harden_branch_predictor (); +if (interrupts_enabled (regs))local_irq_enable ();
arch/arm/mm/fault.c +26 -13
@@ -199,9 +199,6 @@ __do_user_fault(unsigned long addr, unsigned int fsr, unsigned int sig, {struct task_struct *tsk = current; -if (addr >TASK_SIZE ) -harden_branch_predictor (); -#ifdef CONFIG_DEBUG_USER if (((user_debug &UDBG_SEGV ) && (sig ==SIGSEGV )) || ((user_debug &UDBG_BUS ) && (sig ==SIGBUS ))) {
@@ -252,8 +249,10 @@ do_kernel_address_page_fault(struct mm_struct *mm, unsigned long addr,/* * Fault from user mode for a kernel space address. User mode * should not be faulting in kernel space, which includes the -* vector/khelper page. Send a SIGSEGV. +* vector/khelper page. Handle the branch predictor hardening +* while interrupts are still disabled, then send a SIGSEGV. */ +harden_branch_predictor ();__do_user_fault (addr, fsr,SIGSEGV ,SEGV_MAPERR , regs); }else {/*
@@ -423,16 +422,20 @@ do_page_fault(unsigned long addr, unsigned int fsr, struct pt_regs *regs)* We enter here because the first level page table doesn't contain * a valid entry for the address. * -* If the address is in kernel space (>= TASK_SIZE), then we are -* probably faulting in the vmalloc() area. +* If this is a user address (addr < TASK_SIZE), we handle this as a +* normal page fault. This leaves the remainder of the function to handle +* kernel address translation faults. * -* If the init_task's first level page tables contains the relevant -* entry, we copy the it to this task. If not, we send the process -* a signal, fixup the exception, or oops the kernel. +* Since user mode is not permitted to access kernel addresses, pass these +* directly to do_kernel_address_page_fault() to handle. * -* NOTE! We MUST NOT take any locks for this case. We may be in an -* interrupt or a critical region, and should only copy the information -* from the master page table, nothing more. +* Otherwise, we're probably faulting in the vmalloc() area, so try to fix +* that up. Note that we must not take any locks or enable interrupts in +* this case. +* +* If vmalloc() fixup fails, that means the non-leaf page tables did not +* contain an entry for this address, so handle this via +* do_kernel_address_page_fault(). */ #ifdef CONFIG_MMU static int __kprobes
@@ -498,7 +501,8 @@ do_translation_fault(unsigned long addr, unsigned int fsr,return 0 ; bad_area: -do_bad_area (addr, fsr, regs); +do_kernel_address_page_fault (current->mm, addr, fsr, regs); + return 0; }#else /* CONFIG_MMU */
@@ -518,7 +522,16 @@ do_translation_fault(unsigned long addr, unsigned int fsr,static int do_sect_fault (unsigned long addr,unsigned int fsr,struct pt_regs *regs) { +/* +* If this is a kernel address, but from user mode, then userspace +* is trying bad stuff. Invoke the branch predictor handling. +* Interrupts are disabled here. +*/ +if (addr >=TASK_SIZE &&user_mode (regs)) +harden_branch_predictor (); +do_bad_area (addr, fsr, regs); +return 0 ; }#endif /* CONFIG_ARM_LPAE */
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 16/175 KVM: VMX: Update SVI during runtime APICv activation
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Dongli Zhang <[email protected]>
[ Upstream commit b2849bec936be642b5420801f902337f2507648e ]
The APICv (apic->apicv_active) can be activated or deactivated at runtime, for instance, because of APICv inhibit reasons. Intel VMX employs different mechanisms to virtualize LAPIC based on whether APICv is active.
When APICv is activated at runtime, GUEST_INTR_STATUS is used to configure and report the current pending IRR and ISR states. Unless a specific vector is explicitly included in EOI_EXIT_BITMAP, its EOI will not be trapped to KVM. Intel VMX automatically clears the corresponding ISR bit based on the GUEST_INTR_STATUS.SVI field.
When APICv is deactivated at runtime, the VM_ENTRY_INTR_INFO_FIELD is used to specify the next interrupt vector to invoke upon VM-entry. The VMX IDT_VECTORING_INFO_FIELD is used to report un-invoked vectors on VM-exit. EOIs are always trapped to KVM, so the software can manually clear pending ISR bits.
There are scenarios where, with APICv activated at runtime, a guest-issued EOI may not be able to clear the pending ISR bit.
Taking vector 236 as an example, here is one scenario.
1. Suppose APICv is inactive. Vector 236 is pending in the IRR.
2. To handle KVM_REQ_EVENT, KVM moves vector 236 from the IRR to the ISR, and configures the VM_ENTRY_INTR_INFO_FIELD via vmx_inject_irq().
3. After VM-entry, vector 236 is invoked through the guest IDT. At this point, the data in VM_ENTRY_INTR_INFO_FIELD is no longer valid. The guest interrupt handler for vector 236 is invoked.
4. Suppose a VM exit occurs very early in the guest interrupt handler, before the EOI is issued.
5. Nothing is reported through the IDT_VECTORING_INFO_FIELD because vector 236 has already been invoked in the guest.
6. Now, suppose APICv is activated. Before the next VM-entry, KVM calls kvm_vcpu_update_apicv() to activate APICv.
7. Unfortunately, GUEST_INTR_STATUS.SVI is not configured, although vector 236 is still pending in the ISR.
8. After VM-entry, the guest finally issues the EOI for vector 236. However, because SVI is not configured, vector 236 is not cleared.
9. ISR is stalled forever on vector 236.
Here is another scenario.
1. Suppose APICv is inactive. Vector 236 is pending in the IRR.
2. To handle KVM_REQ_EVENT, KVM moves vector 236 from the IRR to the ISR, and configures the VM_ENTRY_INTR_INFO_FIELD via vmx_inject_irq().
3. VM-exit occurs immediately after the next VM-entry. The vector 236 is not invoked through the guest IDT. Instead, it is saved to the IDT_VECTORING_INFO_FIELD during the VM-exit.
4. KVM calls kvm_queue_interrupt() to re-queue the un-invoked vector 236 into vcpu->arch.interrupt. A KVM_REQ_EVENT is requested.
5. Now, suppose APICv is activated. Before the next VM-entry, KVM calls kvm_vcpu_update_apicv() to activate APICv.
6. Although APICv is now active, KVM still uses the legacy VM_ENTRY_INTR_INFO_FIELD to re-inject vector 236. GUEST_INTR_STATUS.SVI is not configured.
7. After the next VM-entry, vector 236 is invoked through the guest IDT. Finally, an EOI occurs. However, due to the lack of GUEST_INTR_STATUS.SVI configuration, vector 236 is not cleared from the ISR.
8. ISR is stalled forever on vector 236.
Using QEMU as an example, vector 236 is stuck in ISR forever.
(qemu) info lapic 1
dumping local APIC state for CPU 1
LVT0 0x00010700 active-hi edge masked ExtINT (vec 0) LVT1 0x00010400 active-hi edge masked NMI
LVTPC 0x00000400 active-hi edge NMI
LVTERR 0x000000fe active-hi edge Fixed (vec 254)
LVTTHMR 0x00010000 active-hi edge masked Fixed (vec 0)
LVTT 0x000400ec active-hi edge tsc-deadline Fixed (vec 236)
Timer DCR=0x0 (divide by 2) initial_count = 0 current_count = 0
SPIV 0x000001ff APIC enabled, focus=off, spurious vec 255
ICR 0x000000fd physical edge de-assert no-shorthand
ICR2 0x00000000 cpu 0 (X2APIC ID)
ESR 0x00000000
ISR 236
IRR 37(level) 236
The issue isn't applicable to AMD SVM as KVM simply writes vmcb01 directly irrespective of whether L1 (vmcs01) or L2 (vmcb02) is active (unlike VMX, there is no need/cost to switch between VMCBs). In addition, APICV_INHIBIT_REASON_IRQWIN ensures AMD SVM AVIC is not activated until the last interrupt is EOI'd.
Fix the bug by configuring Intel VMX GUEST_INTR_STATUS.SVI if APICv is activated at runtime.
--- arch/x86/kvm/vmx/vmx.c | 4 ---- arch/x86/kvm/x86.c | 7 +++++++ 2 files changed, 7 insertions(+), 4 deletions(-)
arch/x86/kvm/vmx/vmx.c +0 -4
@@ -6851,10 +6851,6 @@ static void vmx_hwapic_isr_update(struct kvm_vcpu *vcpu, int max_isr)* VM-Exit, otherwise L1 with run with a stale SVI. */ if (is_guest_mode (vcpu)) { -/* -* KVM is supposed to forward intercepted L2 EOIs to L1 if VID -* is enabled in vmcs12; as above, the EOIs affect L2's vAPIC. -*/ to_vmx (vcpu)->nested.update_vmcs01_hwapic_isr = true;return ; }
arch/x86/kvm/x86.c +7 -0
@@ -10426,9 +10426,16 @@ void __kvm_vcpu_update_apicv(struct kvm_vcpu *vcpu)* pending. At the same time, KVM_REQ_EVENT may not be set as APICv was * still active when the interrupt got accepted. Make sure * kvm_check_and_inject_events() is called to check for that. +* +* Update SVI when APICv gets enabled, otherwise SVI won't reflect the +* highest bit in vISR and the next accelerated EOI in the guest won't +* be virtualized correctly (the CPU uses SVI to determine which vISR +* vector to clear). */ if (!apic->apicv_active)kvm_make_request (KVM_REQ_EVENT , vcpu); +else +kvm_apic_update_hwapic_isr (vcpu); out:preempt_enable ();
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 17/175 RDMA/bnxt_re: zero shared page before exposing to userspace
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Lord Ulf Henrik Holmberg <[email protected]>
commit f6b079629becfa977f9c51fe53ad2e6dcc55ef44 upstream.
bnxt_re_alloc_ucontext() allocates uctx->shpg via __get_free_page(GFP_KERNEL). The buddy allocator does not zero pages without __GFP_ZERO, so the page contains stale kernel data from whatever object most recently freed it.
The page is then mapped into userspace via vm_insert_page() under BNXT_RE_MMAP_SH_PAGE in bnxt_re_mmap(). The driver only ever writes 4 bytes (a u32 AVID) at offset BNXT_RE_AVID_OFFT (0x10) inside bnxt_re_create_ah(); the remaining 4092 bytes of the page are exposed to userspace unsanitised, leaking kernel memory contents.
Any user with access to /dev/infiniband/uverbsX on a host with a bnxt_re device (typically rdma group membership) can read this data via a single mmap() at pgoff 0 after IB_USER_VERBS_CMD_GET_CONTEXT.
Other shared pages in the same file already use get_zeroed_page() correctly:
drivers/infiniband/hw/bnxt_re/ib_verbs.c
srq->uctx_srq_page = (void *)get_zeroed_page(GFP_KERNEL);
cq->uctx_cq_page = (void *)get_zeroed_page(GFP_KERNEL);uctx->shpg is the only outlier. Bring it in line with the existing convention by switching to get_zeroed_page().
--- drivers/infiniband/hw/bnxt_re/ib_verbs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/infiniband/hw/bnxt_re/ib_verbs.c +1 -1
@@ -4146,7 +4146,7 @@ int bnxt_re_alloc_ucontext(struct ib_uco uctx->rdev = rdev; - uctx->shpg = (void *)__get_free_page (GFP_KERNEL ); + uctx->shpg = (void *)get_zeroed_page (GFP_KERNEL );if (!uctx->shpg) { rc = -ENOMEM ; goto fail;
Greg Kroah-Hartman
maintainerPATCH 18/175 i2c: stub: Reject I2C block transfers with invalid length
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Weiming Shi <[email protected]>
commit 6036b5067a8199ba7a2dc7b377d4b9dd276d5f9e upstream.
The I2C_SMBUS_I2C_BLOCK_DATA case in stub_xfer() uses data->block[0] as the transfer length. The existing check only clamps it to avoid overrunning the chip->words[256] register array, but does not validate it against I2C_SMBUS_BLOCK_MAX (32), which is the limit of the union i2c_smbus_data.block buffer (34 bytes total). The driver is a development/test tool (CONFIG_I2C_STUB=m, not built by default) that must be loaded with a chip_addr= parameter.
A local user with access to /dev/i2c-* can issue an I2C_SMBUS ioctl with I2C_SMBUS_I2C_BLOCK_DATA and data->block[0] > 32, causing stub_xfer() to read or write past the end of the union i2c_smbus_data.block buffer:
BUG: KASAN: stack-out-of-bounds in stub_xfer (drivers/i2c/i2c-stub.c:223) Read of size 1 at addr ffff88800abcfd92 by task exploit/81 Call Trace: <TASK> stub_xfer (drivers/i2c/i2c-stub.c:223) __i2c_smbus_xfer (drivers/i2c/i2c-core-smbus.c:593) i2c_smbus_xfer (drivers/i2c/i2c-core-smbus.c:536) i2cdev_ioctl_smbus (drivers/i2c/i2c-dev.c:391) i2cdev_ioctl (drivers/i2c/i2c-dev.c:478) __x64_sys_ioctl (fs/ioctl.c:583) do_syscall_64 (arch/x86/entry/syscall_64.c:94) entry_SYSCALL_64_after_hwframe (arch/x86/entry/entry_64.S:130) </TASK>
The bug exists because i2c-stub implements .smbus_xfer directly, bypassing the I2C_SMBUS_BLOCK_MAX validation in i2c_smbus_xfer_emulated(). The I2C_SMBUS_BLOCK_DATA case in the same function correctly validates against I2C_SMBUS_BLOCK_MAX, but the I2C_SMBUS_I2C_BLOCK_DATA case does not.
Fix by rejecting transfers with data->block[0] == 0 or data->block[0] > I2C_SMBUS_BLOCK_MAX with -EINVAL, consistent with both the I2C_SMBUS_BLOCK_DATA case in the same function and the I2C_SMBUS_I2C_BLOCK_DATA validation in i2c_smbus_xfer_emulated().
--- drivers/i2c/i2c-stub.c | 5 +++++ 1 file changed, 5 insertions(+)
drivers/i2c/i2c-stub.c +5 -0
@@ -214,6 +214,11 @@ static s32 stub_xfer(struct i2c_adapter* We ignore banks here, because banked chips don't use I2C * block transfers */ +if (data->block[0 ] ==0 || + data->block[0 ] >I2C_SMBUS_BLOCK_MAX ) { + ret = -EINVAL ; +break ; + }if (data->block[0 ] >256 - command)/* Avoid overrun */ data->block[0 ] =256 - command; len = data->block[0 ];
Greg Kroah-Hartman
maintainerPATCH 19/175 net: qualcomm: rmnet: fix endpoint use-after-free in rmnet_dellink()
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Weiming Shi <[email protected]>
commit d00c953a8f69921f484b629801766da68f27f658 upstream.
rmnet_dellink() removes the endpoint from the hash table with hlist_del_init_rcu() and then immediately frees it with kfree(). However, RCU readers on the receive path (rmnet_rx_handler -> __rmnet_map_ingress_handler) may still hold a reference to the endpoint and dereference ep->egress_dev after the memory has been freed. The endpoint is a kmalloc-32 object, and the stale read at offset 8 corresponds to the egress_dev pointer.
BUG: unable to handle page fault for address: ffffffffde942eef Oops: 0002 [#1] SMP NOPTI CPU: 1 UID: 0 PID: 137 Comm: poc_write Not tainted 7.0.0+ #4 PREEMPTLAZY RIP: 0010:rmnet_vnd_rx_fixup (rmnet_vnd.c:27) Call Trace: <TASK> __rmnet_map_ingress_handler (rmnet_handlers.c:48 rmnet_handlers.c:101) rmnet_rx_handler (rmnet_handlers.c:129 rmnet_handlers.c:235) __netif_receive_skb_core.constprop.0 (net/core/dev.c:6096) __netif_receive_skb_one_core (net/core/dev.c:6208) netif_receive_skb (net/core/dev.c:6467) tun_get_user (drivers/net/tun.c:1955) tun_chr_write_iter (drivers/net/tun.c:2003) vfs_write (fs/read_write.c:688) ksys_write (fs/read_write.c:740) </TASK>
Add an rcu_head field to struct rmnet_endpoint and replace kfree() with kfree_rcu() so the endpoint memory remains valid through the RCU grace period. Also remove the rmnet_vnd_dellink() call and inline only the nr_rmnet_devs decrement, since rmnet_vnd_dellink() would set ep->egress_dev to NULL during the grace period, creating a data race with lockless readers.
--- drivers/net/ethernet/qualcomm/rmnet/rmnet_config.c | 8 ++++---- drivers/net/ethernet/qualcomm/rmnet/rmnet_config.h | 1 + 2 files changed, 5 insertions(+), 4 deletions(-)
drivers/net/ethernet/qualcomm/rmnet/rmnet_config.c +4 -4
@@ -210,8 +210,8 @@ static void rmnet_dellink(struct net_dev ep =rmnet_get_endpoint (real_port, mux_id);if (ep) {hlist_del_init_rcu (&ep->hlnode); -rmnet_vnd_dellink (mux_id, real_port, ep); -kfree (ep); + real_port->nr_rmnet_devs--; +kfree_rcu (ep, rcu); }netdev_upper_dev_unlink (real_dev, dev);
@@ -235,9 +235,9 @@ static void rmnet_force_unassociate_devihash_for_each_safe (port->muxed_ep, bkt_ep, tmp_ep, ep, hlnode) {unregister_netdevice_queue (ep->egress_dev, &list);netdev_upper_dev_unlink (real_dev, ep->egress_dev); -rmnet_vnd_dellink (ep->mux_id, port, ep);hlist_del_init_rcu (&ep->hlnode); -kfree (ep); + port->nr_rmnet_devs--; +kfree_rcu (ep, rcu); }rmnet_unregister_real_device (real_dev);unregister_netdevice_many (&list);
drivers/net/ethernet/qualcomm/rmnet/rmnet_config.h +1 -0
@@ -18,6 +18,7 @@ struct rmnet_endpoint {u8 mux_id;struct net_device *egress_dev;struct hlist_node hlnode; +struct rcu_head rcu; };struct rmnet_egress_agg_params {
Greg Kroah-Hartman
maintainerPATCH 2/175 net/sched: fix pedit partial COW leading to page cache corruption
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Rajat Gupta <[email protected]>
[ Upstream commit 899ee91156e57784090c5565e4f31bd7dbffbc5a ]
tcf_pedit_act() computes the COW range for skb_ensure_writable() once before the key loop using tcfp_off_max_hint, but the hint does not account for the runtime header offset added by typed keys. This can leave part of the write region un-COW'd.
Fix by moving skb_ensure_writable() inside the per-key loop where the actual write offset is known, and add overflow checking on the offset arithmetic. For negative offsets (e.g. Ethernet header edits at ingress), use skb_cow() to COW the headroom instead. Guard offset_valid() against INT_MIN, where negation is undefined.
Conflicts:
include/net/tc_act/tc_pedit.h
--- include/net/tc_act/tc_pedit.h | 1 - net/sched/act_pedit.c | 77 +++++++++++++++++++---------------- 2 files changed, 41 insertions(+), 37 deletions(-)
include/net/tc_act/tc_pedit.h +0 -1
@@ -14,7 +14,6 @@ struct tcf_pedit_key_ex {struct tcf_pedit_parms {struct tc_pedit_key *tcfp_keys;struct tcf_pedit_key_ex *tcfp_keys_ex; -u32 tcfp_off_max_hint;unsigned char tcfp_nkeys;unsigned char tcfp_flags;struct rcu_head rcu;
net/sched/act_pedit.c +41 -36
155 lines not on this page · raw message
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 20/175 agp/amd64: Fix broken error propagation in agp_amd64_probe()
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Mingyu Wang <[email protected]>
commit b08472db93b1ccff84a7adec5779d47f0e9d3a30 upstream.
A NULL pointer dereference was observed in the AMD64 AGP driver when running in a virtualized environment (e.g. qemu/kvm) without a physical AMD northbridge. The crash occurs in amd64_fetch_size() when attempting to dereference the pointer returned by node_to_amd_nb(0).
The root cause of this crash is broken error propagation in agp_amd64_probe(): When no AMD northbridges are found, cache_nbs() correctly returns -ENODEV. However, the probe function erroneously checks the return value against exactly -1, rather than < 0.
As a result, the hardware absence error is masked, allowing the driver to improperly proceed with initialization. It eventually calls agp_add_bridge(), which invokes amd64_fetch_size(). Since the hardware does not exist, node_to_amd_nb(0) returns NULL, leading to a General Protection Fault (GPF) when accessing its ->misc member.
Fix the issue by correcting the error check in agp_amd64_probe() to abort properly when cache_nbs() returns any negative error code. This prevents the driver from erroneously proceeding without hardware, thereby avoiding the subsequent NULL pointer dereference at its source.
--- drivers/char/agp/amd64-agp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/char/agp/amd64-agp.c +1 -1
@@ -546,7 +546,7 @@ static int agp_amd64_probe(struct pci_de/* Fill in the mode register */ pci_read_config_dword (pdev, bridge->capndx+PCI_AGP_STATUS , &bridge->mode); -if (cache_nbs (pdev, cap_ptr) ==-1 ) { +if (cache_nbs (pdev, cap_ptr) <0 ) {agp_put_bridge (bridge);return -ENODEV ; }
Greg Kroah-Hartman
maintainerPATCH 21/175 bpf: Reject sleepable kprobe_multi programs at attach time
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Varun R Mallya <[email protected]>
commit eb7024bfcc5f68ed11ed9dd4891a3073c15f04a8 upstream.
kprobe.multi programs run in atomic/RCU context and cannot sleep. However, bpf_kprobe_multi_link_attach() did not validate whether the program being attached had the sleepable flag set, allowing sleepable helpers such as bpf_copy_from_user() to be invoked from a non-sleepable context.
This causes a "sleeping function called from invalid context" splat:
BUG: sleeping function called from invalid context at ./include/linux/uaccess.h:169 in_atomic(): 1, irqs_disabled(): 0, non_block: 0, pid: 1787, name: sudo preempt_count: 1, expected: 0 RCU nest depth: 2, expected: 0
Fix this by rejecting sleepable programs early in bpf_kprobe_multi_link_attach(), before any further processing.
[shung-hsi.yu: sleepable flag was in 'struct bpf_prog_aux' before commit 66c8473135c6 "bpf: move sleepable flag from bpf_prog_aux to bpf_prog"]
--- kernel/trace/bpf_trace.c | 4 ++++ 1 file changed, 4 insertions(+)
kernel/trace/bpf_trace.c +4 -0
@@ -2905,6 +2905,10 @@ int bpf_kprobe_multi_link_attach(const union bpf_attr *attr, struct bpf_prog *prif (prog->expected_attach_type !=BPF_TRACE_KPROBE_MULTI )return -EINVAL ; +/* kprobe_multi is not allowed to be sleepable. */ +if (prog->aux->sleepable) +return -EINVAL ; + flags = attr->link_create.kprobe_multi.flags;if (flags & ~BPF_F_KPROBE_MULTI_RETURN )return -EINVAL ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 22/175 selftests/bpf: Add test to ensure kprobe_multi is not sleepable
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Varun R Mallya <[email protected]>
commit c7cab53f9d5273f0cf2a26bdf178c4e074bdfb50 upstream.
Add a selftest to ensure that kprobe_multi programs cannot be attached using the BPF_F_SLEEPABLE flag. This test succeeds when the kernel rejects attachment of kprobe_multi when the BPF_F_SLEEPABLE flag is set.
[shung-hsi.yu: borrowed 'saved_error' variable from commit 00cdcd2900bd ("selftests/bpf: Don't use libbpf_get_error() in kprobe_multi_test"). ]
--- .../bpf/prog_tests/kprobe_multi_test.c | 34 +++++++++++++++++++ .../bpf/progs/kprobe_multi_sleepable.c | 25 ++++++++++++++ 2 files changed, 59 insertions(+) create mode 100644 tools/testing/selftests/bpf/progs/kprobe_multi_sleepable.c
tools/testing/selftests/bpf/prog_tests/kprobe_multi_test.c +34 -0
@@ -4,6 +4,7 @@#include "trace_helpers.h" #include "kprobe_multi_empty.skel.h" #include "kprobe_multi_override.skel.h" +#include "kprobe_multi_sleepable.skel.h" #include "bpf/libbpf_internal.h" #include "bpf/hashmap.h"
@@ -214,7 +215,9 @@ static void test_attach_api_syms(void)static void test_attach_api_fails (void ) {LIBBPF_OPTS (bpf_kprobe_multi_opts, opts); +LIBBPF_OPTS (bpf_test_run_opts, topts);struct kprobe_multi *skel =NULL ; +struct kprobe_multi_sleepable *sl_skel =NULL ;struct bpf_link *link =NULL ;unsigned long long addrs[2 ];const char *syms[2 ] = {
@@ -222,6 +225,7 @@ static void test_attach_api_fails(void) "bpf_fentry_test2", };__u64 cookies[2 ]; +int saved_error, err; addrs[0 ] =ksym_get_addr ("bpf_fentry_test1" ); addrs[1 ] =ksym_get_addr ("bpf_fentry_test2" );
@@ -300,9 +304,39 @@ static void test_attach_api_fails(void)if (!ASSERT_EQ (libbpf_get_error (link), -EINVAL ,"fail_5_error" )) goto cleanup; +/* fail_9 - sleepable kprobe multi should not attach */ + sl_skel =kprobe_multi_sleepable__open (); +if (!ASSERT_OK_PTR (sl_skel,"sleep_skel_open" )) + goto cleanup; + + sl_skel->bss->user_ptr = sl_skel; + + err =bpf_program__set_flags (sl_skel->progs.handle_kprobe_multi_sleepable, +BPF_F_SLEEPABLE ); +if (!ASSERT_OK (err,"sleep_skel_set_flags" )) + goto cleanup; + + err =kprobe_multi_sleepable__load (sl_skel); +if (!ASSERT_OK (err,"sleep_skel_load" )) + goto cleanup; + + link =bpf_program__attach_kprobe_multi_opts (sl_skel->progs.handle_kprobe_multi_sleepable, +"bpf_fentry_test1" ,NULL ); + saved_error = -errno; + +if (!ASSERT_ERR_PTR (link,"fail_9" )) + goto cleanup; + +if (!ASSERT_EQ (saved_error, -EINVAL ,"fail_9_error" )) + goto cleanup; + + err =bpf_prog_test_run_opts (bpf_program__fd (sl_skel->progs.fentry), &topts); +ASSERT_OK (err,"bpf_prog_test_run_opts" ); + cleanup:bpf_link__destroy (link);kprobe_multi__destroy (skel); +kprobe_multi_sleepable__destroy (sl_skel); }static size_t symbol_hash (long key,void *ctx__maybe_unused )
tools/testing/selftests/bpf/progs/kprobe_multi_sleepable.c new file +25 -0
@@ -0,0 +1,25 @@ +// SPDX-License-Identifier: GPL-2.0 + +#include "vmlinux.h" +#include <bpf/bpf_helpers.h> +#include <bpf/bpf_tracing.h> + +void *user_ptr =0 ; + +SEC("kprobe.multi") +int handle_kprobe_multi_sleepable (struct pt_regs *ctx) +{ +int a, err; + + err =bpf_copy_from_user (&a,sizeof (a), user_ptr); +barrier_var (a); +return err; +} + +SEC("fentry/bpf_fentry_test1") +int BPF_PROG (fentry ) +{ +return 0 ; +} + +char _license[] SEC("license") = "GPL";
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 23/175 af_unix: Reject SIOCATMARK on non-stream sockets
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jiexun Wang <[email protected]>
commit d119775f2bad827edc28071c061fdd4a91f889a5 upstream.
SIOCATMARK reports whether the receive queue is at the urgent mark for MSG_OOB.
In AF_UNIX, MSG_OOB is supported only for SOCK_STREAM sockets. SOCK_DGRAM and SOCK_SEQPACKET reject MSG_OOB in sendmsg() and recvmsg(), so they should not support SIOCATMARK either.
Return -EOPNOTSUPP for non-stream sockets before checking the receive queue.
--- net/unix/af_unix.c | 3 +++ 1 file changed, 3 insertions(+)
net/unix/af_unix.c +3 -0
@@ -3139,6 +3139,9 @@ static int unix_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)struct sk_buff *skb;int answ =0 ; +if (sk->sk_type !=SOCK_STREAM ) +return -EOPNOTSUPP ; + skb =skb_peek (&sk->sk_receive_queue);if (skb && skb ==READ_ONCE (unix_sk (sk)->oob_skb)) answ =1 ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 24/175 bpf: Track equal scalars history on per-instruction level
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Eduard Zingerman <[email protected]>
[ Upstream commit 4bf79f9be434e000c8e12fe83b2f4402480f1460 ]
Use bpf_verifier_state->jmp_history to track which registers were updated by find_equal_scalars() (renamed to collect_linked_regs()) when conditional jump was verified. Use recorded information in backtrack_insn() to propagate precision.
E.g. for the following program:
while verifying instructions
1: r1 = r0 | 2: if r1 < 8 goto ... | push r0,r1 as linked registers in jmp_history 3: if r0 > 16 goto ... | push r0,r1 as linked registers in jmp_history 4: r2 = r10 | 5: r2 += r0 v mark_chain_precision(r0)
while doing mark_chain_precision(r0)
5: r2 += r0 | mark r0 precise 4: r2 = r10 | 3: if r0 > 16 goto ... | mark r0,r1 as precise 2: if r1 < 8 goto ... | mark r0,r1 as precise 1: r1 = r0 v
Technically, do this as follows:
- Use 10 bits to identify each register that gains range because of sync_linked_regs():
- 3 bits for frame number;
- 6 bits for register or stack slot number;
- 1 bit to indicate if register is spilled.
- Use u64 as a vector of 6 such records + 4 bits for vector length.
- Augment struct bpf_jmp_history_entry with a field 'linked_regs' representing such vector.
- When doing check_cond_jmp_op() remember up to 6 registers that gain range because of sync_linked_regs() in such a vector.
- Don't propagate range information and reset IDs for registers that don't fit in 6-value vector.
- Push a pair {instruction index, linked registers vector} to bpf_verifier_state->jmp_history.
- When doing backtrack_insn() check if any of recorded linked registers is currently marked precise, if so mark all linked registers as precise.
This also requires fixes for two test_verifier tests:
- precise: test 1
- precise: test 2
Both tests contain the following instruction sequence:
19: (bf) r2 = r9 ; R2=scalar(id=3) R9=scalar(id=3)
20: (a5) if r2 < 0x8 goto pc+1 ; R2=scalar(id=3,umin=8)
21: (95) exit
22: (07) r2 += 1 ; R2_w=scalar(id=3+1,...) 23: (bf) r1 = r10 ; R1_w=fp0 R10=fp0 24: (07) r1 += -8 ; R1_w=fp-8 25: (b7) r3 = 0 ; R3_w=0
26: (85) call bpf_probe_read_kernel#113
The call to bpf_probe_read_kernel() at (26) forces r2 to be precise. Previously, this forced all registers with same id to become precise immediately when mark_chain_precision() is called.
After this change, the precision is propagated to registers sharing same id only when 'if' instruction is backtracked.
Hence verification log for both tests is changed:
regs=r2,r9 -> regs=r2 for instructions 25..20.
[ zhenzhong: backport to 6.6.y verifier layout and adapt
sync_linked_regs() to the pre-BPF_ADD_CONST scalar-id code. ]
--- include/linux/bpf_verifier.h | 4 + kernel/bpf/verifier.c | 253 ++++++++++++++++-- .../bpf/progs/verifier_subprog_precision.c | 2 +- .../testing/selftests/bpf/verifier/precise.c | 2 +- 4 files changed, 237 insertions(+), 24 deletions(-)
include/linux/bpf_verifier.h +4 -0
@@ -345,6 +345,10 @@ struct bpf_jmp_history_entry { u32 prev_idx : 22;/* special flags, e.g., whether insn is doing register stack spill/load */ u32 flags : 10; +/* additional registers that need precision tracking when this +* jump is backtracked, vector of six 10-bit records +*/ +u64 linked_regs; };/* Maximum number of register states that can exist at once */
kernel/bpf/verifier.c +231 -22
400 lines not on this page · raw message
tools/testing/selftests/bpf/progs/verifier_subprog_precision.c +1 -1
@@ -141,7 +141,7 @@ __msg("mark_precise: frame0: last_idx 14 first_idx 9") __msg("mark_precise: frame0: regs=r6 stack= before 13: (bf) r1 = r7") __msg("mark_precise: frame0: regs=r6 stack= before 12: (27) r6 *= 4") __msg("mark_precise: frame0: regs=r6 stack= before 11: (25) if r6 > 0x3 goto pc+4") -__msg("mark_precise: frame0: regs=r6 stack= before 10: (bf) r6 = r0") +__msg("mark_precise: frame0: regs=r0,r6 stack= before 10: (bf) r6 = r0")__msg ("mark_precise: frame0: regs=r0 stack= before 9: (85) call bpf_loop" ) /* State entering callback body popped from states stack */__msg ("from 9 to 17: frame1:" )
tools/testing/selftests/bpf/verifier/precise.c +1 -1
@@ -44,7 +44,7 @@ mark_precise: frame0: regs=r2 stack= before 23\ mark_precise: frame0: regs=r2 stack= before 22\ mark_precise: frame0: regs=r2 stack= before 20\ - mark_precise: frame0: parent state regs=r2 stack=:\ + mark_precise: frame0: parent state regs=r2,r9 stack=:\ mark_precise: frame0: last_idx 19 first_idx 10\ mark_precise: frame0: regs=r2,r9 stack= before 19\ mark_precise: frame0: regs=r9 stack= before 18\
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 25/175 bpf: Remove mark_precise_scalar_ids()
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Eduard Zingerman <[email protected]>
[ Upstream commit 842edb5507a1038e009d27e69d13b94b6f085763 ]
Function mark_precise_scalar_ids() is superseded by bt_sync_linked_regs() and equal scalars tracking in jump history. mark_precise_scalar_ids() propagates precision over registers sharing same ID on parent/child state boundaries, while jump history records allow bt_sync_linked_regs() to propagate same information with instruction level granularity, which is strictly more precise.
This commit removes mark_precise_scalar_ids() and updates test cases in progs/verifier_scalar_ids to reflect new verifier behavior.
The tests are updated in the following manner:
- mark_precise_scalar_ids() propagated precision regardless of presence of conditional jumps, while new jump history based logic only kicks in when conditional jumps are present.
Hence test cases are augmented with conditional jumps to still trigger precision propagation.
- As equal scalars tracking no longer relies on parent/child state boundaries some test cases are no longer interesting, such test cases are removed, namely:
- precision_same_state and precision_cross_state are superseded by
linked_regs_bpf_k;
- precision_same_state_broken_link and equal_scalars_broken_link are superseded by linked_regs_broken_link.
[ zhenzhong: backport to 6.6.y after adapting the first linked-regs
history commit to the older scalar-id verifier layout. ]
--- kernel/bpf/verifier.c | 115 ------------ .../selftests/bpf/progs/verifier_scalar_ids.c | 171 ++++++------------ .../testing/selftests/bpf/verifier/precise.c | 2 +- 3 files changed, 56 insertions(+), 232 deletions(-)
kernel/bpf/verifier.c +0 -115
@@ -4265,96 +4265,6 @@ static void mark_all_scalars_imprecise(struct bpf_verifier_env *env, struct bpf_ } } -static bool idset_contains (struct bpf_idset *s,u32 id) -{ -u32 i; - -for (i =0 ; i < s->count; ++i) -if (s->ids[i] == id) -return true; - -return false; -} - -static int idset_push (struct bpf_idset *s,u32 id) -{ -if (WARN_ON_ONCE (s->count >=ARRAY_SIZE (s->ids))) -return -EFAULT ; - s->ids[s->count++] = id; -return 0 ; -} - -static void idset_reset (struct bpf_idset *s) -{ - s->count =0 ; -} - -/* Collect a set of IDs for all registers currently marked as precise in env->bt. -* Mark all registers with these IDs as precise. -*/ -static int mark_precise_scalar_ids (struct bpf_verifier_env *env,struct bpf_verifier_state *st) -{ -struct bpf_idset *precise_ids = &env->idset_scratch; -struct backtrack_state *bt = &env->bt; -struct bpf_func_state *func; -struct bpf_reg_state *reg; -DECLARE_BITMAP (mask,64 ); -int i, fr; - -idset_reset (precise_ids); - -for (fr = bt->frame; fr >=0 ; fr--) { - func = st->frame[fr]; - -bitmap_from_u64 (mask,bt_frame_reg_mask (bt, fr)); -for_each_set_bit (i, mask,32 ) { - reg = &func->regs[i]; -if (!reg->id || reg->type !=SCALAR_VALUE ) -continue ; -if (idset_push (precise_ids, reg->id)) -return -EFAULT ; - } - -bitmap_from_u64 (mask,bt_frame_stack_mask (bt, fr)); -for_each_set_bit (i, mask,64 ) { -if (i >= func->allocated_stack /BPF_REG_SIZE ) -break ; -if (!is_spilled_scalar_reg (&func->stack[i])) -continue ; - reg = &func->stack[i].spilled_ptr; -if (!reg->id) -continue ; -if (idset_push (precise_ids, reg->id)) -return -EFAULT ; - } - } - -for (fr =0 ; fr <= st->curframe; ++fr) { - func = st->frame[fr]; - -for (i =BPF_REG_0 ; i <BPF_REG_10 ; ++i) { - reg = &func->regs[i]; -if (!reg->id) -continue ; -if (!idset_contains (precise_ids, reg->id)) -continue ; -bt_set_frame_reg (bt, fr, i); - } -for (i =0 ; i < func->allocated_stack /BPF_REG_SIZE ; ++i) { -if (!is_spilled_scalar_reg (&func->stack[i])) -continue ; - reg = &func->stack[i].spilled_ptr; -if (!reg->id) -continue ; -if (!idset_contains (precise_ids, reg->id)) -continue ; -bt_set_frame_slot (bt, fr, i); - } - } - -return 0 ; -} -/* * __mark_chain_precision() backtracks BPF program instruction sequence and * chain of verifier states making sure that register *regno* (if regno >= 0)
@@ -4487,31 +4397,6 @@ static int __mark_chain_precision(struct bpf_verifier_env *env, int regno) bt->frame, last_idx, first_idx, subseq_idx); } -/* If some register with scalar ID is marked as precise, -* make sure that all registers sharing this ID are also precise. -* This is needed to estimate effect of sync_linked_regs(). -* Do this at the last instruction of each state, -* bpf_reg_state::id fields are valid for these instructions. -* -* Allows to track precision in situation like below: -* -* r2 = unknown value -* ... -* --- state #0 --- -* ... -* r1 = r2 // r1 and r2 now share the same ID -* ... -* --- state #1 {r1.id = A, r2.id = A} --- -* ... -* if (r2 > 10) goto exit; // sync_linked_regs() assigns range to r1 -* ... -* --- state #2 {r1.id = A, r2.id = A} --- -* r3 = r10 -* r3 += r1 // need to mark both r1 and r2 -*/ -if (mark_precise_scalar_ids (env, st)) -return -EFAULT ; -if (last_idx <0 ) {/* we are at the entry into subprog, which * is expected for global funcs, but only if
tools/testing/selftests/bpf/progs/verifier_scalar_ids.c +55 -116
263 lines not on this page · raw message
tools/testing/selftests/bpf/verifier/precise.c +1 -1
@@ -106,7 +106,7 @@ mark_precise: frame0: regs=r2 stack= before 22\ mark_precise: frame0: parent state regs=r2 stack=:\ mark_precise: frame0: last_idx 20 first_idx 20\ - mark_precise: frame0: regs=r2,r9 stack= before 20\ + mark_precise: frame0: regs=r2 stack= before 20\ mark_precise: frame0: parent state regs=r2,r9 stack=:\ mark_precise: frame0: last_idx 19 first_idx 17\ mark_precise: frame0: regs=r2,r9 stack= before 19\
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 26/175 selftests/bpf: Tests for per-insn sync_linked_regs() precision tracking
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Eduard Zingerman <[email protected]>
[ Upstream commit bebc17b1c03b224a0b4aec6a171815e39f8ba9bc ]
Add a few test cases to verify precision tracking for scalars gaining range because of sync_linked_regs():
- check what happens when more than 6 registers might gain range in sync_linked_regs();
- check if precision is propagated correctly when operand of conditional jump gained range in sync_linked_regs() and one of linked registers is marked precise;
- check if precision is propagated correctly when operand of conditional jump gained range in sync_linked_regs() and a other-linked operand of the conditional jump is marked precise;
- add a minimized reproducer for precision tracking bug reported in [0];
- Check that mark_chain_precision() for one of the conditional jump operands does not trigger equal scalars precision propagation.
[0] https://lore.kernel.org/bpf/CAEf4BzZ0xidVCqB47XnkXcNhkPWF6_nTV7yt+_Lf0kcFEut2Mg@mail.gmail.com/
[ zhenzhong: keep the linked_regs_broken_link_2 reject check, but
drop the mark_precise log expectations because 6.6.y does not derive the scalar-vs-scalar range for that non-constant JMP_X comparison. ]
--- .../selftests/bpf/progs/verifier_scalar_ids.c | 162 ++++++++++++++++++ 1 file changed, 162 insertions(+)
tools/testing/selftests/bpf/progs/verifier_scalar_ids.c +162 -0
@@ -47,6 +47,72 @@ __naked void linked_regs_bpf_k(void) : __clobber_all); } +/* Registers r{0,1,2} share same ID when 'if r1 > ...' insn is processed, +* check that verifier marks r{1,2} as precise while backtracking +* 'if r1 > ...' with r0 already marked. +*/ +SEC("socket") +__success __log_level(2) +__flag(BPF_F_TEST_STATE_FREQ) +__msg("frame0: regs=r0 stack= before 5: (2d) if r1 > r3 goto pc+0") +__msg("frame0: parent state regs=r0,r1,r2,r3 stack=:") +__msg("frame0: regs=r0,r1,r2,r3 stack= before 4: (b7) r3 = 7") +__naked void linked_regs_bpf_x_src (void ) +{ + asmvolatile ( +/* r0 = random number up to 0xff */ +"call %[bpf_ktime_get_ns];" +"r0 &= 0xff;" +/* tie r0.id == r1.id == r2.id */ +"r1 = r0;" +"r2 = r0;" +"r3 = 7;" +"if r1 > r3 goto +0;" +/* force r0 to be precise, this eventually marks r1 and r2 as +* precise as well because of shared IDs +*/ +"r4 = r10;" +"r4 += r0;" +"r0 = 0;" +"exit;" + : + : __imm(bpf_ktime_get_ns) + : __clobber_all); +} + +/* Registers r{0,1,2} share same ID when 'if r1 > r3' insn is processed, +* check that verifier marks r{0,1,2} as precise while backtracking +* 'if r1 > r3' with r3 already marked. +*/ +SEC("socket") +__success __log_level(2) +__flag(BPF_F_TEST_STATE_FREQ) +__msg("frame0: regs=r3 stack= before 5: (2d) if r1 > r3 goto pc+0") +__msg("frame0: parent state regs=r0,r1,r2,r3 stack=:") +__msg("frame0: regs=r0,r1,r2,r3 stack= before 4: (b7) r3 = 7") +__naked void linked_regs_bpf_x_dst (void ) +{ + asmvolatile ( +/* r0 = random number up to 0xff */ +"call %[bpf_ktime_get_ns];" +"r0 &= 0xff;" +/* tie r0.id == r1.id == r2.id */ +"r1 = r0;" +"r2 = r0;" +"r3 = 7;" +"if r1 > r3 goto +0;" +/* force r0 to be precise, this eventually marks r1 and r2 as +* precise as well because of shared IDs +*/ +"r4 = r10;" +"r4 += r3;" +"r0 = 0;" +"exit;" + : + : __imm(bpf_ktime_get_ns) + : __clobber_all); +} +/* Same as linked_regs_bpf_k, but break one of the * links, note that r1 is absent from regs=... in __msg below. */
@@ -280,6 +346,102 @@ __naked void precision_two_ids(void) : __clobber_all); } +SEC("socket") +__success __log_level(2) +__flag(BPF_F_TEST_STATE_FREQ) +/* check thar r0 and r6 have different IDs after 'if', + * collect_linked_regs() can't tie more than 6 registers for a single insn. + */ +__msg("8: (25) if r0 > 0x7 goto pc+0 ; R0=scalar(id=1") +__msg ("9: (bf) r6 = r6 ; R6_w=scalar(id=2" ) +/* check that r{0-5} are marked precise after 'if' */ +__msg("frame0: regs=r0 stack= before 8: (25) if r0 > 0x7 goto pc+0") +__msg("frame0: parent state regs=r0,r1,r2,r3,r4,r5 stack=:") +__naked void linked_regs_too_many_regs (void ) +{ + asmvolatile ( +/* r0 = random number up to 0xff */ +"call %[bpf_ktime_get_ns];" +"r0 &= 0xff;" +/* tie r{0-6} IDs */ +"r1 = r0;" +"r2 = r0;" +"r3 = r0;" +"r4 = r0;" +"r5 = r0;" +"r6 = r0;" +/* propagate range for r{0-6} */ +"if r0 > 7 goto +0;" +/* make r6 appear in the log */ +"r6 = r6;" +/* force r0 to be precise, +* this would cause r{0-4} to be precise because of shared IDs +*/ +"r7 = r10;" +"r7 += r0;" +"r0 = 0;" +"exit;" + : + : __imm(bpf_ktime_get_ns) + : __clobber_all); +} + +SEC("socket") +__failure __log_level(2) +__flag(BPF_F_TEST_STATE_FREQ) +__msg("div by zero") +__naked void linked_regs_broken_link_2 (void ) +{ + asmvolatile ( +"call %[bpf_get_prandom_u32];" +"r7 = r0;" +"r8 = r0;" +"call %[bpf_get_prandom_u32];" +"if r0 > 1 goto +0;" +/* r7.id == r8.id, +* thus r7 precision implies r8 precision, +* which implies r0 precision because of the conditional below. +*/ +"if r8 >= r0 goto 1f;" +/* break id relation between r7 and r8 */ +"r8 += r8;" +/* make r7 precise */ +"if r7 == 0 goto 1f;" +"r0 /= 0;" +"1:" +"r0 = 42;" +"exit;" + : + : __imm(bpf_get_prandom_u32) + : __clobber_all); +} + +/* Check that mark_chain_precision() for one of the conditional jump +* operands does not trigger equal scalars precision propagation. +*/ +SEC("socket") +__success __log_level(2) +__msg("3: (25) if r1 > 0x100 goto pc+0") +__msg("frame0: regs=r1 stack= before 2: (bf) r1 = r0") +__naked void cjmp_no_linked_regs_trigger (void ) +{ + asmvolatile ( +/* r0 = random number up to 0xff */ +"call %[bpf_ktime_get_ns];" +"r0 &= 0xff;" +/* tie r0.id == r1.id */ +"r1 = r0;" +/* the jump below would be predicted, thus r1 would be marked precise, +* this should not imply precision mark for r0 +*/ +"if r1 > 256 goto +0;" +"r0 = 0;" +"exit;" + : + : __imm(bpf_ktime_get_ns) + : __clobber_all); +} +/* Verify that check_ids() is used by regsafe() for scalars. * * r9 = ... some pointer with range X ...
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 27/175 selftests/bpf: Update comments find_equal_scalars->sync_linked_regs
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Eduard Zingerman <[email protected]>
[ Upstream commit cfbf25481d6dec0089c99c9d33a2ea634fe8f008 ]
find_equal_scalars() is renamed to sync_linked_regs(), this commit updates existing references in the selftests comments.
--- tools/testing/selftests/bpf/progs/verifier_spill_fill.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
tools/testing/selftests/bpf/progs/verifier_spill_fill.c +2 -2
@@ -392,7 +392,7 @@ __naked void spill_32bit_of_64bit_fail(void) *(u32 *)(r10 -8 ) = r1; \/* 32-bit fill r2 from stack. */ \ r2 = *(u32 *)(r10 -8 ); \ -/* Compare r2 with another register to trigger find_equal_scalars.\ +/* Compare r2 with another register to trigger sync_linked_regs.\ * Having one random bit is important here, otherwise the verifier cuts\ * the corners. If the ID was mistakenly preserved on spill, this would\ * cause the verifier to think that r1 is also equal to zero in one of\
@@ -431,7 +431,7 @@ __naked void spill_16bit_of_32bit_fail(void) *(u16 *)(r10 -8 ) = r1; \/* 16-bit fill r2 from stack. */ \ r2 = *(u16 *)(r10 -8 ); \ -/* Compare r2 with another register to trigger find_equal_scalars.\ +/* Compare r2 with another register to trigger sync_linked_regs.\ * Having one random bit is important here, otherwise the verifier cuts\ * the corners. If the ID was mistakenly preserved on spill, this would\ * cause the verifier to think that r1 is also equal to zero in one of\
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 28/175 ring-buffer: Remove ring_buffer_read_prepare_sync()
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Bjoern Doebel <[email protected]>
[ Upstream commit 119a5d573622ae90ba730d18acfae9bb75d77b9a ]
When the ring buffer was first introduced, reading the non-consuming "trace" file required disabling the writing of the ring buffer. To make sure the writing was fully disabled before iterating the buffer with a non-consuming read, it would set the disable flag of the buffer and then call an RCU synchronization to make sure all the buffers were synchronized.
The function ring_buffer_read_start() originally would initialize the iterator and call an RCU synchronization, but this was for each individual per CPU buffer where this would get called many times on a machine with many CPUs before the trace file could be read. The commit 72c9ddfd4c5bf ("ring-buffer: Make non-consuming read less expensive with lots of cpus.") separated ring_buffer_read_start into ring_buffer_read_prepare(), ring_buffer_read_sync() and then ring_buffer_read_start() to allow each of the per CPU buffers to be prepared, call the read_buffer_read_sync() once, and then the ring_buffer_read_start() for each of the CPUs which made things much faster.
The commit 1039221cc278 ("ring-buffer: Do not disable recording when there is an iterator") removed the requirement of disabling the recording of the ring buffer in order to iterate it, but it did not remove the synchronization that was happening that was required to wait for all the buffers to have no more writers. It's now OK for the buffers to have writers and no synchronization is needed.
Remove the synchronization and put back the interface for the ring buffer iterator back before commit 72c9ddfd4c5bf was applied.
--- include/linux/ring_buffer.h | 4 +-- kernel/trace/ring_buffer.c | 67 ++++++------------------------------- kernel/trace/trace.c | 14 +++----- kernel/trace/trace_kdb.c | 8 ++--- 4 files changed, 18 insertions(+), 75 deletions(-)
include/linux/ring_buffer.h +1 -3
@@ -129,9 +129,7 @@ ring_buffer_consume(struct trace_buffer *buffer, int cpu, u64 *ts, unsigned long *lost_events);struct ring_buffer_iter * -ring_buffer_read_prepare (struct trace_buffer *buffer,int cpu,gfp_t flags); -void ring_buffer_read_prepare_sync (void ); -void ring_buffer_read_start (struct ring_buffer_iter *iter); +ring_buffer_read_start (struct trace_buffer *buffer,int cpu,gfp_t flags);void ring_buffer_read_finish (struct ring_buffer_iter *iter); struct ring_buffer_event *
kernel/trace/ring_buffer.c +10 -57
89 lines not on this page · raw message
kernel/trace/trace.c +4 -10
@@ -4792,21 +4792,15 @@ __tracing_open(struct inode *inode, struct file *file, bool snapshot)if (iter->cpu_file ==RING_BUFFER_ALL_CPUS ) {for_each_tracing_cpu (cpu) { iter->buffer_iter[cpu] = -ring_buffer_read_prepare (iter->array_buffer->buffer, - cpu,GFP_KERNEL ); - } -ring_buffer_read_prepare_sync (); -for_each_tracing_cpu (cpu) { -ring_buffer_read_start (iter->buffer_iter[cpu]); +ring_buffer_read_start (iter->array_buffer->buffer, + cpu,GFP_KERNEL );tracing_iter_reset (iter, cpu); } }else { cpu = iter->cpu_file; iter->buffer_iter[cpu] = -ring_buffer_read_prepare (iter->array_buffer->buffer, - cpu,GFP_KERNEL ); -ring_buffer_read_prepare_sync (); -ring_buffer_read_start (iter->buffer_iter[cpu]); +ring_buffer_read_start (iter->array_buffer->buffer, + cpu,GFP_KERNEL );tracing_iter_reset (iter, cpu); }
kernel/trace/trace_kdb.c +3 -5
@@ -43,17 +43,15 @@ static void ftrace_dump_buf(int skip_entries, long cpu_file)if (cpu_file ==RING_BUFFER_ALL_CPUS ) {for_each_tracing_cpu (cpu) { iter.buffer_iter[cpu] = -ring_buffer_read_prepare (iter.array_buffer->buffer, - cpu,GFP_ATOMIC ); -ring_buffer_read_start (iter.buffer_iter[cpu]); +ring_buffer_read_start (iter.array_buffer->buffer, + cpu,GFP_ATOMIC );tracing_iter_reset (&iter, cpu); } }else { iter.cpu_file = cpu_file; iter.buffer_iter[cpu_file] = -ring_buffer_read_prepare (iter.array_buffer->buffer, +ring_buffer_read_start (iter.array_buffer->buffer, cpu_file,GFP_ATOMIC ); -ring_buffer_read_start (iter.buffer_iter[cpu_file]);tracing_iter_reset (&iter, cpu_file); }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 29/175 regulator: core: fix locking in regulator_resolve_supply() error path
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: André Draszik <[email protected]>
commit 497330b203d2c59c5ff3fa4c34d14494d7203bc3 upstream.
If late enabling of a supply regulator fails in regulator_resolve_supply(), the code currently triggers a lockdep warning:
WARNING: drivers/regulator/core.c:2649 at _regulator_put+0x80/0xa0, CPU#6: kworker/u32:4/596
...
Call trace:
_regulator_put+0x80/0xa0 (P)
regulator_resolve_supply+0x7cc/0xbe0
regulator_register_resolve_supply+0x28/0xb8as the regulator_list_mutex must be held when calling _regulator_put().
To solve this, simply switch to using regulator_put().
While at it, we should also make sure that no concurrent access happens to our rdev while we clear out the supply pointer. Add appropriate locking to ensure that.
While the code in question will be removed altogether in a follow-up commit, I believe it is still beneficial to have this corrected before removal for future reference.
--- drivers/regulator/core.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-)
drivers/regulator/core.c +9 -1
@@ -2176,8 +2176,16 @@ static int regulator_resolve_supply(struif (rdev->use_count) { ret =regulator_enable (rdev->supply);if (ret <0 ) { -_regulator_put (rdev->supply); +struct regulator *supply; + +regulator_lock_two (rdev, rdev->supply->rdev, &ww_ctx); + + supply = rdev->supply; rdev->supply =NULL ; + +regulator_unlock_two (rdev, supply->rdev, &ww_ctx); + +regulator_put (supply); goto out; } }
Greg Kroah-Hartman
maintainerPATCH 3/175 drm/amd/display: Bound VBIOS record-chain walk loops
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Harry Wentland <[email protected]>
[ Upstream commit ff287df16a1a58aca78b08d1f3ee09fc44da0351 ]
[Why & How]
All record-chain walk loops in bios_parser.c and bios_parser2.c use for(;;) and only terminate on a 0xFF record_type sentinel or zero record_size. A malformed VBIOS image missing the terminator record causes unbounded iteration at probe time, potentially hundreds of thousands of iterations with record_size=1. In the final iterations near the BIOS image boundary, struct casts beyond the 2-byte header validated by GET_IMAGE can also read out of bounds.
Cap all 14 record-chain walk loops to BIOS_MAX_NUM_RECORD (256) iterations. The atombios.h defines up to 22 distinct record types and atomfirmware.h has 13. Assuming an average of less than 10 records per type (which is reasonable since most are connector- based) 256 is a generous upper bound.
--- .../gpu/drm/amd/display/dc/bios/bios_parser.c | 15 +++++++---- .../drm/amd/display/dc/bios/bios_parser2.c | 27 ++++++++++++------- .../amd/display/dc/bios/bios_parser_helper.h | 5 ++++ 3 files changed, 33 insertions(+), 14 deletions(-)
drivers/gpu/drm/amd/display/dc/bios/bios_parser.c +10 -5
@@ -225,6 +225,7 @@ static enum bp_result bios_parser_get_i2c_info(struct dc_bios *dcb,ATOM_COMMON_RECORD_HEADER *header;ATOM_I2C_RECORD *record;struct bios_parser *bp =BP_FROM_DCB (dcb); +int i;if (!info)return BP_RESULT_BADINPUT ;
@@ -237,7 +238,7 @@ static enum bp_result bios_parser_get_i2c_info(struct dc_bios *dcb, offset =le16_to_cpu (object->usRecordOffset) + bp->object_info_tbl_offset; -for (;;) { +for (i =0 ; i <BIOS_MAX_NUM_RECORD ; i++) { header =GET_IMAGE (ATOM_COMMON_RECORD_HEADER , offset);if (!header)
@@ -296,11 +297,12 @@ static enum bp_result bios_parser_get_device_tag_record( {ATOM_COMMON_RECORD_HEADER *header;uint32_t offset; +int i; offset =le16_to_cpu (object->usRecordOffset) + bp->object_info_tbl_offset; -for (;;) { +for (i =0 ; i <BIOS_MAX_NUM_RECORD ; i++) { header =GET_IMAGE (ATOM_COMMON_RECORD_HEADER , offset);if (!header)
@@ -873,6 +875,7 @@ static ATOM_HPD_INT_RECORD *get_hpd_record(struct bios_parser *bp, {ATOM_COMMON_RECORD_HEADER *header;uint32_t offset; +int i;if (!object) {BREAK_TO_DEBUGGER ();/* Invalid object */
@@ -882,7 +885,7 @@ static ATOM_HPD_INT_RECORD *get_hpd_record(struct bios_parser *bp, offset =le16_to_cpu (object->usRecordOffset) + bp->object_info_tbl_offset; -for (;;) { +for (i =0 ; i <BIOS_MAX_NUM_RECORD ; i++) { header =GET_IMAGE (ATOM_COMMON_RECORD_HEADER , offset);if (!header)
@@ -1577,6 +1580,7 @@ static ATOM_ENCODER_CAP_RECORD_V2 *get_encoder_cap_record( {ATOM_COMMON_RECORD_HEADER *header;uint32_t offset; +int i;if (!object) {BREAK_TO_DEBUGGER ();/* Invalid object */
@@ -1586,7 +1590,7 @@ static ATOM_ENCODER_CAP_RECORD_V2 *get_encoder_cap_record( offset =le16_to_cpu (object->usRecordOffset) + bp->object_info_tbl_offset; -for (;;) { +for (i =0 ; i <BIOS_MAX_NUM_RECORD ; i++) { header =GET_IMAGE (ATOM_COMMON_RECORD_HEADER , offset);if (!header)
@@ -2675,6 +2679,7 @@ static enum bp_result update_slot_layout_info(struct dc_bios *dcb, unsigned int record_offset) {unsigned int j; +unsigned int n;struct bios_parser *bp;ATOM_BRACKET_LAYOUT_RECORD *record;ATOM_COMMON_RECORD_HEADER *record_header;
@@ -2684,7 +2689,7 @@ static enum bp_result update_slot_layout_info(struct dc_bios *dcb, record =NULL ; record_header =NULL ; -for (;;) { +for (n =0 ; n <BIOS_MAX_NUM_RECORD ; n++) { record_header =GET_IMAGE (ATOM_COMMON_RECORD_HEADER , record_offset);if (record_header ==NULL ) {
drivers/gpu/drm/amd/display/dc/bios/bios_parser2.c +18 -9
@@ -391,6 +391,7 @@ static enum bp_result bios_parser_get_i2c_info(struct dc_bios *dcb,struct atom_i2c_record *record;struct atom_i2c_record dummy_record = {0 };struct bios_parser *bp =BP_FROM_DCB (dcb); +int i;if (!info)return BP_RESULT_BADINPUT ;
@@ -424,7 +425,7 @@ static enum bp_result bios_parser_get_i2c_info(struct dc_bios *dcb,break ; } -for (;;) { +for (i =0 ; i <BIOS_MAX_NUM_RECORD ; i++) { header = GET_IMAGE(struct atom_common_record_header, offset);if (!header)
@@ -529,6 +530,7 @@ static struct atom_hpd_int_record *get_hpd_record_for_path_v3(struct bios_parser {struct atom_common_record_header *header;uint32_t offset; +int i;if (!object) {BREAK_TO_DEBUGGER ();/* Invalid object */
@@ -537,7 +539,7 @@ static struct atom_hpd_int_record *get_hpd_record_for_path_v3(struct bios_parser offset = object->disp_recordoffset + bp->object_info_tbl_offset; -for (;;) { +for (i =0 ; i <BIOS_MAX_NUM_RECORD ; i++) { header = GET_IMAGE(struct atom_common_record_header, offset);if (!header)
@@ -607,6 +609,7 @@ static struct atom_hpd_int_record *get_hpd_record( {struct atom_common_record_header *header;uint32_t offset; +int i;if (!object) {BREAK_TO_DEBUGGER ();/* Invalid object */
@@ -616,7 +619,7 @@ static struct atom_hpd_int_record *get_hpd_record( offset =le16_to_cpu (object->disp_recordoffset) + bp->object_info_tbl_offset; -for (;;) { +for (i =0 ; i <BIOS_MAX_NUM_RECORD ; i++) { header = GET_IMAGE(struct atom_common_record_header, offset);if (!header)
@@ -2125,6 +2128,7 @@ static struct atom_encoder_caps_record *get_encoder_cap_record( {struct atom_common_record_header *header;uint32_t offset; +int i;if (!object) {BREAK_TO_DEBUGGER ();/* Invalid object */
@@ -2133,7 +2137,7 @@ static struct atom_encoder_caps_record *get_encoder_cap_record( offset = object->encoder_recordoffset + bp->object_info_tbl_offset; -for (;;) { +for (i =0 ; i <BIOS_MAX_NUM_RECORD ; i++) { header = GET_IMAGE(struct atom_common_record_header, offset);if (!header)
@@ -2162,6 +2166,7 @@ static struct atom_disp_connector_caps_record *get_disp_connector_caps_record( {struct atom_common_record_header *header;uint32_t offset; +int i;if (!object) {BREAK_TO_DEBUGGER ();/* Invalid object */
@@ -2170,7 +2175,7 @@ static struct atom_disp_connector_caps_record *get_disp_connector_caps_record( offset = object->disp_recordoffset + bp->object_info_tbl_offset; -for (;;) { +for (i =0 ; i <BIOS_MAX_NUM_RECORD ; i++) { header = GET_IMAGE(struct atom_common_record_header, offset);if (!header)
@@ -2198,6 +2203,7 @@ static struct atom_connector_caps_record *get_connector_caps_record(struct bios_ {struct atom_common_record_header *header;uint32_t offset; +int i;if (!object) {BREAK_TO_DEBUGGER ();/* Invalid object */
@@ -2206,7 +2212,7 @@ static struct atom_connector_caps_record *get_connector_caps_record(struct bios_ offset = object->disp_recordoffset + bp->object_info_tbl_offset; -for (;;) { +for (i =0 ; i <BIOS_MAX_NUM_RECORD ; i++) { header = GET_IMAGE(struct atom_common_record_header, offset);if (!header)
@@ -2286,6 +2292,7 @@ static struct atom_connector_speed_record *get_connector_speed_cap_record(struct {struct atom_common_record_header *header;uint32_t offset; +int i;if (!object) {BREAK_TO_DEBUGGER ();/* Invalid object */
@@ -2294,7 +2301,7 @@ static struct atom_connector_speed_record *get_connector_speed_cap_record(struct offset = object->disp_recordoffset + bp->object_info_tbl_offset; -for (;;) { +for (i =0 ; i <BIOS_MAX_NUM_RECORD ; i++) { header = GET_IMAGE(struct atom_common_record_header, offset);if (!header)
@@ -3154,6 +3161,7 @@ static enum bp_result update_slot_layout_info( {unsigned int record_offset;unsigned int j; +unsigned int n;struct atom_display_object_path_v2 *object;struct atom_bracket_layout_record *record;struct atom_common_record_header *record_header;
@@ -3175,7 +3183,7 @@ static enum bp_result update_slot_layout_info( (object->disp_recordoffset) + (unsigned int )(bp->object_info_tbl_offset); -for (;;) { +for (n =0 ; n <BIOS_MAX_NUM_RECORD ; n++) { record_header = (struct atom_common_record_header *) GET_IMAGE(struct atom_common_record_header,
@@ -3269,6 +3277,7 @@ static enum bp_result update_slot_layout_info_v2( struct slot_layout_info *slot_layout_info) {unsigned int record_offset; +unsigned int n;struct atom_display_object_path_v3 *object;struct atom_bracket_layout_record_v2 *record;struct atom_common_record_header *record_header;
@@ -3291,7 +3300,7 @@ static enum bp_result update_slot_layout_info_v2( (object->disp_recordoffset) + (unsigned int )(bp->object_info_tbl_offset); -for (;;) { +for (n =0 ; n <BIOS_MAX_NUM_RECORD ; n++) { record_header = (struct atom_common_record_header *) GET_IMAGE(struct atom_common_record_header,
drivers/gpu/drm/amd/display/dc/bios/bios_parser_helper.h +5 -0
@@ -38,4 +38,9 @@ uint32_t bios_get_vga_enabled_displays(struct dc_bios *bios);#define GET_IMAGE (type, offset) ((type *) bios_get_image(&bp->base, offset, sizeof(type))) +/* Upper bound on the number of records in a VBIOS record chain. Prevents +* unbounded looping if the VBIOS image is malformed and lacks a terminator. +*/ +#define BIOS_MAX_NUM_RECORD 256 +#endif
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 30/175 dlm: prevent NPD when writing a positive value to event_done
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Thadeu Lima de Souza Cascardo <[email protected]>
commit 8e2bad543eca5c25cd02cbc63d72557934d45f13 upstream.
do_uevent returns the value written to event_done. In case it is a positive value, new_lockspace would undo all the work, and lockspace would not be set. __dlm_new_lockspace, however, would treat that positive value as a success due to commit 8511a2728ab8 ("dlm: fix use count with multiple joins").
Down the line, device_create_lockspace would pass that NULL lockspace to dlm_find_lockspace_local, leading to a NULL pointer dereference.
Treating such positive values as successes prevents the problem. Given this has been broken for so long, this is unlikely to break userspace expectations.
--- fs/dlm/lockspace.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
fs/dlm/lockspace.c +1 -1
@@ -631,7 +631,7 @@ static int new_lockspace(const char *namlockspace to start running (via sysfs) in dlm_ls_start(). */ error =do_uevent (ls,1 ); -if (error) +if (error <0 ) goto out_recoverd;/* wait until recovery is successful or failed */
Greg Kroah-Hartman
maintainerPATCH 31/175 netfilter: nf_tables: always walk all pending catchall elements
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Florian Westphal <[email protected]>
commit 7cb9a23d7ae40a702577d3d8bacb7026f04ac2a9 upstream.
During transaction processing we might have more than one catchall element:
1 live catchall element and 1 pending element that is coming as part of the new batch.
If the map holding the catchall elements is also going away, its required to toggle all catchall elements and not just the first viable candidate.
Otherwise, we get:
WARNING: ./include/net/netfilter/nf_tables.h:1281 at nft_data_release+0xb7/0xe0 [nf_tables], CPU#2: nft/1404 RIP: 0010:nft_data_release+0xb7/0xe0 [nf_tables] [..] __nft_set_elem_destroy+0x106/0x380 [nf_tables] nf_tables_abort_release+0x348/0x8d0 [nf_tables] nf_tables_abort+0xcf2/0x3ac0 [nf_tables] nfnetlink_rcv_batch+0x9c9/0x20e0 [..]
--- net/netfilter/nf_tables_api.c | 2 -- 1 file changed, 2 deletions(-)
net/netfilter/nf_tables_api.c +0 -2
@@ -652,7 +652,6 @@ static void nft_map_catchall_deactivate( elem.priv = catchall->elem;nft_set_elem_change_active (ctx->net, set, ext);nft_setelem_data_deactivate (ctx->net, set, &elem); -break ; } }
@@ -5615,7 +5614,6 @@ static void nft_map_catchall_activate(conft_clear (ctx->net, ext); elem.priv = catchall->elem;nft_setelem_data_activate (ctx->net, set, &elem); -break ; } }
Greg Kroah-Hartman
maintainerPATCH 32/175 mptcp: pm: fix extra_subflows underflow on userspace PM subflow creation
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Tao Cui <[email protected]>
[ Upstream commit 14e9fea30b68fc75b2b3d97396a7e6adb544bd2a ]
The userspace PM increments extra_subflows after __mptcp_subflow_connect() succeeds, but __mptcp_subflow_connect() calls mptcp_pm_close_subflow() on failure to roll back the pre-increment done by the kernel PM's fill_*() helpers. Because the userspace PM hasn't incremented yet at that point, this decrement is spurious and causes extra_subflows to underflow.
Fix it by aligning the userspace PM with the kernel PM: increment extra_subflows before calling __mptcp_subflow_connect(), so the existing error path in subflow.c correctly rolls it back on failure. Also simplify the error handling by taking pm.lock only when needed for cleanup.
--- net/mptcp/pm_userspace.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-)
net/mptcp/pm_userspace.c +8 -5
@@ -408,18 +408,21 @@ int mptcp_nl_cmd_sf_create(struct sk_buf goto create_err; } +spin_lock_bh (&msk->pm.lock); + msk->pm.subflows++; +spin_unlock_bh (&msk->pm.lock); +lock_sock (sk); err =__mptcp_subflow_connect (sk, &addr_l, &addr_r);release_sock (sk); -spin_lock_bh (&msk->pm.lock); -if (err) +if (err) { +spin_lock_bh (&msk->pm.lock);mptcp_userspace_pm_delete_local_addr (msk, &local); -else - msk->pm.subflows++; -spin_unlock_bh (&msk->pm.lock); +spin_unlock_bh (&msk->pm.lock); + } create_err:sock_put ((struct sock *)msk);
Greg Kroah-Hartman
maintainerPATCH 33/175 hv: utils: handle and propagate errors in kvp_register
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Thorsten Blum <[email protected]>
[ Upstream commit 3fcf923302a8f5c0dc3af3d2ca2657cb5fae4297 ]
Make kvp_register() return an error code instead of silently ignoring failures, and propagate the error from kvp_handle_handshake() instead of returning success.
This propagates both kzalloc_obj() and hvutil_transport_send() failures to kvp_handle_handshake() and thus to kvp_on_msg().
--- drivers/hv/hv_kvp.c | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-)
drivers/hv/hv_kvp.c +14 -13
@@ -93,7 +93,7 @@ static void kvp_send_key(struct work_strstatic void kvp_respond_to_host (struct hv_kvp_msg *msg,int error);static void kvp_timeout_func (struct work_struct *dummy);static void kvp_host_handshake_func (struct work_struct *dummy); -static void kvp_register (int ); +static int kvp_register (int ); static DECLARE_DELAYED_WORK(kvp_timeout_work, kvp_timeout_func); static DECLARE_DELAYED_WORK(kvp_host_handshake_work, kvp_host_handshake_func);
@@ -127,24 +127,26 @@ static void kvp_register_done(void)hv_poll_channel (kvp_transaction.recv_channel, kvp_poll_wrapper); } -static void +static int kvp_register (int reg_value) {struct hv_kvp_msg *kvp_msg;char *version; +int ret; kvp_msg =kzalloc (sizeof (*kvp_msg),GFP_KERNEL ); +if (!kvp_msg) +return -ENOMEM ; -if (kvp_msg) { - version = kvp_msg->body.kvp_register.version; - kvp_msg->kvp_hdr.operation = reg_value; -strcpy (version,HV_DRV_VERSION ); - -hvutil_transport_send (hvt, kvp_msg,sizeof (*kvp_msg), - kvp_register_done); -kfree (kvp_msg); - } + version = kvp_msg->body.kvp_register.version; + kvp_msg->kvp_hdr.operation = reg_value; +strcpy (version,HV_DRV_VERSION ); + + ret =hvutil_transport_send (hvt, kvp_msg,sizeof (*kvp_msg), + kvp_register_done); +kfree (kvp_msg); +return ret; }static void kvp_timeout_func (struct work_struct *dummy)
@@ -186,9 +188,8 @@ static int kvp_handle_handshake(struct h*/ pr_debug ("KVP: userspace daemon ver. %d connected\n" , msg->kvp_hdr.operation); -kvp_register (dm_reg_value); -return 0 ; +return kvp_register (dm_reg_value); }
Greg Kroah-Hartman
maintainerPATCH 34/175 futex/requeue: Prevent NULL pointer dereference in remove_waiter() on self-deadlock
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ji'an Zhou <[email protected]>
[ Upstream commit 74e144274af39935b0f410c0ee4d2b91c3730414 ]
When FUTEX_CMP_REQUEUE_PI requeues a non-top waiter that already owns the target PI futex, task_blocks_on_rt_mutex() returns -EDEADLK before setting waiter->task.
The subsequent remove_waiter() in rt_mutex_start_proxy_lock() dereferences the NULL waiter->task, causing a kernel crash.
Add a self-deadlock check for non-top waiters before calling rt_mutex_start_proxy_lock(), analogous to the top-waiter check in futex_lock_pi_atomic().
--- kernel/futex/requeue.c | 6 ++++++ 1 file changed, 6 insertions(+)
kernel/futex/requeue.c +6 -0
@@ -629,6 +629,12 @@ retry_private:continue ; } +/* Self-deadlock: non-top waiter already owns the PI futex. */ +if (rt_mutex_owner (&pi_state->pi_mutex) == this->task) { + ret = -EDEADLK ; +break ; + } + ret =rt_mutex_start_proxy_lock (&pi_state->pi_mutex, this->rt_waiter, this->task);
Greg Kroah-Hartman
maintainerPATCH 35/175 Drivers: hv: vmbus: Improve the logic of reserving fb_mmio on Gen2 VMs
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Dexuan Cui <[email protected]>
[ Upstream commit 016a25e4b0df4d77e7c258edee4aaf982e4ee809 ]
If vmbus_reserve_fb() in the kdump/kexec kernel fails to properly reserve the framebuffer MMIO range (which is below 4GB) due to a Gen2 VM's screen.lfb_base being zero [1], there is an MMIO conflict between the drivers hyperv-drm and pci-hyperv: when the driver pci-hyperv's hv_allocate_config_window() calls vmbus_allocate_mmio() to get an MMIO range, typically it gets a 32-bit MMIO range that overlaps with the framebuffer MMIO range, and later hv_pci_enter_d0() fails with an error message "PCI Pass-through VSP failed D0 Entry with status" since the host thinks that PCI devices must not use MMIO space that the host has assigned to the framebuffer.
This is especially an issue if pci-hyperv is built-in and hyperv-drm is built as a module. Consequently, the kdump/kexec kernel fails to detect PCI devices via pci-hyperv, and may fail to mount the root file system, which may reside in a NVMe disk. The issue described here has existed for SR-IOV VF NICs since day one of the pci-hyperv driver, and has been worked around on x64 when possible. With the recent introduction of ARM64 VMs that boot from NVMe, there is no workaround, so we need a formal fix.
On Gen2 VMs, if the screen.lfb_base is 0 in the kdump/kexec kernel [1], fall back to the low MMIO base, which should be equal to the framebuffer MMIO base [2] (the statement is true according to my testing on x64 Windows Server 2016, and on x64 and ARM64 Windows Server 2025 and on Azure. I checked with the Hyper-V team and they said the statement should continue to be true for Gen2 VMs). In the first kernel, screen.lfb_base is not 0; if the user specifies a very high resolution, it's not enough to only reserve 8MB: let's always reserve half of the space below 4GB, but cap the reservation to 128MB, which is the required framebuffer size of the highest resolution 7680*4320 supported by Hyper-V.
While at it, fix the comparison "end > VTPM_BASE_ADDRESS" by changing the > to >=. Here the 'end' is an inclusive end (typically, it's 0xFFFF_FFFF for the low MMIO range).
Note: vmbus_reserve_fb() now also reserves an MMIO range at the beginning of the low MMIO range on CVMs, which have no framebuffers (the 'screen.lfb_base' in vmbus_reserve_fb() is 0 for CVMs), just in case the host might treat the beginning of the low MMIO range specially [3]. BTW, the OpenHCL kernel is not affected by the change, because that kernel boots with DeviceTree rather than ACPI (so vmbus_reserve_fb() won't run there), and there is no framebuffer device for that kernel.
Note: normally Gen1 VMs don't have the MMIO conflict issue because the framebuffer MMIO range (which is hardcoded to base=4GB-128MB and size=64MB for Gen1 VMs by the host) is always reported via the legacy PCI graphics device's BAR, so the kdump/kexec kernel can reserve the 64MB MMIO range; however, if the VM is configured to use a very high resolution and the required framebuffer size exceeds 64MB (AFAIK, in practice, this isn't a typical configuration by users), the hyperv-drm driver may need to allocate an MMIO range above 4GB and change the framebuffer MMIO location to the allocated MMIO range -- in this case, there can still be issues [4] which can't be easily fixed: any possible affected Gen1 users would have to use a resolution whose framebuffer size is <= 64MB, or switch to Gen2 VMs.
[1] https://lore.kernel.org/all/SA1PR21MB692176C1BC53BFC9EAE5CF8EBF51A@SA1PR21MB6921.namprd21.prod.outlook.com/
[2] https://lore.kernel.org/all/SA1PR21MB69218F955B62DFF62E3E88D2BF222@SA1PR21MB6921.namprd21.prod.outlook.com/
[3] https://lore.kernel.org/all/SN6PR02MB415726B17D5A6027CD1717E8D4342@SN6PR02MB4157.namprd02.prod.outlook.com/
[4] https://lore.kernel.org/all/SA1PR21MB69213486F821CA5A2C793C81BF342@SA1PR21MB6921.namprd21.prod.outlook.com/
--- drivers/hv/vmbus_drv.c | 29 ++++++++++++++++++++++++++--- 1 file changed, 26 insertions(+), 3 deletions(-)
drivers/hv/vmbus_drv.c +26 -3
@@ -2029,8 +2029,8 @@ static acpi_status vmbus_walk_resources(return AE_NO_MEMORY ;/* If this range overlaps the virtual TPM, truncate it. */ -if (end >VTPM_BASE_ADDRESS && start <VTPM_BASE_ADDRESS ) - end =VTPM_BASE_ADDRESS ; +if (end >=VTPM_BASE_ADDRESS && start <VTPM_BASE_ADDRESS ) + end =VTPM_BASE_ADDRESS -1 ; new_res->name ="hyperv mmio" ; new_res->flags =IORESOURCE_MEM ;
@@ -2097,12 +2097,31 @@ static void vmbus_mmio_remove(void)static void __maybe_unused vmbus_reserve_fb (void ) {resource_size_t start =0 , size; +resource_size_t low_mmio_base;struct pci_dev *pdev;if (efi_enabled (EFI_BOOT )) {/* Gen2 VM: get FB base from EFI framebuffer */ start = screen_info.lfb_base; size =max_t (__u32, screen_info.lfb_size,0x800000 ); + + low_mmio_base = hyperv_mmio->start; +if (!low_mmio_base ||upper_32_bits (low_mmio_base) || + (start && start < low_mmio_base)) { +pr_warn ("Unexpected low mmio base %pa\n" , &low_mmio_base); + }else { +/* +* If the kdump/kexec or CVM kernel's lfb_base +* is 0, fall back to the low mmio base. +*/ +if (!start) + start = low_mmio_base; +/* +* Reserve half of the space below 4GB for high +* resolutions, but cap the reservation to 128MB. +*/ + size =min ((SZ_4G - start) /2 ,SZ_128M ); + } }else {/* Gen1 VM: get FB base from PCI */ pdev = pci_get_device(PCI_VENDOR_ID_MICROSOFT,
@@ -2122,8 +2141,10 @@ static void __maybe_unused vmbus_reservepci_dev_put (pdev); } -if (!start) +if (!start) { +pr_warn ("Unexpected framebuffer mmio base of zero\n" );return ; + }/* * Make a claim for the frame buffer in the resource tree under the
@@ -2133,6 +2154,8 @@ static void __maybe_unused vmbus_reserve*/ for (; !fb_mmio && (size >=0x100000 ); size >>=1 ) fb_mmio =__request_region (hyperv_mmio, start, size, fb_mmio_name,0 ); + +pr_info ("hv_mmio=%pR,%pR fb=%pR\n" , hyperv_mmio, hyperv_mmio->sibling, fb_mmio); }/**
Greg Kroah-Hartman
maintainerPATCH 36/175 locking/rtmutex: Skip remove_waiter() when waiter is not enqueued
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Davidlohr Bueso <[email protected]>
[ Upstream commit 40a25d59e85b3c8709ac2424d44f65610467871e ]
syzbot triggered the following splat in remove_waiter() via FUTEX_CMP_REQUEUE_PI:
KASAN: null-ptr-deref in range [0x0000000000000a88-0x0000000000000a8f] class_raw_spinlock_constructor remove_waiter+0x159/0x1200 kernel/locking/rtmutex.c:1561 rt_mutex_start_proxy_lock+0x103/0x120 futex_requeue+0x10e4/0x20d0 __x64_sys_futex+0x34f/0x4d0
task_blocks_on_rt_mutex() does not arm the waiter upon deadlock detection, leaving waiter->task nil, where 3bfdc63936dd ("rtmutex: Use waiter::task instead of current in remove_waiter()") made this fatal.
Furthermore, rt_mutex_start_proxy_lock() should not be calling into remove_waiter() upon a successfully grabbing the rtmutex. 1a1fb985f2e2 ("futex: Handle early deadlock return correctly"), moved the remove_waiter() out of __rt_mutex_start_proxy_lock() (where 'ret' was only ever 0 or < 0) into the wrapper. Tighten this check to account for try_to_take_rt_mutex().
--- kernel/locking/rtmutex.c | 3 +++ kernel/locking/rtmutex_api.c | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-)
kernel/locking/rtmutex.c +3 -0
@@ -1524,6 +1524,9 @@ static void __sched remove_waiter(structlockdep_assert_held (&lock->wait_lock); +if (!waiter_task)/* never enqueued */ +return ; + scoped_guard(raw_spinlock, &waiter_task->pi_lock) {rt_mutex_dequeue (lock, waiter); waiter_task->pi_blocked_on =NULL ;
kernel/locking/rtmutex_api.c +1 -1
@@ -344,7 +344,7 @@ int __sched rt_mutex_start_proxy_lock(straw_spin_lock_irq (&lock->wait_lock); ret =__rt_mutex_start_proxy_lock (lock, waiter, task); -if (unlikely (ret)) +if (unlikely (ret <0 ))remove_waiter (lock, waiter);raw_spin_unlock_irq (&lock->wait_lock);
Greg Kroah-Hartman
maintainerPATCH 37/175 phonet: Pass ifindex to fill_addr().
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Kuniyuki Iwashima <[email protected]>
[ Upstream commit 08a9572be36819b5d9011604edfa5db6c5062a7a ]
We will convert addr_doit() and getaddr_dumpit() to RCU, both of which call fill_addr().
The former will call phonet_address_notify() outside of RCU due to GFP_KERNEL, so dev will not be available in fill_addr().
Let's pass ifindex directly to fill_addr().
Stable-dep-of: 71de0177b28d ("net: phonet: free phonet_device after RCU grace period")
--- net/phonet/pn_netlink.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-)
net/phonet/pn_netlink.c +7 -6
@@ -19,7 +19,7 @@/* Device address handling */ -static int fill_addr (struct sk_buff *skb,struct net_device *dev,u8 addr, +static int fill_addr (struct sk_buff *skb,u32 ifindex,u8 addr,u32 portid,u32 seq,int event);void phonet_address_notify (int event,struct net_device *dev,u8 addr)
@@ -31,7 +31,8 @@ void phonet_address_notify(int event, st nla_total_size(1), GFP_KERNEL);if (skb ==NULL ) goto errout; - err =fill_addr (skb, dev, addr,0 ,0 , event); + + err =fill_addr (skb, dev->ifindex, addr,0 ,0 , event);if (err <0 ) {WARN_ON (err == -EMSGSIZE );kfree_skb (skb);
@@ -92,8 +93,8 @@ static int addr_doit(struct sk_buff *skbreturn err; } -static int fill_addr (struct sk_buff *skb,struct net_device *dev,u8 addr, -u32 portid,u32 seq,int event) +static int fill_addr (struct sk_buff *skb,u32 ifindex,u8 addr, +u32 portid,u32 seq,int event) {struct ifaddrmsg *ifm;struct nlmsghdr *nlh;
@@ -107,7 +108,7 @@ static int fill_addr(struct sk_buff *skb ifm->ifa_prefixlen =0 ; ifm->ifa_flags =IFA_F_PERMANENT ; ifm->ifa_scope =RT_SCOPE_LINK ; - ifm->ifa_index = dev->ifindex; + ifm->ifa_index = ifindex;if (nla_put_u8 (skb,IFA_LOCAL , addr)) goto nla_put_failure;nlmsg_end (skb, nlh);
@@ -140,7 +141,7 @@ static int getaddr_dumpit(struct sk_buffif (addr_idx++ < addr_start_idx)continue ; -if (fill_addr (skb, pnd->netdev, addr <<2 , +if (fill_addr (skb, pnd->netdev->ifindex, addr <<2 ,NETLINK_CB (cb->skb).portid, cb->nlh->nlmsg_seq,RTM_NEWADDR ) <0 ) goto out;
Greg Kroah-Hartman
maintainerPATCH 38/175 phonet: Pass net and ifindex to phonet_address_notify().
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Kuniyuki Iwashima <[email protected]>
[ Upstream commit 68ed5c38b512b734caf3da1f87db4a99fcfe3002 ]
Currently, phonet_address_notify() fetches netns and ifindex from dev.
Once addr_doit() is converted to RCU, phonet_address_notify() will be called outside of RCU due to GFP_KERNEL, and dev will be unavailable there.
Let's pass net and ifindex to phonet_address_notify().
Stable-dep-of: 71de0177b28d ("net: phonet: free phonet_device after RCU grace period")
--- include/net/phonet/pn_dev.h | 2 +- net/phonet/pn_dev.c | 10 +++++++--- net/phonet/pn_netlink.c | 12 ++++++------ 3 files changed, 14 insertions(+), 10 deletions(-)
include/net/phonet/pn_dev.h +1 -1
@@ -38,7 +38,7 @@ int phonet_address_add(struct net_deviceint phonet_address_del (struct net_device *dev,u8 addr);u8 phonet_address_get (struct net_device *dev,u8 addr);int phonet_address_lookup (struct net *net,u8 addr); -void phonet_address_notify (int event,struct net_device *dev,u8 addr); +void phonet_address_notify (struct net *net,int event,u32 ifindex,u8 addr);int phonet_route_add (struct net_device *dev,u8 daddr);int phonet_route_del (struct net_device *dev,u8 daddr);
net/phonet/pn_dev.c +7 -3
@@ -98,10 +98,13 @@ static void phonet_device_destroy(structmutex_unlock (&pndevs->lock);if (pnd) { +struct net *net =dev_net (dev); +u32 ifindex = dev->ifindex;u8 addr;for_each_set_bit (addr, pnd->addrs,64 ) -phonet_address_notify (RTM_DELADDR , dev, addr); +phonet_address_notify (net,RTM_DELADDR , ifindex, addr); +kfree (pnd); } }
@@ -244,8 +247,9 @@ static int phonet_device_autoconf(struct ret =phonet_address_add (dev, req.ifr_phonet_autoconf.device);if (ret)return ret; -phonet_address_notify (RTM_NEWADDR , dev, - req.ifr_phonet_autoconf.device); + +phonet_address_notify (dev_net (dev),RTM_NEWADDR , dev->ifindex, + req.ifr_phonet_autoconf.device);return 0 ; }
net/phonet/pn_netlink.c +6 -6
@@ -22,7 +22,7 @@static int fill_addr (struct sk_buff *skb,u32 ifindex,u8 addr,u32 portid,u32 seq,int event); -void phonet_address_notify (int event,struct net_device *dev,u8 addr) +void phonet_address_notify (struct net *net,int event,u32 ifindex,u8 addr) {struct sk_buff *skb;int err = -ENOBUFS ;
@@ -32,17 +32,17 @@ void phonet_address_notify(int event, stif (skb ==NULL ) goto errout; - err =fill_addr (skb, dev->ifindex, addr,0 ,0 , event); + err =fill_addr (skb, ifindex, addr,0 ,0 , event);if (err <0 ) {WARN_ON (err == -EMSGSIZE );kfree_skb (skb); goto errout; } -rtnl_notify (skb,dev_net (dev),0 , -RTNLGRP_PHONET_IFADDR ,NULL ,GFP_KERNEL ); + +rtnl_notify (skb, net,0 ,RTNLGRP_PHONET_IFADDR ,NULL ,GFP_KERNEL );return ; errout: -rtnl_set_sk_err (dev_net (dev),RTNLGRP_PHONET_IFADDR , err); +rtnl_set_sk_err (net,RTNLGRP_PHONET_IFADDR , err); }static const struct nla_policy ifa_phonet_policy[IFA_MAX +1 ] = {
@@ -89,7 +89,7 @@ static int addr_doit(struct sk_buff *skbelse err =phonet_address_del (dev, pnaddr);if (!err) -phonet_address_notify (nlh->nlmsg_type, dev, pnaddr); +phonet_address_notify (net, nlh->nlmsg_type, ifm->ifa_index, pnaddr);return err; }
Greg Kroah-Hartman
maintainerPATCH 39/175 net: phonet: free phonet_device after RCU grace period
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Santosh Kalluri <[email protected]>
[ Upstream commit 71de0177b28da751f407581a4515cf4d762f6296 ]
phonet_device_destroy() removes a phonet_device from the per-net device list with list_del_rcu(), but frees it immediately. RCU readers walking the same list can still hold a pointer to the object after it has been removed, leading to a slab-use-after-free.
Use kfree_rcu(), matching the lifetime rule already used by phonet_address_del() for the same object type.
--- net/phonet/pn_dev.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
net/phonet/pn_dev.c +1 -1
@@ -105,7 +105,7 @@ static void phonet_device_destroy(structfor_each_set_bit (addr, pnd->addrs,64 )phonet_address_notify (net,RTM_DELADDR , ifindex, addr); -kfree (pnd); +kfree_rcu (pnd, rcu); } }
Greg Kroah-Hartman
maintainerPATCH 4/175 ip6_vti: set netns_immutable on the fallback device.
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Eric Dumazet <[email protected]>
[ Upstream commit d289d5307762d1838aaece22c6b6fcad9e8865f9 ]
john1988 and Noam Rathaus reported that vti6_init_net() does not set the netns_immutable flag on the per-netns fallback tunnel device (ip6_vti0).
Other similar tunnel drivers (like ip6_tunnel, sit, ip6_gre, and ip_tunnel) correctly set this flag during their fallback device initialization to prevent them from being moved to another network namespace.
[Salvatore Bonaccorso: Backport for version without 0c493da86374 ("net:
rename netns_local to netns_immutable") in v6.15-rc1 and without 05c1280a2bcf ("netdev_features: convert NETIF_F_NETNS_LOCAL to dev->netns_local") in v6.12-rc1 and use NETIF_F_NETNS_LOCAL device feature.]
--- net/ipv6/ip6_vti.c | 1 + 1 file changed, 1 insertion(+)
net/ipv6/ip6_vti.c +1 -0
@@ -1166,6 +1166,7 @@ static int __net_init vti6_init_net(struct net *net) goto err_alloc_dev;dev_net_set (ip6n->fb_tnl_dev, net); ip6n->fb_tnl_dev->rtnl_link_ops = &vti6_link_ops; + ip6n->fb_tnl_dev->features |=NETIF_F_NETNS_LOCAL ; err =vti6_fb_tnl_dev_init (ip6n->fb_tnl_dev);if (err <0 )
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 40/175 rxrpc: Fix the ACK parser to extract the SACK table for parsing
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: David Howells <[email protected]>
[ Upstream commit 333b6d5bb9f87827ac2639c737bf9613dbae7253 ]
Fix modification of the received skbuff in rxrpc_input_soft_acks() and a potential incorrect access of the buffer in a fragmented UDP packet (the packet would probably have to be deliberately pre-generated as fragmented) when AF_RXRPC tries to extract the contents of the SACK table by copying out the contents of the SACK table into a buffer before attempting to parse
AF_RXRPC assumes that it can just call skb_condense() and then validly access the SACK table from skb->data and that it will be a flat buffer - but skb_condense() can silently fail to do anything under some circumstances.
Note that whilst rxrpc_input_soft_acks() should be able to parse extended ACKs, the rest of AF_RXRPC doesn't currently support that.
Further, there's then no need to call skb_condense() in rxrpc_input_ack(), so don't.
--- net/rxrpc/input.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-)
net/rxrpc/input.c +12 -1
@@ -781,7 +781,18 @@ static void rxrpc_input_soft_acks(structstruct rxrpc_skb_priv *sp =rxrpc_skb (skb);unsigned int i, old_nacks =0 ;rxrpc_seq_t lowest_nak = seq + sp->nr_acks; -u8 *acks = skb->data +sizeof (struct rxrpc_wire_header ) +sizeof (struct rxrpc_ackpacket ); +u8 sack[256 ]__aligned(sizeof(unsigned long)) ; +u8 *acks = sack; + +/* Extract the SACK table into a flat buffer rather than accessing it +* directly through skb->data, which is not guaranteed to be linear for +* a fragmented packet (skb_condense() can silently fail to linearise +* it). +*/ +if (skb_copy_bits (skb, +sizeof (struct rxrpc_wire_header ) +sizeof (struct rxrpc_ackpacket ), + sack,umin (sp->nr_acks,sizeof (sack))) <0 ) +return ;for (i =0 ; i < sp->nr_acks; i++) {if (acks[i] ==RXRPC_ACK_TYPE_ACK ) {
Greg Kroah-Hartman
maintainerPATCH 41/175 slimbus: qcom-ngd-ctrl: Fix up platform_driver registration
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Bjorn Andersson <[email protected]>
[ Upstream commit 8663e8334d7b6007f5d8a4e5dd270246f35107a6 ]
Device drivers should not invoke platform_driver_register()/unregister() in their probe and remove paths. They should further not rely on platform_driver_unregister() as their only means of "deleting" their child devices.
Introduce a helper to unregister the child device and move the platform_driver_register()/unregister() to module_init()/exit().
--- drivers/slimbus/qcom-ngd-ctrl.c | 36 +++++++++++++++++++++++++++++++++--- 1 file changed, 33 insertions(+), 3 deletions(-)
drivers/slimbus/qcom-ngd-ctrl.c +33 -3
@@ -1561,6 +1561,13 @@ static int of_qcom_slim_ngd_register(strreturn -ENODEV ; } +static void qcom_slim_ngd_unregister (struct qcom_slim_ngd_ctrl *ctrl) +{ +struct qcom_slim_ngd *ngd = ctrl->ngd; + +platform_device_del (ngd->pdev); +} +static int qcom_slim_ngd_probe (struct platform_device *pdev) {struct device *dev = &pdev->dev;
@@ -1663,7 +1670,6 @@ static int qcom_slim_ngd_ctrl_probe(stru goto err_pdr_lookup; } -platform_driver_register (&qcom_slim_ngd_driver);return of_qcom_slim_ngd_register (dev, ctrl); err_pdr_alloc:
@@ -1677,7 +1683,9 @@ err_pdr_lookup:static int qcom_slim_ngd_ctrl_remove (struct platform_device *pdev) { -platform_driver_unregister (&qcom_slim_ngd_driver); +struct qcom_slim_ngd_ctrl *ctrl =platform_get_drvdata (pdev); + +qcom_slim_ngd_unregister (ctrl);return 0 ; }
@@ -1756,6 +1764,28 @@ static struct platform_driver qcom_slim_ }, }; -module_platform_driver (qcom_slim_ngd_ctrl_driver); +static int qcom_slim_ngd_init (void ) +{ +int ret; + + ret =platform_driver_register (&qcom_slim_ngd_driver); +if (ret) +return ret; + + ret =platform_driver_register (&qcom_slim_ngd_ctrl_driver); +if (ret) +platform_driver_unregister (&qcom_slim_ngd_driver); + +return ret; +} + +static void qcom_slim_ngd_exit (void ) +{ +platform_driver_unregister (&qcom_slim_ngd_ctrl_driver); +platform_driver_unregister (&qcom_slim_ngd_driver); +} + +module_init (qcom_slim_ngd_init); +module_exit (qcom_slim_ngd_exit);MODULE_LICENSE ("GPL v2" );MODULE_DESCRIPTION ("Qualcomm SLIMBus NGD controller" );
Greg Kroah-Hartman
maintainerPATCH 42/175 slimbus: qcom-ngd-ctrl: Balance pm_runtime enablement for NGD
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Bjorn Andersson <[email protected]>
[ Upstream commit 6a003446b725c44b9e3ffa111b0effbaa2d43085 ]
The pm_runtime_enable() and pm_runtime_use_autosuspend() calls are supposed to be balanced on exit, add these calls.
--- drivers/slimbus/qcom-ngd-ctrl.c | 3 +++ 1 file changed, 3 insertions(+)
drivers/slimbus/qcom-ngd-ctrl.c +3 -0
@@ -1585,6 +1585,8 @@ static int qcom_slim_ngd_probe(struct pl ret =qcom_slim_ngd_qmi_svc_event_init (ctrl);if (ret) {dev_err (&pdev->dev,"QMI service registration failed:%d" , ret); +pm_runtime_dont_use_autosuspend (dev); +pm_runtime_disable (dev);return ret; }
@@ -1694,6 +1696,7 @@ static int qcom_slim_ngd_remove(struct p {struct qcom_slim_ngd_ctrl *ctrl =platform_get_drvdata (pdev); +pm_runtime_dont_use_autosuspend (&pdev->dev);pm_runtime_disable (&pdev->dev);pdr_handle_release (ctrl->pdr);qcom_unregister_ssr_notifier (ctrl->notifier, &ctrl->nb);
Greg Kroah-Hartman
maintainerPATCH 43/175 fuse: re-lock request before replacing page cache folio
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Joanne Koong <[email protected]>
[ Upstream commit a078484921052d0badd827fcc2770b5cfc1d4120 ]
fuse_try_move_folio() unlocks the request on entry but does not re-lock it on the success path. This means fuse_chan_abort() can end the request and free the fuse_io_args (eg fuse_readpages_end()) while the subsequent copy chain logic after fuse_try_move_folio() accesses the fuse_io_args, leading to use-after-free issues.
Fix this by calling lock_request() before replace_page_cache_folio(). This ensures the request is locked on the success path which will prevent the fuse_io_args from being freed while the later copying logic runs, and also ensures that the ap->folios[i]->mapping is never null since ap->folios[i] will always point to the newfolio after replace_page_cache_folio().
--- fs/fuse/dev.c | 19 +++++-------------- 1 file changed, 5 insertions(+), 14 deletions(-)
fs/fuse/dev.c +5 -14
@@ -843,6 +843,10 @@ static int fuse_try_move_page(struct fusif (WARN_ON (folio_test_mlocked (oldfolio))) goto out_fallback_unlock; + err =lock_request (cs->req); +if (err) + goto out_fallback_unlock; +replace_page_cache_folio (oldfolio, newfolio);folio_get (newfolio);
@@ -856,20 +860,7 @@ static int fuse_try_move_page(struct fus*/ pipe_buf_release (cs->pipe, buf); - err =0 ; -spin_lock (&cs->req->waitq.lock); -if (test_bit (FR_ABORTED , &cs->req->flags)) - err = -ENOENT ; -else - *pagep = &newfolio->page; -spin_unlock (&cs->req->waitq.lock); - -if (err) { -folio_unlock (newfolio); -folio_put (newfolio); - goto out_put_old; - } - + *pagep = &newfolio->page;folio_unlock (oldfolio);/* Drop ref for ap->pages[] array */ folio_put (oldfolio);
Greg Kroah-Hartman
maintainerPATCH 44/175 scripts/sorttable: Remove unused macro defines
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Steven Rostedt <[email protected]>
[ Upstream commit 28b24394c6e9a3166fcb4480cba054562526657c ]
The code of sorttable.h was copied from the recordmcount.h which defined a bunch of Elf MACROs so that they could be used between 32bit and 64bit functions. But there's several MACROs that sorttable.h does not use but was copied over. Remove them to clean up the code.
--- scripts/sorttable.h | 27 --------------------------- 1 file changed, 27 deletions(-)
scripts/sorttable.h +0 -27
@@ -27,19 +27,10 @@#undef Elf_Ehdr#undef Elf_Shdr#undef Elf_Rel -#undef Elf_Rela#undef Elf_Sym -#undef ELF_R_SYM -#undef Elf_r_sym -#undef ELF_R_INFO -#undef Elf_r_info -#undef ELF_ST_BIND#undef ELF_ST_TYPE -#undef fn_ELF_R_SYM -#undef fn_ELF_R_INFO#undef uint_t#undef _r -#undef _w#ifdef SORTTABLE_64 # define extable_ent_size 16
@@ -52,19 +43,10 @@# define Elf_Ehdr Elf64_Ehdr# define Elf_Shdr Elf64_Shdr# define Elf_Rel Elf64_Rel -# define Elf_Rela Elf64_Rela# define Elf_Sym Elf64_Sym -# define ELF_R_SYM ELF64_R_SYM -# define Elf_r_sym Elf64_r_sym -# define ELF_R_INFO ELF64_R_INFO -# define Elf_r_info Elf64_r_info -# define ELF_ST_BIND ELF64_ST_BIND# define ELF_ST_TYPE ELF64_ST_TYPE -# define fn_ELF_R_SYM fn_ELF64_R_SYM -# define fn_ELF_R_INFO fn_ELF64_R_INFO# define uint_t uint64_t# define _r r8 -# define _w w8#else # define extable_ent_size 8# define compare_extable compare_extable_32
@@ -76,19 +58,10 @@# define Elf_Ehdr Elf32_Ehdr# define Elf_Shdr Elf32_Shdr# define Elf_Rel Elf32_Rel -# define Elf_Rela Elf32_Rela# define Elf_Sym Elf32_Sym -# define ELF_R_SYM ELF32_R_SYM -# define Elf_r_sym Elf32_r_sym -# define ELF_R_INFO ELF32_R_INFO -# define Elf_r_info Elf32_r_info -# define ELF_ST_BIND ELF32_ST_BIND# define ELF_ST_TYPE ELF32_ST_TYPE -# define fn_ELF_R_SYM fn_ELF32_R_SYM -# define fn_ELF_R_INFO fn_ELF32_R_INFO# define uint_t uint32_t# define _r r -# define _w w#endif #if defined(SORTTABLE_64 ) && defined(UNWINDER_ORC_ENABLED )
Greg Kroah-Hartman
maintainerPATCH 45/175 scripts/sorttable: Remove unused write functions
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Steven Rostedt <[email protected]>
[ Upstream commit 4f48a28b37d594dab38092514a42ae9f4b781553 ]
The code of sorttable.h was copied from the recordmcount.h which defined various write functions for different sizes (2, 4, 8 byte lengths). But sorttable only uses the 4 byte writes. Remove the extra versions as they are not used.
--- scripts/sorttable.c | 26 -------------------------- 1 file changed, 26 deletions(-)
scripts/sorttable.c +0 -26
@@ -68,8 +68,6 @@ static uint32_t (*r)(const uint32_t *);static uint16_t (*r2)(const uint16_t *);static uint64_t (*r8)(const uint64_t *);static void (*w)(uint32_t ,uint32_t *); -static void (*w2)(uint16_t ,uint16_t *); -static void (*w8)(uint64_t ,uint64_t *);typedef void (*table_sort_t )(char *,int );/*
@@ -146,31 +144,11 @@ static void wbe(uint32_t val, uint32_t *put_unaligned_be32 (val, x); } -static void w2be (uint16_t val,uint16_t *x) -{ -put_unaligned_be16 (val, x); -} - -static void w8be (uint64_t val,uint64_t *x) -{ -put_unaligned_be64 (val, x); -} -static void wle (uint32_t val,uint32_t *x) {put_unaligned_le32 (val, x); } -static void w2le (uint16_t val,uint16_t *x) -{ -put_unaligned_le16 (val, x); -} - -static void w8le (uint64_t val,uint64_t *x) -{ -put_unaligned_le64 (val, x); -} -/* * Move reserved section indices SHN_LORESERVE..SHN_HIRESERVE out of * the way to -256..-1, to avoid conflicting with real section
@@ -277,16 +255,12 @@ static int do_file(char const *const fna r2 = r2le; r8 = r8le; w = wle; - w2 = w2le; - w8 = w8le;break ;case ELFDATA2MSB : r = rbe; r2 = r2be; r8 = r8be; w = wbe; - w2 = w2be; - w8 = w8be;break ;default : fprintf(stderr, "unrecognized ELF data encoding %d: %s\n",
Greg Kroah-Hartman
maintainerPATCH 5/175 drm/v3d: Store the active job inside the queues state
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Maíra Canal <[email protected]>
[ Upstream commit 0d3768826d38c0ac740f8b45cd13346630535f2b ]
Instead of storing the queue's active job in four different variables, store the active job inside the queue's state. This way, it's possible to access all active jobs using an index based in enum v3d_queue.
Stable-dep-of: 7f93fad5ea0a ("drm/v3d: Skip CSD when it has zeroed workgroups")
--- drivers/gpu/drm/v3d/v3d_drv.h | 8 +++----- drivers/gpu/drm/v3d/v3d_gem.c | 5 +++-- drivers/gpu/drm/v3d/v3d_irq.c | 24 ++++++++++++++---------- drivers/gpu/drm/v3d/v3d_sched.c | 26 ++++++++++++++++++-------- 4 files changed, 38 insertions(+), 25 deletions(-)
drivers/gpu/drm/v3d/v3d_drv.h +3 -5
@@ -26,6 +26,9 @@ struct v3d_queue_state {u64 fence_context;u64 emit_seqno; + +/* Currently active job for this queue */ +struct v3d_job *active_job; };/* Performance monitor object. The perform lifetime is controlled by userspace
@@ -110,11 +113,6 @@ struct v3d_dev {struct work_struct overflow_mem_work; -struct v3d_bin_job *bin_job; -struct v3d_render_job *render_job; -struct v3d_tfu_job *tfu_job; -struct v3d_csd_job *csd_job; -struct v3d_queue_state queue[V3D_MAX_QUEUES ];/* Spinlock used to synchronize the overflow memory
drivers/gpu/drm/v3d/v3d_gem.c +3 -2
@@ -1071,14 +1071,15 @@ void v3d_gem_destroy(struct drm_device *dev) {struct v3d_dev *v3d =to_v3d_dev (dev); +enum v3d_queue q;v3d_sched_fini (v3d);/* Waiting for jobs to finish would need to be done before * unregistering V3D. */ -WARN_ON (v3d->bin_job); -WARN_ON (v3d->render_job); +for (q =0 ; q <V3D_MAX_QUEUES ; q++) +WARN_ON (v3d->queue[q].active_job);drm_mm_takedown (&v3d->mm);
drivers/gpu/drm/v3d/v3d_irq.c +14 -10
@@ -40,6 +40,8 @@ v3d_overflow_mem_work(struct work_struct *work) container_of(work, struct v3d_dev, overflow_mem_work);struct drm_device *dev = &v3d->drm;struct v3d_bo *bo =v3d_bo_create (dev,NULL /* XXX: GMP */ ,256 *1024 ); +struct v3d_queue_state *queue = &v3d->queue[V3D_BIN ]; +struct v3d_bin_job *bin_job;struct drm_gem_object *obj;unsigned long irqflags;
@@ -59,13 +61,15 @@ v3d_overflow_mem_work(struct work_struct *work)* some binner pool anyway. */ spin_lock_irqsave (&v3d->job_lock, irqflags); -if (!v3d->bin_job) { + bin_job = (struct v3d_bin_job *)queue->active_job; + +if (!bin_job) {spin_unlock_irqrestore (&v3d->job_lock, irqflags); goto out; }drm_gem_object_get (obj); -list_add_tail (&bo->unref_head, &v3d->bin_job->render->unref_list); +list_add_tail (&bo->unref_head, &bin_job->render->unref_list);spin_unlock_irqrestore (&v3d->job_lock, irqflags);V3D_CORE_WRITE (0 ,V3D_PTB_BPOA , bo->node.start <<PAGE_SHIFT );
@@ -99,11 +103,11 @@ v3d_irq(int irq, void *arg)if (intsts &V3D_INT_FLDONE ) {struct v3d_fence *fence = -to_v3d_fence (v3d->bin_job->base.irq_fence); +to_v3d_fence (v3d->queue[V3D_BIN ].active_job->irq_fence);trace_v3d_bcl_irq (&v3d->drm, fence->seqno); - v3d->bin_job =NULL ; + v3d->queue[V3D_BIN ].active_job =NULL ;dma_fence_signal (&fence->base); status =IRQ_HANDLED ;
@@ -111,11 +115,11 @@ v3d_irq(int irq, void *arg)if (intsts &V3D_INT_FRDONE ) {struct v3d_fence *fence = -to_v3d_fence (v3d->render_job->base.irq_fence); +to_v3d_fence (v3d->queue[V3D_RENDER ].active_job->irq_fence);trace_v3d_rcl_irq (&v3d->drm, fence->seqno); - v3d->render_job =NULL ; + v3d->queue[V3D_RENDER ].active_job =NULL ;dma_fence_signal (&fence->base); status =IRQ_HANDLED ;
@@ -123,11 +127,11 @@ v3d_irq(int irq, void *arg)if (intsts &V3D_INT_CSDDONE ) {struct v3d_fence *fence = -to_v3d_fence (v3d->csd_job->base.irq_fence); +to_v3d_fence (v3d->queue[V3D_CSD ].active_job->irq_fence);trace_v3d_csd_irq (&v3d->drm, fence->seqno); - v3d->csd_job =NULL ; + v3d->queue[V3D_CSD ].active_job =NULL ;dma_fence_signal (&fence->base); status =IRQ_HANDLED ;
@@ -162,11 +166,11 @@ v3d_hub_irq(int irq, void *arg)if (intsts &V3D_HUB_INT_TFUC ) {struct v3d_fence *fence = -to_v3d_fence (v3d->tfu_job->base.irq_fence); +to_v3d_fence (v3d->queue[V3D_TFU ].active_job->irq_fence);trace_v3d_tfu_irq (&v3d->drm, fence->seqno); - v3d->tfu_job =NULL ; + v3d->queue[V3D_TFU ].active_job =NULL ;dma_fence_signal (&fence->base); status =IRQ_HANDLED ;
drivers/gpu/drm/v3d/v3d_sched.c +18 -8
@@ -80,14 +80,18 @@ static struct dma_fence *v3d_bin_job_run(struct drm_sched_job *sched_job)struct dma_fence *fence;unsigned long irqflags; -if (unlikely (job->base.base.s_fence->finished.error)) +if (unlikely (job->base.base.s_fence->finished.error)) { +spin_lock_irqsave (&v3d->job_lock, irqflags); + v3d->queue[V3D_BIN ].active_job =NULL ; +spin_unlock_irqrestore (&v3d->job_lock, irqflags);return NULL ; + }/* Lock required around bin_job update vs * v3d_overflow_mem_work(). */ spin_lock_irqsave (&v3d->job_lock, irqflags); - v3d->bin_job = job; + v3d->queue[V3D_BIN ].active_job = &job->base;/* Clear out the overflow allocation, so we don't * reuse the overflow attached to a previous job. */
@@ -134,10 +138,12 @@ static struct dma_fence *v3d_render_job_run(struct drm_sched_job *sched_job)struct drm_device *dev = &v3d->drm;struct dma_fence *fence; -if (unlikely (job->base.base.s_fence->finished.error)) +if (unlikely (job->base.base.s_fence->finished.error)) { + v3d->queue[V3D_RENDER ].active_job =NULL ;return NULL ; + } - v3d->render_job = job; + v3d->queue[V3D_RENDER ].active_job = &job->base;/* Can we avoid this flush? We need to be careful of * scheduling, though -- imagine job0 rendering to texture and
@@ -179,10 +185,12 @@ v3d_tfu_job_run(struct drm_sched_job *sched_job)struct drm_device *dev = &v3d->drm;struct dma_fence *fence; -if (unlikely (job->base.base.s_fence->finished.error)) +if (unlikely (job->base.base.s_fence->finished.error)) { + v3d->queue[V3D_TFU ].active_job =NULL ;return NULL ; + } - v3d->tfu_job = job; + v3d->queue[V3D_TFU ].active_job = &job->base; fence =v3d_fence_create (v3d,V3D_TFU );if (IS_ERR (fence))
@@ -221,10 +229,12 @@ v3d_csd_job_run(struct drm_sched_job *sched_job)struct dma_fence *fence;int i; -if (unlikely (job->base.base.s_fence->finished.error)) +if (unlikely (job->base.base.s_fence->finished.error)) { + v3d->queue[V3D_CSD ].active_job =NULL ;return NULL ; + } - v3d->csd_job = job; + v3d->queue[V3D_CSD ].active_job = &job->base;v3d_invalidate_caches (v3d);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 6/175 drm/v3d: Skip CSD when it has zeroed workgroups
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Maíra Canal <[email protected]>
[ Upstream commit 7f93fad5ea0affc9e1505dd0f7596c0fdb496213 ]
A compute shader dispatch encodes its workgroup counts in the CFG0..CFG2 registers. Kicking off a dispatch with a zero count in any of the three dimensions is invalid. First, the hardware will process 0 as 65536, while the user-space driver exposes a maximum of 65535. Over that, a submission with a zeroed workgroup dimension should be a no-op.
These zeroed counts can reach the dispatch path through an indirect CSD job, whose workgroup counts are only known once the indirect buffer is read and may legitimately be zero, but such scenario should only result in a no-op.
Overwrite the indirect CSD job workgroup counts with the indirect BO ones, even if they are zeroed, and don't submit the job to the hardware when any of the workgroup counts is zero, so the job completes immediately instead of running the shader.
--- drivers/gpu/drm/v3d/v3d_sched.c | 10 ++++++++++ 1 file changed, 10 insertions(+)
drivers/gpu/drm/v3d/v3d_sched.c +10 -0
@@ -234,6 +234,16 @@ v3d_csd_job_run(struct drm_sched_job *sched_job)return NULL ; } +/* The HW interprets a workgroup size of 0 as 65536; however, the +* user-space driver exposes a maximum of 65535. Therefore, a 0 in +* any dimension means that we have no workgroups and the compute +* shader should not be dispatched. +*/ +if (!V3D_GET_FIELD (job->args.cfg[0 ],V3D_CSD_QUEUED_CFG0_NUM_WGS_X ) || + !V3D_GET_FIELD (job->args.cfg[1 ],V3D_CSD_QUEUED_CFG1_NUM_WGS_Y ) || + !V3D_GET_FIELD (job->args.cfg[2 ],V3D_CSD_QUEUED_CFG2_NUM_WGS_Z )) +return NULL ; + v3d->queue[V3D_CSD ].active_job = &job->base;v3d_invalidate_caches (v3d);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 7/175 batman-adv: tt: prevent TVLV entry number overflow
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Sven Eckelmann <[email protected]>
commit 99d9958fa10fb684b2a8e2c48a8d704122721420 upstream.
The helpers to prepare the buffers for the local and global TT based replies are trying to sum up all TT entries which can be found for each VLAN. In theory, this sum can be too big for an u16 and therefore overflow. A too small buffer would then be allocated for the TVLV.
The too small buffer will be handled gracefully by batadv_tt_tvlv_generate() and is not causing a buffer overflow - just a truncated reply. But this overflow shouldn't have happened in the first and the too small buffer should never have been allocated when an overflow was detected.
--- net/batman-adv/translation-table.c | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-)
net/batman-adv/translation-table.c +17 -3
@@ -850,11 +850,18 @@ batadv_tt_prepare_tvlv_global_data(struct batadv_orig_node *orig_node,u16 total_entries =0 ;u8 *tt_change_ptr;int vlan_entries; +u16 sum_entries;spin_lock_bh (&orig_node->vlan_list_lock);hlist_for_each_entry (vlan, &orig_node->vlan_list, list) { vlan_entries =atomic_read (&vlan->tt.num_entries); - total_entries += vlan_entries; + +if (check_add_overflow (vlan_entries, total_entries, &sum_entries)) { + *tt_len =0 ; + goto out; + } + + total_entries = sum_entries; num_vlan++; }
@@ -941,15 +948,22 @@ batadv_tt_prepare_tvlv_local_data(struct batadv_priv *bat_priv,struct batadv_softif_vlan *vlan;size_t change_offset;u16 num_vlan =0 ; -u16 vlan_entries =0 ;u16 total_entries =0 ;u16 tvlv_len;u8 *tt_change_ptr; +int vlan_entries; +u16 sum_entries;spin_lock_bh (&bat_priv->softif_vlan_list_lock);hlist_for_each_entry (vlan, &bat_priv->softif_vlan_list, list) { vlan_entries =atomic_read (&vlan->tt.num_entries); - total_entries += vlan_entries; + +if (check_add_overflow (vlan_entries, total_entries, &sum_entries)) { + tvlv_len =0 ; + goto out; + } + + total_entries = sum_entries; num_vlan++; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 8/175 debugobjects: Allow to refill the pool before SYSTEM_SCHEDULING
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Sebastian Andrzej Siewior <[email protected]>
commit 06e0ae988f6e3499785c407429953ade19c1096b upstream.
The pool of free objects is refilled on several occasions such as object initialisation. On PREEMPT_RT refilling is limited to preemptible sections due to sleeping locks used by the memory allocator. The system boots with disabled interrupts so the pool can not be refilled.
If too many objects are initialized and the pool gets empty then debugobjects disables itself.
Refiling can also happen early in the boot with disabled interrupts as long as the scheduler is not operational. If the scheduler can not preempt a task then a sleeping lock can not be contended.
Allow to additionally refill the pool if the scheduler is not operational.
--- lib/debugobjects.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
lib/debugobjects.c +1 -1
@@ -605,7 +605,7 @@ static void debug_objects_fill_pool(void)* raw_spinlock_t are basically the same type and this lock-type * inversion works just fine. */ -if (!IS_ENABLED (CONFIG_PREEMPT_RT ) ||preemptible ()) { +if (!IS_ENABLED (CONFIG_PREEMPT_RT ) ||preemptible () || system_state <SYSTEM_SCHEDULING ) {/* * Annotate away the spinlock_t inside raw_spinlock_t warning * by temporarily raising the wait-type to WAIT_SLEEP, matching
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 9/175 debugobjects: Use LD_WAIT_CONFIG instead of LD_WAIT_SLEEP
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Sebastian Andrzej Siewior <[email protected]>
commit 37de2dbc318ee10577c1c2704de5a803e75e55a2 upstream.
fill_pool_map is used to suppress nesting violations caused by acquiring a spinlock_t (from within the memory allocator) while holding a raw_spinlock_t. The used annotation is wrong.
LD_WAIT_SLEEP is for always sleeping lock types such as mutex_t. LD_WAIT_CONFIG is for lock type which are sleeping while spinning on PREEMPT_RT such as spinlock_t.
Use LD_WAIT_CONFIG as override.
--- lib/debugobjects.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
lib/debugobjects.c +2 -2
@@ -608,10 +608,10 @@ static void debug_objects_fill_pool(void)if (!IS_ENABLED (CONFIG_PREEMPT_RT ) ||preemptible () || system_state <SYSTEM_SCHEDULING ) {/* * Annotate away the spinlock_t inside raw_spinlock_t warning -* by temporarily raising the wait-type to WAIT_SLEEP, matching +* by temporarily raising the wait-type to LD_WAIT_CONFIG, matching * the preemptible() condition above. */ - static DEFINE_WAIT_OVERRIDE_MAP(fill_pool_map, LD_WAIT_SLEEP); + static DEFINE_WAIT_OVERRIDE_MAP(fill_pool_map, LD_WAIT_CONFIG);lock_map_acquire_try (&fill_pool_map);fill_pool ();lock_map_release (&fill_pool_map);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainercover 6.6.144-rc1 review
This is the start of the stable review cycle for the 6.6.144 release. There are 175 patches in this series, all will be posted as a response to this one. If anyone has any issues with these being applied, please let me know.
Responses should be made by Sat, 04 Jul 2026 15:50:58 +0000. Anything received after that time might be too late.
The whole patch series can be found in one patch at:
https://www.kernel.org/pub/linux/kernel/v6.x/stable-review/patch-6.6.144-rc1.gz
or in the git tree and branch at:
git://git.kernel.org/pub/scm/linux/kernel/git/stable/linux-stable-rc.git linux-6.6.y
and the diffstat can be found below.
thanks,
greg k-h
-------------
Pseudo-Shortlog of commits:
Greg Kroah-Hartman <[email protected]>
Linux 6.6.144-rc1
Giovanni Cabiddu <[email protected]>
crypto: qat - remove unused character device and IOCTLs
Herbert Xu <[email protected]>
crypto: qat - Return pointer directly in adf_ctl_alloc_resources
Thorsten Blum <[email protected]>
crypto: qat - Replace kzalloc() + copy_from_user() with memdup_user()
Bagas Sanjaya <[email protected]>
Documentation: ioctl-number: Extend "Include File" column width
Georgi Djakov <[email protected]>
drivers/base/memory: set mem->altmap after successful device registration
Stepan Ionichev <[email protected]>
serial: 8250_dw: unregister 8250 port if clk_notifier_register() fails
Viken Dadhaniya <[email protected]>
serial: qcom_geni: Fix RX DMA stall when SE_DMA_RX_LEN_IN is zero
Hem Parekh <[email protected]>
ksmbd: fix out-of-bounds read in smb_check_perm_dacl()
Markus Elfring <[email protected]>
NFS: Prevent resource leak in nfs_alloc_server()
Michael Bommarito <[email protected]>
NFSv4/pNFS: reject zero-length r_addr in nfs4_decode_mp_ds_addr
Dominik Woźniak <[email protected]>
nfsd: check get_user() return when reading princhashlen
Jeff Layton <[email protected]>
nfsd: fix posix_acl leak on SETACL decode failure
Guannan Wang <[email protected]>
NFSD: Fix SECINFO_NO_NAME decode error cleanup
Steffen Persvold <[email protected]>
fbdev: modedb: Fix misaligned fields in the 1920x1080-60 mode
Tuo Li <[email protected]>
fbdev: modedb: fix a possible UAF in fb_find_mode()
Ian Bridges <[email protected]>
fbdev: Fix fb_new_modelist to prevent null-ptr-deref in fb_videomode_to_var
Wentao Liang <[email protected]>
power: reset: linkstation-poweroff: fix use-after-free in the linkstation_poweroff_init()
Ashutosh Desai <[email protected]>
KVM: SVM: Fix page overflow in sev_dbg_crypt() for ENCRYPT path
Hyunwoo Kim <[email protected]>
KVM: x86: hyper-v: Bound the bank index when querying sparse banks
Jonas Jelonek <[email protected]>
MIPS: smp: report dying CPU to RCU in stop_this_cpu()
Yizhou Zhao <[email protected]>
9p: avoid putting oldfid in p9_client_walk() error path
Zhang Cen <[email protected]>
ocfs2: reject oversized group bitmap descriptors
Yuho Choi <[email protected]>
rpmsg: char: Fix use-after-free on probe error path
Wentao Liang <[email protected]>
fpga: region: fix use-after-free in child_regions_with_firmware()
Qingshuang Fu <[email protected]>
irqchip/imgpdc: Fix resource leak, add missing chained handler cleanup on remove
Wentao Liang <[email protected]>
pNFS: Fix use-after-free in pnfs_update_layout()
Huacai Chen <[email protected]>
LoongArch: Report dying CPU to RCU in stop_this_cpu()
Doruk Tan Ozturk <[email protected]>
tipc: fix slab-use-after-free Read in tipc_aead_decrypt_done
Michal Koutný <[email protected]>
blk-cgroup: fix UAF in __blkcg_rstat_flush()
Fan Wu <[email protected]>
hdlc_ppp: sync per-proto timers before freeing hdlc state
Tristan Madani <[email protected]>
gfs2: fix use-after-free in gfs2_qd_dealloc
Michael Bommarito <[email protected]>
exfat: fix potential use-after-free in exfat_find_dir_entry()
Maciej W. Rozycki <[email protected]>
MIPS: DEC: Prevent initial console buffer from landing in XKPHYS
Dawei Feng <[email protected]>
bpf: use kvfree() for replaced sysctl write buffer
Wenjie Qi <[email protected]>
f2fs: keep atomic write retry from zeroing original data
Yongpeng Yang <[email protected]>
f2fs: fix incorrect FI_NO_EXTENT handling in __destroy_extent_node()
Zhang Cen <[email protected]>
f2fs: validate ACL entry sizes in f2fs_acl_from_disk()
Sunmin Jeong <[email protected]>
f2fs: fix to round down start offset of fallocate for pin file
Wenjie Qi <[email protected]>
f2fs: validate compress cache inode only when enabled
Junjie Cao <[email protected]>
wifi: iwlwifi: mvm: fix race condition in PTP removal
Luka Gejak <[email protected]>
wifi: rtw88: usb: fix memory leaks on USB write failures
Luka Gejak <[email protected]>
wifi: rtw88: increase TX report timeout to fix race condition
Bitterblue Smith <[email protected]>
wifi: rtlwifi: rtl8821ae: Fix C2H bit location in RX descriptor
Jose Ignacio Tornos Martinez <[email protected]>
wifi: ath11k: fix warning when unbinding
Zenm Chen <[email protected]>
wifi: mt76: mt76x2u: Add support for ELECOM WDC-867SU3S
Shaomin Chen <[email protected]>
keys: Pin request_key_auth payload in instantiate paths
Jarkko Sakkinen <[email protected]>
KEYS: fix overflow in keyctl_pkey_params_get_2()
Arnd Bergmann <[email protected]>
err.h: use __always_inline on all error pointer helpers
Ian Bridges <[email protected]>
fbdev: fix use-after-free in store_modes()
Koichiro Den <[email protected]>
NTB: epf: Avoid pci_iounmap() with offset when PEER_SPAD and CONFIG share BAR
Ruslan Valiyev <[email protected]>
apparmor: fix use-after-free in rawdata dedup loop
Bryam Vargas <[email protected]>
apparmor: mediate the implicit connect of TCP fast open sendmsg
Yiming Qian <[email protected]>
net: skmsg: preserve sg.copy across SG transforms
Doruk Tan Ozturk <[email protected]>
mac802154: llsec: add skb_cow_data() before in-place crypto
Kuniyuki Iwashima <[email protected]>
af_unix: Set gc_in_progress to true in unix_gc().
Chaitanya Kulkarni <[email protected]>
nvmet-tcp: fix race between ICReq handling and queue teardown
Konstantin Komarov <[email protected]>
ntfs3: reject direct userspace writes to reserved $LX* xattrs
Wongi Lee <[email protected]>
ipv4: account for fraggap on the paged allocation path
Eric Dumazet <[email protected]>
inet: add indirect call wrapper for getfrag() calls
Wongi Lee <[email protected]>
ipv6: account for fraggap on the paged allocation path
Sven Eckelmann <[email protected]>
batman-adv: tvlv: avoid race of cifsnotfound handler state
Sven Eckelmann <[email protected]>
batman-adv: tvlv: enforce 2-byte alignment
Sven Eckelmann <[email protected]>
batman-adv: dat: prevent false sharing between VLANs
Sven Eckelmann <[email protected]>
batman-adv: tt: track roam count per VID
Sven Eckelmann <[email protected]>
batman-adv: tt: don't merge change entries with different VIDs
Sven Eckelmann <[email protected]>
batman-adv: tp_meter: handle overlapping packets
Sven Eckelmann <[email protected]>
batman-adv: tp_meter: prevent parallel modifications of last_recv
Sven Eckelmann <[email protected]>
batman-adv: tp_meter: annotate last_recv_time access with READ/WRITE_ONCE
Sven Eckelmann <[email protected]>
batman-adv: tp_meter: restrict number of unacked list entries
Sven Eckelmann <[email protected]>
batman-adv: v: prevent OGM aggregation on disabled hardif
Sven Eckelmann <[email protected]>
batman-adv: frag: avoid underflow of TTL
Sven Eckelmann <[email protected]>
batman-adv: frag: ensure fragment is writable before modifying TTL
Sven Eckelmann <[email protected]>
batman-adv: fix (m|b)cast csum after decrementing TTL
Sven Eckelmann <[email protected]>
batman-adv: ensure bcast is writable before modifying TTL
Sven Eckelmann <[email protected]>
batman-adv: tp_meter: initialize last_recv_time during init
Sven Eckelmann <[email protected]>
batman-adv: prevent ELP transmission interval underflow
Sven Eckelmann <[email protected]>
batman-adv: bla: annotate lasttime access with READ/WRITE_ONCE
Sven Eckelmann <[email protected]>
batman-adv: tp_meter: add only finished tp_vars to lists
Sven Eckelmann <[email protected]>
batman-adv: tp_meter: handle seqno wrap-around for fast recovery detection
Sven Eckelmann <[email protected]>
batman-adv: tp_meter: fix fast recovery precondition
Sven Eckelmann <[email protected]>
batman-adv: tp_meter: avoid divide-by-zero for dec_cwnd
Sven Eckelmann <[email protected]>
batman-adv: tp_meter: avoid window underflow
Sven Eckelmann <[email protected]>
batman-adv: tp_meter: initialize dec_cwnd explicitly
Sven Eckelmann <[email protected]>
batman-adv: tp_meter: initialize dup_acks explicitly
Sven Eckelmann <[email protected]>
batman-adv: tp_meter: keep unacked list in ascending ordered
Paul Moore <[email protected]>
selinux: fix overlayfs mmap() and mprotect() access checks
Paul Moore <[email protected]>
lsm: add backing_file LSM hooks
Amir Goldstein <[email protected]>
fs: prepare for adding LSM blob to backing_file
Pauli Virtanen <[email protected]>
Bluetooth: btmtk: accept too short WMT FUNC_CTRL events
Tristan Madani <[email protected]>
Bluetooth: btmtk: validate WMT event SKB length before struct access
Petr Machata <[email protected]>
Revert "ptp: add testptp mask test"
Sean Christopherson <[email protected]>
KVM: x86/mmu: Ensure hugepage is in by slot before checking max mapping level
Paolo Bonzini <[email protected]>
KVM: x86: Fix shadow paging use-after-free due to unexpected role
Christian Brauner <[email protected]>
eventpoll: fix ep_remove struct eventpoll / struct file UAF
Christian Brauner <[email protected]>
eventpoll: move epi_fget() up
Christian Brauner <[email protected]>
eventpoll: rename ep_remove_safe() back to ep_remove()
Christian Brauner <[email protected]>
eventpoll: drop vestigial __ prefix from ep_remove_{file,epi}()
Christian Brauner <[email protected]>
eventpoll: kill __ep_remove()
Christian Brauner <[email protected]>
eventpoll: split __ep_remove()
Christian Brauner <[email protected]>
eventpoll: use hlist_is_singular_node() in __ep_remove()
Christian Brauner <[email protected]>
file: add fput() cleanup helper
Miklos Szeredi <[email protected]>
virtiofs: fix UAF on submount umount
Ruslan Valiyev <[email protected]>
media: vidtv: fix NULL pointer dereference in vidtv_mux_push_si
Gil Portnoy <[email protected]>
ksmbd: reject non-VALID session in compound request branch
Yi Yang <[email protected]>
vc_screen: fix null-ptr-deref in vcs_notifier() during concurrent vcs_write
Vasily Gorbik <[email protected]>
scripts/sorttable: Fix endianness handling in build-time mcount sort
Steven Rostedt <[email protected]>
scripts/sorttable: Allow matches to functions before function entry
Steven Rostedt <[email protected]>
scripts/sorttable: Use normal sort if theres no relocs in the mcount section
Steven Rostedt <[email protected]>
ftrace: Check against is_kernel_text() instead of kaslr_offset()
Steven Rostedt <[email protected]>
ftrace: Test mcount_loc addr before calling ftrace_call_addr()
Guenter Roeck <[email protected]>
ftrace: Do not over-allocate ftrace memory
Steven Rostedt <[email protected]>
ftrace: Have ftrace pages output reflect freed pages
Steven Rostedt <[email protected]>
ftrace: Update the mcount_loc check of skipped entries
Steven Rostedt <[email protected]>
scripts/sorttable: Zero out weak functions in mcount_loc table
Steven Rostedt <[email protected]>
scripts/sorttable: Always use an array for the mcount_loc sorting
Steven Rostedt <[email protected]>
scripts/sorttable: Have mcount rela sort use direct values
Steven Rostedt <[email protected]>
arm64: scripts/sorttable: Implement sorting mcount_loc at boot for arm64
Steven Rostedt <[email protected]>
scripts/sorttable: Use a structure of function pointers for elf helpers
Steven Rostedt <[email protected]>
scripts/sorttable: Get start/stop_mcount_loc from ELF file directly
Steven Rostedt <[email protected]>
scripts/sorttable: Move code from sorttable.h into sorttable.c
Steven Rostedt <[email protected]>
scripts/sorttable: Use uint64_t for mcount sorting
Steven Rostedt <[email protected]>
scripts/sorttable: Add helper functions for Elf_Sym
Steven Rostedt <[email protected]>
scripts/sorttable: Add helper functions for Elf_Shdr
Steven Rostedt <[email protected]>
scripts/sorttable: Add helper functions for Elf_Ehdr
Steven Rostedt <[email protected]>
scripts/sorttable: Convert Elf_Sym MACRO over to a union
Steven Rostedt <[email protected]>
scripts/sorttable: Replace Elf_Shdr Macro with a union
Steven Rostedt <[email protected]>
scripts/sorttable: Convert Elf_Ehdr to union
Steven Rostedt <[email protected]>
scripts/sorttable: Make compare_extable() into two functions
Steven Rostedt <[email protected]>
scripts/sorttable: Have the ORC code use the _r() functions to read
Steven Rostedt <[email protected]>
scripts/sorttable: Remove unneeded Elf_Rel
Steven Rostedt <[email protected]>
scripts/sorttable: Remove unused write functions
Steven Rostedt <[email protected]>
scripts/sorttable: Remove unused macro defines
Joanne Koong <[email protected]>
fuse: re-lock request before replacing page cache folio
Bjorn Andersson <[email protected]>
slimbus: qcom-ngd-ctrl: Balance pm_runtime enablement for NGD
Bjorn Andersson <[email protected]>
slimbus: qcom-ngd-ctrl: Fix up platform_driver registration
David Howells <[email protected]>
rxrpc: Fix the ACK parser to extract the SACK table for parsing
Santosh Kalluri <[email protected]>
net: phonet: free phonet_device after RCU grace period
Kuniyuki Iwashima <[email protected]>
phonet: Pass net and ifindex to phonet_address_notify().
Kuniyuki Iwashima <[email protected]>
phonet: Pass ifindex to fill_addr().
Davidlohr Bueso <[email protected]>
locking/rtmutex: Skip remove_waiter() when waiter is not enqueued
Dexuan Cui <[email protected]>
Drivers: hv: vmbus: Improve the logic of reserving fb_mmio on Gen2 VMs
Ji'an Zhou <[email protected]>
futex/requeue: Prevent NULL pointer dereference in remove_waiter() on self-deadlock
Thorsten Blum <[email protected]>
hv: utils: handle and propagate errors in kvp_register
Tao Cui <[email protected]>
mptcp: pm: fix extra_subflows underflow on userspace PM subflow creation
Florian Westphal <[email protected]>
netfilter: nf_tables: always walk all pending catchall elements
Thadeu Lima de Souza Cascardo <[email protected]>
dlm: prevent NPD when writing a positive value to event_done
André Draszik <[email protected]>
regulator: core: fix locking in regulator_resolve_supply() error path
Bjoern Doebel <[email protected]>
ring-buffer: Remove ring_buffer_read_prepare_sync()
Eduard Zingerman <[email protected]>
selftests/bpf: Update comments find_equal_scalars->sync_linked_regs
Eduard Zingerman <[email protected]>
selftests/bpf: Tests for per-insn sync_linked_regs() precision tracking
Eduard Zingerman <[email protected]>
bpf: Remove mark_precise_scalar_ids()
Eduard Zingerman <[email protected]>
bpf: Track equal scalars history on per-instruction level
Jiexun Wang <[email protected]>
af_unix: Reject SIOCATMARK on non-stream sockets
Varun R Mallya <[email protected]>
selftests/bpf: Add test to ensure kprobe_multi is not sleepable
Varun R Mallya <[email protected]>
bpf: Reject sleepable kprobe_multi programs at attach time
Mingyu Wang <[email protected]>
agp/amd64: Fix broken error propagation in agp_amd64_probe()
Weiming Shi <[email protected]>
net: qualcomm: rmnet: fix endpoint use-after-free in rmnet_dellink()
Weiming Shi <[email protected]>
i2c: stub: Reject I2C block transfers with invalid length
Lord Ulf Henrik Holmberg <[email protected]>
RDMA/bnxt_re: zero shared page before exposing to userspace
Dongli Zhang <[email protected]>
KVM: VMX: Update SVI during runtime APICv activation
Russell King (Oracle) <[email protected]>
ARM: fix branch predictor hardening
Russell King (Oracle) <[email protected]>
ARM: fix hash_name() fault
Russell King (Oracle) <[email protected]>
ARM: allow __do_kernel_fault() to report execution of memory faults
Russell King (Oracle) <[email protected]>
ARM: group is_permission_fault() with is_translation_fault()
Waiman Long <[email protected]>
debugobjects: Dont call fill_pool() in early boot hardirq context
Helen Koike <[email protected]>
debugobjects: Do not fill_pool() if pi_blocked_on
Sebastian Andrzej Siewior <[email protected]>
debugobjects: Use LD_WAIT_CONFIG instead of LD_WAIT_SLEEP
Sebastian Andrzej Siewior <[email protected]>
debugobjects: Allow to refill the pool before SYSTEM_SCHEDULING
Sven Eckelmann <[email protected]>
batman-adv: tt: prevent TVLV entry number overflow
Maíra Canal <[email protected]>
drm/v3d: Skip CSD when it has zeroed workgroups
Maíra Canal <[email protected]>
drm/v3d: Store the active job inside the queue's state
Eric Dumazet <[email protected]>
ip6_vti: set netns_immutable on the fallback device.
Harry Wentland <[email protected]>
drm/amd/display: Bound VBIOS record-chain walk loops
Rajat Gupta <[email protected]>
net/sched: fix pedit partial COW leading to page cache corruption
Jann Horn <[email protected]>
fuse: limit FUSE_NOTIFY_RETRIEVE to uptodate folios
-------------
Diffstat:
Documentation/userspace-api/ioctl/ioctl-number.rst | 463 ++++---- Makefile | 4 +- arch/arm/mm/alignment.c | 4 + arch/arm/mm/fault.c | 94 +- arch/arm64/Kconfig | 1 + arch/loongarch/kernel/smp.c | 1 + arch/mips/dec/prom/console.c | 7 +- arch/mips/kernel/smp.c | 2 + arch/x86/kvm/hyperv.c | 5 + arch/x86/kvm/mmu/mmu.c | 28 +- arch/x86/kvm/svm/sev.c | 1 + arch/x86/kvm/vmx/vmx.c | 4 - arch/x86/kvm/x86.c | 7 + block/blk-cgroup.c | 21 +- drivers/base/memory.c | 3 +- drivers/bluetooth/btmtk.c | 15 +- drivers/char/agp/amd64-agp.c | 2 +- .../crypto/intel/qat/qat_common/adf_cfg_common.h | 32 - drivers/crypto/intel/qat/qat_common/adf_cfg_user.h | 38 - .../crypto/intel/qat/qat_common/adf_common_drv.h | 3 - drivers/crypto/intel/qat/qat_common/adf_ctl_drv.c | 413 +------- drivers/crypto/intel/qat/qat_common/adf_dev_mgr.c | 70 -- drivers/fpga/of-fpga-region.c | 3 +- drivers/gpu/drm/amd/display/dc/bios/bios_parser.c | 15 +- drivers/gpu/drm/amd/display/dc/bios/bios_parser2.c | 27 +- .../drm/amd/display/dc/bios/bios_parser_helper.h | 5 + drivers/gpu/drm/v3d/v3d_drv.h | 8 +- drivers/gpu/drm/v3d/v3d_gem.c | 5 +- drivers/gpu/drm/v3d/v3d_irq.c | 24 +- drivers/gpu/drm/v3d/v3d_sched.c | 36 +- drivers/hv/hv_kvp.c | 25 +- drivers/hv/vmbus_drv.c | 29 +- drivers/i2c/i2c-stub.c | 5 + drivers/infiniband/hw/bnxt_re/ib_verbs.c | 2 +- drivers/irqchip/irq-imgpdc.c | 6 + drivers/media/test-drivers/vidtv/vidtv_mux.c | 8 +- drivers/net/ethernet/qualcomm/rmnet/rmnet_config.c | 8 +- drivers/net/ethernet/qualcomm/rmnet/rmnet_config.h | 1 + drivers/net/wan/hdlc_ppp.c | 15 +- drivers/net/wireless/ath/ath11k/dp.c | 1 + drivers/net/wireless/intel/iwlwifi/mvm/ptp.c | 2 +- drivers/net/wireless/mediatek/mt76/mt76x2/usb.c | 1 + .../net/wireless/realtek/rtlwifi/rtl8821ae/trx.h | 2 +- drivers/net/wireless/realtek/rtw88/tx.c | 7 +- drivers/net/wireless/realtek/rtw88/usb.c | 13 +- drivers/ntb/hw/epf/ntb_hw_epf.c | 3 +- drivers/nvme/target/tcp.c | 29 +- drivers/power/reset/linkstation-poweroff.c | 2 +- drivers/regulator/core.c | 10 +- drivers/rpmsg/rpmsg_char.c | 15 +- drivers/slimbus/qcom-ngd-ctrl.c | 39 +- drivers/tty/serial/8250/8250_dw.c | 4 +- drivers/tty/serial/qcom_geni_serial.c | 9 +- drivers/tty/vt/vc_screen.c | 2 +- drivers/video/fbdev/core/fbmem.c | 12 + drivers/video/fbdev/core/fbsysfs.c | 10 +- drivers/video/fbdev/core/modedb.c | 5 +- fs/dlm/lockspace.c | 2 +- fs/eventpoll.c | 142 +-- fs/exfat/dir.c | 4 +- fs/f2fs/acl.c | 18 +- fs/f2fs/data.c | 16 +- fs/f2fs/extent_cache.c | 19 +- fs/f2fs/file.c | 9 +- fs/f2fs/inode.c | 9 +- fs/file_table.c | 46 +- fs/fuse/dev.c | 23 +- fs/fuse/file.c | 8 +- fs/gfs2/super.c | 1 + fs/internal.h | 3 +- fs/nfs/client.c | 1 + fs/nfs/pnfs.c | 2 +- fs/nfs/pnfs_nfs.c | 4 +- fs/nfsd/nfs2acl.c | 17 +- fs/nfsd/nfs3acl.c | 17 +- fs/nfsd/nfs4recover.c | 3 +- fs/nfsd/nfs4xdr.c | 3 +- fs/ntfs3/xattr.c | 12 + fs/ocfs2/suballoc.c | 22 + fs/open.c | 7 +- fs/overlayfs/file.c | 8 +- fs/smb/server/smb2pdu.c | 5 + fs/smb/server/smbacl.c | 4 +- include/keys/request_key_auth-type.h | 2 + include/linux/bpf_verifier.h | 4 + include/linux/err.h | 12 +- include/linux/file.h | 2 + include/linux/fs.h | 15 +- include/linux/kvm_host.h | 7 +- include/linux/lsm_audit.h | 2 +- include/linux/lsm_hook_defs.h | 5 + include/linux/lsm_hooks.h | 1 + include/linux/ring_buffer.h | 4 +- include/linux/security.h | 22 + include/linux/skmsg.h | 15 +- include/net/phonet/pn_dev.h | 2 +- include/net/tc_act/tc_pedit.h | 1 - kernel/bpf/cgroup.c | 2 +- kernel/bpf/verifier.c | 366 ++++--- kernel/futex/requeue.c | 6 + kernel/locking/rtmutex.c | 3 + kernel/locking/rtmutex_api.c | 2 +- kernel/trace/bpf_trace.c | 4 + kernel/trace/ftrace.c | 68 +- kernel/trace/ring_buffer.c | 67 +- kernel/trace/trace.c | 14 +- kernel/trace/trace_kdb.c | 8 +- lib/debugobjects.c | 56 +- net/9p/client.c | 3 +- net/batman-adv/bat_iv_ogm.c | 11 +- net/batman-adv/bat_v.c | 1 + net/batman-adv/bat_v_ogm.c | 23 +- net/batman-adv/bridge_loop_avoidance.c | 28 +- net/batman-adv/distributed-arp-table.c | 12 +- net/batman-adv/fragmentation.c | 22 +- net/batman-adv/fragmentation.h | 3 +- net/batman-adv/netlink.c | 10 +- net/batman-adv/routing.c | 64 +- net/batman-adv/tp_meter.c | 115 +- net/batman-adv/translation-table.c | 32 +- net/batman-adv/tvlv.c | 69 +- net/batman-adv/types.h | 21 +- net/core/filter.c | 27 + net/core/skmsg.c | 2 + net/ipv4/ip_output.c | 20 +- net/ipv6/ip6_output.c | 22 +- net/ipv6/ip6_vti.c | 1 + net/mac802154/llsec.c | 14 + net/mptcp/pm_userspace.c | 13 +- net/netfilter/nf_tables_api.c | 2 - net/phonet/pn_dev.c | 12 +- net/phonet/pn_netlink.c | 23 +- net/rxrpc/input.c | 13 +- net/sched/act_pedit.c | 77 +- net/tipc/crypto.c | 9 + net/tls/tls_sw.c | 4 + net/unix/af_unix.c | 3 + net/unix/garbage.c | 2 + scripts/link-vmlinux.sh | 4 +- scripts/sorttable.c | 1119 +++++++++++++++++++- scripts/sorttable.h | 500 --------- security/apparmor/include/policy_unpack.h | 19 + security/apparmor/lsm.c | 16 +- security/apparmor/policy.c | 8 +- security/keys/internal.h | 2 + security/keys/keyctl.c | 24 +- security/keys/keyctl_pkey.c | 9 +- security/keys/request_key_auth.c | 33 +- security/security.c | 110 ++ security/selinux/hooks.c | 256 +++-- security/selinux/include/objsec.h | 11 + .../selftests/bpf/prog_tests/kprobe_multi_test.c | 34 + .../selftests/bpf/progs/kprobe_multi_sleepable.c | 25 + .../selftests/bpf/progs/verifier_scalar_ids.c | 333 ++++-- .../selftests/bpf/progs/verifier_spill_fill.c | 4 +- .../bpf/progs/verifier_subprog_precision.c | 2 +- tools/testing/selftests/bpf/verifier/precise.c | 4 +- tools/testing/selftests/ptp/testptp.c | 19 +- 158 files changed, 3649 insertions(+), 2242 deletions(-)
Greg Kroah-Hartman
maintainerPATCH 47/175 scripts/sorttable: Have the ORC code use the _r() functions to read
6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Steven Rostedt <[email protected]>
[ Upstream commit 66990c003306c240d570b3ba274ec4f68cf18c91 ]
The ORC code reads the section information directly from the file. This currently works because the default read function is for 64bit little endian machines. But if for some reason that ever changes, this will break. Instead of having a surprise breakage, use the _r() functions that will read the values from the file properly.
--- scripts/sorttable.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-)
scripts/sorttable.h +4 -4
@@ -299,14 +299,14 @@ static int do_sort(Elf_Ehdr *ehdr,#if defined(SORTTABLE_64 ) && defined(UNWINDER_ORC_ENABLED )/* locate the ORC unwind tables */ if (!strcmp (secstrings + idx,".orc_unwind_ip" )) { - orc_ip_size = s->sh_size; + orc_ip_size =_r (&s->sh_size); g_orc_ip_table = (int *)((void *)ehdr + - s->sh_offset); +_r (&s->sh_offset)); }if (!strcmp (secstrings + idx,".orc_unwind" )) { - orc_size = s->sh_size; + orc_size =_r (&s->sh_size); g_orc_table = (struct orc_entry *)((void *)ehdr + - s->sh_offset); +_r (&s->sh_offset)); }#endif }/* for loop */
Greg Kroah-Hartman
maintainerPATCH 56/175 scripts/sorttable: Move code from sorttable.h into sorttable.c
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Steven Rostedt <[email protected]>
[ Upstream commit 58d87678a0f46c6120904b4326aaf5ebf4454c69 ]
Instead of having the main code live in a header file and included twice with MACROs that define the Elf structures for 64 bit or 32 bit, move the code in the C file now that the Elf structures are defined in a union that has both. All accesses to the Elf structure fields are done through helper function pointers. If the file being parsed if for a 64 bit architecture, all the helper functions point to the 64 bit versions to retrieve the Elf fields. The same is true if the architecture is 32 bit, where the function pointers will point to the 32 bit helper functions.
Note, when the value of a field can be either 32 bit or 64 bit, a 64 bit is always returned, as it works for the 32 bit code as well.
This makes the code easier to read and maintain, and it now all exists in sorttable.c and sorttable.h may be removed.
--- scripts/sorttable.c | 473 +++++++++++++++++++++++++++++++++++++++++++++++++- scripts/sorttable.h | 485 ---------------------------------------------------- 2 files changed, 460 insertions(+), 498 deletions(-) delete mode 100644 scripts/sorttable.h
scripts/sorttable.c +460 -13
@@ -327,10 +327,423 @@ static inline void *get_index(void *starreturn start + (entsize * index); } -/* 32 bit and 64 bit are very similar */ -#include "sorttable.h" -#define SORTTABLE_64 -#include "sorttable.h" + +static int (*compare_extable)(const void *a,const void *b); +static uint64_t (*ehdr_shoff)(Elf_Ehdr *ehdr); +static uint16_t (*ehdr_shstrndx)(Elf_Ehdr *ehdr); +static uint16_t (*ehdr_shentsize)(Elf_Ehdr *ehdr); +static uint16_t (*ehdr_shnum)(Elf_Ehdr *ehdr); +static uint64_t (*shdr_addr)(Elf_Shdr *shdr); +static uint64_t (*shdr_offset)(Elf_Shdr *shdr); +static uint64_t (*shdr_size)(Elf_Shdr *shdr); +static uint64_t (*shdr_entsize)(Elf_Shdr *shdr); +static uint32_t (*shdr_link)(Elf_Shdr *shdr); +static uint32_t (*shdr_name)(Elf_Shdr *shdr); +static uint32_t (*shdr_type)(Elf_Shdr *shdr); +static uint8_t (*sym_type)(Elf_Sym *sym); +static uint32_t (*sym_name)(Elf_Sym *sym); +static uint64_t (*sym_value)(Elf_Sym *sym); +static uint16_t (*sym_shndx)(Elf_Sym *sym); + +static int extable_ent_size; +static int long_size; + + +#ifdef UNWINDER_ORC_ENABLED +/* ORC unwinder only support X86_64 */ +#include <asm/orc_types.h> + +#define ERRSTR_MAXSZ 256 + +static char g_err[ERRSTR_MAXSZ ]; +static int *g_orc_ip_table; +static struct orc_entry *g_orc_table; + +static pthread_t orc_sort_thread; + +static inline unsigned long orc_ip (const int *ip) +{ +return (unsigned long )ip + *ip; +} + +static int orc_sort_cmp (const void *_a,const void *_b) +{ +struct orc_entry *orc_a, *orc_b; +const int *a = g_orc_ip_table + *(int *)_a; +const int *b = g_orc_ip_table + *(int *)_b; +unsigned long a_val =orc_ip (a); +unsigned long b_val =orc_ip (b); + +if (a_val > b_val) +return 1 ; +if (a_val < b_val) +return -1 ; + +/* +* The "weak" section terminator entries need to always be on the left +* to ensure the lookup code skips them in favor of real entries. +* These terminator entries exist to handle any gaps created by +* whitelisted .o files which didn't get objtool generation. +*/ + orc_a = g_orc_table + (a - g_orc_ip_table); + orc_b = g_orc_table + (b - g_orc_ip_table); +if (orc_a->type ==ORC_TYPE_UNDEFINED && orc_b->type ==ORC_TYPE_UNDEFINED ) +return 0 ; +return orc_a->type ==ORC_TYPE_UNDEFINED ?-1 :1 ; +} + +static void *sort_orctable (void *arg) +{ +int i; +int *idxs =NULL ; +int *tmp_orc_ip_table =NULL ; +struct orc_entry *tmp_orc_table =NULL ; +unsigned int *orc_ip_size = (unsigned int *)arg; +unsigned int num_entries = *orc_ip_size /sizeof (int ); +unsigned int orc_size = num_entries *sizeof (struct orc_entry ); + + idxs = (int *)malloc (*orc_ip_size); +if (!idxs) { +snprintf (g_err,ERRSTR_MAXSZ ,"malloc idxs: %s" , +strerror (errno)); +pthread_exit (g_err); + } + + tmp_orc_ip_table = (int *)malloc (*orc_ip_size); +if (!tmp_orc_ip_table) { +snprintf (g_err,ERRSTR_MAXSZ ,"malloc tmp_orc_ip_table: %s" , +strerror (errno)); +pthread_exit (g_err); + } + + tmp_orc_table = (struct orc_entry *)malloc (orc_size); +if (!tmp_orc_table) { +snprintf (g_err,ERRSTR_MAXSZ ,"malloc tmp_orc_table: %s" , +strerror (errno)); +pthread_exit (g_err); + } + +/* initialize indices array, convert ip_table to absolute address */ +for (i =0 ; i < num_entries; i++) { + idxs[i] = i; + tmp_orc_ip_table[i] = g_orc_ip_table[i] + i *sizeof (int ); + } +memcpy (tmp_orc_table, g_orc_table, orc_size); + +qsort (idxs, num_entries,sizeof (int ), orc_sort_cmp); + +for (i =0 ; i < num_entries; i++) { +if (idxs[i] == i) +continue ; + +/* convert back to relative address */ + g_orc_ip_table[i] = tmp_orc_ip_table[idxs[i]] - i *sizeof (int ); + g_orc_table[i] = tmp_orc_table[idxs[i]]; + } + +free (idxs); +free (tmp_orc_ip_table); +free (tmp_orc_table); +pthread_exit (NULL ); +} +#endif + +#ifdef MCOUNT_SORT_ENABLED +static pthread_t mcount_sort_thread; + +struct elf_mcount_loc { +Elf_Ehdr *ehdr; +Elf_Shdr *init_data_sec; +uint64_t start_mcount_loc; +uint64_t stop_mcount_loc; +}; + +/* Sort the addresses stored between __start_mcount_loc to __stop_mcount_loc in vmlinux */ +static void *sort_mcount_loc (void *arg) +{ +struct elf_mcount_loc *emloc = (struct elf_mcount_loc *)arg; +uint64_t offset = emloc->start_mcount_loc -shdr_addr (emloc->init_data_sec) + +shdr_offset (emloc->init_data_sec); +uint64_t count = emloc->stop_mcount_loc - emloc->start_mcount_loc; +unsigned char *start_loc = (void *)emloc->ehdr + offset; + +qsort (start_loc, count/long_size, long_size, compare_extable); +return NULL ; +} + +/* Get the address of __start_mcount_loc and __stop_mcount_loc in System.map */ +static void get_mcount_loc (uint64_t *_start,uint64_t *_stop) +{ +FILE *file_start, *file_stop; +char start_buff[20 ]; +char stop_buff[20 ]; +int len =0 ; + + file_start =popen (" grep start_mcount System.map | awk '{print $1}' " ,"r" ); +if (!file_start) { +fprintf (stderr,"get start_mcount_loc error!" ); +return ; + } + + file_stop =popen (" grep stop_mcount System.map | awk '{print $1}' " ,"r" ); +if (!file_stop) { +fprintf (stderr,"get stop_mcount_loc error!" ); +pclose (file_start); +return ; + } + +while (fgets (start_buff,sizeof (start_buff), file_start) !=NULL ) { + len =strlen (start_buff); + start_buff[len -1 ] ='\0' ; + } + *_start =strtoul (start_buff,NULL ,16 ); + +while (fgets (stop_buff,sizeof (stop_buff), file_stop) !=NULL ) { + len =strlen (stop_buff); + stop_buff[len -1 ] ='\0' ; + } + *_stop =strtoul (stop_buff,NULL ,16 ); + +pclose (file_start); +pclose (file_stop); +} +#endif +static int do_sort (Elf_Ehdr *ehdr, +char const *const fname, +table_sort_t custom_sort) +{ +int rc =-1 ; +Elf_Shdr *shdr_start; +Elf_Shdr *strtab_sec =NULL ; +Elf_Shdr *symtab_sec =NULL ; +Elf_Shdr *extab_sec =NULL ; +Elf_Shdr *string_sec; +Elf_Sym *sym; +const Elf_Sym *symtab; +Elf32_Word *symtab_shndx =NULL ; +Elf_Sym *sort_needed_sym =NULL ; +Elf_Shdr *sort_needed_sec; +uint32_t *sort_needed_loc; +void *sym_start; +void *sym_end; +const char *secstrings; +const char *strtab; +char *extab_image; +int sort_need_index; +int symentsize; +int shentsize; +int idx; +int i; +unsigned int shnum; +unsigned int shstrndx; +#ifdef MCOUNT_SORT_ENABLED +struct elf_mcount_loc mstruct = {0 }; +uint64_t _start_mcount_loc =0 ; +uint64_t _stop_mcount_loc =0 ; +#endif +#ifdef UNWINDER_ORC_ENABLED +unsigned int orc_ip_size =0 ; +unsigned int orc_size =0 ; +unsigned int orc_num_entries =0 ; +#endif + + shdr_start = (Elf_Shdr *)((char *)ehdr +ehdr_shoff (ehdr)); + shentsize =ehdr_shentsize (ehdr); + + shstrndx =ehdr_shstrndx (ehdr); +if (shstrndx ==SHN_XINDEX ) + shstrndx =shdr_link (shdr_start); + string_sec =get_index (shdr_start, shentsize, shstrndx); + secstrings = (const char *)ehdr +shdr_offset (string_sec); + + shnum =ehdr_shnum (ehdr); +if (shnum ==SHN_UNDEF ) + shnum =shdr_size (shdr_start); + +for (i =0 ; i < shnum; i++) { +Elf_Shdr *shdr =get_index (shdr_start, shentsize, i); + + idx =shdr_name (shdr); +if (!strcmp (secstrings + idx,"__ex_table" )) + extab_sec = shdr; +if (!strcmp (secstrings + idx,".symtab" )) + symtab_sec = shdr; +if (!strcmp (secstrings + idx,".strtab" )) + strtab_sec = shdr; + +if (shdr_type (shdr) ==SHT_SYMTAB_SHNDX ) + symtab_shndx = (Elf32_Word *)((const char *)ehdr + +shdr_offset (shdr)); + +#ifdef MCOUNT_SORT_ENABLED +/* locate the .init.data section in vmlinux */ +if (!strcmp (secstrings + idx,".init.data" )) { +get_mcount_loc (&_start_mcount_loc, &_stop_mcount_loc); + mstruct.ehdr = ehdr; + mstruct.init_data_sec = shdr; + mstruct.start_mcount_loc = _start_mcount_loc; + mstruct.stop_mcount_loc = _stop_mcount_loc; + } +#endif + +#ifdef UNWINDER_ORC_ENABLED +/* locate the ORC unwind tables */ +if (!strcmp (secstrings + idx,".orc_unwind_ip" )) { + orc_ip_size =shdr_size (shdr); + g_orc_ip_table = (int *)((void *)ehdr + +shdr_offset (shdr)); + } +if (!strcmp (secstrings + idx,".orc_unwind" )) { + orc_size =shdr_size (shdr); + g_orc_table = (struct orc_entry *)((void *)ehdr + +shdr_offset (shdr)); + } +#endif + }/* for loop */ + +#ifdef UNWINDER_ORC_ENABLED +if (!g_orc_ip_table || !g_orc_table) { +fprintf (stderr, +"incomplete ORC unwind tables in file: %s\n" , fname); + goto out; + } + + orc_num_entries = orc_ip_size /sizeof (int ); +if (orc_ip_size %sizeof (int ) !=0 || + orc_size %sizeof (struct orc_entry ) !=0 || + orc_num_entries != orc_size /sizeof (struct orc_entry )) { +fprintf (stderr, +"inconsistent ORC unwind table entries in file: %s\n" , + fname); + goto out; + } + +/* create thread to sort ORC unwind tables concurrently */ +if (pthread_create (&orc_sort_thread,NULL , + sort_orctable, &orc_ip_size)) { +fprintf (stderr, +"pthread_create orc_sort_thread failed '%s': %s\n" , +strerror (errno), fname); + goto out; + } +#endif + +#ifdef MCOUNT_SORT_ENABLED +if (!mstruct.init_data_sec || !_start_mcount_loc || !_stop_mcount_loc) { +fprintf (stderr, +"incomplete mcount's sort in file: %s\n" , + fname); + goto out; + } + +/* create thread to sort mcount_loc concurrently */ +if (pthread_create (&mcount_sort_thread,NULL , &sort_mcount_loc, &mstruct)) { +fprintf (stderr, +"pthread_create mcount_sort_thread failed '%s': %s\n" , +strerror (errno), fname); + goto out; + } +#endif +if (!extab_sec) { +fprintf (stderr,"no __ex_table in file: %s\n" , fname); + goto out; + } + +if (!symtab_sec) { +fprintf (stderr,"no .symtab in file: %s\n" , fname); + goto out; + } + +if (!strtab_sec) { +fprintf (stderr,"no .strtab in file: %s\n" , fname); + goto out; + } + + extab_image = (void *)ehdr +shdr_offset (extab_sec); + strtab = (const char *)ehdr +shdr_offset (strtab_sec); + symtab = (const Elf_Sym *)((const char *)ehdr +shdr_offset (symtab_sec)); + +if (custom_sort) { +custom_sort (extab_image,shdr_size (extab_sec)); + }else { +int num_entries =shdr_size (extab_sec) / extable_ent_size; +qsort (extab_image, num_entries, + extable_ent_size, compare_extable); + } + +/* find the flag main_extable_sort_needed */ + sym_start = (void *)ehdr +shdr_offset (symtab_sec); + sym_end = sym_start +shdr_size (symtab_sec); + symentsize =shdr_entsize (symtab_sec); + +for (sym = sym_start; (void *)sym + symentsize < sym_end; + sym = (void *)sym + symentsize) { +if (sym_type (sym) !=STT_OBJECT ) +continue ; +if (!strcmp (strtab +sym_name (sym), +"main_extable_sort_needed" )) { + sort_needed_sym = sym; +break ; + } + } + +if (!sort_needed_sym) { +fprintf (stderr, +"no main_extable_sort_needed symbol in file: %s\n" , + fname); + goto out; + } + + sort_need_index =get_secindex (sym_shndx (sym), + ((void *)sort_needed_sym - (void *)symtab) / symentsize, + symtab_shndx); + sort_needed_sec =get_index (shdr_start, shentsize, sort_need_index); + sort_needed_loc = (void *)ehdr + +shdr_offset (sort_needed_sec) + +sym_value (sort_needed_sym) -shdr_addr (sort_needed_sec); + +/* extable has been sorted, clear the flag */ +w (0 , sort_needed_loc); + rc =0 ; + +out: +#ifdef UNWINDER_ORC_ENABLED +if (orc_sort_thread) { +void *retval =NULL ; +/* wait for ORC tables sort done */ + rc =pthread_join (orc_sort_thread, &retval); +if (rc) { +fprintf (stderr, +"pthread_join failed '%s': %s\n" , +strerror (errno), fname); + }else if (retval) { + rc =-1 ; +fprintf (stderr, +"failed to sort ORC tables '%s': %s\n" , + (char *)retval, fname); + } + } +#endif + +#ifdef MCOUNT_SORT_ENABLED +if (mcount_sort_thread) { +void *retval =NULL ; +/* wait for mcount sort done */ + rc =pthread_join (mcount_sort_thread, &retval); +if (rc) { +fprintf (stderr, +"pthread_join failed '%s': %s\n" , +strerror (errno), fname); + }else if (retval) { + rc =-1 ; +fprintf (stderr, +"failed to sort mcount '%s': %s\n" , + (char *)retval, fname); + } + } +#endif +return rc; +}static int compare_relative_table (const void *a,const void *b) {
@@ -399,7 +812,6 @@ static void sort_relative_table_with_datstatic int do_file (char const *const fname,void *addr) { -int rc =-1 ;Elf_Ehdr *ehdr = addr;table_sort_t custom_sort =NULL ;
@@ -462,29 +874,64 @@ static int do_file(char const *const fna r2(&ehdr->e32.e_shentsize) != sizeof(Elf32_Shdr)) {fprintf (stderr,"unrecognized ET_EXEC/ET_DYN file: %s\n" , fname); -break ; +return -1 ; } - rc =do_sort_32 (ehdr, fname, custom_sort); + + compare_extable = compare_extable_32; + ehdr_shoff = ehdr32_shoff; + ehdr_shentsize = ehdr32_shentsize; + ehdr_shstrndx = ehdr32_shstrndx; + ehdr_shnum = ehdr32_shnum; + shdr_addr = shdr32_addr; + shdr_offset = shdr32_offset; + shdr_link = shdr32_link; + shdr_size = shdr32_size; + shdr_name = shdr32_name; + shdr_type = shdr32_type; + shdr_entsize = shdr32_entsize; + sym_type = sym32_type; + sym_name = sym32_name; + sym_value = sym32_value; + sym_shndx = sym32_shndx; + long_size =4 ; + extable_ent_size =8 ;break ;case ELFCLASS64 : - {if (r2 (&ehdr->e64.e_ehsize) !=sizeof (Elf64_Ehdr) ||r2 (&ehdr->e64.e_shentsize) !=sizeof (Elf64_Shdr)) {fprintf (stderr,"unrecognized ET_EXEC/ET_DYN file: %s\n" , fname); -break ; - } - rc =do_sort_64 (ehdr, fname, custom_sort); +return -1 ; } + + compare_extable = compare_extable_64; + ehdr_shoff = ehdr64_shoff; + ehdr_shentsize = ehdr64_shentsize; + ehdr_shstrndx = ehdr64_shstrndx; + ehdr_shnum = ehdr64_shnum; + shdr_addr = shdr64_addr; + shdr_offset = shdr64_offset; + shdr_link = shdr64_link; + shdr_size = shdr64_size; + shdr_name = shdr64_name; + shdr_type = shdr64_type; + shdr_entsize = shdr64_entsize; + sym_type = sym64_type; + sym_name = sym64_name; + sym_value = sym64_value; + sym_shndx = sym64_shndx; + long_size =8 ; + extable_ent_size =16 ; +break ;default :fprintf (stderr,"unrecognized ELF class %d %s\n" , ehdr->e32.e_ident[EI_CLASS ], fname); -break ; +return -1 ; } -return rc; +return do_sort (ehdr, fname, custom_sort); }int main (int argc,char *argv[])
scripts/sorttable.h deleted +0 -485
485 lines not on this page · raw message
Greg Kroah-Hartman
maintainerPATCH 57/175 scripts/sorttable: Get start/stop_mcount_loc from ELF file directly
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Steven Rostedt <[email protected]>
[ Upstream commit 4acda8edefa1ce66d3de845f1c12745721cd14c3 ]
The get_mcount_loc() does a cheesy trick to find the start_mcount_loc and stop_mcount_loc values. That trick is:
file_start = popen(" grep start_mcount System.map | awk '{print $1}' ", "r");
and
file_stop = popen(" grep stop_mcount System.map | awk '{print $1}' ", "r");
Those values are stored in the Elf symbol table. Use that to capture those values. Using the symbol table is more efficient and more robust. The above could fail if another variable had "start_mcount" or "stop_mcount" as part of its name.
--- scripts/sorttable.c | 95 ++++++++++++++++++++++++---------------------------- 1 file changed, 45 insertions(+), 50 deletions(-)
scripts/sorttable.c +45 -50
@@ -472,42 +472,41 @@ static void *sort_mcount_loc(void *arg) }/* Get the address of __start_mcount_loc and __stop_mcount_loc in System.map */ -static void get_mcount_loc (uint64_t *_start,uint64_t *_stop) +static void get_mcount_loc (struct elf_mcount_loc *emloc,Elf_Shdr *symtab_sec, +const char *strtab) { -FILE *file_start, *file_stop; -char start_buff[20 ]; -char stop_buff[20 ]; -int len =0 ; +Elf_Sym *sym, *end_sym; +int symentsize =shdr_entsize (symtab_sec); +int found =0 ; + + sym = (void *)emloc->ehdr +shdr_offset (symtab_sec); + end_sym = (void *)sym +shdr_size (symtab_sec); + +while (sym < end_sym) { +if (!strcmp (strtab +sym_name (sym),"__start_mcount_loc" )) { + emloc->start_mcount_loc =sym_value (sym); +if (++found ==2 ) +break ; + }else if (!strcmp (strtab +sym_name (sym),"__stop_mcount_loc" )) { + emloc->stop_mcount_loc =sym_value (sym); +if (++found ==2 ) +break ; + } + sym = (void *)sym + symentsize; + } - file_start =popen (" grep start_mcount System.map | awk '{print $1}' " ,"r" ); -if (!file_start) { +if (!emloc->start_mcount_loc) {fprintf (stderr,"get start_mcount_loc error!" );return ; } - file_stop =popen (" grep stop_mcount System.map | awk '{print $1}' " ,"r" ); -if (!file_stop) { +if (!emloc->stop_mcount_loc) {fprintf (stderr,"get stop_mcount_loc error!" ); -pclose (file_start);return ; } - -while (fgets (start_buff,sizeof (start_buff), file_start) !=NULL ) { - len =strlen (start_buff); - start_buff[len -1 ] ='\0' ; - } - *_start =strtoul (start_buff,NULL ,16 ); - -while (fgets (stop_buff,sizeof (stop_buff), file_stop) !=NULL ) { - len =strlen (stop_buff); - stop_buff[len -1 ] ='\0' ; - } - *_stop =strtoul (stop_buff,NULL ,16 ); - -pclose (file_start); -pclose (file_stop); }#endif +static int do_sort (Elf_Ehdr *ehdr,char const *const fname,table_sort_t custom_sort)
@@ -538,8 +537,6 @@ static int do_sort(Elf_Ehdr *ehdr,unsigned int shstrndx;#ifdef MCOUNT_SORT_ENABLED struct elf_mcount_loc mstruct = {0 }; -uint64_t _start_mcount_loc =0 ; -uint64_t _stop_mcount_loc =0 ;#endif #ifdef UNWINDER_ORC_ENABLED unsigned int orc_ip_size =0 ;
@@ -577,13 +574,8 @@ static int do_sort(Elf_Ehdr *ehdr,#ifdef MCOUNT_SORT_ENABLED /* locate the .init.data section in vmlinux */ -if (!strcmp (secstrings + idx,".init.data" )) { -get_mcount_loc (&_start_mcount_loc, &_stop_mcount_loc); - mstruct.ehdr = ehdr; +if (!strcmp (secstrings + idx,".init.data" )) mstruct.init_data_sec = shdr; - mstruct.start_mcount_loc = _start_mcount_loc; - mstruct.stop_mcount_loc = _stop_mcount_loc; - }#endif #ifdef UNWINDER_ORC_ENABLED
@@ -627,23 +619,6 @@ static int do_sort(Elf_Ehdr *ehdr, goto out; }#endif - -#ifdef MCOUNT_SORT_ENABLED -if (!mstruct.init_data_sec || !_start_mcount_loc || !_stop_mcount_loc) { -fprintf (stderr, -"incomplete mcount's sort in file: %s\n" , - fname); - goto out; - } - -/* create thread to sort mcount_loc concurrently */ -if (pthread_create (&mcount_sort_thread,NULL , &sort_mcount_loc, &mstruct)) { -fprintf (stderr, -"pthread_create mcount_sort_thread failed '%s': %s\n" , -strerror (errno), fname); - goto out; - } -#endif if (!extab_sec) {fprintf (stderr,"no __ex_table in file: %s\n" , fname); goto out;
@@ -663,6 +638,26 @@ static int do_sort(Elf_Ehdr *ehdr, strtab = (const char *)ehdr +shdr_offset (strtab_sec); symtab = (const Elf_Sym *)((const char *)ehdr +shdr_offset (symtab_sec)); +#ifdef MCOUNT_SORT_ENABLED + mstruct.ehdr = ehdr; +get_mcount_loc (&mstruct, symtab_sec, strtab); + +if (!mstruct.init_data_sec || !mstruct.start_mcount_loc || !mstruct.stop_mcount_loc) { +fprintf (stderr, +"incomplete mcount's sort in file: %s\n" , + fname); + goto out; + } + +/* create thread to sort mcount_loc concurrently */ +if (pthread_create (&mcount_sort_thread,NULL , &sort_mcount_loc, &mstruct)) { +fprintf (stderr, +"pthread_create mcount_sort_thread failed '%s': %s\n" , +strerror (errno), fname); + goto out; + } +#endif +if (custom_sort) {custom_sort (extab_image,shdr_size (extab_sec)); }else {
Greg Kroah-Hartman
maintainerPATCH 58/175 scripts/sorttable: Use a structure of function pointers for elf helpers
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Steven Rostedt <[email protected]>
[ Upstream commit 1e5f6771c247b28135307058d2cfe3b0153733dc ]
Instead of having a series of function pointers that gets assigned to the Elf64 or Elf32 versions, put them all into a single structure and use that. Add the helper function that chooses the structure into the macros that build the different versions of the elf functions.
--- scripts/sorttable.c | 175 +++++++++++++++++++++++++++++++++++----------------- 1 file changed, 118 insertions(+), 57 deletions(-)
scripts/sorttable.c +118 -57
@@ -85,6 +85,25 @@ static uint64_t (*r8)(const uint64_t *);static void (*w)(uint32_t ,uint32_t *);typedef void (*table_sort_t )(char *,int ); +static struct elf_funcs { +int (*compare_extable)(const void *a,const void *b); +uint64_t (*ehdr_shoff)(Elf_Ehdr *ehdr); +uint16_t (*ehdr_shstrndx)(Elf_Ehdr *ehdr); +uint16_t (*ehdr_shentsize)(Elf_Ehdr *ehdr); +uint16_t (*ehdr_shnum)(Elf_Ehdr *ehdr); +uint64_t (*shdr_addr)(Elf_Shdr *shdr); +uint64_t (*shdr_offset)(Elf_Shdr *shdr); +uint64_t (*shdr_size)(Elf_Shdr *shdr); +uint64_t (*shdr_entsize)(Elf_Shdr *shdr); +uint32_t (*shdr_link)(Elf_Shdr *shdr); +uint32_t (*shdr_name)(Elf_Shdr *shdr); +uint32_t (*shdr_type)(Elf_Shdr *shdr); +uint8_t (*sym_type)(Elf_Sym *sym); +uint32_t (*sym_name)(Elf_Sym *sym); +uint64_t (*sym_value)(Elf_Sym *sym); +uint16_t (*sym_shndx)(Elf_Sym *sym); +} e; +static uint64_t ehdr64_shoff (Elf_Ehdr *ehdr) {return r8 (&ehdr->e64.e_shoff);
@@ -95,6 +114,11 @@ static uint64_t ehdr32_shoff(Elf_Ehdr *ereturn r (&ehdr->e32.e_shoff); } +static uint64_t ehdr_shoff (Elf_Ehdr *ehdr) +{ +return e.ehdr_shoff (ehdr); +} +#define EHDR_HALF (fn_name) \ static uint16_t ehdr64_##fn_name(Elf_Ehdr *ehdr) \ { \
@@ -104,6 +128,11 @@ static uint16_t ehdr64_##fn_name(Elf_Ehd static uint16_t ehdr32_##fn_name(Elf_Ehdr *ehdr) \ { \ return r2(&ehdr->e32.e_##fn_name); \ +} \ + \ +static uint16_t ehdr_##fn_name(Elf_Ehdr *ehdr) \ +{ \ + return e.ehdr_##fn_name(ehdr); \ }EHDR_HALF (shentsize)
@@ -119,6 +148,11 @@ static uint32_t shdr64_##fn_name(Elf_Shd static uint32_t shdr32_##fn_name(Elf_Shdr *shdr) \ { \ return r(&shdr->e32.sh_##fn_name); \ +} \ + \ +static uint32_t shdr_##fn_name(Elf_Shdr *shdr) \ +{ \ + return e.shdr_##fn_name(shdr); \ }#define SHDR_ADDR (fn_name) \
@@ -130,6 +164,11 @@ static uint64_t shdr64_##fn_name(Elf_Shd static uint64_t shdr32_##fn_name(Elf_Shdr *shdr) \ { \ return r(&shdr->e32.sh_##fn_name); \ +} \ + \ +static uint64_t shdr_##fn_name(Elf_Shdr *shdr) \ +{ \ + return e.shdr_##fn_name(shdr); \ }#define SHDR_WORD (fn_name) \
@@ -141,6 +180,10 @@ static uint32_t shdr64_##fn_name(Elf_Shd static uint32_t shdr32_##fn_name(Elf_Shdr *shdr) \ { \ return r(&shdr->e32.sh_##fn_name); \ +} \ +static uint32_t shdr_##fn_name(Elf_Shdr *shdr) \ +{ \ + return e.shdr_##fn_name(shdr); \ }SHDR_ADDR (addr)
@@ -161,6 +204,11 @@ static uint64_t sym64_##fn_name(Elf_Sym static uint64_t sym32_##fn_name(Elf_Sym *sym) \ { \ return r(&sym->e32.st_##fn_name); \ +} \ + \ +static uint64_t sym_##fn_name(Elf_Sym *sym) \ +{ \ + return e.sym_##fn_name(sym); \ }#define SYM_WORD (fn_name) \
@@ -172,6 +220,11 @@ static uint32_t sym64_##fn_name(Elf_Sym static uint32_t sym32_##fn_name(Elf_Sym *sym) \ { \ return r(&sym->e32.st_##fn_name); \ +} \ + \ +static uint32_t sym_##fn_name(Elf_Sym *sym) \ +{ \ + return e.sym_##fn_name(sym); \ }#define SYM_HALF (fn_name) \
@@ -183,6 +236,11 @@ static uint16_t sym64_##fn_name(Elf_Sym static uint16_t sym32_##fn_name(Elf_Sym *sym) \ { \ return r2(&sym->e32.st_##fn_name); \ +} \ + \ +static uint16_t sym_##fn_name(Elf_Sym *sym) \ +{ \ + return e.sym_##fn_name(sym); \ }static uint8_t sym64_type (Elf_Sym *sym)
@@ -195,6 +253,11 @@ static uint8_t sym32_type(Elf_Sym *sym)return ELF32_ST_TYPE (sym->e32.st_info); } +static uint8_t sym_type (Elf_Sym *sym) +{ +return e.sym_type (sym); +} + SYM_ADDR(value) SYM_WORD(name) SYM_HALF(shndx)
@@ -322,29 +385,16 @@ static int compare_extable_64(const voidreturn av > bv; } +static int compare_extable (const void *a,const void *b) +{ +return e.compare_extable (a, b); +} +static inline void *get_index (void *start,int entsize,int index) {return start + (entsize * index); } - -static int (*compare_extable)(const void *a,const void *b); -static uint64_t (*ehdr_shoff)(Elf_Ehdr *ehdr); -static uint16_t (*ehdr_shstrndx)(Elf_Ehdr *ehdr); -static uint16_t (*ehdr_shentsize)(Elf_Ehdr *ehdr); -static uint16_t (*ehdr_shnum)(Elf_Ehdr *ehdr); -static uint64_t (*shdr_addr)(Elf_Shdr *shdr); -static uint64_t (*shdr_offset)(Elf_Shdr *shdr); -static uint64_t (*shdr_size)(Elf_Shdr *shdr); -static uint64_t (*shdr_entsize)(Elf_Shdr *shdr); -static uint32_t (*shdr_link)(Elf_Shdr *shdr); -static uint32_t (*shdr_name)(Elf_Shdr *shdr); -static uint32_t (*shdr_type)(Elf_Shdr *shdr); -static uint8_t (*sym_type)(Elf_Sym *sym); -static uint32_t (*sym_name)(Elf_Sym *sym); -static uint64_t (*sym_value)(Elf_Sym *sym); -static uint16_t (*sym_shndx)(Elf_Sym *sym); -static int extable_ent_size;static int long_size;
@@ -864,7 +914,30 @@ static int do_file(char const *const fna }switch (ehdr->e32.e_ident[EI_CLASS ]) { -case ELFCLASS32 : +case ELFCLASS32 : { +struct elf_funcs efuncs = { + .compare_extable = compare_extable_32, + .ehdr_shoff = ehdr32_shoff, + .ehdr_shentsize = ehdr32_shentsize, + .ehdr_shstrndx = ehdr32_shstrndx, + .ehdr_shnum = ehdr32_shnum, + .shdr_addr = shdr32_addr, + .shdr_offset = shdr32_offset, + .shdr_link = shdr32_link, + .shdr_size = shdr32_size, + .shdr_name = shdr32_name, + .shdr_type = shdr32_type, + .shdr_entsize = shdr32_entsize, + .sym_type = sym32_type, + .sym_name = sym32_name, + .sym_value = sym32_value, + .sym_shndx = sym32_shndx, + }; + + e = efuncs; + long_size =4 ; + extable_ent_size =8 ; +if (r2 (&ehdr->e32.e_ehsize) !=sizeof (Elf32_Ehdr) ||r2 (&ehdr->e32.e_shentsize) !=sizeof (Elf32_Shdr)) { fprintf(stderr,
@@ -872,26 +945,32 @@ static int do_file(char const *const fnareturn -1 ; } - compare_extable = compare_extable_32; - ehdr_shoff = ehdr32_shoff; - ehdr_shentsize = ehdr32_shentsize; - ehdr_shstrndx = ehdr32_shstrndx; - ehdr_shnum = ehdr32_shnum; - shdr_addr = shdr32_addr; - shdr_offset = shdr32_offset; - shdr_link = shdr32_link; - shdr_size = shdr32_size; - shdr_name = shdr32_name; - shdr_type = shdr32_type; - shdr_entsize = shdr32_entsize; - sym_type = sym32_type; - sym_name = sym32_name; - sym_value = sym32_value; - sym_shndx = sym32_shndx; - long_size =4 ; - extable_ent_size =8 ; + }break ; -case ELFCLASS64 : +case ELFCLASS64 : { +struct elf_funcs efuncs = { + .compare_extable = compare_extable_64, + .ehdr_shoff = ehdr64_shoff, + .ehdr_shentsize = ehdr64_shentsize, + .ehdr_shstrndx = ehdr64_shstrndx, + .ehdr_shnum = ehdr64_shnum, + .shdr_addr = shdr64_addr, + .shdr_offset = shdr64_offset, + .shdr_link = shdr64_link, + .shdr_size = shdr64_size, + .shdr_name = shdr64_name, + .shdr_type = shdr64_type, + .shdr_entsize = shdr64_entsize, + .sym_type = sym64_type, + .sym_name = sym64_name, + .sym_value = sym64_value, + .sym_shndx = sym64_shndx, + }; + + e = efuncs; + long_size =8 ; + extable_ent_size =16 ; +if (r2 (&ehdr->e64.e_ehsize) !=sizeof (Elf64_Ehdr) ||r2 (&ehdr->e64.e_shentsize) !=sizeof (Elf64_Shdr)) { fprintf(stderr,
@@ -900,25 +979,7 @@ static int do_file(char const *const fnareturn -1 ; } - compare_extable = compare_extable_64; - ehdr_shoff = ehdr64_shoff; - ehdr_shentsize = ehdr64_shentsize; - ehdr_shstrndx = ehdr64_shstrndx; - ehdr_shnum = ehdr64_shnum; - shdr_addr = shdr64_addr; - shdr_offset = shdr64_offset; - shdr_link = shdr64_link; - shdr_size = shdr64_size; - shdr_name = shdr64_name; - shdr_type = shdr64_type; - shdr_entsize = shdr64_entsize; - sym_type = sym64_type; - sym_name = sym64_name; - sym_value = sym64_value; - sym_shndx = sym64_shndx; - long_size =8 ; - extable_ent_size =16 ; - + }break ;default : fprintf(stderr, "unrecognized ELF class %d %s\n",
Greg Kroah-Hartman
maintainerPATCH 59/175 arm64: scripts/sorttable: Implement sorting mcount_loc at boot for arm64
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Steven Rostedt <[email protected]>
[ Upstream commit b3d09d06e052e1d754645acea4e4d1e96f81c934 ]
The mcount_loc section holds the addresses of the functions that get patched by ftrace when enabling function callbacks. It can contain tens of thousands of entries. These addresses must be sorted. If they are not sorted at compile time, they are sorted at boot. Sorting at boot does take some time and does have a small impact on boot performance.
x86 and arm32 have the addresses in the mcount_loc section of the ELF file. But for arm64, the section just contains zeros. The .rela.dyn Elf_Rela section holds the addresses and they get patched at boot during the relocation phase.
In order to sort these addresses, the Elf_Rela needs to be updated instead of the location in the binary that holds the mcount_loc section. Have the sorttable code, allocate an array to hold the functions, load the addresses from the Elf_Rela entries, sort them, then put them back in order into the Elf_rela entries so that they will be sorted at boot up without having to sort them during boot up.
--- arch/arm64/Kconfig | 1 scripts/sorttable.c | 185 +++++++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 183 insertions(+), 3 deletions(-)
arch/arm64/Kconfig +1 -0
@@ -202,6 +202,7 @@ config ARM64 if DYNAMIC_FTRACE_WITH_ARGS select HAVE_SAMPLE_FTRACE_DIRECT select HAVE_SAMPLE_FTRACE_DIRECT_MULTI + select HAVE_BUILDTIME_MCOUNT_SORT select HAVE_EFFICIENT_UNALIGNED_ACCESS select HAVE_FAST_GUP select HAVE_FTRACE_MCOUNT_RECORD
scripts/sorttable.c +182 -3
280 lines not on this page · raw message
Greg Kroah-Hartman
maintainerPATCH 60/175 scripts/sorttable: Have mcount rela sort use direct values
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Steven Rostedt <[email protected]>
[ Upstream commit a0265659322540d656727b9e132edfb6f06b6c1a ]
The mcount_loc sorting for when the values are stored in the Elf_Rela entries uses the compare_extable() function to do the compares in the qsort(). That function does handle byte swapping if the machine being compiled for is a different endian than the host machine. But the sort_relocs() function sorts an array that pulled in the values from the Elf_Rela section and has already done the swapping.
Create two new compare functions that will sort the direct values. One will sort 32 bit values and the other will sort the 64 bit value. One of these will be assigned to a compare_values function pointer and that will be used for sorting the Elf_Rela mcount values.
--- scripts/sorttable.c | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-)
scripts/sorttable.c +25 -1
@@ -552,6 +552,28 @@ static void *sort_orctable(void *arg)#ifdef MCOUNT_SORT_ENABLED +static int compare_values_64 (const void *a,const void *b) +{ +uint64_t av = *(uint64_t *)a; +uint64_t bv = *(uint64_t *)b; + +if (av < bv) +return -1 ; +return av > bv; +} + +static int compare_values_32 (const void *a,const void *b) +{ +uint32_t av = *(uint32_t *)a; +uint32_t bv = *(uint32_t *)b; + +if (av < bv) +return -1 ; +return av > bv; +} + +static int (*compare_values)(const void *a,const void *b); +/* Only used for sorting mcount table */ static void rela_write_addend (Elf_Rela *rela,uint64_t val) {
@@ -583,6 +605,8 @@ static void *sort_relocs(Elf_Ehdr *ehdr,void *vals;void *ptr; + compare_values = long_size ==4 ? compare_values_32 : compare_values_64; + shdr_start = (Elf_Shdr *)((char *)ehdr +ehdr_shoff (ehdr)); shentsize =ehdr_shentsize (ehdr);
@@ -640,7 +664,7 @@ static void *sort_relocs(Elf_Ehdr *ehdr, } } count = ptr - vals; -qsort (vals, count / long_size, long_size, compare_extable); +qsort (vals, count / long_size, long_size, compare_values); ptr = vals;for (int i =0 ; i < shnum; i++) {
Greg Kroah-Hartman
maintainerPATCH 61/175 scripts/sorttable: Always use an array for the mcount_loc sorting
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Steven Rostedt <[email protected]>
[ Upstream commit 5fb964f5ba53afda0e2b6dbc00b8205461ffe04a ]
The sorting of the mcount_loc section is done directly to the section for x86 and arm32 but it uses a separate array for arm64 as arm64 has the values for the mcount_loc stored in the rela sections of the vmlinux ELF file.
In order to use the same code to remove weak functions, always use a separate array to do the sorting. This requires splitting up the filling of the array into one function and the placing the contents of the array back into the rela sections or into the mcount_loc section into a separate file.
--- scripts/sorttable.c | 122 ++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 90 insertions(+), 32 deletions(-)
scripts/sorttable.c +90 -32
@@ -594,31 +594,19 @@ struct elf_mcount_loc {uint64_t stop_mcount_loc; }; -/* Sort the relocations not the address itself */ -static void *sort_relocs (Elf_Ehdr *ehdr,uint64_t start_loc,uint64_t size) +/* Fill the array with the content of the relocs */ +static int fill_relocs (void *ptr,uint64_t size,Elf_Ehdr *ehdr,uint64_t start_loc) {Elf_Shdr *shdr_start;Elf_Rela *rel;unsigned int shnum; -unsigned int count; +unsigned int count =0 ;int shentsize; -void *vals; -void *ptr; - - compare_values = long_size ==4 ? compare_values_32 : compare_values_64; +void *array_end = ptr + size; shdr_start = (Elf_Shdr *)((char *)ehdr +ehdr_shoff (ehdr)); shentsize =ehdr_shentsize (ehdr); - vals =malloc (long_size * size); -if (!vals) { -snprintf (m_err,ERRSTR_MAXSZ ,"Failed to allocate sort array" ); -pthread_exit (m_err); -return NULL ; - } - - ptr = vals; - shnum =ehdr_shnum (ehdr);if (shnum ==SHN_UNDEF ) shnum =shdr_size (shdr_start);
@@ -637,22 +625,18 @@ static void *sort_relocs(Elf_Ehdr *ehdr,uint64_t offset =rela_offset (rel);if (offset >= start_loc && offset < start_loc + size) { -if (ptr + long_size > vals + size) { -free (vals); +if (ptr + long_size > array_end) {snprintf (m_err,ERRSTR_MAXSZ ,"Too many relocations" ); -pthread_exit (m_err); -return NULL ; +return -1 ; }/* Make sure this has the correct type */ if (rela_info (rel) != rela_type) { -free (vals);snprintf (m_err,ERRSTR_MAXSZ ,"rela has type %lx but expected %lx\n" , (long )rela_info (rel), rela_type); -pthread_exit (m_err); -return NULL ; +return -1 ; }if (long_size ==4 )
@@ -660,13 +644,28 @@ static void *sort_relocs(Elf_Ehdr *ehdr,else *(uint64_t *)ptr =rela_addend (rel); ptr += long_size; + count++; } } } - count = ptr - vals; -qsort (vals, count / long_size, long_size, compare_values); +return count; +} + +/* Put the sorted vals back into the relocation elements */ +static void replace_relocs (void *ptr,uint64_t size,Elf_Ehdr *ehdr,uint64_t start_loc) +{ +Elf_Shdr *shdr_start; +Elf_Rela *rel; +unsigned int shnum; +int shentsize; + + shdr_start = (Elf_Shdr *)((char *)ehdr +ehdr_shoff (ehdr)); + shentsize =ehdr_shentsize (ehdr); + + shnum =ehdr_shnum (ehdr); +if (shnum ==SHN_UNDEF ) + shnum =shdr_size (shdr_start); - ptr = vals;for (int i =0 ; i < shnum; i++) {Elf_Shdr *shdr =get_index (shdr_start, shentsize, i);void *end;
@@ -689,8 +688,32 @@ static void *sort_relocs(Elf_Ehdr *ehdr, } } } -free (vals); -return NULL ; +} + +static int fill_addrs (void *ptr,uint64_t size,void *addrs) +{ +void *end = ptr + size; +int count =0 ; + +for (; ptr < end; ptr += long_size, addrs += long_size, count++) { +if (long_size ==4 ) + *(uint32_t *)ptr =r (addrs); +else + *(uint64_t *)ptr =r8 (addrs); + } +return count; +} + +static void replace_addrs (void *ptr,uint64_t size,void *addrs) +{ +void *end = ptr + size; + +for (; ptr < end; ptr += long_size, addrs += long_size) { +if (long_size ==4 ) +w (*(uint32_t *)ptr, addrs); +else +w8 (*(uint64_t *)ptr, addrs); + } }/* Sort the addresses stored between __start_mcount_loc to __stop_mcount_loc in vmlinux */
@@ -699,14 +722,49 @@ static void *sort_mcount_loc(void *arg)struct elf_mcount_loc *emloc = (struct elf_mcount_loc *)arg;uint64_t offset = emloc->start_mcount_loc -shdr_addr (emloc->init_data_sec) +shdr_offset (emloc->init_data_sec); -uint64_t count = emloc->stop_mcount_loc - emloc->start_mcount_loc; +uint64_t size = emloc->stop_mcount_loc - emloc->start_mcount_loc;unsigned char *start_loc = (void *)emloc->ehdr + offset; +Elf_Ehdr *ehdr = emloc->ehdr; +void *e_msg =NULL ; +void *vals; +int count; + + vals =malloc (long_size * size); +if (!vals) { +snprintf (m_err,ERRSTR_MAXSZ ,"Failed to allocate sort array" ); +pthread_exit (m_err); + }if (sort_reloc) -return sort_relocs (emloc->ehdr, emloc->start_mcount_loc, count); + count =fill_relocs (vals, size, ehdr, emloc->start_mcount_loc); +else + count =fill_addrs (vals, size, start_loc); + +if (count <0 ) { + e_msg = m_err; + goto out; + } + +if (count != size / long_size) { +snprintf (m_err,ERRSTR_MAXSZ ,"Expected %u mcount elements but found %u\n" , + (int )(size / long_size), count); + e_msg = m_err; + goto out; + } + + compare_values = long_size ==4 ? compare_values_32 : compare_values_64; + +qsort (vals, count, long_size, compare_values); + +if (sort_reloc) +replace_relocs (vals, size, ehdr, emloc->start_mcount_loc); +else +replace_addrs (vals, size, start_loc); + +out: +free (vals); -qsort (start_loc, count/long_size, long_size, compare_extable); -return NULL ; +pthread_exit (e_msg); }/* Get the address of __start_mcount_loc and __stop_mcount_loc in System.map */
Greg Kroah-Hartman
maintainerPATCH 62/175 scripts/sorttable: Zero out weak functions in mcount_loc table
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Steven Rostedt <[email protected]>
[ Upstream commit ef378c3b8233855497a414b9d67bf22592c928a4 ]
When a function is annotated as "weak" and is overridden, the code is not removed. If it is traced, the fentry/mcount location in the weak function will be referenced by the "__mcount_loc" section. This will then be added to the available_filter_functions list. Since only the address of the functions are listed, to find the name to show, a search of kallsyms is used.
Since kallsyms will return the function by simply finding the function that the address is after but before the next function, an address of a weak function will show up as the function before it. This is because kallsyms does not save names of weak functions. This has caused issues in the past, as now the traced weak function will be listed in available_filter_functions with the name of the function before it.
At best, this will cause the previous function's name to be listed twice. At worse, if the previous function was marked notrace, it will now show up as a function that can be traced. Note that it only shows up that it can be traced but will not be if enabled, which causes confusion.
https://lore.kernel.org/all/[email protected]/
The commit b39181f7c6907 ("ftrace: Add FTRACE_MCOUNT_MAX_OFFSET to avoid adding weak function") was a workaround to this by checking the function address before printing its name. If the address was too far from the function given by the name then instead of printing the name it would
print: __ftrace_invalid_address___<invalid-offset>
The real issue is that these invalid addresses are listed in the ftrace table look up which available_filter_functions is derived from. A place holder must be listed in that file because set_ftrace_filter may take a series of indexes into that file instead of names to be able to do O(1) lookups to enable filtering (many tools use this method).
Even if kallsyms saved the size of the function, it does not remove the need of having these place holders. The real solution is to not add a weak function into the ftrace table in the first place.
To solve this, the sorttable.c code that sorts the mcount regions during the build is modified to take a "nm -S vmlinux" input, sort it, and any function listed in the mcount_loc section that is not within a boundary of the function list given by nm is considered a weak function and is zeroed out.
Note, this does not mean they will remain zero when booting as KASLR will still shift those addresses. To handle this, the entries in the mcount_loc section will be ignored if they are zero or match the kaslr_offset() value.
Before:
~# grep __ftrace_invalid_address___ /sys/kernel/tracing/available_filter_functions | wc -l 551
After:
~# grep __ftrace_invalid_address___ /sys/kernel/tracing/available_filter_functions | wc -l 0
--- kernel/trace/ftrace.c | 6 +- scripts/link-vmlinux.sh | 4 + scripts/sorttable.c | 128 +++++++++++++++++++++++++++++++++++++++++++++++- 3 files changed, 134 insertions(+), 4 deletions(-)
kernel/trace/ftrace.c +5 -1
@@ -6525,6 +6525,7 @@ static int ftrace_process_locs(struct mounsigned long count;unsigned long *p;unsigned long addr; +unsigned long kaslr;unsigned long flags =0 ;/* Shut up gcc */ int ret = -ENOMEM ;
@@ -6573,6 +6574,9 @@ static int ftrace_process_locs(struct mo ftrace_pages->next = start_pg; } +/* For zeroed locations that were shifted for core kernel */ + kaslr = !mod ?kaslr_offset () :0 ; + p = start; pg = start_pg;while (p < end) {
@@ -6584,7 +6588,7 @@ static int ftrace_process_locs(struct mo* object files to satisfy alignments. * Skip any NULL pointers. */ -if (!addr) { +if (!addr || addr == kaslr) { skipped++;continue ; }
scripts/link-vmlinux.sh +3 -1
@@ -198,13 +198,15 @@ mksysmap() sorttable() { - ${objtree}/scripts/sorttable ${1} + ${NM} -S ${1} > .tmp_vmlinux.nm-sort + ${objtree}/scripts/sorttable -s .tmp_vmlinux.nm-sort ${1} } # Delete output files in case of error cleanup() { rm -f .btf.* + rm -f .tmp_vmlinux.nm-sort rm -f System.map rm -f vmlinux rm -f vmlinux.map
scripts/sorttable.c +126 -2
158 lines not on this page · raw message
Greg Kroah-Hartman
maintainerPATCH 63/175 ftrace: Update the mcount_loc check of skipped entries
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Steven Rostedt <[email protected]>
[ Upstream commit 4a3efc6baff931da9a85c6d2e42c87bd9a827399 ]
Now that weak functions turn into skipped entries, update the check to make sure the amount that was allocated would fit both the entries that were allocated as well as those that were skipped.
--- kernel/trace/ftrace.c | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-)
kernel/trace/ftrace.c +22 -1
@@ -6632,7 +6632,28 @@ static int ftrace_process_locs(struct mo/* We should have used all pages unless we skipped some */ if (pg_unuse) { -WARN_ON (!skipped); +unsigned long pg_remaining, remaining =0 ; +unsigned long skip; + +/* Count the number of entries unused and compare it to skipped. */ + pg_remaining = (ENTRIES_PER_PAGE << pg->order) - pg->index; + +if (!WARN (skipped < pg_remaining,"Extra allocated pages for ftrace" )) { + + skip = skipped - pg_remaining; + +for (pg = pg_unuse; pg; pg = pg->next) + remaining +=1 << pg->order; + + skip =DIV_ROUND_UP (skip,ENTRIES_PER_PAGE ); + +/* +* Check to see if the number of pages remaining would +* just fit the number of entries skipped. +*/ +WARN (skip != remaining,"Extra allocated pages for ftrace: %lu with %lu skipped" , + remaining, skipped); + }/* Need to synchronize with ftrace_location_range() */ synchronize_rcu ();ftrace_free_pages (pg_unuse);
Greg Kroah-Hartman
maintainerPATCH 64/175 ftrace: Have ftrace pages output reflect freed pages
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Steven Rostedt <[email protected]>
[ Upstream commit 264143c4e54412095f4b615e65bf736fc3c60af0 ]
The amount of memory that ftrace uses to save the descriptors to manage the functions it can trace is shown at output. But if there are a lot of functions that are skipped because they were weak or the architecture added holes into the tables, then the extra pages that were allocated are freed. But these freed pages are not reflected in the numbers shown, and they can even be inconsistent with what is reported:
ftrace: allocating 57482 entries in 225 pages
ftrace: allocated 224 pages with 3 groups
The above shows the number of original entries that are in the mcount_loc section and the pages needed to save them (225), but the second output reflects the number of pages that were actually used. The two should be consistent as:
ftrace: allocating 56739 entries in 224 pages
ftrace: allocated 224 pages with 3 groups
The above also shows the accurate number of entires that were actually stored and does not include the entries that were removed.
--- kernel/trace/ftrace.c | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-)
kernel/trace/ftrace.c +12 -3
@@ -6527,6 +6527,7 @@ static int ftrace_process_locs(struct mounsigned long addr;unsigned long kaslr;unsigned long flags =0 ;/* Shut up gcc */ +unsigned long pages;int ret = -ENOMEM ; count = end - start;
@@ -6534,6 +6535,8 @@ static int ftrace_process_locs(struct moif (!count)return 0 ; + pages =DIV_ROUND_UP (count,ENTRIES_PER_PAGE ); +/* * Sorting mcount in vmlinux at build time depend on * CONFIG_BUILDTIME_MCOUNT_SORT, while mcount loc in
@@ -6645,6 +6648,8 @@ static int ftrace_process_locs(struct mofor (pg = pg_unuse; pg; pg = pg->next) remaining +=1 << pg->order; + pages -= remaining; + skip =DIV_ROUND_UP (skip,ENTRIES_PER_PAGE );/*
@@ -6658,6 +6663,13 @@ static int ftrace_process_locs(struct mosynchronize_rcu ();ftrace_free_pages (pg_unuse); } + +if (!mod) { + count -= skipped; +pr_info ("ftrace: allocating %ld entries in %ld pages\n" , + count, pages); + } +return ret; }
@@ -7315,9 +7327,6 @@ void __init ftrace_init(void) goto failed; } -pr_info ("ftrace: allocating %ld entries in %ld pages\n" , - count,DIV_ROUND_UP (count,ENTRIES_PER_PAGE )); - ret =ftrace_process_locs (NULL , __start_mcount_loc, __stop_mcount_loc);
Greg Kroah-Hartman
maintainerPATCH 65/175 ftrace: Do not over-allocate ftrace memory
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Guenter Roeck <[email protected]>
[ Upstream commit be55257fab181b93af38f8c4b1b3cb453a78d742 ]
The pg_remaining calculation in ftrace_process_locs() assumes that ENTRIES_PER_PAGE multiplied by 2^order equals the actual capacity of the allocated page group. However, ENTRIES_PER_PAGE is PAGE_SIZE / ENTRY_SIZE (integer division). When PAGE_SIZE is not a multiple of ENTRY_SIZE (e.g. 4096 / 24 = 170 with remainder 16), high-order allocations (like 256 pages) have significantly more capacity than 256 * 170. This leads to pg_remaining being underestimated, which in turn makes skip (derived from skipped - pg_remaining) larger than expected, causing the WARN(skip != remaining) to trigger.
Extra allocated pages for ftrace: 2 with 654 skipped
WARNING: CPU: 0 PID: 0 at kernel/trace/ftrace.c:7295 ftrace_process_locs+0x5bf/0x5e0
A similar problem in ftrace_allocate_records() can result in allocating too many pages. This can trigger the second warning in ftrace_process_locs().
Extra allocated pages for ftrace
WARNING: CPU: 0 PID: 0 at kernel/trace/ftrace.c:7276 ftrace_process_locs+0x548/0x580
Use the actual capacity of a page group to determine the number of pages to allocate. Have ftrace_allocate_pages() return the number of allocated pages to avoid having to calculate it. Use the actual page group capacity when validating the number of unused pages due to skipped entries. Drop the definition of ENTRIES_PER_PAGE since it is no longer used.
--- kernel/trace/ftrace.c | 29 +++++++++++++++-------------- 1 file changed, 15 insertions(+), 14 deletions(-)
kernel/trace/ftrace.c +15 -14
@@ -1117,7 +1117,6 @@ struct ftrace_page { };#define ENTRY_SIZE sizeof(struct dyn_ftrace) -#define ENTRIES_PER_PAGE (PAGE_SIZE / ENTRY_SIZE)static struct ftrace_page *ftrace_pages_start;static struct ftrace_page *ftrace_pages;
@@ -3245,7 +3244,8 @@ static int ftrace_update_code(struct modreturn 0 ; } -static int ftrace_allocate_records (struct ftrace_page *pg,int count) +static int ftrace_allocate_records (struct ftrace_page *pg,int count, +unsigned long *num_pages) {int order;int pages;
@@ -3255,7 +3255,7 @@ static int ftrace_allocate_records(strucreturn -EINVAL ;/* We want to fill as much as possible, with no empty pages */ - pages =DIV_ROUND_UP (count,ENTRIES_PER_PAGE ); + pages =DIV_ROUND_UP (count *ENTRY_SIZE ,PAGE_SIZE ); order =fls (pages) -1 ; again:
@@ -3270,6 +3270,7 @@ static int ftrace_allocate_records(struc } ftrace_number_of_pages +=1 << order; + *num_pages +=1 << order; ftrace_number_of_groups++; cnt = (PAGE_SIZE << order) /ENTRY_SIZE ;
@@ -3298,12 +3299,14 @@ static void ftrace_free_pages(struct ftr }static struct ftrace_page * -ftrace_allocate_pages (unsigned long num_to_init) +ftrace_allocate_pages (unsigned long num_to_init,unsigned long *num_pages) {struct ftrace_page *start_pg;struct ftrace_page *pg;int cnt; + *num_pages =0 ; +if (!num_to_init)return NULL ;
@@ -3317,7 +3320,7 @@ ftrace_allocate_pages(unsigned long num_* waste as little space as possible. */ for (;;) { - cnt =ftrace_allocate_records (pg, num_to_init); + cnt =ftrace_allocate_records (pg, num_to_init, num_pages);if (cnt <0 ) goto free_pages;
@@ -6535,8 +6538,6 @@ static int ftrace_process_locs(struct moif (!count)return 0 ; - pages =DIV_ROUND_UP (count,ENTRIES_PER_PAGE ); -/* * Sorting mcount in vmlinux at build time depend on * CONFIG_BUILDTIME_MCOUNT_SORT, while mcount loc in
@@ -6549,7 +6550,7 @@ static int ftrace_process_locs(struct motest_is_sorted (start, count); } - start_pg =ftrace_allocate_pages (count); + start_pg =ftrace_allocate_pages (count, &pages);if (!start_pg)return -ENOMEM ;
@@ -6636,27 +6637,27 @@ static int ftrace_process_locs(struct mo/* We should have used all pages unless we skipped some */ if (pg_unuse) {unsigned long pg_remaining, remaining =0 ; -unsigned long skip; +long skip;/* Count the number of entries unused and compare it to skipped. */ - pg_remaining = (ENTRIES_PER_PAGE << pg->order) - pg->index; + pg_remaining = (PAGE_SIZE << pg->order) /ENTRY_SIZE - pg->index;if (!WARN (skipped < pg_remaining,"Extra allocated pages for ftrace" )) { skip = skipped - pg_remaining; -for (pg = pg_unuse; pg; pg = pg->next) +for (pg = pg_unuse; pg && skip >0 ; pg = pg->next) { remaining +=1 << pg->order; + skip -= (PAGE_SIZE << pg->order) /ENTRY_SIZE ; + } pages -= remaining; - skip =DIV_ROUND_UP (skip,ENTRIES_PER_PAGE ); -/* * Check to see if the number of pages remaining would * just fit the number of entries skipped. */ -WARN (skip != remaining,"Extra allocated pages for ftrace: %lu with %lu skipped" , +WARN (pg || skip >0 ,"Extra allocated pages for ftrace: %lu with %lu skipped" , remaining, skipped); }/* Need to synchronize with ftrace_location_range() */
Greg Kroah-Hartman
maintainerPATCH 48/175 scripts/sorttable: Make compare_extable() into two functions
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Steven Rostedt <[email protected]>
[ Upstream commit 7ffc0d0819f438779ed592e2e2e3576f43ce14f0 ]
Instead of having the compare_extable() part of the sorttable.h header where it get's defined twice, since it is a very simple function, just define it twice in sorttable.c, and then it can use the proper read functions for the word size and endianess and the Elf_Addr macro can be removed from sorttable.h.
Also add a micro optimization. Instead of:
if (a < b)
return -1;
if (a > b)
return 1;
return 0;That can be shorten to:
if (a < b)
return -1;
return a > b;
--- scripts/sorttable.c | 20 ++++++++++++++++++++ scripts/sorttable.h | 14 -------------- 2 files changed, 20 insertions(+), 14 deletions(-)
scripts/sorttable.c +20 -0
@@ -173,6 +173,26 @@ static inline unsigned int get_secindex(return r (&symtab_shndx_start[sym_offs]); } +static int compare_extable_32 (const void *a,const void *b) +{ +Elf32_Addr av =r (a); +Elf32_Addr bv =r (b); + +if (av < bv) +return -1 ; +return av > bv; +} + +static int compare_extable_64 (const void *a,const void *b) +{ +Elf64_Addr av =r8 (a); +Elf64_Addr bv =r8 (b); + +if (av < bv) +return -1 ; +return av > bv; +} +/* 32 bit and 64 bit are very similar */ #include "sorttable.h" #define SORTTABLE_64
scripts/sorttable.h +0 -14
@@ -23,7 +23,6 @@#undef sort_mcount_loc#undef elf_mcount_loc#undef do_sort -#undef Elf_Addr#undef Elf_Ehdr#undef Elf_Shdr#undef Elf_Sym
@@ -38,7 +37,6 @@# define sort_mcount_loc sort_mcount_loc_64# define elf_mcount_loc elf_mcount_loc_64# define do_sort do_sort_64 -# define Elf_Addr Elf64_Addr# define Elf_Ehdr Elf64_Ehdr# define Elf_Shdr Elf64_Shdr# define Elf_Sym Elf64_Sym
@@ -52,7 +50,6 @@# define sort_mcount_loc sort_mcount_loc_32# define elf_mcount_loc elf_mcount_loc_32# define do_sort do_sort_32 -# define Elf_Addr Elf32_Addr# define Elf_Ehdr Elf32_Ehdr# define Elf_Shdr Elf32_Shdr# define Elf_Sym Elf32_Sym
@@ -160,17 +157,6 @@ static void *sort_orctable(void *arg) }#endif -static int compare_extable (const void *a,const void *b) -{ -Elf_Addr av =_r (a); -Elf_Addr bv =_r (b); - -if (av < bv) -return -1 ; -if (av > bv) -return 1 ; -return 0 ; -}#ifdef MCOUNT_SORT_ENABLED pthread_t mcount_sort_thread;
Greg Kroah-Hartman
maintainerPATCH 66/175 ftrace: Test mcount_loc addr before calling ftrace_call_addr()
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Steven Rostedt <[email protected]>
[ Upstream commit 6eeca746fa5f1dd03c6ee05cb03f5eb1ddda1c81 ]
The addresses in the mcount_loc can be zeroed and then moved by KASLR making them invalid addresses. ftrace_call_addr() for ARM 64 expects a valid address to kernel text. If the addr read from the mcount_loc section is invalid, it must not call ftrace_call_addr(). Move the addr check before calling ftrace_call_addr() in ftrace_process_locs().
--- kernel/trace/ftrace.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-)
kernel/trace/ftrace.c +5 -1
@@ -6585,7 +6585,9 @@ static int ftrace_process_locs(struct mo pg = start_pg;while (p < end) {unsigned long end_offset; - addr =ftrace_call_adjust (*p++); + + addr = *p++; +/* * Some architecture linkers will pad between * the different mcount_loc sections of different
@@ -6597,6 +6599,8 @@ static int ftrace_process_locs(struct mocontinue ; } + addr =ftrace_call_adjust (addr); + end_offset = (pg->index+1 ) *sizeof (pg->records[0 ]);if (end_offset >PAGE_SIZE << pg->order) {/* We should have allocated enough */
Greg Kroah-Hartman
maintainerPATCH 67/175 ftrace: Check against is_kernel_text() instead of kaslr_offset()
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Steven Rostedt <[email protected]>
[ Upstream commit da0f622b344be769ed61e7c1caf95cd0cdb47964 ]
As kaslr_offset() is architecture dependent and also may not be defined by all architectures, when zeroing out unused weak functions, do not check against kaslr_offset(), but instead check if the address is within the kernel text sections. If KASLR added a shift to the zeroed out function, it would still not be located in the kernel text. This is a more robust way to test if the text is valid or not.
--- kernel/trace/ftrace.c | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-)
kernel/trace/ftrace.c +12 -5
@@ -6528,7 +6528,6 @@ static int ftrace_process_locs(struct mounsigned long count;unsigned long *p;unsigned long addr; -unsigned long kaslr;unsigned long flags =0 ;/* Shut up gcc */ unsigned long pages;int ret = -ENOMEM ;
@@ -6578,9 +6577,6 @@ static int ftrace_process_locs(struct mo ftrace_pages->next = start_pg; } -/* For zeroed locations that were shifted for core kernel */ - kaslr = !mod ?kaslr_offset () :0 ; - p = start; pg = start_pg;while (p < end) {
@@ -6594,7 +6590,18 @@ static int ftrace_process_locs(struct mo* object files to satisfy alignments. * Skip any NULL pointers. */ -if (!addr || addr == kaslr) { +if (!addr) { + skipped++; +continue ; + } + +/* +* If this is core kernel, make sure the address is in core +* or inittext, as weak functions get zeroed and KASLR can +* move them to something other than zero. It just will not +* move it to an area where kernel text is. +*/ +if (!mod && !(is_kernel_text (addr) ||is_kernel_inittext (addr))) { skipped++;continue ; }
Greg Kroah-Hartman
maintainerPATCH 68/175 scripts/sorttable: Use normal sort if theres no relocs in the mcount section
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Steven Rostedt <[email protected]>
[ Upstream commit 46514b3c2c17c67cefe84b0c1a59e0aaf6093131 ]
When ARM 64 is compiled with gcc, the mcount_loc section will be filled with zeros and the addresses will be located in the Elf_Rela sections. To sort the mcount_loc section, the addresses from the Elf_Rela need to be placed into an array and that is sorted.
But when ARM 64 is compiled with clang, it does it the same way as other architectures and leaves the addresses as is in the mcount_loc section.
To handle both cases, ARM 64 will first try to sort the Elf_Rela section, and if it doesn't find any functions, it will then fall back to the sorting of the addresses in the mcount_loc section itself.
--- scripts/sorttable.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-)
scripts/sorttable.c +7 -2
@@ -827,9 +827,14 @@ static void *sort_mcount_loc(void *arg)pthread_exit (m_err); } -if (sort_reloc) +if (sort_reloc) { count =fill_relocs (vals, size, ehdr, emloc->start_mcount_loc); -else +/* gcc may use relocs to save the addresses, but clang does not. */ +if (!count) { + count =fill_addrs (vals, size, start_loc); + sort_reloc =0 ; + } + }else count =fill_addrs (vals, size, start_loc);if (count <0 ) {
Greg Kroah-Hartman
maintainerPATCH 69/175 scripts/sorttable: Allow matches to functions before function entry
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Steven Rostedt <[email protected]>
[ Upstream commit dc208c69c033d3caba0509da1ae065d2b5ff165f ]
ARM 64 uses -fpatchable-function-entry=4,2 which adds padding before the function and the addresses in the mcount_loc point there instead of the function entry that is returned by nm. In order to find a function from nm to make sure it's not an unused weak function, the entries in the mcount_loc section needs to match the entries from nm. Since it can be an instruction before the entry, add a before_func variable that ARM 64 can set to 8, and if the mcount_loc entry is within 8 bytes of the nm function entry, then it will be considered a match.
--- scripts/sorttable.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-)
scripts/sorttable.c +6 -1
@@ -611,13 +611,16 @@ static int add_field(uint64_t addr, uintreturn 0 ; } +/* Used for when mcount/fentry is before the function entry */ +static int before_func; +/* Only return match if the address lies inside the function size */ static int cmp_func_addr (const void *K ,const void *A ) {uint64_t key = *(const uint64_t *)K ;const struct func_info *a =A ; -if (key < a->addr) +if (key + before_func < a->addr)return -1 ;return key >= a->addr + a->size; }
@@ -1253,6 +1256,8 @@ static int do_file(char const *const fna#ifdef MCOUNT_SORT_ENABLED sort_reloc = true; rela_type =0x403 ; +/* arm64 uses patchable function entry placing before function */ + before_func =8 ;#endif /* fallthrough */ case EM_386 :
Greg Kroah-Hartman
maintainerPATCH 70/175 scripts/sorttable: Fix endianness handling in build-time mcount sort
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Vasily Gorbik <[email protected]>
[ Upstream commit 023f124a64174c47e18340ded7e2a39b96eb9523 ]
Kernel cross-compilation with BUILDTIME_MCOUNT_SORT produces zeroed mcount values if the build-host endianness does not match the ELF file endianness.
The mcount values array is converted from ELF file
endianness to build-host endianness during initialization in fill_relocs()/fill_addrs(). Avoid extra conversion of these values during weak-function zeroing; otherwise, they do not match nm-parsed addresses and all mcount values are zeroed out.
--- scripts/sorttable.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
scripts/sorttable.c +1 -1
@@ -857,7 +857,7 @@ static void *sort_mcount_loc(void *arg)for (void *ptr = vals; ptr < vals + size; ptr += long_size) {uint64_t key; - key = long_size ==4 ?r ((uint32_t *)ptr) :r8 ((uint64_t *)ptr); + key = long_size ==4 ? *(uint32_t *)ptr : *(uint64_t *)ptr;if (!find_func (key)) {if (long_size ==4 ) *(uint32_t *)ptr =0 ;
Greg Kroah-Hartman
maintainerPATCH 71/175 vc_screen: fix null-ptr-deref in vcs_notifier() during concurrent vcs_write
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yi Yang <[email protected]>
commit a287620312dc6dcb9a093417a0e589bf30fcf38a upstream.
A KASAN null-ptr-deref was observed in vcs_notifier():
BUG: KASAN: null-ptr-deref in vcs_notifier+0x98/0x130
Read of size 2 at addr qmp_cmd_name: qmp_capabilities, arguments: {}The issue is a race condition in vcs_write(). When the console_lock is temporarily dropped (to copy data from userspace), the vc_data pointer obtained from vcs_vc() may become stale. After re-acquiring the lock, vcs_vc() is called again to re-validate the pointer. If the vc has been deallocated in the meantime, vcs_vc() returns NULL, and the while loop breaks (with written > 0). However, after the loop, vcs_scr_updated(vc) is still called with the now-NULL vc pointer, leading to a null pointer dereference in the notifier chain (vcs_notifier dereferences param->vc).
Fix this by adding a NULL check for vc before calling vcs_scr_updated().
--- drivers/tty/vt/vc_screen.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/tty/vt/vc_screen.c +1 -1
@@ -699,7 +699,7 @@ vcs_write(struct file *file, const char } *ppos += written; ret = written; -if (written) +if (written && vc)vcs_scr_updated (vc); unlock_out:
Greg Kroah-Hartman
maintainerPATCH 72/175 ksmbd: reject non-VALID session in compound request branch
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Gil Portnoy <[email protected]>
commit 609ca17d869d04ba249e32cdcbf13c0b1c66f43c upstream.
smb2_check_user_session() takes a shortcut for any operation that is not the first in a COMPOUND request: it reuses work->sess (the session bound by the first operation) and validates only the SessionId, then returns "valid". It never re-checks work->sess->state == SMB2_SESSION_VALID, and a SessionId of 0xFFFFFFFFFFFFFFFF (ULLONG_MAX, the MS-SMB2 related-operation value) skips even the id comparison. The standalone path (ksmbd_session_lookup_all() plus the SESSION_SETUP state machine) does enforce the VALID state; the compound branch bypasses all of it.
A SESSION_SETUP carrying only an NTLM Type-1 (NtLmNegotiate) blob publishes a fresh SMB2_SESSION_IN_PROGRESS session whose sess->user is still NULL (->user is assigned later, by ntlm_authenticate()). Used as operation 1 of a COMPOUND with operation 2 = TREE_CONNECT (related, SessionId=ULLONG_MAX, \\host\IPC$), the tree-connect then runs on that IN_PROGRESS session and reaches ksmbd_ipc_tree_connect_request(), which dereferences user_name(sess->user) with sess->user == NULL (transport_ipc.c:687/701/704) -> remote NULL-pointer dereference and a kernel Oops that wedges the ksmbd worker for all clients.
Reject any non-first compound operation that lands on a session which is not SMB2_SESSION_VALID, mirroring the validity the standalone lookup path enforces. SESSION_SETUP itself legitimately runs on an IN_PROGRESS session, but it is never carried as a non-first compound operation, so multi-leg authentication is unaffected by this check.
--- fs/smb/server/smb2pdu.c | 5 +++++ 1 file changed, 5 insertions(+)
fs/smb/server/smb2pdu.c +5 -0
@@ -606,6 +606,11 @@ int smb2_check_user_session(struct ksmbd sess_id, work->sess->id);return -EINVAL ; } +if (work->sess->state !=SMB2_SESSION_VALID ) { +pr_err ("compound request on a non-valid session (state %d)\n" , + work->sess->state); +return -EINVAL ; + }return 1 ; }
Greg Kroah-Hartman
maintainerPATCH 73/175 media: vidtv: fix NULL pointer dereference in vidtv_mux_push_si
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ruslan Valiyev <[email protected]>
commit 7d8bf3d8f91073f4db347ed3aa6302b56107499c upstream.
syzbot reported a general protection fault invidtv_psi_ts_psi_write_into [1].
vidtv_mux_get_pid_ctx() can return NULL, but vidtv_mux_push_si() does not check for this before dereferencing the returned pointer to access the continuity counter. This leads to a general protection fault when accessing a near-NULL address.
The root cause is that vidtv_mux_pid_ctx_init() does not check the return value of vidtv_mux_create_pid_ctx_once() for PMT section PIDs. If the allocation fails, the PID context is never created, but init returns success. The subsequent vidtv_mux_push_si() call then gets NULL from vidtv_mux_get_pid_ctx() and crashes.
Fix both the root cause (add error check in vidtv_mux_pid_ctx_init for PMT PIDs) and add defensive NULL checks in vidtv_mux_push_si for all vidtv_mux_get_pid_ctx() calls.
[1]
Oops: general protection fault, probably for non-canonical address 0xdffffc0000000000: 0000 [#1] SMP KASAN PTI KASAN: null-ptr-deref in range [0x0000000000000000-0x0000000000000007] Workqueue: events vidtv_mux_tick RIP: 0010:vidtv_psi_ts_psi_write_into+0x54a/0xbc0 drivers/media/test-drivers/vidtv/vidtv_psi.c:197 Call Trace: <TASK> vidtv_psi_table_header_write_into drivers/media/test-drivers/vidtv/vidtv_psi.c:799 [inline] vidtv_psi_pmt_write_into+0x3b2/0xa70 drivers/media/test-drivers/vidtv/vidtv_psi.c:1231 vidtv_mux_push_si+0x932/0xe80 drivers/media/test-drivers/vidtv/vidtv_mux.c:196 vidtv_mux_tick+0xe9b/0x1480 drivers/media/test-drivers/vidtv/vidtv_mux.c:408
--- drivers/media/test-drivers/vidtv/vidtv_mux.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-)
drivers/media/test-drivers/vidtv/vidtv_mux.c +7 -1
@@ -101,7 +101,8 @@ static int vidtv_mux_pid_ctx_init(struct/* add a ctx for all PMT sections */ while (p) { pid =vidtv_psi_get_pat_program_pid (p); -vidtv_mux_create_pid_ctx_once (m, pid); +if (!vidtv_mux_create_pid_ctx_once (m, pid)) + goto free; p = p->next; }
@@ -170,6 +171,9 @@ static u32 vidtv_mux_push_si(struct vidt nit_ctx =vidtv_mux_get_pid_ctx (m,VIDTV_NIT_PID ); eit_ctx =vidtv_mux_get_pid_ctx (m,VIDTV_EIT_PID ); +if (!pat_ctx || !sdt_ctx || !nit_ctx || !eit_ctx) +return 0 ; + pat_args.offset = m->mux_buf_offset; pat_args.continuity_counter = &pat_ctx->cc;
@@ -186,6 +190,8 @@ static u32 vidtv_mux_push_si(struct vidt } pmt_ctx =vidtv_mux_get_pid_ctx (m, pmt_pid); +if (!pmt_ctx) +continue ; pmt_args.offset = m->mux_buf_offset; pmt_args.pmt = m->si.pmt_secs[i];
Greg Kroah-Hartman
maintainerPATCH 74/175 virtiofs: fix UAF on submount umount
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Miklos Szeredi <[email protected]>
commit 06b41351779e9289e8785694ade9042ae85e41ea upstream.
iput() called from fuse_release_end() can Oops if the super block has already been destroyed. Normally this is prevented by waiting for num_waiting to go down to zero before commencing with super block shutdown.
This only works, however, for the last submount instance, as the wait counter is per connection, not per superblock.
Revert to using synchronous release requests for the auto_submounts case, which is virtiofs only at this time.
--- fs/fuse/file.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-)
fs/fuse/file.c +7 -1
@@ -357,8 +357,14 @@ void fuse_file_release(struct inode *ino* aio and closes the fd before the aio completes. Since aio takes its * own ref to the file, the IO completion has to drop the ref, which is * how the fuse server can end up closing its clients' files. +* +* Exception is virtio-fs, which is not affected by the above (server is +* on host, cannot close open files in guest). Virtio-fs needs sync +* release, because the num_waiting mechanism to wait for all requests +* before commencing with fs shutdown doesn't work if submounts are +* used. */ -fuse_file_put (ff, false); +fuse_file_put (ff, ff->fm->fc->auto_submounts); }void fuse_release_common (struct file *file,bool isdir)
Greg Kroah-Hartman
maintainerPATCH 75/175 file: add fput() cleanup helper
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Christian Brauner <[email protected]>
[ Upstream commit 257b1c2c78c25643526609dee0c15f1544eb3252 ]
Add a simple helper to put a file reference.
--- include/linux/file.h | 2 ++ 1 file changed, 2 insertions(+)
include/linux/file.h +2 -0
@@ -11,6 +11,7 @@#include <linux/posix_types.h> #include <linux/errno.h> #include <linux/cleanup.h> +#include <linux/err.h> struct file ;
@@ -93,6 +94,7 @@ extern void put_unused_fd(unsigned int fd); DEFINE_CLASS(get_unused_fd, int, if (_T >= 0) put_unused_fd(_T), get_unused_fd_flags(flags), unsigned flags) +DEFINE_FREE(fput, struct file *, if (!IS_ERR_OR_NULL(_T)) fput(_T))extern void fd_install (unsigned int fd,struct file *file);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 49/175 scripts/sorttable: Convert Elf_Ehdr to union
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Steven Rostedt <[email protected]>
[ Upstream commit 157fb5b3cfd2cb5950314f926a76e567fc1921c5 ]
In order to remove the double #include of sorttable.h for 64 and 32 bit to create duplicate functions for both, replace the Elf_Ehdr macro with a union that defines both Elf64_Ehdr and Elf32_Ehdr, with field e64 for the 64bit version, and e32 for the 32bit version.
Then a macro etype can be used instead to get to the proper value.
This will eventually be replaced with just single functions that can handle both 32bit and 64bit ELF parsing.
--- scripts/sorttable.c | 36 ++++++++++++++++++++---------------- scripts/sorttable.h | 12 ++++++------ 2 files changed, 26 insertions(+), 22 deletions(-)
scripts/sorttable.c +20 -16
@@ -64,6 +64,11 @@#define EM_LOONGARCH 258#endif +typedef union { +Elf32_Ehdr e32; +Elf64_Ehdr e64; +}Elf_Ehdr ; +static uint32_t (*r)(const uint32_t *);static uint16_t (*r2)(const uint16_t *);static uint64_t (*r8)(const uint64_t *);
@@ -266,10 +271,10 @@ static void sort_relative_table_with_datstatic int do_file (char const *const fname,void *addr) {int rc =-1 ; -Elf32_Ehdr *ehdr = addr; +Elf_Ehdr *ehdr = addr;table_sort_t custom_sort =NULL ; -switch (ehdr->e_ident[EI_DATA ]) { +switch (ehdr->e32.e_ident[EI_DATA ]) {case ELFDATA2LSB : r = rle; r2 = r2le;
@@ -284,18 +289,18 @@ static int do_file(char const *const fnabreak ;default :fprintf (stderr,"unrecognized ELF data encoding %d: %s\n" , - ehdr->e_ident[EI_DATA ], fname); + ehdr->e32.e_ident[EI_DATA ], fname);return -1 ; } -if (memcmp (ELFMAG , ehdr->e_ident,SELFMAG ) !=0 || - (r2 (&ehdr->e_type) !=ET_EXEC &&r2 (&ehdr->e_type) !=ET_DYN ) || - ehdr->e_ident[EI_VERSION ] !=EV_CURRENT ) { +if (memcmp (ELFMAG , ehdr->e32.e_ident,SELFMAG ) !=0 || + (r2 (&ehdr->e32.e_type) !=ET_EXEC &&r2 (&ehdr->e32.e_type) !=ET_DYN ) || + ehdr->e32.e_ident[EI_VERSION ] !=EV_CURRENT ) {fprintf (stderr,"unrecognized ET_EXEC/ET_DYN file %s\n" , fname);return -1 ; } -switch (r2 (&ehdr->e_machine)) { +switch (r2 (&ehdr->e32.e_machine)) {case EM_386 :case EM_AARCH64 :case EM_LOONGARCH :
@@ -318,14 +323,14 @@ static int do_file(char const *const fnabreak ;default :fprintf (stderr,"unrecognized e_machine %d %s\n" , -r2 (&ehdr->e_machine), fname); +r2 (&ehdr->e32.e_machine), fname);return -1 ; } -switch (ehdr->e_ident[EI_CLASS ]) { +switch (ehdr->e32.e_ident[EI_CLASS ]) {case ELFCLASS32 : -if (r2 (&ehdr->e_ehsize) !=sizeof (Elf32_Ehdr) || -r2 (&ehdr->e_shentsize) !=sizeof (Elf32_Shdr)) { +if (r2 (&ehdr->e32.e_ehsize) !=sizeof (Elf32_Ehdr) || +r2 (&ehdr->e32.e_shentsize) !=sizeof (Elf32_Shdr)) {fprintf (stderr,"unrecognized ET_EXEC/ET_DYN file: %s\n" , fname);break ;
@@ -334,20 +339,19 @@ static int do_file(char const *const fnabreak ;case ELFCLASS64 : { -Elf64_Ehdr *const ghdr = (Elf64_Ehdr *)ehdr; -if (r2 (&ghdr->e_ehsize) !=sizeof (Elf64_Ehdr) || -r2 (&ghdr->e_shentsize) !=sizeof (Elf64_Shdr)) { +if (r2 (&ehdr->e64.e_ehsize) !=sizeof (Elf64_Ehdr) || +r2 (&ehdr->e64.e_shentsize) !=sizeof (Elf64_Shdr)) {fprintf (stderr,"unrecognized ET_EXEC/ET_DYN file: %s\n" , fname);break ; } - rc =do_sort_64 (ghdr, fname, custom_sort); + rc =do_sort_64 (ehdr, fname, custom_sort); }break ;default :fprintf (stderr,"unrecognized ELF class %d %s\n" , - ehdr->e_ident[EI_CLASS ], fname); + ehdr->e32.e_ident[EI_CLASS ], fname);break ; }
scripts/sorttable.h +6 -6
@@ -23,12 +23,12 @@#undef sort_mcount_loc#undef elf_mcount_loc#undef do_sort -#undef Elf_Ehdr#undef Elf_Shdr#undef Elf_Sym#undef ELF_ST_TYPE#undef uint_t#undef _r +#undef etype#ifdef SORTTABLE_64 # define extable_ent_size 16
@@ -37,12 +37,12 @@# define sort_mcount_loc sort_mcount_loc_64# define elf_mcount_loc elf_mcount_loc_64# define do_sort do_sort_64 -# define Elf_Ehdr Elf64_Ehdr# define Elf_Shdr Elf64_Shdr# define Elf_Sym Elf64_Sym# define ELF_ST_TYPE ELF64_ST_TYPE# define uint_t uint64_t# define _r r8 +# define etype e64#else # define extable_ent_size 8# define compare_extable compare_extable_32
@@ -50,12 +50,12 @@# define sort_mcount_loc sort_mcount_loc_32# define elf_mcount_loc elf_mcount_loc_32# define do_sort do_sort_32 -# define Elf_Ehdr Elf32_Ehdr# define Elf_Shdr Elf32_Shdr# define Elf_Sym Elf32_Sym# define ELF_ST_TYPE ELF32_ST_TYPE# define uint_t uint32_t# define _r r +# define etype e32#endif #if defined(SORTTABLE_64 ) && defined(UNWINDER_ORC_ENABLED )
@@ -222,7 +222,7 @@ static int do_sort(Elf_Ehdr *ehdr, table_sort_t custom_sort) {int rc =-1 ; -Elf_Shdr *s, *shdr = (Elf_Shdr *)((char *)ehdr +_r (&ehdr->e_shoff)); +Elf_Shdr *s, *shdr = (Elf_Shdr *)((char *)ehdr +_r (&ehdr->etype.e_shoff));Elf_Shdr *strtab_sec =NULL ;Elf_Shdr *symtab_sec =NULL ;Elf_Shdr *extab_sec =NULL ;
@@ -249,12 +249,12 @@ static int do_sort(Elf_Ehdr *ehdr,unsigned int orc_num_entries =0 ;#endif - shstrndx =r2 (&ehdr->e_shstrndx); + shstrndx =r2 (&ehdr->etype.e_shstrndx);if (shstrndx ==SHN_XINDEX ) shstrndx =r (&shdr[0 ].sh_link); secstrings = (const char *)ehdr +_r (&shdr[shstrndx].sh_offset); - shnum =r2 (&ehdr->e_shnum); + shnum =r2 (&ehdr->etype.e_shnum);if (shnum ==SHN_UNDEF ) shnum =_r (&shdr[0 ].sh_size);
Greg Kroah-Hartman
maintainerPATCH 76/175 eventpoll: use hlist_is_singular_node() in __ep_remove()
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Christian Brauner <[email protected]>
[ Upstream commit 3d9fd0abc94d8cd430cc7cd7d37ce5e5aae2cd2b ]
Replace the open-coded "epi is the only entry in file->f_ep" check with hlist_is_singular_node(). Same semantics, and the helper avoids the head-cacheline access in the common false case.
Stable-dep-of: a6dc643c6931 ("eventpoll: fix ep_remove struct eventpoll / struct file UAF")
--- fs/eventpoll.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
fs/eventpoll.c +1 -1
@@ -745,7 +745,7 @@ static bool __ep_remove(struct eventpoll *ep, struct epitem *epi, bool force) to_free =NULL ; head = file->f_ep; -if (head->first == &epi->fllink && !epi->fllink.next) { +if (hlist_is_singular_node (&epi->fllink, head)) {/* See eventpoll_release() for details. */ WRITE_ONCE (file->f_ep,NULL );if (!is_file_epoll (file)) {
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 77/175 eventpoll: split __ep_remove()
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Christian Brauner <[email protected]>
[ Upstream commit 0f7bdfd413000985de09fc39eb9efa1e091a3ce0 ]
Split __ep_remove() to delineate file removal from epoll item removal.
Stable-dep-of: a6dc643c6931 ("eventpoll: fix ep_remove struct eventpoll / struct file UAF")
--- fs/eventpoll.c | 27 +++++++++++++++++++++++---- 1 file changed, 23 insertions(+), 4 deletions(-)
fs/eventpoll.c +23 -4
@@ -715,6 +715,9 @@ static void ep_free(struct eventpoll *ep)kfree_rcu (ep, rcu); } +static void __ep_remove_file (struct eventpoll *ep,struct epitem *epi,struct file *file); +static bool __ep_remove_epi (struct eventpoll *ep,struct epitem *epi); +/* * Removes a "struct epitem" from the eventpoll RB tree and deallocates * all the associated resources. Must be called with "mtx" held.
@@ -726,8 +729,6 @@ static void ep_free(struct eventpoll *ep)static bool __ep_remove (struct eventpoll *ep,struct epitem *epi,bool force) {struct file *file = epi->ffd.file; -struct epitems_head *to_free; -struct hlist_head *head;lockdep_assert_irqs_enabled ();
@@ -743,8 +744,21 @@ static bool __ep_remove(struct eventpoll *ep, struct epitem *epi, bool force)return false; } - to_free =NULL ; - head = file->f_ep; +__ep_remove_file (ep, epi, file); +return __ep_remove_epi (ep, epi); +} + +/* +* Called with &file->f_lock held, +* returns with it released +*/ +static void __ep_remove_file (struct eventpoll *ep,struct epitem *epi,struct file *file) +{ +struct epitems_head *to_free =NULL ; +struct hlist_head *head = file->f_ep; + +lockdep_assert_held (&ep->mtx); +if (hlist_is_singular_node (&epi->fllink, head)) {/* See eventpoll_release() for details. */ WRITE_ONCE (file->f_ep,NULL );
@@ -758,6 +772,11 @@ static bool __ep_remove(struct eventpoll *ep, struct epitem *epi, bool force)hlist_del_rcu (&epi->fllink);spin_unlock (&file->f_lock);free_ephead (to_free); +} + +static bool __ep_remove_epi (struct eventpoll *ep,struct epitem *epi) +{ +lockdep_assert_held (&ep->mtx);rb_erase_cached (&epi->rbn, &ep->rbr);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 78/175 eventpoll: kill __ep_remove()
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Christian Brauner <[email protected]>
[ Upstream commit e9e5cd40d7c403e19f21d0f7b8b8ba3a76b58330 ]
Remove the boolean conditional in __ep_remove() and restructure the code so the check for racing with eventpoll_release_file() are only done in the ep_remove_safe() path where they belong.
Stable-dep-of: a6dc643c6931 ("eventpoll: fix ep_remove struct eventpoll / struct file UAF")
--- fs/eventpoll.c | 67 ++++++++++++++++++++++---------------------------- 1 file changed, 30 insertions(+), 37 deletions(-)
fs/eventpoll.c +30 -37
@@ -715,49 +715,18 @@ static void ep_free(struct eventpoll *ep)kfree_rcu (ep, rcu); } -static void __ep_remove_file (struct eventpoll *ep,struct epitem *epi,struct file *file); -static bool __ep_remove_epi (struct eventpoll *ep,struct epitem *epi); - -/* -* Removes a "struct epitem" from the eventpoll RB tree and deallocates -* all the associated resources. Must be called with "mtx" held. -* If the dying flag is set, do the removal only if force is true. -* This prevents ep_clear_and_put() from dropping all the ep references -* while running concurrently with eventpoll_release_file(). -* Returns true if the eventpoll can be disposed. -*/ -static bool __ep_remove (struct eventpoll *ep,struct epitem *epi,bool force) -{ -struct file *file = epi->ffd.file; - -lockdep_assert_irqs_enabled (); - -/* -* Removes poll wait queue hooks. -*/ -ep_unregister_pollwait (ep, epi); - -/* Remove the current item from the list of epoll hooks */ -spin_lock (&file->f_lock); -if (epi->dying && !force) { -spin_unlock (&file->f_lock); -return false; - } - -__ep_remove_file (ep, epi, file); -return __ep_remove_epi (ep, epi); -} -/* * Called with &file->f_lock held, * returns with it released */ -static void __ep_remove_file (struct eventpoll *ep,struct epitem *epi,struct file *file) +static void __ep_remove_file (struct eventpoll *ep,struct epitem *epi, +struct file *file) {struct epitems_head *to_free =NULL ;struct hlist_head *head = file->f_ep;lockdep_assert_held (&ep->mtx); +lockdep_assert_held (&file->f_lock);if (hlist_is_singular_node (&epi->fllink, head)) {/* See eventpoll_release() for details. */
@@ -804,7 +773,25 @@ static bool __ep_remove_epi(struct eventpoll *ep, struct epitem *epi)*/ static void ep_remove_safe (struct eventpoll *ep,struct epitem *epi) { -if (__ep_remove (ep, epi, false)) +struct file *file = epi->ffd.file; + +lockdep_assert_irqs_enabled (); +lockdep_assert_held (&ep->mtx); + +ep_unregister_pollwait (ep, epi); + +/* sync with eventpoll_release_file() */ +if (unlikely (READ_ONCE (epi->dying))) +return ; + +spin_lock (&file->f_lock); +if (epi->dying) { +spin_unlock (&file->f_lock); +return ; + } +__ep_remove_file (ep, epi, file); + +if (__ep_remove_epi (ep, epi))WARN_ON_ONCE (ep_refcount_dec_and_test (ep)); }
@@ -1013,7 +1000,7 @@ void eventpoll_release_file(struct file *file)spin_lock (&file->f_lock);if (file->f_ep && file->f_ep->first) { epi = hlist_entry(file->f_ep->first, struct epitem, fllink); - epi->dying = true; +WRITE_ONCE (epi->dying, true);spin_unlock (&file->f_lock);/*
@@ -1022,7 +1009,13 @@ void eventpoll_release_file(struct file *file)*/ ep = epi->ep;mutex_lock (&ep->mtx); - dispose =__ep_remove (ep, epi, true); + +ep_unregister_pollwait (ep, epi); + +spin_lock (&file->f_lock); +__ep_remove_file (ep, epi, file); + dispose =__ep_remove_epi (ep, epi); +mutex_unlock (&ep->mtx);if (dispose &&ep_refcount_dec_and_test (ep))
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 79/175 eventpoll: drop vestigial __ prefix from ep_remove_{file,epi}()
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Christian Brauner <[email protected]>
[ Upstream commit 0feaf644f7180c4a91b6b405a881afbfd958f1cf ]
With __ep_remove() gone, the double-underscore on __ep_remove_file() and __ep_remove_epi() no longer contrasts with a __-less parent and just reads as noise. Rename both to ep_remove_file() and ep_remove_epi(). No functional change.
Stable-dep-of: a6dc643c6931 ("eventpoll: fix ep_remove struct eventpoll / struct file UAF")
--- fs/eventpoll.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-)
fs/eventpoll.c +6 -6
@@ -719,7 +719,7 @@ static void ep_free(struct eventpoll *ep)* Called with &file->f_lock held, * returns with it released */ -static void __ep_remove_file (struct eventpoll *ep,struct epitem *epi, +static void ep_remove_file (struct eventpoll *ep,struct epitem *epi,struct file *file) {struct epitems_head *to_free =NULL ;
@@ -743,7 +743,7 @@ static void __ep_remove_file(struct eventpoll *ep, struct epitem *epi,free_ephead (to_free); } -static bool __ep_remove_epi (struct eventpoll *ep,struct epitem *epi) +static bool ep_remove_epi (struct eventpoll *ep,struct epitem *epi) {lockdep_assert_held (&ep->mtx);
@@ -789,9 +789,9 @@ static void ep_remove_safe(struct eventpoll *ep, struct epitem *epi)spin_unlock (&file->f_lock);return ; } -__ep_remove_file (ep, epi, file); +ep_remove_file (ep, epi, file); -if (__ep_remove_epi (ep, epi)) +if (ep_remove_epi (ep, epi))WARN_ON_ONCE (ep_refcount_dec_and_test (ep)); }
@@ -1013,8 +1013,8 @@ void eventpoll_release_file(struct file *file)ep_unregister_pollwait (ep, epi);spin_lock (&file->f_lock); -__ep_remove_file (ep, epi, file); - dispose =__ep_remove_epi (ep, epi); +ep_remove_file (ep, epi, file); + dispose =ep_remove_epi (ep, epi);mutex_unlock (&ep->mtx);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 80/175 eventpoll: rename ep_remove_safe() back to ep_remove()
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Christian Brauner <[email protected]>
[ Upstream commit 0bade234723e40e4937be912e105785d6a51464e ]
The current name is just confusing and doesn't clarify anything.
Stable-dep-of: a6dc643c6931 ("eventpoll: fix ep_remove struct eventpoll / struct file UAF")
--- fs/eventpoll.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-)
fs/eventpoll.c +8 -8
@@ -771,7 +771,7 @@ static bool ep_remove_epi(struct eventpoll *ep, struct epitem *epi)/* * ep_remove variant for callers owing an additional reference to the ep */ -static void ep_remove_safe (struct eventpoll *ep,struct epitem *epi) +static void ep_remove (struct eventpoll *ep,struct epitem *epi) {struct file *file = epi->ffd.file;
@@ -818,7 +818,7 @@ static void ep_clear_and_put(struct eventpoll *ep)/* * Walks through the whole tree and try to free each "struct epitem". -* Note that ep_remove_safe() will not remove the epitem in case of a +* Note that ep_remove() will not remove the epitem in case of a * racing eventpoll_release_file(); the latter will do the removal. * At this point we are sure no poll callbacks will be lingering around. * Since we still own a reference to the eventpoll struct, the loop can't
@@ -827,7 +827,7 @@ static void ep_clear_and_put(struct eventpoll *ep)for (rbp =rb_first_cached (&ep->rbr); rbp; rbp = next) { next =rb_next (rbp); epi = rb_entry(rbp, struct epitem, rbn); -ep_remove_safe (ep, epi); +ep_remove (ep, epi);cond_resched (); }
@@ -1497,21 +1497,21 @@ static int ep_insert(struct eventpoll *ep, const struct epoll_event *event,mutex_unlock (&tep->mtx);/* -* ep_remove_safe() calls in the later error paths can't lead to +* ep_remove() calls in the later error paths can't lead to * ep_free() as the ep file itself still holds an ep reference. */ ep_get (ep);/* now check if we've created too many backpaths */ if (unlikely (full_check &&reverse_path_check ())) { -ep_remove_safe (ep, epi); +ep_remove (ep, epi);return -EINVAL ; }if (epi->event.events &EPOLLWAKEUP ) { error =ep_create_wakeup_source (epi);if (error) { -ep_remove_safe (ep, epi); +ep_remove (ep, epi);return error; } }
@@ -1535,7 +1535,7 @@ static int ep_insert(struct eventpoll *ep, const struct epoll_event *event,* high memory pressure. */ if (unlikely (!epq.epi)) { -ep_remove_safe (ep, epi); +ep_remove (ep, epi);return -ENOMEM ; }
@@ -2227,7 +2227,7 @@ int do_epoll_ctl(int epfd, int op, int fd, struct epoll_event *epds,* The eventpoll itself is still alive: the refcount * can't go to zero here. */ -ep_remove_safe (ep, epi); +ep_remove (ep, epi); error =0 ; }else { error = -ENOENT ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 81/175 eventpoll: move epi_fget() up
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Christian Brauner <[email protected]>
[ Upstream commit 86e87059e6d1fd5115a31949726450ed03c1073b ]
We'll need it when removing files so move it up. No functional change.
Stable-dep-of: a6dc643c6931 ("eventpoll: fix ep_remove struct eventpoll / struct file UAF") [file_ref_get(&file->f_ref) from original commit left as
atomic_long_inc_not_zero(&file->f_count) due to v6.12.y missing commit 90ee6ed776c0 ("fs: port files to file_ref") and its dependent commit 08ef26ea9ab3 ("fs: add file_ref")]
--- fs/eventpoll.c | 56 +++++++++++++++++++++++++------------------------- 1 file changed, 28 insertions(+), 28 deletions(-)
fs/eventpoll.c +28 -28
@@ -715,6 +715,34 @@ static void ep_free(struct eventpoll *ep)kfree_rcu (ep, rcu); } +/* +* The ffd.file pointer may be in the process of being torn down due to +* being closed, but we may not have finished eventpoll_release() yet. +* +* Normally, even with the atomic_long_inc_not_zero, the file may have +* been free'd and then gotten re-allocated to something else (since +* files are not RCU-delayed, they are SLAB_TYPESAFE_BY_RCU). +* +* But for epoll, users hold the ep->mtx mutex, and as such any file in +* the process of being free'd will block in eventpoll_release_file() +* and thus the underlying file allocation will not be free'd, and the +* file re-use cannot happen. +* +* For the same reason we can avoid a rcu_read_lock() around the +* operation - 'ffd.file' cannot go away even if the refcount has +* reached zero (but we must still not call out to ->poll() functions +* etc). +*/ +static struct file *epi_fget (const struct epitem *epi) +{ +struct file *file; + + file = epi->ffd.file; +if (!atomic_long_inc_not_zero (&file->f_count)) + file =NULL ; +return file; +} +/* * Called with &file->f_lock held, * returns with it released
@@ -886,34 +914,6 @@ static __poll_t __ep_eventpoll_poll(struct file *file, poll_table *wait, int depreturn res; } -/* -* The ffd.file pointer may be in the process of being torn down due to -* being closed, but we may not have finished eventpoll_release() yet. -* -* Normally, even with the atomic_long_inc_not_zero, the file may have -* been free'd and then gotten re-allocated to something else (since -* files are not RCU-delayed, they are SLAB_TYPESAFE_BY_RCU). -* -* But for epoll, users hold the ep->mtx mutex, and as such any file in -* the process of being free'd will block in eventpoll_release_file() -* and thus the underlying file allocation will not be free'd, and the -* file re-use cannot happen. -* -* For the same reason we can avoid a rcu_read_lock() around the -* operation - 'ffd.file' cannot go away even if the refcount has -* reached zero (but we must still not call out to ->poll() functions -* etc). -*/ -static struct file *epi_fget (const struct epitem *epi) -{ -struct file *file; - - file = epi->ffd.file; -if (!atomic_long_inc_not_zero (&file->f_count)) - file =NULL ; -return file; -} -/* * Differs from ep_eventpoll_poll() in that internal callers already have * the ep->mtx so we need to start from depth=1, such that mutex_lock_nested()
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 82/175 eventpoll: fix ep_remove struct eventpoll / struct file UAF
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Christian Brauner <[email protected]>
[ Upstream commit a6dc643c69311677c574a0f17a3f4d66a5f3744b ]
ep_remove() (via ep_remove_file()) cleared file->f_ep under file->f_lock but then kept using @file inside the critical section (is_file_epoll(), hlist_del_rcu() through the head, spin_unlock). A concurrent __fput() taking the eventpoll_release() fastpath in that window observed the transient NULL, skipped eventpoll_release_file() and ran to f_op->release / file_free().
For the epoll-watches-epoll case, f_op->release is ep_eventpoll_release() -> ep_clear_and_put() -> ep_free(), which kfree()s the watched struct eventpoll. Its embedded ->refs hlist_head is exactly where epi->fllink.pprev points, so the subsequent hlist_del_rcu()'s "*pprev = next" scribbles into freed kmalloc-192 memory.
In addition, struct file is SLAB_TYPESAFE_BY_RCU, so the slot backing @file could be recycled by alloc_empty_file() -- reinitializing f_lock and f_ep -- while ep_remove() is still nominally inside that lock. The upshot is an attacker-controllable kmem_cache_free() against the wrong slab cache.
Pin @file via epi_fget() at the top of ep_remove() and gate the critical section on the pin succeeding. With the pin held @file cannot reach refcount zero, which holds __fput() off and transitively keeps the watched struct eventpoll alive across the hlist_del_rcu() and the f_lock use, closing both UAFs.
If the pin fails @file has already reached refcount zero and its __fput() is in flight. Because we bailed before clearing f_ep, that path takes the eventpoll_release() slow path into eventpoll_release_file() and blocks on ep->mtx until the waiter side's ep_clear_and_put() drops it. The bailed epi's share of ep->refcount stays intact, so the trailing ep_refcount_dec_and_test() in ep_clear_and_put() cannot free the eventpoll out from under eventpoll_release_file(); the orphaned epi is then cleaned up there.
A successful pin also proves we are not racing eventpoll_release_file() on this epi, so drop the now-redundant re-check of epi->dying under f_lock. The cheap lockless READ_ONCE(epi->dying) fast-path bailout stays.
--- fs/eventpoll.c | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-)
fs/eventpoll.c +10 -6
@@ -801,22 +801,26 @@ static bool ep_remove_epi(struct eventpoll *ep, struct epitem *epi)*/ static void ep_remove (struct eventpoll *ep,struct epitem *epi) { -struct file *file = epi->ffd.file; + struct file *file __free(fput) = NULL;lockdep_assert_irqs_enabled ();lockdep_assert_held (&ep->mtx);ep_unregister_pollwait (ep, epi); -/* sync with eventpoll_release_file() */ +/* cheap sync with eventpoll_release_file() */ if (unlikely (READ_ONCE (epi->dying)))return ; -spin_lock (&file->f_lock); -if (epi->dying) { -spin_unlock (&file->f_lock); +/* +* If we manage to grab a reference it means we're not in +* eventpoll_release_file() and aren't going to be. +*/ + file =epi_fget (epi); +if (!file)return ; - } + +spin_lock (&file->f_lock);ep_remove_file (ep, epi, file);if (ep_remove_epi (ep, epi))
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 83/175 KVM: x86: Fix shadow paging use-after-free due to unexpected role
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Paolo Bonzini <[email protected]>
commit 81ccda30b4e83d8f5cc4fd50503c44e3a33abfeb upstream.
Commit 0cb2af2ea66ad ("KVM: x86: Fix shadow paging use-after-free due to unexpected GFN") fixed a shadow paging mismatch between stored and computed GFNs; the bug could be triggered by changing a PDE mapping from outside the guest, and then deleting a memslot. The rmap_remove() call would miss entries created after the PDE change because the GFN of the leaf SPTE does not match the GFN of the struct kvm_mmu_page.
A similar hole however remains if the modified PDE points to a non-leaf page. In this case the gfn can be made to match, but the role does not
match: the original large 2MB page creates a kvm_mmu_page with direct=1, while the new 4KB needs a kvm_mmu_page with direct=0. However, kvm_mmu_get_child_sp() does not compare the role, and therefore reuses the page.
The next step is installing a leaf (4KB) SPTE on the new path which records an rmap entry under the gfn resolved by the walk. But when that child is zapped its parent kvm_mmu_page has direct=1 and kvm_mmu_page_get_gfn() computes the gfn for the 4KB page as sp->gfn + index instead of using sp->shadowed_translation[] (or sp->gfns[] in older kernels). It therefore fails to remove the recorded entry.
When the memslot is dropped the shadow page is freed but the rmap entry survives, as in the scenario that was already fixed. Code that later walks that gfn (dirty logging, MMU notifier invalidation, and so on) dereferences an sptep that lies in the freed page, causing the use-after-free.
--- arch/x86/kvm/mmu/mmu.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-)
arch/x86/kvm/mmu/mmu.c +6 -4
@@ -2337,13 +2337,15 @@ static struct kvm_mmu_page *kvm_mmu_get_child_sp(struct kvm_vcpu *vcpu, u64 *sptep, gfn_t gfn, bool direct, unsigned int access) { - union kvm_mmu_page_role role; + union kvm_mmu_page_role role = kvm_mmu_child_role(sptep, direct, access); -if (is_shadow_present_pte (*sptep) && !is_large_pte (*sptep) && -spte_to_child_sp (*sptep) &&spte_to_child_sp (*sptep)->gfn == gfn) +if (is_shadow_present_pte (*sptep) && + !is_large_pte (*sptep) && +spte_to_child_sp (*sptep) && +spte_to_child_sp (*sptep)->gfn == gfn && +spte_to_child_sp (*sptep)->role.word == role.word)return ERR_PTR (-EEXIST ); - role =kvm_mmu_child_role (sptep, direct, access);return kvm_mmu_get_shadow_page (vcpu, gfn, role); }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 84/175 KVM: x86/mmu: Ensure hugepage is in by slot before checking max mapping level
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Sean Christopherson <[email protected]>
commit ef057cbf825e03b63f6edf5980f96abf3c53089d upstream.
When recovering hugepages in the shadow MMU, verify that the base gfn of the shadow page is actually contained within the target memslot, *before* querying the max mapping level given the shadow page's gfn. Failure to pre-check the validity of the gfn can lead to an out-of-bounds access to the slot's lpage_info (which typically manifests as a host #PF because the lpage_info is vmalloc'd) if the guest creates a hugepage mapping (in its PTEs) that extends "below" the bounds of a memslot.
When faulting in memory for a guest, and the size of the guest mapping is greater than KVM's (current) max mapping, then KVM will create a "direct" shadow page (direct in that there are no gPTEs to shadow, and so the target gfn is a direct calculation given the base gfn of the shadow page). The hugepage recovery flow looks for such direct shadow pages, as forcing 4KiB mappings when dirty logging generates the guest > host mapping size case. When the 4KiB restriction is lifted, then KVM can replace the shadow page with a hugepage.
But if KVM originally used a smaller mapping than the guest because the range of memory covered by the guest hugepage exceeds the bounds of a memslot, then KVM will link a direct shadow page with a gfn that is outside the bounds of the memslot being used to fault in memory. The rmap entry added for the leaf mapping is correct and within bounds, but the gfn of the leaf SPTE's parent shadow page will be out of bounds.
BUG: unable to handle page fault for address: ffffc90000806ffc #PF: supervisor read access in kernel mode #PF: error_code(0x0000) - not-present page PGD 100000067 P4D 100000067 PUD 1002a7067 PMD 10612f067 PTE 0 Oops: Oops: 0000 [#1] SMP CPU: 13 UID: 1000 PID: 757 Comm: mmu_stress_test Not tainted 7.1.0-rc1-48ce1e26eace-x86_pir_to_irr_comments-vm #341 PREEMPT Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS 0.0.0 02/06/2015 RIP: 0010:kvm_mmu_max_mapping_level+0x79/0x2b0 [kvm] Call Trace: <TASK> kvm_mmu_recover_huge_pages+0x21b/0x320 [kvm] kvm_set_memslot+0x1ee/0x590 [kvm] kvm_set_memory_region.part.0+0x3a1/0x4d0 [kvm] kvm_vm_ioctl+0x9bf/0x15d0 [kvm] __x64_sys_ioctl+0x8a/0xd0 do_syscall_64+0xb7/0xbb0 entry_SYSCALL_64_after_hwframe+0x4b/0x53 RIP: 0033:0x7f21c0f1a9bf </TASK>
Don't bother pre-checking the bounds of the potential hugepage, i.e. don't check that e.g. sp->gfn + KVM_PAGES_PER_HPAGE(sp->role.level + 1) is also within the memslot, as the checks performed by kvm_mmu_max_mapping_level() are a superset of the basic bounds checks. I.e. pre-checking the full range would be a dubious micro-optimization.
--- arch/x86/kvm/mmu/mmu.c | 18 ++++++++++++------ include/linux/kvm_host.h | 7 ++++++- 2 files changed, 18 insertions(+), 7 deletions(-)
arch/x86/kvm/mmu/mmu.c +12 -6
@@ -6582,13 +6582,19 @@ static bool kvm_mmu_zap_collapsible_spte(struct kvm *kvm, sp =sptep_to_sp (sptep);/* -* We cannot do huge page mapping for indirect shadow pages, -* which are found on the last rmap (level = 1) when not using -* tdp; such shadow pages are synced with the page table in -* the guest, and the guest page table is using 4K page size -* mapping if the indirect sp has level = 1. +* Direct shadow page can be replaced by a hugepage if the host +* mapping level allows it and the memslot maps all of the host +* hugepage. Note! If the memslot maps only part of the +* hugepage, sp->gfn may be below slot->base_gfn, and querying +* the max mapping level would cause an out-of-bounds lpage_info +* access. So the gfn bounds check *must* be done first. +* +* Indirect shadow pages are created when the guest page tables +* are using 4K pages. Since the host mapping is always +* constrained by the page size in the guest, indirect shadow +* pages are never collapsible. */ -if (sp->role.direct && +if (sp->role.direct &&is_gfn_in_memslot (slot, sp->gfn) && sp->role.level <kvm_mmu_max_mapping_level (kvm, slot, sp->gfn,PG_LEVEL_NUM )) {kvm_zap_one_rmap_spte (kvm, rmap_head, sptep);
include/linux/kvm_host.h +6 -1
@@ -1650,6 +1650,11 @@ int kvm_request_irq_source_id(struct kvm *kvm);void kvm_free_irq_source_id (struct kvm *kvm,int irq_source_id);bool kvm_arch_irqfd_allowed (struct kvm *kvm,struct kvm_irqfd *args); +static inline bool is_gfn_in_memslot (const struct kvm_memory_slot *slot,gfn_t gfn) +{ +return gfn >= slot->base_gfn && gfn < slot->base_gfn + slot->npages; +} +/* * Returns a pointer to the memslot if it contains gfn. * Otherwise returns NULL.
@@ -1660,7 +1665,7 @@ try_get_memslot(struct kvm_memory_slot *slot, gfn_t gfn)if (!slot)return NULL ; -if (gfn >= slot->base_gfn && gfn < slot->base_gfn + slot->npages) +if (is_gfn_in_memslot (slot, gfn))return slot;else return NULL ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 85/175 Revert "ptp: add testptp mask test"
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Petr Machata <[email protected]>
This reverts commit 59ac47a0275fcd5a7637c3d5da20b0905563c7f5, which is commit 26285e689c6cd2cf3849568c83b2ebe53f467143 upstream.
The reverted commit extends the selftest to test timestamp event queue mask manipulation in testptp. It exercises masks PTP_MASK_CLEAR_ALL and PTP_MASK_EN_SINGLE, introduced in commit c5a445b1e934 ("ptp: support event queue reader channel masks"), which is not on this stable branch. The test case thus cannot be built against this tree's own UAPI headers.
The reverted commit was introduced to resolve a missing dependency of commit 8d9f22c570ba ("testptp: Add option to open PHC in readonly mode"), which is 76868642e427 upstream. The only conflict between the two is the getopt string, and there is otherwise no direct dependency between the two.
This patch therefore reverts the cited commit, with hand-resolving the getopt string to include 'r' (as introduced by c6dc458227a3), but not 'F' (introduced by c1c50689799d).
--- tools/testing/selftests/ptp/testptp.c | 19 +------------------ 1 file changed, 1 insertion(+), 18 deletions(-)
tools/testing/selftests/ptp/testptp.c +1 -18
@@ -121,7 +121,6 @@ static void usage(char *progname)" -d name device to open\n" " -e val read 'val' external time stamp events\n" " -f val adjust the ptp clock frequency by 'val' ppb\n" -" -F chan Enable single channel mask and keep device open for debugfs verification.\n" " -g get the ptp clock time\n" " -h prints this message\n" " -i val index for event/trigger\n"
@@ -190,7 +189,6 @@ int main(int argc, char *argv[])int seconds =0 ;int readonly =0 ;int settime =0 ; -int channel =-1 ;int64_t t1, t2, tp;int64_t interval, offset;
@@ -200,7 +198,7 @@ int main(int argc, char *argv[]) progname =strrchr (argv[0 ],'/' ); progname = progname ?1 +progname : argv[0 ]; -while (EOF != (c =getopt (argc, argv,"cd:e:f:F:ghH:i:k:lL:n:o:p:P:rsSt:T:w:x:Xz" ))) { +while (EOF != (c =getopt (argc, argv,"cd:e:f:ghH:i:k:lL:n:o:p:P:rsSt:T:w:x:Xz" ))) {switch (c) {case 'c' : capabilities =1 ;
@@ -214,9 +212,6 @@ int main(int argc, char *argv[])case 'f' : adjfreq =atoi (optarg);break ; -case 'F' : - channel =atoi (optarg); -break ;case 'g' : gettime =1 ;break ;
@@ -618,18 +613,6 @@ int main(int argc, char *argv[])free (xts); } -if (channel >=0 ) { -if (ioctl (fd,PTP_MASK_CLEAR_ALL )) { -perror ("PTP_MASK_CLEAR_ALL" ); - }else if (ioctl (fd,PTP_MASK_EN_SINGLE , (unsigned int *)&channel)) { -perror ("PTP_MASK_EN_SINGLE" ); - }else { -printf ("Channel %d exclusively enabled. Check on debugfs.\n" , channel); -printf ("Press any key to continue\n." ); -getchar (); - } - } -close (fd);return 0 ; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 50/175 scripts/sorttable: Replace Elf_Shdr Macro with a union
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Steven Rostedt <[email protected]>
[ Upstream commit 545f6cf8f4c9a268e0bab2637f1d279679befdbf ]
In order to remove the double #include of sorttable.h for 64 and 32 bit to create duplicate functions for both, replace the Elf_Shdr macro with a union that defines both Elf64_Shdr and Elf32_Shdr, with field e64 for the 64bit version, and e32 for the 32bit version.
It can then use the macro etype to get the proper value.
This will eventually be replaced with just single functions that can handle both 32bit and 64bit ELF parsing.
--- scripts/sorttable.c | 10 +++++++ scripts/sorttable.h | 74 ++++++++++++++++++++++++++++------------------------ 2 files changed, 51 insertions(+), 33 deletions(-)
scripts/sorttable.c +10 -0
@@ -69,6 +69,11 @@ typedef union {Elf64_Ehdr e64; } Elf_Ehdr; +typedef union { +Elf32_Shdr e32; +Elf64_Shdr e64; +}Elf_Shdr ; +static uint32_t (*r)(const uint32_t *);static uint16_t (*r2)(const uint16_t *);static uint64_t (*r8)(const uint64_t *);
@@ -198,6 +203,11 @@ static int compare_extable_64(const voidreturn av > bv; } +static inline void *get_index (void *start,int entsize,int index) +{ +return start + (entsize * index); +} +/* 32 bit and 64 bit are very similar */ #include "sorttable.h" #define SORTTABLE_64
scripts/sorttable.h +41 -33
170 lines not on this page · raw message
Greg Kroah-Hartman
maintainerPATCH 86/175 Bluetooth: btmtk: validate WMT event SKB length before struct access
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Tristan Madani <[email protected]>
[ Upstream commit 634a4408c0615c523cf7531790f4f14a422b9206 ]
btmtk_usb_hci_wmt_sync() casts the WMT event response SKB data to struct btmtk_hci_wmt_evt (7 bytes) and struct btmtk_hci_wmt_evt_funcc (9 bytes) without first checking that the SKB contains enough data. A short firmware response causes out-of-bounds reads from SKB tailroom.
Use skb_pull_data() to validate and advance past the base WMT event header. For the FUNC_CTRL case, pull the additional status field bytes before accessing them.
--- drivers/bluetooth/btmtk.c | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-)
drivers/bluetooth/btmtk.c +13 -2
@@ -655,8 +655,13 @@ int btmtk_usb_hci_wmt_sync(struct hci_dev *hdev,if (data->evt_skb ==NULL ) goto err_free_wc; -/* Parse and handle the return WMT event */ - wmt_evt = (struct btmtk_hci_wmt_evt *)data->evt_skb->data; + wmt_evt =skb_pull_data (data->evt_skb,sizeof (*wmt_evt)); +if (!wmt_evt) { +bt_dev_err (hdev,"WMT event too short (%u bytes)" , + data->evt_skb->len); + err = -EINVAL ; + goto err_free_skb; + }if (wmt_evt->whdr.op != hdr->op) {bt_dev_err (hdev,"Wrong op received %d expected %d" , wmt_evt->whdr.op, hdr->op);
@@ -672,6 +677,12 @@ int btmtk_usb_hci_wmt_sync(struct hci_dev *hdev, status =BTMTK_WMT_PATCH_DONE ;break ;case BTMTK_WMT_FUNC_CTRL : +if (!skb_pull_data (data->evt_skb, +sizeof (wmt_evt_funcc->status))) { + err = -EINVAL ; + goto err_free_skb; + } + wmt_evt_funcc = (struct btmtk_hci_wmt_evt_funcc *)wmt_evt;if (be16_to_cpu (wmt_evt_funcc->status) ==0x404 ) status =BTMTK_WMT_ON_DONE ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 87/175 Bluetooth: btmtk: accept too short WMT FUNC_CTRL events
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Pauli Virtanen <[email protected]>
[ Upstream commit e3ac0d9f1a205f33a43fba3b79ef74d2f604c78b ]
MT7925 (USB ID 0e8d:e025) on fw version 20260106153314 sends WMT FUNC_CTRL events that are missing the status field.
Prior to commit 006b9943b982 ("Bluetooth: btmtk: validate WMT event SKB length before struct access") the status was read from out-of-bounds of SKB data, which usually would result to success with BTMTK_WMT_ON_UNDONE, although I don't know the intent here. The bounds check added in that commit returns with error instead, producing "Bluetooth: hci0: Failed to send wmt func ctrl (-22)" and makes the device unusable.
Fix the regression by interpreting too short packet as status BTMTK_WMT_ON_UNDONE, which makes the device work normally again.
--- drivers/bluetooth/btmtk.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
drivers/bluetooth/btmtk.c +2 -2
@@ -679,8 +679,8 @@ int btmtk_usb_hci_wmt_sync(struct hci_dev *hdev,case BTMTK_WMT_FUNC_CTRL :if (!skb_pull_data (data->evt_skb,sizeof (wmt_evt_funcc->status))) { - err = -EINVAL ; - goto err_free_skb; + status =BTMTK_WMT_ON_UNDONE ; +break ; } wmt_evt_funcc = (struct btmtk_hci_wmt_evt_funcc *)wmt_evt;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 88/175 fs: prepare for adding LSM blob to backing_file
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Amir Goldstein <[email protected]>
[ Upstream commit 880bd496ec72a6dcb00cb70c430ef752ba242ae7 ]
In preparation to adding LSM blob to backing_file struct, factor out helpers init_backing_file() and backing_file_free().
[1. The commit def3ae83da02
("fs: store real path instead of fake path in backing file f_path") is not merged, The 6.6 LTS version accordingly operates on &ff->real_path instead of &ff->user_path.
2. Mainline's file_free() does both the backing_file cleanup and the kmem_cache_free() synchronously. Linux 6.6.y defers the actual kfree() to file_free_rcu() via call_rcu(), so only path_put() is done synchronously in file_free().]
--- fs/file_table.c | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-)
fs/file_table.c +19 -1
@@ -72,11 +72,16 @@ static void file_free_rcu(struct rcu_head *head)kmem_cache_free (filp_cachep, f); } +static inline void backing_file_free (struct backing_file *ff) +{ +path_put (&ff->real_path); +} +static inline void file_free (struct file *f) {security_file_free (f);if (unlikely (f->f_mode &FMODE_BACKING )) -path_put (backing_file_real_path (f)); +backing_file_free (backing_file (f));if (likely (!(f->f_mode &FMODE_NOACCOUNT )))percpu_counter_dec (&nr_files);call_rcu (&f->f_rcuhead, file_free_rcu);
@@ -252,6 +257,12 @@ struct file *alloc_empty_file_noaccount(int flags, const struct cred *cred)return f; } +static int init_backing_file (struct backing_file *ff) +{ +memset (&ff->real_path,0 ,sizeof (ff->real_path)); +return 0 ; +} +/* * Variant of alloc_empty_file() that allocates a backing_file container * and doesn't check and modify nr_files.
@@ -274,7 +285,14 @@ struct file *alloc_empty_backing_file(int flags, const struct cred *cred)return ERR_PTR (error); } +/* The f_mode flags must be set before fput(). */ ff->file.f_mode |=FMODE_BACKING |FMODE_NOACCOUNT ; + error =init_backing_file (ff); +if (unlikely (error)) { +fput (&ff->file); +return ERR_PTR (error); + } +return &ff->file; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 89/175 lsm: add backing_file LSM hooks
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Paul Moore <[email protected]>
[ Upstream commit 6af36aeb147a06dea47c49859cd6ca5659aeb987 ]
Stacked filesystems such as overlayfs do not currently provide the necessary mechanisms for LSMs to properly enforce access controls on the mmap() and mprotect() operations. In order to resolve this gap, a LSM security blob is being added to the backing_file struct and the following new LSM hooks are being created:
security_backing_file_alloc()
security_backing_file_free()
security_mmap_backing_file()
The first two hooks are to manage the lifecycle of the LSM security blob in the backing_file struct, while the third provides a new mmap() access control point for the underlying backing file. It is also expected that LSMs will likely want to update their security_file_mprotect() callback to address issues with their mprotect() controls, but that does not require a change to the security_file_mprotect() LSM hook.
There are a three other small changes to support these new LSM hooks:
* Pass the user file associated with a backing file down to alloc_empty_backing_file() so it can be included in the security_backing_file_alloc() hook.
* Add getter and setter functions for the backing_file struct LSM blob as the backing_file struct remains private to fs/file_table.c.
* Constify the file struct field in the LSM common_audit_data struct to better support LSMs that need to pass a const file struct pointer into the common LSM audit code.
Thanks to Arnd Bergmann for identifying the missing EXPORT_SYMBOL_GPL() and supplying a fixup.
[1. Mainline uses call_int_hook(FUNC, ...) with the default IRC baked into the macro. Linux 6.6.y uses call_int_hook(FUNC, IRC, ...) requiring an explicit default return value.
2. fs/backing-file.c does not exist in LTS
Linux 6.6.y places backing_file_open() in fs/open.c and lacks a dedicated fs/backing-file.c. The backing_file_mmap() function and scoped_with_creds() do not exist in 6.6.y. Therefore the LTS patch calls security_mmap_backing_file() directly in ovl_mmap() in fs/overlayfs/file.c rather than modifying backing_file_mmap().
3. Missing filesystems/modules
Linux 6.6.y does not have backing_tmpfile_open(), fs/fuse/passthrough.c, or the erofs ishare mmap path that the mainline patch touches. These hunks are dropped in the 6.6 LTS backport.
4. Use macro backing_file to replace inline function to eliminate the const warning.]
--- fs/file_table.c | 32 +++++++--- fs/internal.h | 3 +- fs/open.c | 7 ++- fs/overlayfs/file.c | 8 ++- include/linux/fs.h | 15 ++++- include/linux/lsm_audit.h | 2 +- include/linux/lsm_hook_defs.h | 5 ++ include/linux/lsm_hooks.h | 1 + include/linux/security.h | 22 +++++++ security/security.c | 110 ++++++++++++++++++++++++++++++++++ 10 files changed, 190 insertions(+), 15 deletions(-)
fs/file_table.c +24 -8
@@ -48,12 +48,12 @@ static struct percpu_counter nr_files __cacheline_aligned_in_smp;struct backing_file {struct file file;struct path real_path; +#ifdef CONFIG_SECURITY +void *security; +#endif }; -static inline struct backing_file *backing_file (struct file *f) -{ - return container_of(f, struct backing_file, file); -} +#define backing_file (f) container_of(f, struct backing_file, file)struct path *backing_file_real_path (struct file *f) {
@@ -72,8 +72,21 @@ static void file_free_rcu(struct rcu_head *head)kmem_cache_free (filp_cachep, f); } +#ifdef CONFIG_SECURITY +void *backing_file_security (const struct file *f) +{ +return backing_file (f)->security; +} + +void backing_file_set_security (struct file *f,void *security) +{ +backing_file (f)->security = security; +} +#endif /* CONFIG_SECURITY */ +static inline void backing_file_free (struct backing_file *ff) { +security_backing_file_free (&ff->file);path_put (&ff->real_path); }
@@ -257,10 +270,12 @@ struct file *alloc_empty_file_noaccount(int flags, const struct cred *cred)return f; } -static int init_backing_file (struct backing_file *ff) +static int init_backing_file (struct backing_file *ff, +const struct file *user_file) {memset (&ff->real_path,0 ,sizeof (ff->real_path)); -return 0 ; +backing_file_set_security (&ff->file,NULL ); +return security_backing_file_alloc (&ff->file, user_file); }/*
@@ -270,7 +285,8 @@ static int init_backing_file(struct backing_file *ff)* This is only for kernel internal use, and the allocate file must not be * installed into file tables or such. */ -struct file *alloc_empty_backing_file (int flags,const struct cred *cred) +struct file *alloc_empty_backing_file (int flags,const struct cred *cred, +const struct file *user_file) {struct backing_file *ff;int error;
@@ -287,7 +303,7 @@ struct file *alloc_empty_backing_file(int flags, const struct cred *cred)/* The f_mode flags must be set before fput(). */ ff->file.f_mode |=FMODE_BACKING |FMODE_NOACCOUNT ; - error =init_backing_file (ff); + error =init_backing_file (ff, user_file);if (unlikely (error)) {fput (&ff->file);return ERR_PTR (error);
fs/internal.h +2 -1
@@ -93,7 +93,8 @@ extern void chroot_fs_refs(const struct path *, const struct path *);*/ struct file *alloc_empty_file (int flags,const struct cred *cred);struct file *alloc_empty_file_noaccount (int flags,const struct cred *cred); -struct file *alloc_empty_backing_file (int flags,const struct cred *cred); +struct file *alloc_empty_backing_file (int flags,const struct cred *cred, +const struct file *user_file);static inline void put_file_access (struct file *file) {
fs/open.c +4 -3
@@ -1175,18 +1175,19 @@ EXPORT_SYMBOL_GPL(kernel_file_open);* the backing inode on the underlying filesystem, which can be * retrieved using backing_file_real_path(). */ -struct file *backing_file_open (const struct path *path,int flags, +struct file *backing_file_open (const struct file *user_file,int flags,const struct path *real_path,const struct cred *cred) { +const struct path *user_path = &user_file->f_path;struct file *f;int error; - f =alloc_empty_backing_file (flags, cred); + f =alloc_empty_backing_file (flags, cred, user_file);if (IS_ERR (f))return f; - f->f_path = *path; + f->f_path = *user_path;path_get (real_path); *backing_file_real_path (f) = *real_path; error =do_dentry_open (f,d_inode (real_path->dentry),NULL );
fs/overlayfs/file.c +7 -1
@@ -60,7 +60,7 @@ static struct file *ovl_open_realfile(const struct file *file,if (!inode_owner_or_capable (real_idmap, realinode)) flags &= ~O_NOATIME ; - realfile =backing_file_open (&file->f_path, flags, realpath, + realfile =backing_file_open (file, flags, realpath,current_cred ()); }revert_creds (old_cred);
@@ -527,6 +527,7 @@ static int ovl_fsync(struct file *file, loff_t start, loff_t end, int datasync)static int ovl_mmap (struct file *file,struct vm_area_struct *vma) { +struct file *user_file = vma->vm_file;struct file *realfile = file->private_data;const struct cred *old_cred;int ret;
@@ -540,6 +541,11 @@ static int ovl_mmap(struct file *file, struct vm_area_struct *vma)vma_set_file (vma, realfile); old_cred =ovl_override_creds (file_inode (file)->i_sb); + ret =security_mmap_backing_file (vma, realfile, user_file); +if (ret) { +revert_creds (old_cred); +return ret; + } ret =call_mmap (vma->vm_file, vma);revert_creds (old_cred);ovl_file_accessed (file);
include/linux/fs.h +14 -1
@@ -2515,11 +2515,24 @@ struct file *dentry_open(const struct path *path, int flags, const struct cred *creds);struct file *dentry_create (const struct path *path,int flags,umode_t mode,const struct cred *cred); -struct file *backing_file_open (const struct path *path,int flags, +struct file *backing_file_open (const struct file *user_file,int flags,const struct path *real_path,const struct cred *cred);struct path *backing_file_real_path (struct file *f); +#ifdef CONFIG_SECURITY +void *backing_file_security (const struct file *f); +void backing_file_set_security (struct file *f,void *security); +#else +static inline void *backing_file_security (const struct file *f) +{ +return NULL ; +} +static inline void backing_file_set_security (struct file *f,void *security) +{ +} +#endif /* CONFIG_SECURITY */ +/* * file_real_path - get the path corresponding to f_inode *
include/linux/lsm_audit.h +1 -1
@@ -93,7 +93,7 @@ struct common_audit_data {#endif char *kmod_name;struct lsm_ioctlop_audit *op; -struct file *file; +const struct file *file;struct lsm_ibpkey_audit *ibpkey;struct lsm_ibendport_audit *ibendport;int reason;
include/linux/lsm_hook_defs.h +5 -0
@@ -169,6 +169,9 @@ LSM_HOOK(int, 0, kernfs_init_security, struct kernfs_node *kn_dir, LSM_HOOK(int, 0, file_permission, struct file *file, int mask) LSM_HOOK(int, 0, file_alloc_security, struct file *file) LSM_HOOK(void, LSM_RET_VOID, file_free_security, struct file *file) +LSM_HOOK(int, 0, backing_file_alloc, struct file *backing_file, + const struct file *user_file) +LSM_HOOK(void, LSM_RET_VOID, backing_file_free, struct file *backing_file) LSM_HOOK(int, 0, file_ioctl, struct file *file, unsigned int cmd, unsigned long arg) LSM_HOOK(int, 0, file_ioctl_compat, struct file *file, unsigned int cmd,
@@ -176,6 +179,8 @@ LSM_HOOK(int, 0, file_ioctl_compat, struct file *file, unsigned int cmd, LSM_HOOK(int, 0, mmap_addr, unsigned long addr) LSM_HOOK(int, 0, mmap_file, struct file *file, unsigned long reqprot, unsigned long prot, unsigned long flags) +LSM_HOOK(int, 0, mmap_backing_file, struct vm_area_struct *vma, + struct file *backing_file, struct file *user_file) LSM_HOOK(int, 0, file_mprotect, struct vm_area_struct *vma, unsigned long reqprot, unsigned long prot) LSM_HOOK(int, 0, file_lock, struct file *file, unsigned int cmd)
include/linux/lsm_hooks.h +1 -0
@@ -59,6 +59,7 @@ struct security_hook_list {struct lsm_blob_sizes {int lbs_cred;int lbs_file; +int lbs_backing_file;int lbs_inode;int lbs_superblock;int lbs_ipc;
include/linux/security.h +22 -0
@@ -389,11 +389,17 @@ int security_kernfs_init_security(struct kernfs_node *kn_dir,int security_file_permission (struct file *file,int mask);int security_file_alloc (struct file *file);void security_file_free (struct file *file); +int security_backing_file_alloc (struct file *backing_file, +const struct file *user_file); +void security_backing_file_free (struct file *backing_file);int security_file_ioctl (struct file *file,unsigned int cmd,unsigned long arg);int security_file_ioctl_compat (struct file *file,unsigned int cmd,unsigned long arg);int security_mmap_file (struct file *file,unsigned long prot,unsigned long flags); +int security_mmap_backing_file (struct vm_area_struct *vma, +struct file *backing_file, +struct file *user_file);int security_mmap_addr (unsigned long addr);int security_file_mprotect (struct vm_area_struct *vma,unsigned long reqprot,unsigned long prot);
@@ -984,6 +990,15 @@ static inline int security_file_alloc(struct file *file)static inline void security_file_free (struct file *file) { } +static inline int security_backing_file_alloc (struct file *backing_file, +const struct file *user_file) +{ +return 0 ; +} + +static inline void security_backing_file_free (struct file *backing_file) +{ } +static inline int security_file_ioctl (struct file *file,unsigned int cmd,unsigned long arg) {
@@ -1003,6 +1018,13 @@ static inline int security_mmap_file(struct file *file, unsigned long prot,return 0 ; } +static inline int security_mmap_backing_file (struct vm_area_struct *vma, +struct file *backing_file, +struct file *user_file) +{ +return 0 ; +} +static inline int security_mmap_addr (unsigned long addr) {return cap_mmap_addr (addr);
security/security.c +110 -0
152 lines not on this page · raw message
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 90/175 selinux: fix overlayfs mmap() and mprotect() access checks
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Paul Moore <[email protected]>
[ Upstream commit 82544d36b1729153c8aeb179e84750f0c085d3b1 ]
The existing SELinux security model for overlayfs is to allow access if the current task is able to access the top level file (the "user" file) and the mounter's credentials are sufficient to access the lower level file (the "backing" file). Unfortunately, the current code does not properly enforce these access controls for both mmap() and mprotect() operations on overlayfs filesystems.
This patch makes use of the newly created security_mmap_backing_file() LSM hook to provide the missing backing file enforcement for mmap() operations, and leverages the backing file API and new LSM blob to provide the necessary information to properly enforce the mprotect() access controls.
[backing_file_user_path() not available
Mainline uses backing_file_user_path(file) to obtain the user-visible path from a backing file. The 6.6.y version uses &file->f_path directly]
--- security/selinux/hooks.c | 242 ++++++++++++++++++++++-------- security/selinux/include/objsec.h | 11 ++ 2 files changed, 189 insertions(+), 64 deletions(-)
security/selinux/hooks.c +178 -64
@@ -1717,49 +1717,72 @@ static inline int file_path_has_perm(const struct cred *cred,static int bpf_fd_pass (const struct file *file,u32 sid);#endif -/* Check whether a task can use an open file descriptor to -access an inode in a given way. Check access to the -descriptor itself, and then use dentry_has_perm to -check a particular permission to the file. -Access to the descriptor is implicitly granted if it -has the same SID as the process. If av is zero, then -access to the file is not checked, e.g. for cases -where only the descriptor is affected like seek. */ -static int file_has_perm (const struct cred *cred, -struct file *file, -u32 av) +static int __file_has_perm (const struct cred *cred,const struct file *file, +u32 av,bool bf_user_file) + { -struct file_security_struct *fsec =selinux_file (file); -struct inode *inode =file_inode (file);struct common_audit_data ad; -u32 sid =cred_sid (cred); +struct inode *inode; +u32 ssid =cred_sid (cred); +u32 tsid_fd;int rc; - ad.type =LSM_AUDIT_DATA_FILE ; - ad.u.file = file; +if (bf_user_file) { +struct backing_file_security_struct *bfsec; +const struct path *path; -if (sid != fsec->sid) { - rc =avc_has_perm (sid, fsec->sid, -SECCLASS_FD , -FD__USE , - &ad); +if (WARN_ON (!(file->f_mode &FMODE_BACKING ))) +return -EIO ; + + bfsec =selinux_backing_file (file); + path = &file->f_path; + tsid_fd = bfsec->uf_sid; + inode =d_inode (path->dentry); + + ad.type =LSM_AUDIT_DATA_PATH ; + ad.u.path = *path; + }else { +struct file_security_struct *fsec =selinux_file (file); + + tsid_fd = fsec->sid; + inode =file_inode (file); + + ad.type =LSM_AUDIT_DATA_FILE ; + ad.u.file = file; + } + +if (ssid != tsid_fd) { + rc =avc_has_perm (ssid, tsid_fd,SECCLASS_FD ,FD__USE , &ad);if (rc) - goto out; +return rc; }#ifdef CONFIG_BPF_SYSCALL - rc =bpf_fd_pass (file,cred_sid (cred)); +/* regardless of backing vs user file, use the underlying file here */ + rc =bpf_fd_pass (file, ssid);if (rc)return rc;#endif /* av is zero if only checking access to the descriptor. */ - rc =0 ;if (av) - rc =inode_has_perm (cred, inode, av, &ad); +return inode_has_perm (cred, inode, av, &ad); -out: -return rc; +return 0 ; +} + +/* Check whether a task can use an open file descriptor to +access an inode in a given way. Check access to the +descriptor itself, and then use dentry_has_perm to +check a particular permission to the file. +Access to the descriptor is implicitly granted if it +has the same SID as the process. If av is zero, then +access to the file is not checked, e.g. for cases +where only the descriptor is affected like seek. */ +static inline int file_has_perm (const struct cred *cred, +const struct file *file,u32 av) +{ +return __file_has_perm (cred, file, av, false); }/*
@@ -3638,6 +3661,17 @@ static int selinux_file_alloc_security(struct file *file)return 0 ; } +static int selinux_backing_file_alloc (struct file *backing_file, +const struct file *user_file) +{ +struct backing_file_security_struct *bfsec; + + bfsec =selinux_backing_file (backing_file); + bfsec->uf_sid =selinux_file (user_file)->sid; + +return 0 ; +} +/* * Check whether a task has the ioctl permission and cmd * operation to an inode.
@@ -3755,42 +3789,55 @@ static int selinux_file_ioctl_compat(struct file *file, unsigned int cmd,static int default_noexec__ro_after_init ; -static int file_map_prot_check (struct file *file,unsigned long prot,int shared) +static int __file_map_prot_check (const struct cred *cred, +const struct file *file,unsigned long prot, +bool shared,bool bf_user_file) { -const struct cred *cred =current_cred (); -u32 sid =cred_sid (cred); -int rc =0 ; +struct inode *inode =NULL ; +bool prot_exec = prot &PROT_EXEC ; +bool prot_write = prot &PROT_WRITE ; + +if (file) { +if (bf_user_file) + inode =d_inode (file->f_path.dentry); +else + inode =file_inode (file); + } + +if (default_noexec && prot_exec && + (!file ||IS_PRIVATE (inode) || (!shared && prot_write))) { +int rc; +u32 sid =cred_sid (cred); -if (default_noexec && - (prot &PROT_EXEC ) && (!file ||IS_PRIVATE (file_inode (file)) || - (!shared && (prot &PROT_WRITE )))) {/* -* We are making executable an anonymous mapping or a -* private file mapping that will also be writable. -* This has an additional check. +* We are making executable an anonymous mapping or a private +* file mapping that will also be writable. */ - rc =avc_has_perm (sid, sid,SECCLASS_PROCESS , -PROCESS__EXECMEM ,NULL ); + rc =avc_has_perm (sid, sid,SECCLASS_PROCESS ,PROCESS__EXECMEM , +NULL );if (rc) - goto error; +return rc; }if (file) { -/* read access is always possible with a mapping */ +/* "read" always possible, "write" only if shared */ u32 av =FILE__READ ; - -/* write access only matters if the mapping is shared */ -if (shared && (prot &PROT_WRITE )) +if (shared && prot_write) av |=FILE__WRITE ; - -if (prot &PROT_EXEC ) +if (prot_exec) av |=FILE__EXECUTE ; -return file_has_perm (cred, file, av); +return __file_has_perm (cred, file, av, bf_user_file); } -error: -return rc; +return 0 ; +} + +static inline int file_map_prot_check (const struct cred *cred, +const struct file *file, +unsigned long prot,bool shared) +{ +return __file_map_prot_check (cred, file, prot, shared, false); }static int selinux_mmap_addr (unsigned long addr)
@@ -3806,36 +3853,80 @@ static int selinux_mmap_addr(unsigned long addr)return rc; } -static int selinux_mmap_file (struct file *file, -unsigned long reqprot__always_unused , -unsigned long prot,unsigned long flags) +static int selinux_mmap_file_common (const struct cred *cred,struct file *file, +unsigned long prot,bool shared) { -struct common_audit_data ad; -int rc; -if (file) { +int rc; +struct common_audit_data ad; + ad.type =LSM_AUDIT_DATA_FILE ; ad.u.file = file; - rc =inode_has_perm (current_cred (),file_inode (file), -FILE__MAP , &ad); + rc =inode_has_perm (cred,file_inode (file),FILE__MAP , &ad);if (rc)return rc; } -return file_map_prot_check (file, prot, - (flags &MAP_TYPE ) ==MAP_SHARED ); +return file_map_prot_check (cred, file, prot, shared); +} + +static int selinux_mmap_file (struct file *file, +unsigned long reqprot__always_unused , +unsigned long prot,unsigned long flags) +{ +return selinux_mmap_file_common (current_cred (), file, prot, + (flags &MAP_TYPE ) ==MAP_SHARED ); +} + +/** +* selinux_mmap_backing_file - Check mmap permissions on a backing file +* @vma: memory region +* @backing_file: stacked filesystem backing file +* @user_file: user visible file +* +* This is called after selinux_mmap_file() on stacked filesystems, and it +* is this function's responsibility to verify access to @backing_file and +* setup the SELinux state for possible later use in the mprotect() code path. +* +* By the time this function is called, mmap() access to @user_file has already +* been authorized and @vma->vm_file has been set to point to @backing_file. +* +* Return zero on success, negative values otherwise. +*/ +static int selinux_mmap_backing_file (struct vm_area_struct *vma, +struct file *backing_file, +struct file *user_file__always_unused ) +{ +unsigned long prot =0 ; + +/* translate vma->vm_flags perms into PROT perms */ +if (vma->vm_flags &VM_READ ) + prot |=PROT_READ ; +if (vma->vm_flags &VM_WRITE ) + prot |=PROT_WRITE ; +if (vma->vm_flags &VM_EXEC ) + prot |=PROT_EXEC ; + +return selinux_mmap_file_common (backing_file->f_cred, backing_file, + prot, vma->vm_flags &VM_SHARED ); }static int selinux_file_mprotect (struct vm_area_struct *vma,unsigned long reqprot__always_unused ,unsigned long prot) { +int rc;const struct cred *cred =current_cred ();u32 sid =cred_sid (cred); +const struct file *file = vma->vm_file; +bool backing_file; +bool shared = vma->vm_flags &VM_SHARED ; + +/* check if we need to trigger the "backing files are awful" mode */ + backing_file = file && (file->f_mode &FMODE_BACKING );if (default_noexec && (prot &PROT_EXEC ) && !(vma->vm_flags &VM_EXEC )) { -int rc =0 ;/* * We don't use the vma_is_initial_heap() helper as it has * a history of problems and is currently broken on systems
@@ -3849,11 +3940,15 @@ static int selinux_file_mprotect(struct vm_area_struct *vma, vma->vm_end <= vma->vm_mm->brk) { rc =avc_has_perm (sid, sid,SECCLASS_PROCESS ,PROCESS__EXECHEAP ,NULL ); - } else if (!vma->vm_file && (vma_is_initial_stack(vma) || +if (rc) +return rc; + } else if (!file && (vma_is_initial_stack(vma) || vma_is_stack_for_current(vma))) { rc =avc_has_perm (sid, sid,SECCLASS_PROCESS ,PROCESS__EXECSTACK ,NULL ); - } else if (vma->vm_file && vma->anon_vma) { +if (rc) +return rc; + } else if (file && vma->anon_vma) {/* * We are making executable a file mapping that has * had some COW done. Since pages might have been
@@ -3861,13 +3956,29 @@ static int selinux_file_mprotect(struct vm_area_struct *vma,* modified content. This typically should only * occur for text relocations. */ - rc =file_has_perm (cred, vma->vm_file,FILE__EXECMOD ); + rc =__file_has_perm (cred, file,FILE__EXECMOD , + backing_file); +if (rc) +return rc; +if (backing_file) { + rc =file_has_perm (file->f_cred, file, +FILE__EXECMOD ); +if (rc) +return rc; + } } + } + + rc =__file_map_prot_check (cred, file, prot, shared, backing_file); +if (rc) +return rc; +if (backing_file) { + rc =file_map_prot_check (file->f_cred, file, prot, shared);if (rc)return rc; } -return file_map_prot_check (vma->vm_file, prot, vma->vm_flags&VM_SHARED ); +return 0 ; }static int selinux_file_lock (struct file *file,unsigned int cmd)
@@ -6870,6 +6981,7 @@ static void selinux_bpf_prog_free(struct bpf_prog_aux *aux)struct lsm_blob_sizes selinux_blob_sizes__ro_after_init = { .lbs_cred =sizeof (struct task_security_struct ), .lbs_file =sizeof (struct file_security_struct ), + .lbs_backing_file =sizeof (struct backing_file_security_struct ), .lbs_inode =sizeof (struct inode_security_struct ), .lbs_ipc =sizeof (struct ipc_security_struct ), .lbs_msg_msg =sizeof (struct msg_security_struct ),
@@ -7074,9 +7186,11 @@ static struct security_hook_list selinux_hooks[] __ro_after_init = {LSM_HOOK_INIT (file_permission, selinux_file_permission),LSM_HOOK_INIT (file_alloc_security, selinux_file_alloc_security), +LSM_HOOK_INIT (backing_file_alloc, selinux_backing_file_alloc),LSM_HOOK_INIT (file_ioctl, selinux_file_ioctl),LSM_HOOK_INIT (file_ioctl_compat, selinux_file_ioctl_compat),LSM_HOOK_INIT (mmap_file, selinux_mmap_file), +LSM_HOOK_INIT (mmap_backing_file, selinux_mmap_backing_file),LSM_HOOK_INIT (mmap_addr, selinux_mmap_addr),LSM_HOOK_INIT (file_mprotect, selinux_file_mprotect), LSM_HOOK_INIT(file_lock, selinux_file_lock),
security/selinux/include/objsec.h +11 -0
@@ -60,6 +60,10 @@ struct file_security_struct {u32 pseqno;/* Policy seqno at the time of file open */ }; +struct backing_file_security_struct { +u32 uf_sid;/* associated user file fsec->sid */ +}; +struct superblock_security_struct {u32 sid;/* SID of file system superblock */ u32 def_sid;/* default SID for labeling */
@@ -158,6 +162,13 @@ static inline struct file_security_struct *selinux_file(const struct file *file)return file->f_security + selinux_blob_sizes.lbs_file; } +static inline struct backing_file_security_struct * +selinux_backing_file (const struct file *backing_file) +{ +void *blob =backing_file_security (backing_file); +return blob + selinux_blob_sizes.lbs_backing_file; +} +static inline struct inode_security_struct *selinux_inode (const struct inode *inode) {
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 91/175 batman-adv: tp_meter: keep unacked list in ascending ordered
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Sven Eckelmann <[email protected]>
commit 5aa8651527ea0b610e7a09fb3b8204c1398b9525 upstream.
When batadv_tp_handle_out_of_order inserts a new entry in the list of unacked (out of order) packets, it searches from the entry with the newest sequence number towards oldest sequence number. If an entry is found which is older than the newly entry, the new entry has to be added after the found one to keep the ascending order.
But for this operation list_add_tail() was used. But this function adds an entry _before_ another one. As result, the list would contain a lot of swapped sequence numbers. The consumer of this list (batadv_tp_ack_unordered()) would then fail to correctly ack packets.
--- net/batman-adv/tp_meter.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
net/batman-adv/tp_meter.c +1 -1
@@ -1325,7 +1325,7 @@ static bool batadv_tp_handle_out_of_order(struct batadv_tp_vars *tp_vars,* one is attached _after_ it. In this way the list is kept in * ascending order */ -list_add_tail (&new->list, &un->list); +list_add (&new->list, &un->list); added = true;break ; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 51/175 scripts/sorttable: Convert Elf_Sym MACRO over to a union
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Steven Rostedt <[email protected]>
[ Upstream commit 200d015e73b4da69bcd8212a7c58695452b12bad ]
In order to remove the double #include of sorttable.h for 64 and 32 bit to create duplicate functions for both, replace the Elf_Sym macro with a union that defines both Elf64_Sym and Elf32_Sym, with field e64 for the 64bit version, and e32 for the 32bit version.
It can then use the macro etype to get the proper value.
This will eventually be replaced with just single functions that can handle both 32bit and 64bit ELF parsing.
--- scripts/sorttable.c | 5 +++++ scripts/sorttable.h | 25 ++++++++++++++----------- 2 files changed, 19 insertions(+), 11 deletions(-)
scripts/sorttable.c +5 -0
@@ -74,6 +74,11 @@ typedef union {Elf64_Shdr e64; } Elf_Shdr; +typedef union { +Elf32_Sym e32; +Elf64_Sym e64; +}Elf_Sym ; +static uint32_t (*r)(const uint32_t *);static uint16_t (*r2)(const uint16_t *);static uint64_t (*r8)(const uint64_t *);
scripts/sorttable.h +14 -11
@@ -23,7 +23,6 @@#undef sort_mcount_loc#undef elf_mcount_loc#undef do_sort -#undef Elf_Sym#undef ELF_ST_TYPE#undef uint_t#undef _r
@@ -36,7 +35,6 @@# define sort_mcount_loc sort_mcount_loc_64# define elf_mcount_loc elf_mcount_loc_64# define do_sort do_sort_64 -# define Elf_Sym Elf64_Sym# define ELF_ST_TYPE ELF64_ST_TYPE# define uint_t uint64_t# define _r r8
@@ -48,7 +46,6 @@# define sort_mcount_loc sort_mcount_loc_32# define elf_mcount_loc elf_mcount_loc_32# define do_sort do_sort_32 -# define Elf_Sym Elf32_Sym# define ELF_ST_TYPE ELF32_ST_TYPE# define uint_t uint32_t# define _r r
@@ -230,10 +227,13 @@ static int do_sort(Elf_Ehdr *ehdr,Elf_Sym *sort_needed_sym =NULL ;Elf_Shdr *sort_needed_sec;uint32_t *sort_needed_loc; +void *sym_start; +void *sym_end;const char *secstrings;const char *strtab;char *extab_image;int sort_need_index; +int symentsize;int shentsize;int idx;int i;
@@ -376,12 +376,15 @@ static int do_sort(Elf_Ehdr *ehdr, }/* find the flag main_extable_sort_needed */ -for (sym = (void *)ehdr +_r (&symtab_sec->etype.sh_offset); - sym < sym +_r (&symtab_sec->etype.sh_size) /sizeof (Elf_Sym); - sym++) { -if (ELF_ST_TYPE (sym->st_info) !=STT_OBJECT ) + sym_start = (void *)ehdr +_r (&symtab_sec->etype.sh_offset); + sym_end = sym_start +_r (&symtab_sec->etype.sh_size); + symentsize =_r (&symtab_sec->etype.sh_entsize); + +for (sym = sym_start; (void *)sym + symentsize < sym_end; + sym = (void *)sym + symentsize) { +if (ELF_ST_TYPE (sym->etype.st_info) !=STT_OBJECT )continue ; -if (!strcmp (strtab +r (&sym->st_name), +if (!strcmp (strtab +r (&sym->etype.st_name),"main_extable_sort_needed" )) { sort_needed_sym = sym;break ;
@@ -395,13 +398,13 @@ static int do_sort(Elf_Ehdr *ehdr, goto out; } - sort_need_index =get_secindex (r2 (&sym->st_shndx), - sort_needed_sym - symtab, + sort_need_index =get_secindex (r2 (&sym->etype.st_shndx), + ((void *)sort_needed_sym - (void *)symtab) / symentsize, symtab_shndx); sort_needed_sec =get_index (shdr_start, shentsize, sort_need_index); sort_needed_loc = (void *)ehdr +_r (&sort_needed_sec->etype.sh_offset) + -_r (&sort_needed_sym->st_value) - +_r (&sort_needed_sym->etype.st_value) -_r (&sort_needed_sec->etype.sh_addr);/* extable has been sorted, clear the flag */
Greg Kroah-Hartman
maintainerPATCH 52/175 scripts/sorttable: Add helper functions for Elf_Ehdr
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Steven Rostedt <[email protected]>
[ Upstream commit 1dfb59a228dde59ad7d99b2fa2104e90004995c7 ]
In order to remove the double #include of sorttable.h for 64 and 32 bit to create duplicate functions, add helper functions for Elf_Ehdr. This will create a function pointer for each helper that will get assigned to the appropriate function to handle either the 64bit or 32bit version.
This also moves the _r()/r() wrappers for the Elf_Ehdr references that handle endian and size differences between the different architectures, into the helper function and out of the open code which is more error prone.
--- scripts/sorttable.c | 25 +++++++++++++++++++++++++ scripts/sorttable.h | 20 ++++++++++++++++---- 2 files changed, 41 insertions(+), 4 deletions(-)
scripts/sorttable.c +25 -0
@@ -85,6 +85,31 @@ static uint64_t (*r8)(const uint64_t *);static void (*w)(uint32_t ,uint32_t *);typedef void (*table_sort_t )(char *,int ); +static uint64_t ehdr64_shoff (Elf_Ehdr *ehdr) +{ +return r8 (&ehdr->e64.e_shoff); +} + +static uint64_t ehdr32_shoff (Elf_Ehdr *ehdr) +{ +return r (&ehdr->e32.e_shoff); +} + +#define EHDR_HALF (fn_name) \ +static uint16_t ehdr64_##fn_name(Elf_Ehdr *ehdr) \ +{ \ + return r2(&ehdr->e64.e_##fn_name); \ +} \ + \ +static uint16_t ehdr32_##fn_name(Elf_Ehdr *ehdr) \ +{ \ + return r2(&ehdr->e32.e_##fn_name); \ +} + +EHDR_HALF(shentsize) +EHDR_HALF(shstrndx) +EHDR_HALF(shnum) + /* * Get the whole file as a programming convenience in order to avoid * malloc+lseek+read+free of many pieces. If successful, then mmap
scripts/sorttable.h +16 -4
@@ -27,6 +27,10 @@#undef uint_t#undef _r#undef etype +#undef ehdr_shoff +#undef ehdr_shentsize +#undef ehdr_shstrndx +#undef ehdr_shnum#ifdef SORTTABLE_64 # define extable_ent_size 16
@@ -39,6 +43,10 @@# define uint_t uint64_t# define _r r8# define etype e64 +# define ehdr_shoff ehdr64_shoff +# define ehdr_shentsize ehdr64_shentsize +# define ehdr_shstrndx ehdr64_shstrndx +# define ehdr_shnum ehdr64_shnum#else # define extable_ent_size 8# define compare_extable compare_extable_32
@@ -50,6 +58,10 @@# define uint_t uint32_t# define _r r# define etype e32 +# define ehdr_shoff ehdr32_shoff +# define ehdr_shentsize ehdr32_shentsize +# define ehdr_shstrndx ehdr32_shstrndx +# define ehdr_shnum ehdr32_shnum#endif #if defined(SORTTABLE_64 ) && defined(UNWINDER_ORC_ENABLED )
@@ -250,16 +262,16 @@ static int do_sort(Elf_Ehdr *ehdr,unsigned int orc_num_entries =0 ;#endif - shdr_start = (Elf_Shdr *)((char *)ehdr +_r (&ehdr->etype.e_shoff)); - shentsize =r2 (&ehdr->etype.e_shentsize); + shdr_start = (Elf_Shdr *)((char *)ehdr +ehdr_shoff (ehdr)); + shentsize =ehdr_shentsize (ehdr); - shstrndx =r2 (&ehdr->etype.e_shstrndx); + shstrndx =ehdr_shstrndx (ehdr);if (shstrndx ==SHN_XINDEX ) shstrndx =r (&shdr_start->etype.sh_link); string_sec =get_index (shdr_start, shentsize, shstrndx); secstrings = (const char *)ehdr +_r (&string_sec->etype.sh_offset); - shnum =r2 (&ehdr->etype.e_shnum); + shnum =ehdr_shnum (ehdr);if (shnum ==SHN_UNDEF ) shnum =_r (&shdr_start->etype.sh_size);
Greg Kroah-Hartman
maintainerPATCH 53/175 scripts/sorttable: Add helper functions for Elf_Shdr
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Steven Rostedt <[email protected]>
[ Upstream commit 67afb7f504400e5b4e5ff895459fbb3eb63d4450 ]
In order to remove the double #include of sorttable.h for 64 and 32 bit to create duplicate functions, add helper functions for Elf_Shdr. This will create a function pointer for each helper that will get assigned to the appropriate function to handle either the 64bit or 32bit version.
This also moves the _r()/r() wrappers for the Elf_Shdr references that handle endian and size differences between the different architectures, into the helper function and out of the open code which is more error prone.
--- scripts/sorttable.c | 42 +++++++++++++++++++++++++++++++++ scripts/sorttable.h | 66 +++++++++++++++++++++++++++++++++------------------- 2 files changed, 85 insertions(+), 23 deletions(-)
scripts/sorttable.c +42 -0
@@ -110,6 +110,48 @@ EHDR_HALF(shentsize) EHDR_HALF(shstrndx) EHDR_HALF(shnum) +#define SHDR_WORD (fn_name) \ +static uint32_t shdr64_##fn_name(Elf_Shdr *shdr) \ +{ \ + return r(&shdr->e64.sh_##fn_name); \ +} \ + \ +static uint32_t shdr32_##fn_name(Elf_Shdr *shdr) \ +{ \ + return r(&shdr->e32.sh_##fn_name); \ +} + +#define SHDR_ADDR (fn_name) \ +static uint64_t shdr64_##fn_name(Elf_Shdr *shdr) \ +{ \ + return r8(&shdr->e64.sh_##fn_name); \ +} \ + \ +static uint64_t shdr32_##fn_name(Elf_Shdr *shdr) \ +{ \ + return r(&shdr->e32.sh_##fn_name); \ +} + +#define SHDR_WORD (fn_name) \ +static uint32_t shdr64_##fn_name(Elf_Shdr *shdr) \ +{ \ + return r(&shdr->e64.sh_##fn_name); \ +} \ + \ +static uint32_t shdr32_##fn_name(Elf_Shdr *shdr) \ +{ \ + return r(&shdr->e32.sh_##fn_name); \ +} + +SHDR_ADDR(addr) +SHDR_ADDR(offset) +SHDR_ADDR(size) +SHDR_ADDR(entsize) + +SHDR_WORD(link) +SHDR_WORD(name) +SHDR_WORD(type) +/* * Get the whole file as a programming convenience in order to avoid * malloc+lseek+read+free of many pieces. If successful, then mmap
scripts/sorttable.h +43 -23
142 lines not on this page · raw message
Greg Kroah-Hartman
maintainerPATCH 54/175 scripts/sorttable: Add helper functions for Elf_Sym
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Steven Rostedt <[email protected]>
[ Upstream commit 17bed33ac12f011f4695059960e1b1d6457229a7 ]
In order to remove the double #include of sorttable.h for 64 and 32 bit to create duplicate functions, add helper functions for Elf_Sym. This will create a function pointer for each helper that will get assigned to the appropriate function to handle either the 64bit or 32bit version.
This also removes the last references of etype and _r() macros from the sorttable.h file as their references are now just defined in the appropriate architecture version of the helper functions. All read functions now exist in the helper functions which makes it easier to maintain, as the helper functions define the necessary architecture sizes.
--- scripts/sorttable.c | 47 +++++++++++++++++++++++++++++++++++++++++++++++ scripts/sorttable.h | 30 ++++++++++++++++-------------- 2 files changed, 63 insertions(+), 14 deletions(-)
scripts/sorttable.c +47 -0
@@ -152,6 +152,53 @@ SHDR_WORD(link) SHDR_WORD(name) SHDR_WORD(type) +#define SYM_ADDR (fn_name) \ +static uint64_t sym64_##fn_name(Elf_Sym *sym) \ +{ \ + return r8(&sym->e64.st_##fn_name); \ +} \ + \ +static uint64_t sym32_##fn_name(Elf_Sym *sym) \ +{ \ + return r(&sym->e32.st_##fn_name); \ +} + +#define SYM_WORD (fn_name) \ +static uint32_t sym64_##fn_name(Elf_Sym *sym) \ +{ \ + return r(&sym->e64.st_##fn_name); \ +} \ + \ +static uint32_t sym32_##fn_name(Elf_Sym *sym) \ +{ \ + return r(&sym->e32.st_##fn_name); \ +} + +#define SYM_HALF (fn_name) \ +static uint16_t sym64_##fn_name(Elf_Sym *sym) \ +{ \ + return r2(&sym->e64.st_##fn_name); \ +} \ + \ +static uint16_t sym32_##fn_name(Elf_Sym *sym) \ +{ \ + return r2(&sym->e32.st_##fn_name); \ +} + +static uint8_t sym64_type (Elf_Sym *sym) +{ +return ELF64_ST_TYPE (sym->e64.st_info); +} + +static uint8_t sym32_type (Elf_Sym *sym) +{ +return ELF32_ST_TYPE (sym->e32.st_info); +} + +SYM_ADDR(value) +SYM_WORD(name) +SYM_HALF(shndx) + /* * Get the whole file as a programming convenience in order to avoid * malloc+lseek+read+free of many pieces. If successful, then mmap
scripts/sorttable.h +16 -14
@@ -23,10 +23,7 @@#undef sort_mcount_loc#undef elf_mcount_loc#undef do_sort -#undef ELF_ST_TYPE#undef uint_t -#undef _r -#undef etype#undef ehdr_shoff#undef ehdr_shentsize#undef ehdr_shstrndx
@@ -38,6 +35,10 @@#undef shdr_name#undef shdr_type#undef shdr_entsize +#undef sym_type +#undef sym_name +#undef sym_value +#undef sym_shndx#ifdef SORTTABLE_64 # define extable_ent_size 16
@@ -46,10 +47,7 @@# define sort_mcount_loc sort_mcount_loc_64# define elf_mcount_loc elf_mcount_loc_64# define do_sort do_sort_64 -# define ELF_ST_TYPE ELF64_ST_TYPE# define uint_t uint64_t -# define _r r8 -# define etype e64# define ehdr_shoff ehdr64_shoff# define ehdr_shentsize ehdr64_shentsize# define ehdr_shstrndx ehdr64_shstrndx
@@ -61,6 +59,10 @@# define shdr_name shdr64_name# define shdr_type shdr64_type# define shdr_entsize shdr64_entsize +# define sym_type sym64_type +# define sym_name sym64_name +# define sym_value sym64_value +# define sym_shndx sym64_shndx#else # define extable_ent_size 8# define compare_extable compare_extable_32
@@ -68,10 +70,7 @@# define sort_mcount_loc sort_mcount_loc_32# define elf_mcount_loc elf_mcount_loc_32# define do_sort do_sort_32 -# define ELF_ST_TYPE ELF32_ST_TYPE# define uint_t uint32_t -# define _r r -# define etype e32# define ehdr_shoff ehdr32_shoff# define ehdr_shentsize ehdr32_shentsize# define ehdr_shstrndx ehdr32_shstrndx
@@ -83,6 +82,10 @@# define shdr_name shdr32_name# define shdr_type shdr32_type# define shdr_entsize shdr32_entsize +# define sym_type sym32_type +# define sym_name sym32_name +# define sym_value sym32_value +# define sym_shndx sym32_shndx#endif #if defined(SORTTABLE_64 ) && defined(UNWINDER_ORC_ENABLED )
@@ -414,9 +417,9 @@ static int do_sort(Elf_Ehdr *ehdr,for (sym = sym_start; (void *)sym + symentsize < sym_end; sym = (void *)sym + symentsize) { -if (ELF_ST_TYPE (sym->etype.st_info) !=STT_OBJECT ) +if (sym_type (sym) !=STT_OBJECT )continue ; -if (!strcmp (strtab +r (&sym->etype.st_name), +if (!strcmp (strtab +sym_name (sym),"main_extable_sort_needed" )) { sort_needed_sym = sym;break ;
@@ -430,14 +433,13 @@ static int do_sort(Elf_Ehdr *ehdr, goto out; } - sort_need_index =get_secindex (r2 (&sym->etype.st_shndx), + sort_need_index =get_secindex (sym_shndx (sym), ((void *)sort_needed_sym - (void *)symtab) / symentsize, symtab_shndx); sort_needed_sec =get_index (shdr_start, shentsize, sort_need_index); sort_needed_loc = (void *)ehdr +shdr_offset (sort_needed_sec) + -_r (&sort_needed_sym->etype.st_value) - -shdr_addr (sort_needed_sec); +sym_value (sort_needed_sym) -shdr_addr (sort_needed_sec);/* extable has been sorted, clear the flag */ w (0 , sort_needed_loc);
Greg Kroah-Hartman
maintainerPATCH 55/175 scripts/sorttable: Use uint64_t for mcount sorting
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Steven Rostedt <[email protected]>
[ Upstream commit 1b649e6ab8dc9188d82c64069493afe66ca0edad ]
The mcount sorting defines uint_t to uint64_t on 64bit architectures and uint32_t on 32bit architectures. It can work with just using uint64_t as that will hold the values of both, and they are not used to point into the ELF file.
sizeof(uint_t) is used for defining the size of the mcount_loc section. Instead of using a type, define long_size and use that instead. This will allow the header code to be moved into the C file as generic functions and not need to include sorttable.h twice, once for 64bit and once for 32bit.
--- scripts/sorttable.h | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-)
scripts/sorttable.h +11 -11
@@ -23,7 +23,6 @@#undef sort_mcount_loc#undef elf_mcount_loc#undef do_sort -#undef uint_t#undef ehdr_shoff#undef ehdr_shentsize#undef ehdr_shstrndx
@@ -39,6 +38,7 @@#undef sym_name#undef sym_value#undef sym_shndx +#undef long_size#ifdef SORTTABLE_64 # define extable_ent_size 16
@@ -47,7 +47,6 @@# define sort_mcount_loc sort_mcount_loc_64# define elf_mcount_loc elf_mcount_loc_64# define do_sort do_sort_64 -# define uint_t uint64_t# define ehdr_shoff ehdr64_shoff# define ehdr_shentsize ehdr64_shentsize# define ehdr_shstrndx ehdr64_shstrndx
@@ -63,6 +62,7 @@# define sym_name sym64_name# define sym_value sym64_value# define sym_shndx sym64_shndx +# define long_size 8#else # define extable_ent_size 8# define compare_extable compare_extable_32
@@ -70,7 +70,6 @@# define sort_mcount_loc sort_mcount_loc_32# define elf_mcount_loc elf_mcount_loc_32# define do_sort do_sort_32 -# define uint_t uint32_t# define ehdr_shoff ehdr32_shoff# define ehdr_shentsize ehdr32_shentsize# define ehdr_shstrndx ehdr32_shstrndx
@@ -86,6 +85,7 @@# define sym_name sym32_name# define sym_value sym32_value# define sym_shndx sym32_shndx +# define long_size 4#endif #if defined(SORTTABLE_64 ) && defined(UNWINDER_ORC_ENABLED )
@@ -193,25 +193,25 @@ pthread_t mcount_sort_thread;struct elf_mcount_loc {Elf_Ehdr *ehdr;Elf_Shdr *init_data_sec; -uint_t start_mcount_loc; -uint_t stop_mcount_loc; +uint64_t start_mcount_loc; +uint64_t stop_mcount_loc; };/* Sort the addresses stored between __start_mcount_loc to __stop_mcount_loc in vmlinux */ static void *sort_mcount_loc (void *arg) {struct elf_mcount_loc *emloc = (struct elf_mcount_loc *)arg; -uint_t offset = emloc->start_mcount_loc -shdr_addr (emloc->init_data_sec) +uint64_t offset = emloc->start_mcount_loc -shdr_addr (emloc->init_data_sec) +shdr_offset (emloc->init_data_sec); -uint_t count = emloc->stop_mcount_loc - emloc->start_mcount_loc; +uint64_t count = emloc->stop_mcount_loc - emloc->start_mcount_loc;unsigned char *start_loc = (void *)emloc->ehdr + offset; -qsort (start_loc, count/sizeof (uint_t),sizeof (uint_t), compare_extable); +qsort (start_loc, count/long_size, long_size, compare_extable);return NULL ; }/* Get the address of __start_mcount_loc and __stop_mcount_loc in System.map */ -static void get_mcount_loc (uint_t *_start,uint_t *_stop) +static void get_mcount_loc (uint64_t *_start,uint64_t *_stop) {FILE *file_start, *file_stop;char start_buff[20 ];
@@ -277,8 +277,8 @@ static int do_sort(Elf_Ehdr *ehdr,unsigned int shstrndx;#ifdef MCOUNT_SORT_ENABLED struct elf_mcount_loc mstruct = {0 }; -uint_t _start_mcount_loc =0 ; -uint_t _stop_mcount_loc =0 ; +uint64_t _start_mcount_loc =0 ; +uint64_t _stop_mcount_loc =0 ;#endif #if defined(SORTTABLE_64 ) && defined(UNWINDER_ORC_ENABLED )unsigned int orc_ip_size =0 ;
Greg Kroah-Hartman
maintainerPATCH 46/175 scripts/sorttable: Remove unneeded Elf_Rel
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Steven Rostedt <[email protected]>
[ Upstream commit 6f2c2f93a190467cebd6ebd03feb49514fead5ca ]
The code had references to initialize the Elf_Rel relocation tables, but it was never used. Remove it.
--- scripts/sorttable.h | 23 ++--------------------- 1 file changed, 2 insertions(+), 21 deletions(-)
scripts/sorttable.h +2 -21
@@ -26,7 +26,6 @@#undef Elf_Addr#undef Elf_Ehdr#undef Elf_Shdr -#undef Elf_Rel#undef Elf_Sym#undef ELF_ST_TYPE#undef uint_t
@@ -42,7 +41,6 @@# define Elf_Addr Elf64_Addr# define Elf_Ehdr Elf64_Ehdr# define Elf_Shdr Elf64_Shdr -# define Elf_Rel Elf64_Rel# define Elf_Sym Elf64_Sym# define ELF_ST_TYPE ELF64_ST_TYPE# define uint_t uint64_t
@@ -57,7 +55,6 @@# define Elf_Addr Elf32_Addr# define Elf_Ehdr Elf32_Ehdr# define Elf_Shdr Elf32_Shdr -# define Elf_Rel Elf32_Rel# define Elf_Sym Elf32_Sym# define ELF_ST_TYPE ELF32_ST_TYPE# define uint_t uint32_t
@@ -248,14 +245,10 @@ static int do_sort(Elf_Ehdr *ehdr,Elf32_Word *symtab_shndx =NULL ;Elf_Sym *sort_needed_sym =NULL ;Elf_Shdr *sort_needed_sec; -Elf_Rel *relocs =NULL ; -int relocs_size =0 ;uint32_t *sort_needed_loc;const char *secstrings;const char *strtab;char *extab_image; -int extab_index =0 ; -int i;int idx;unsigned int shnum;unsigned int shstrndx;
@@ -279,23 +272,15 @@ static int do_sort(Elf_Ehdr *ehdr,if (shnum ==SHN_UNDEF ) shnum =_r (&shdr[0 ].sh_size); -for (i =0 , s = shdr; s < shdr + shnum; i++, s++) { +for (s = shdr; s < shdr + shnum; s++) { idx =r (&s->sh_name); -if (!strcmp (secstrings + idx,"__ex_table" )) { +if (!strcmp (secstrings + idx,"__ex_table" )) extab_sec = s; - extab_index = i; - }if (!strcmp (secstrings + idx,".symtab" )) symtab_sec = s;if (!strcmp (secstrings + idx,".strtab" )) strtab_sec = s; -if ((r (&s->sh_type) ==SHT_REL || -r (&s->sh_type) ==SHT_RELA ) && -r (&s->sh_info) == extab_index) { - relocs = (void *)ehdr +_r (&s->sh_offset); - relocs_size =_r (&s->sh_size); - }if (r (&s->sh_type) ==SHT_SYMTAB_SHNDX ) symtab_shndx = (Elf32_Word *)((const char *)ehdr +_r (&s->sh_offset));
@@ -397,10 +382,6 @@ static int do_sort(Elf_Ehdr *ehdr, extable_ent_size, compare_extable); } -/* If there were relocations, we no longer need them. */ -if (relocs) -memset (relocs,0 , relocs_size); -/* find the flag main_extable_sort_needed */ for (sym = (void *)ehdr + _r(&symtab_sec->sh_offset); sym < sym + _r(&symtab_sec->sh_size) / sizeof(Elf_Sym);
Greg Kroah-Hartman
maintainerPATCH 93/175 batman-adv: tp_meter: initialize dec_cwnd explicitly
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Sven Eckelmann <[email protected]>
commit febfb1b86224489535312296ecfa3d4bf467f339 upstream.
When batadv_tp_update_cwnd() is called, dec_cwnd is increased. But dec_cwnd is only initialixed (to 0) when a duplicate Ack was received or when cwnd is below the ss_threshold.
Just initialize the cwnd during the initialization to avoid any potential access of uninitialized data.
--- net/batman-adv/tp_meter.c | 2 ++ 1 file changed, 2 insertions(+)
net/batman-adv/tp_meter.c +2 -0
@@ -1055,6 +1055,8 @@ void batadv_tp_start(struct batadv_priv *bat_priv, const u8 *dst,* soft_interface, hence its MTU */ tp_vars->cwnd =BATADV_TP_PLEN *3 ; + tp_vars->dec_cwnd =0 ; +/* at the beginning initialise the SS threshold to the biggest possible * window size, hence the AWND size */
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 102/175 batman-adv: ensure bcast is writable before modifying TTL
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Sven Eckelmann <[email protected]>
commit 4cd6d3a4b96a8576f1fed8f9f9f17c2dc2978e0c upstream.
Before batman-adv is allowed to write to an skb, it either has to have its own copy of the skb or used skb_cow() to ensure that the data part is not shared.
The old implementation used a shared queue and created copies before attempting to write to it. But with the new implementation, the broadcast packet is already modified when it gets received. Potentially writing to shared buffers in this process.
Adding a skb_cow() right before this operation avoids this and can at the same time prepare it for the modifications required to rebroadcast the packet.
--- net/batman-adv/routing.c | 6 ++++++ 1 file changed, 6 insertions(+)
net/batman-adv/routing.c +6 -0
@@ -1198,6 +1198,12 @@ int batadv_recv_bcast_packet(struct sk_buff *skb,if (batadv_is_my_mac (bat_priv, bcast_packet->orig)) goto free_skb; +/* create a copy of the skb, if needed, to modify it. */ +if (skb_cow (skb,ETH_HLEN ) <0 ) + goto free_skb; + + bcast_packet = (struct batadv_bcast_packet *)skb->data; +if (bcast_packet->ttl-- <2 ) goto free_skb;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 103/175 batman-adv: fix (m|b)cast csum after decrementing TTL
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Sven Eckelmann <[email protected]>
commit e728bbdf32660c8f32b8f5e8d09427a2c131ad60 upstream.
The broadcast and multicast packets can be received at the same time by the local system and forwarded to other nodes. Both are simply decrementing the TTL at the beginning of the receive path - independent of chosen paths (receive/forward). But such a modification of the data conflicts with the hw csum. This is not a problem when the packet is directly forwarded but can cause errors in the local receive path.
Such a problem can then trigger a "hw csum failure". The receiver path must therefore ensure that the csum is fixed for each modification of the payload before batadv_interface_rx() is reached.
Since all batman-adv packet types with a ttl have it as u8 at offset 2, a helper can be used for all of them. But it is only used at the moment for batadv_bcast_packet and batadv_mcast_packet because they are the only ones which deliver the packet locally but unconditionally modify the TTL.
--- net/batman-adv/routing.c | 55 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 54 insertions(+), 1 deletion(-)
net/batman-adv/routing.c +54 -1
@@ -8,6 +8,7 @@#include "main.h" #include <linux/atomic.h> +#include <linux/build_bug.h> #include <linux/byteorder/generic.h> #include <linux/compiler.h> #include <linux/errno.h>
@@ -205,6 +206,58 @@ bool batadv_check_management_packet(struct sk_buff *skb,return true; } +/** +* batadv_skb_decrement_ttl() - decrement ttl in a batman-adv header, csum-safe +* @skb: the received packet with @skb->data pointing to the batman-adv header +* +* Supports the following packet types, all of which carry the TTL at offset 2: +* +* - batadv_ogm_packet +* - batadv_ogm2_packet +* - batadv_icmp_header +* - batadv_icmp_packet +* - batadv_icmp_tp_packet +* - batadv_icmp_packet_rr +* - batadv_unicast_packet +* - batadv_frag_packet +* - batadv_bcast_packet +* - batadv_mcast_packet +* - batadv_coded_packet +* - batadv_unicast_tvlv_packet +* +* Return: true if the packet may be forwarded (ttl decremented), +* false if it must be dropped (ttl would expire) +*/ +static bool batadv_skb_decrement_ttl (struct sk_buff *skb) +{ +static const size_t ttl_offset =2 ; +u8 *ttl_pos; + +BUILD_BUG_ON (offsetof(struct batadv_ogm_packet , ttl) != ttl_offset); +BUILD_BUG_ON (offsetof(struct batadv_ogm2_packet , ttl) != ttl_offset); +BUILD_BUG_ON (offsetof(struct batadv_icmp_header , ttl) != ttl_offset); +BUILD_BUG_ON (offsetof(struct batadv_icmp_packet , ttl) != ttl_offset); +BUILD_BUG_ON (offsetof(struct batadv_icmp_tp_packet , ttl) != ttl_offset); +BUILD_BUG_ON (offsetof(struct batadv_icmp_packet_rr , ttl) != ttl_offset); +BUILD_BUG_ON (offsetof(struct batadv_unicast_packet , ttl) != ttl_offset); +BUILD_BUG_ON (offsetof(struct batadv_frag_packet , ttl) != ttl_offset); +BUILD_BUG_ON (offsetof(struct batadv_bcast_packet , ttl) != ttl_offset); +BUILD_BUG_ON (offsetof(struct batadv_coded_packet , ttl) != ttl_offset); +BUILD_BUG_ON (offsetof(struct batadv_unicast_tvlv_packet , ttl) != ttl_offset); + + ttl_pos = skb->data + ttl_offset; + +/* would expire on this hop -> drop, leave header + csum untouched */ +if (*ttl_pos <2 ) +return false; + +skb_postpull_rcsum (skb, ttl_pos,1 ); + (*ttl_pos)--; +skb_postpush_rcsum (skb, ttl_pos,1 ); + +return true; +} +/** * batadv_recv_my_icmp_packet() - receive an icmp packet locally * @bat_priv: the bat priv with all the soft interface information
@@ -1204,7 +1257,7 @@ int batadv_recv_bcast_packet(struct sk_buff *skb, bcast_packet = (struct batadv_bcast_packet *)skb->data; -if (bcast_packet->ttl-- <2 ) +if (!batadv_skb_decrement_ttl (skb)) goto free_skb; orig_node =batadv_orig_hash_find (bat_priv, bcast_packet->orig);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 104/175 batman-adv: frag: ensure fragment is writable before modifying TTL
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Sven Eckelmann <[email protected]>
commit b7293c6e8c15b2db77809b25cf8389e35331b27a upstream.
Before batman-adv is allowed to write to an skb, it either has to have its own copy of the skb or use skb_cow() to ensure that the data part is not shared. But batadv_frag_skb_fwd() modifies the TTL even when it is shared.
Adding a skb_cow() right before this operation avoids this and can at the same time prepare it for the modifications required to forward the fragment.
--- net/batman-adv/fragmentation.c | 15 ++++++++++++++- net/batman-adv/fragmentation.h | 3 ++- net/batman-adv/routing.c | 3 +-- 3 files changed, 17 insertions(+), 4 deletions(-)
net/batman-adv/fragmentation.c +14 -1
@@ -385,6 +385,8 @@ bool batadv_frag_skb_buffer(struct sk_buff **skb,* @skb: skb to forward * @recv_if: interface that the skb is received on * @orig_node_src: originator that the skb is received from +* @rx_result: set to NET_RX_SUCCESS when the fragment was forwarded and +* NET_RX_DROP when it was dropped; only valid when true is returned * * Look up the next-hop of the fragments payload and check if the merged packet * will exceed the MTU towards the next-hop. If so, the fragment is forwarded
@@ -394,7 +396,8 @@ bool batadv_frag_skb_buffer(struct sk_buff **skb,*/ bool batadv_frag_skb_fwd (struct sk_buff *skb,struct batadv_hard_iface *recv_if, -struct batadv_orig_node *orig_node_src) +struct batadv_orig_node *orig_node_src, +int *rx_result) {struct batadv_priv *bat_priv =netdev_priv (recv_if->soft_iface);struct batadv_orig_node *orig_node_dst;
@@ -417,12 +420,22 @@ bool batadv_frag_skb_fwd(struct sk_buff *skb,*/ total_size =ntohs (packet->total_size);if (total_size > neigh_node->if_incoming->net_dev->mtu) { +if (skb_cow (skb,ETH_HLEN ) <0 ) { +kfree_skb (skb); + *rx_result =NET_RX_DROP ; + ret = true; + goto out; + } + + packet = (struct batadv_frag_packet *)skb->data; +batadv_inc_counter (bat_priv,BATADV_CNT_FRAG_FWD );batadv_add_counter (bat_priv,BATADV_CNT_FRAG_FWD_BYTES , skb->len +ETH_HLEN ); packet->ttl--;batadv_send_unicast_skb (skb, neigh_node); + *rx_result =NET_RX_SUCCESS ; ret = true; }
net/batman-adv/fragmentation.h +2 -1
@@ -19,7 +19,8 @@ void batadv_frag_purge_orig(struct batadv_orig_node *orig, bool (*check_cb)(struct batadv_frag_table_entry *));bool batadv_frag_skb_fwd (struct sk_buff *skb,struct batadv_hard_iface *recv_if, -struct batadv_orig_node *orig_node_src); +struct batadv_orig_node *orig_node_src, +int *rx_result);bool batadv_frag_skb_buffer (struct sk_buff **skb,struct batadv_orig_node *orig_node); int batadv_frag_send_packet(struct sk_buff *skb,
net/batman-adv/routing.c +1 -2
@@ -1174,10 +1174,9 @@ int batadv_recv_frag_packet(struct sk_buff *skb,/* Route the fragment if it is not for us and too big to be merged. */ if (!batadv_is_my_mac (bat_priv, frag_packet->dest) && -batadv_frag_skb_fwd (skb, recv_if, orig_node_src)) { +batadv_frag_skb_fwd (skb, recv_if, orig_node_src, &ret)) {/* skb was consumed */ skb =NULL ; - ret =NET_RX_SUCCESS ; goto put_orig_node; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 105/175 batman-adv: frag: avoid underflow of TTL
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Sven Eckelmann <[email protected]>
commit 493d9d2528e1a09b090e4b37f0f553def7bd5ce9 upstream.
Packets with a TTL are using it to limit the amount of time this packet can be forwarded. But for batadv_frag_packet, the TTL was always only reduced but it was never evaluated. It could even underflow without any effect.
Check the TTL in batadv_frag_skb_fwd() before attempting to prepare it for forwarding. This keeps it in sync with the not fragmented unicast packet.
--- net/batman-adv/fragmentation.c | 7 +++++++ 1 file changed, 7 insertions(+)
net/batman-adv/fragmentation.c +7 -0
@@ -420,6 +420,13 @@ bool batadv_frag_skb_fwd(struct sk_buff *skb,*/ total_size =ntohs (packet->total_size);if (total_size > neigh_node->if_incoming->net_dev->mtu) { +if (packet->ttl <2 ) { +kfree_skb (skb); + *rx_result =NET_RX_DROP ; + ret = true; + goto out; + } +if (skb_cow (skb,ETH_HLEN ) <0 ) {kfree_skb (skb); *rx_result =NET_RX_DROP ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 106/175 batman-adv: v: prevent OGM aggregation on disabled hardif
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Sven Eckelmann <[email protected]>
commit d11c00b95b2a3b3934007fc003dccc6fdcc061ad upstream.
When an interface gets disabled, the worker is correctly disabled by batadv_hardif_disable_interface() -> ... -> batadv_v_ogm_iface_disable(). In this process, the skb aggr_list is also freed.
But batadv_v_ogm_send_meshif() can still queue new skbs (via batadv_v_ogm_queue_on_if()) to the aggr_list. This will only stop after all cores can no longer find the RCU protected list of hard interfaces. These queued skbs will never be freed or consumed by batadv_v_ogm_aggr_work.
The batadv_v_ogm_iface_disable() function must block batadv_v_ogm_queue_on_if() to avoid leak of skbs.
--- net/batman-adv/bat_v.c | 1 + net/batman-adv/bat_v_ogm.c | 12 ++++++++++++ net/batman-adv/types.h | 6 ++++++ 3 files changed, 19 insertions(+)
net/batman-adv/bat_v.c +1 -0
@@ -819,6 +819,7 @@ void batadv_v_hardif_init(struct batadv_hard_iface *hard_iface) hard_iface->bat_v.aggr_len =0 ;skb_queue_head_init (&hard_iface->bat_v.aggr_list); + hard_iface->bat_v.aggr_list_enabled = false;INIT_DELAYED_WORK (&hard_iface->bat_v.aggr_wq, batadv_v_ogm_aggr_work); }
net/batman-adv/bat_v_ogm.c +12 -0
@@ -254,11 +254,18 @@ static void batadv_v_ogm_queue_on_if(struct batadv_priv *bat_priv, }spin_lock_bh (&hard_iface->bat_v.aggr_list.lock); +if (!hard_iface->bat_v.aggr_list_enabled) { +kfree_skb (skb); + goto unlock; + } +if (!batadv_v_ogm_queue_left (skb, hard_iface))batadv_v_ogm_aggr_send (bat_priv, hard_iface); hard_iface->bat_v.aggr_len +=batadv_v_ogm_len (skb);__skb_queue_tail (&hard_iface->bat_v.aggr_list, skb); + +unlock:spin_unlock_bh (&hard_iface->bat_v.aggr_list.lock); }
@@ -421,6 +428,10 @@ int batadv_v_ogm_iface_enable(struct batadv_hard_iface *hard_iface) {struct batadv_priv *bat_priv =netdev_priv (hard_iface->soft_iface); +spin_lock_bh (&hard_iface->bat_v.aggr_list.lock); + hard_iface->bat_v.aggr_list_enabled = true; +spin_unlock_bh (&hard_iface->bat_v.aggr_list.lock); +batadv_v_ogm_start_queue_timer (hard_iface);batadv_v_ogm_start_timer (bat_priv);
@@ -436,6 +447,7 @@ void batadv_v_ogm_iface_disable(struct batadv_hard_iface *hard_iface)cancel_delayed_work_sync (&hard_iface->bat_v.aggr_wq);spin_lock_bh (&hard_iface->bat_v.aggr_list.lock); + hard_iface->bat_v.aggr_list_enabled = false;batadv_v_ogm_aggr_list_free (hard_iface);spin_unlock_bh (&hard_iface->bat_v.aggr_list.lock); }
net/batman-adv/types.h +6 -0
@@ -130,6 +130,12 @@ struct batadv_hard_iface_bat_v {/** @aggr_list: queue for to be aggregated OGM packets */ struct sk_buff_head aggr_list; +/** +* @aggr_list_enabled: aggr_list is active and new skbs can be +* enqueued. Protected by aggr_list.lock after initialization +*/ + bool aggr_list_enabled:1; +/** @aggr_len: size of the OGM aggregate (excluding ethernet header) */ unsigned int aggr_len;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 107/175 batman-adv: tp_meter: restrict number of unacked list entries
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Sven Eckelmann <[email protected]>
commit e7c775110e1858e5a7471a23a9c9658c0af9df89 upstream.
When the unacked_list is unbound, an attacker could send messages with small lengths and appropriated seqno + gaps to force the receiver to allocate more and more unacked_list entries. And the end either causing an out-of-memory situation or increase the management overhead for the (large) list that significant portions of CPU cycles are wasted in searching through the list.
When limiting the list to a specific number, it is important to still correctly add a new entry to the list. But if the list became larger than the limit, the last entry of the list (with the highest seqno) must be dropped to still allow the earlier seqnos to finish and therefore to continue the process. Otherwise, the process might get stuck with too high seqnos which are not handled by batadv_tp_ack_unordered().
--- net/batman-adv/tp_meter.c | 23 ++++++++++++++++++++++- net/batman-adv/types.h | 3 +++ 2 files changed, 25 insertions(+), 1 deletion(-)
net/batman-adv/tp_meter.c +22 -1
@@ -87,6 +87,11 @@#define BATADV_TP_PLEN (BATADV_TP_PACKET_LEN - ETH_HLEN - \ sizeof(struct batadv_unicast_packet)) +/** +* BATADV_TP_MAX_UNACKED - maximum number of packets a receiver didn't yet ack +*/ +#define BATADV_TP_MAX_UNACKED 100 +static u8 batadv_tp_prerandom[4096 ]__read_mostly ;/**
@@ -1195,6 +1200,7 @@ static void batadv_tp_receiver_shutdown(struct timer_list *t)list_for_each_entry_safe (un, safe, &tp_vars->unacked_list, list) {list_del (&un->list);kfree (un); + tp_vars->unacked_count--; }spin_unlock_bh (&tp_vars->unacked_lock);
@@ -1308,6 +1314,7 @@ static bool batadv_tp_handle_out_of_order(struct batadv_tp_vars *tp_vars,/* if the list is empty immediately attach this new object */ if (list_empty (&tp_vars->unacked_list)) {list_add (&new->list, &tp_vars->unacked_list); + tp_vars->unacked_count++; goto out; }
@@ -1338,12 +1345,24 @@ static bool batadv_tp_handle_out_of_order(struct batadv_tp_vars *tp_vars,*/ list_add (&new->list, &un->list); added = true; + tp_vars->unacked_count++;break ; }/* received packet with smallest seqno out of order; add it to front */ -if (!added) +if (!added) {list_add (&new->list, &tp_vars->unacked_list); + tp_vars->unacked_count++; + } + +/* remove the last (biggest) unacked seqno when list is too large */ +if (tp_vars->unacked_count >BATADV_TP_MAX_UNACKED ) { + un =list_last_entry (&tp_vars->unacked_list, + struct batadv_tp_unacked, list); +list_del (&un->list); +kfree (un); + tp_vars->unacked_count--; + } out:spin_unlock_bh (&tp_vars->unacked_lock);
@@ -1380,6 +1399,7 @@ static void batadv_tp_ack_unordered(struct batadv_tp_vars *tp_vars)list_del (&un->list);kfree (un); + tp_vars->unacked_count--; }spin_unlock_bh (&tp_vars->unacked_lock); }
@@ -1430,6 +1450,7 @@ batadv_tp_init_recv(struct batadv_priv *bat_priv,spin_lock_init (&tp_vars->unacked_lock);INIT_LIST_HEAD (&tp_vars->unacked_list); + tp_vars->unacked_count =0 ;kref_get (&tp_vars->refcount);timer_setup (&tp_vars->timer, batadv_tp_receiver_shutdown,0 );
net/batman-adv/types.h +3 -0
@@ -1494,6 +1494,9 @@ struct batadv_tp_vars {/** @unacked_lock: protect unacked_list */ spinlock_t unacked_lock; +/** @unacked_count: number of unacked entries */ +size_t unacked_count; +/** @last_recv_time: time (jiffies) a msg was received */ unsigned long last_recv_time;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 108/175 batman-adv: tp_meter: annotate last_recv_time access with READ/WRITE_ONCE
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Sven Eckelmann <[email protected]>
commit d67c728f07fca2ee6ffdc6dd4421cf2e8691f4d1 upstream.
The last_recv_time field for batadv_tp_receiver tracks the jiffies value of the most recent activity and is used to detect timeouts. These accesses are not consistently protected by a lock, so READ_ONCE/WRITE_ONCE must be used to prevent data races caused by compiler optimizations.
--- net/batman-adv/tp_meter.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-)
net/batman-adv/tp_meter.c +4 -4
@@ -1183,7 +1183,7 @@ static void batadv_tp_receiver_shutdown(struct timer_list *t) bat_priv = tp_vars->bat_priv;/* if there is recent activity rearm the timer */ -if (!batadv_has_timed_out (tp_vars->last_recv_time, +if (!batadv_has_timed_out (READ_ONCE (tp_vars->last_recv_time),BATADV_TP_RECV_TIMEOUT )) {/* reset the receiver shutdown timer */ batadv_tp_reset_receiver_timer (tp_vars);
@@ -1424,7 +1424,7 @@ batadv_tp_init_recv(struct batadv_priv *bat_priv, tp_vars =batadv_tp_list_find_session (bat_priv, icmp->orig, icmp->session,BATADV_TP_RECEIVER );if (tp_vars) { - tp_vars->last_recv_time = jiffies; +WRITE_ONCE (tp_vars->last_recv_time, jiffies); goto out_unlock; }
@@ -1455,7 +1455,7 @@ batadv_tp_init_recv(struct batadv_priv *bat_priv,kref_get (&tp_vars->refcount);timer_setup (&tp_vars->timer, batadv_tp_receiver_shutdown,0 ); - tp_vars->last_recv_time = jiffies; +WRITE_ONCE (tp_vars->last_recv_time, jiffies);kref_get (&tp_vars->refcount);hlist_add_head_rcu (&tp_vars->list, &bat_priv->tp_list);
@@ -1506,7 +1506,7 @@ static void batadv_tp_recv_msg(struct batadv_priv *bat_priv, goto out; } - tp_vars->last_recv_time = jiffies; +WRITE_ONCE (tp_vars->last_recv_time, jiffies); }/* if the packet is a duplicate, it may be the case that an ACK has been
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 109/175 batman-adv: tp_meter: prevent parallel modifications of last_recv
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Sven Eckelmann <[email protected]>
commit 6dde0cfcb36e4d5b3de35b75696937478441eed4 upstream.
When last_recv is updated to store the last receive sequence number, it is assuming that nothing is modifying in parallel while:
* check for outdated packets is done
* out of order check is performed (and packets are stored in out-of-order queue)
* the out-of-order queue was searched for closed gaps
* sequence number for next ack is calculated
Nothing of that was actually protected. It could therefore happen that the last_recv was updated multiple times in parallel and the final sequence number was calculated with deltas which had no connection to the sequence number they were added to.
Lock this whole region with the same lock which was already used to protect the unacked (out-of-order) list.
--- net/batman-adv/tp_meter.c | 22 +++++++++++++--------- net/batman-adv/types.h | 2 +- 2 files changed, 14 insertions(+), 10 deletions(-)
net/batman-adv/tp_meter.c +13 -9
@@ -1294,6 +1294,7 @@ static int batadv_tp_send_ack(struct batadv_priv *bat_priv, const u8 *dst,*/ static bool batadv_tp_handle_out_of_order (struct batadv_tp_vars *tp_vars,const struct sk_buff *skb) + __must_hold(&tp_vars->unacked_lock) {const struct batadv_icmp_tp_packet *icmp;struct batadv_tp_unacked *un, *new;
@@ -1310,12 +1311,11 @@ static bool batadv_tp_handle_out_of_order(struct batadv_tp_vars *tp_vars, payload_len = skb->len -sizeof (struct batadv_unicast_packet ); new->len = payload_len; -spin_lock_bh (&tp_vars->unacked_lock);/* if the list is empty immediately attach this new object */ if (list_empty (&tp_vars->unacked_list)) {list_add (&new->list, &tp_vars->unacked_list); tp_vars->unacked_count++; - goto out; +return true; }/* otherwise loop over the list and either drop the packet because this
@@ -1364,9 +1364,6 @@ static bool batadv_tp_handle_out_of_order(struct batadv_tp_vars *tp_vars, tp_vars->unacked_count--; } -out: -spin_unlock_bh (&tp_vars->unacked_lock); -return true; }
@@ -1376,6 +1373,7 @@ static bool batadv_tp_handle_out_of_order(struct batadv_tp_vars *tp_vars,* @tp_vars: the private data of the current TP meter session */ static void batadv_tp_ack_unordered (struct batadv_tp_vars *tp_vars) + __must_hold(&tp_vars->unacked_lock) {struct batadv_tp_unacked *un, *safe;u32 to_ack;
@@ -1383,7 +1381,6 @@ static void batadv_tp_ack_unordered(struct batadv_tp_vars *tp_vars)/* go through the unacked packet list and possibly ACK them as * well */ -spin_lock_bh (&tp_vars->unacked_lock);list_for_each_entry_safe (un, safe, &tp_vars->unacked_list, list) {/* the list is ordered, therefore it is possible to stop as soon * there is a gap between the last acked seqno and the seqno of
@@ -1401,7 +1398,6 @@ static void batadv_tp_ack_unordered(struct batadv_tp_vars *tp_vars)kfree (un); tp_vars->unacked_count--; } -spin_unlock_bh (&tp_vars->unacked_lock); }/**
@@ -1481,6 +1477,7 @@ static void batadv_tp_recv_msg(struct batadv_priv *bat_priv,const struct batadv_icmp_tp_packet *icmp;struct batadv_tp_vars *tp_vars;size_t packet_size; +u32 to_ack;u32 seqno; icmp = (struct batadv_icmp_tp_packet *)skb->data;
@@ -1509,6 +1506,8 @@ static void batadv_tp_recv_msg(struct batadv_priv *bat_priv,WRITE_ONCE (tp_vars->last_recv_time, jiffies); } +spin_lock_bh (&tp_vars->unacked_lock); +/* if the packet is a duplicate, it may be the case that an ACK has been * lost. Resend the ACK */
@@ -1520,8 +1519,10 @@ static void batadv_tp_recv_msg(struct batadv_priv *bat_priv,/* exit immediately (and do not send any ACK) if the packet has * not been enqueued correctly */ -if (!batadv_tp_handle_out_of_order (tp_vars, skb)) +if (!batadv_tp_handle_out_of_order (tp_vars, skb)) { +spin_unlock_bh (&tp_vars->unacked_lock); goto out; + }/* send a duplicate ACK */ goto send_ack;
@@ -1535,11 +1536,14 @@ static void batadv_tp_recv_msg(struct batadv_priv *bat_priv,batadv_tp_ack_unordered (tp_vars); send_ack: + to_ack = tp_vars->last_recv; +spin_unlock_bh (&tp_vars->unacked_lock); +/* send the ACK. If the received packet was out of order, the ACK that * is going to be sent is a duplicate (the sender will count them and * possibly enter Fast Retransmit as soon as it has reached 3) */ -batadv_tp_send_ack (bat_priv, icmp->orig, tp_vars->last_recv, +batadv_tp_send_ack (bat_priv, icmp->orig, to_ack, icmp->timestamp, icmp->session, icmp->uid); out:batadv_tp_vars_put (tp_vars);
net/batman-adv/types.h +1 -1
@@ -1491,7 +1491,7 @@ struct batadv_tp_vars {/** @unacked_list: list of unacked packets (meta-info only) */ struct list_head unacked_list; -/** @unacked_lock: protect unacked_list */ +/** @unacked_lock: protect unacked_list + &batadv_tp_receiver.last_recv */ spinlock_t unacked_lock;/** @unacked_count: number of unacked entries */
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 110/175 batman-adv: tp_meter: handle overlapping packets
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Sven Eckelmann <[email protected]>
commit cbde75c38b21f022891525078622587ad557b7c1 upstream.
If the size of the packets would change during the transmission, it could happen that some retries of packets are overlapping. In this case, precise comparisons of sequence numbers by the receiver would be wrong. It is then necessary to check if the start sequence number to the end sequence number ("seqno + length") would contain a new range.
If this is the case then this is enough to accept this packet. In all other cases, the packet still has to be dropped (and not acked).
--- net/batman-adv/tp_meter.c | 25 +++++++++++-------------- 1 file changed, 11 insertions(+), 14 deletions(-)
net/batman-adv/tp_meter.c +11 -14
@@ -1284,7 +1284,8 @@ static int batadv_tp_send_ack(struct batadv_priv *bat_priv, const u8 *dst,/** * batadv_tp_handle_out_of_order() - store an out of order packet * @tp_vars: the private data of the current TP meter session -* @skb: the buffer containing the received packet +* @seqno: sequence number of new received packet +* @payload_len: length of the received packet * * Store the out of order packet in the unacked list for late processing. This * packets are kept in this list so that they can be ACKed at once as soon as
@@ -1293,22 +1294,17 @@ static int batadv_tp_send_ack(struct batadv_priv *bat_priv, const u8 *dst,* Return: true if the packed has been successfully processed, false otherwise */ static bool batadv_tp_handle_out_of_order (struct batadv_tp_vars *tp_vars, -const struct sk_buff *skb) +u32 seqno,u32 payload_len) __must_hold(&tp_vars->unacked_lock) { -const struct batadv_icmp_tp_packet *icmp;struct batadv_tp_unacked *un, *new; -u32 payload_len;bool added = false; new =kmalloc (sizeof (*new),GFP_ATOMIC );if (unlikely (!new))return false; - icmp = (struct batadv_icmp_tp_packet *)skb->data; - - new->seqno =ntohl (icmp->seqno); - payload_len = skb->len -sizeof (struct batadv_unicast_packet ); + new->seqno = seqno; new->len = payload_len;/* if the list is empty immediately attach this new object */
@@ -1476,7 +1472,7 @@ static void batadv_tp_recv_msg(struct batadv_priv *bat_priv, {const struct batadv_icmp_tp_packet *icmp;struct batadv_tp_vars *tp_vars; -size_t packet_size; +u32 payload_len;u32 to_ack;u32 seqno;
@@ -1511,15 +1507,17 @@ static void batadv_tp_recv_msg(struct batadv_priv *bat_priv,/* if the packet is a duplicate, it may be the case that an ACK has been * lost. Resend the ACK */ -if (batadv_seq_before (seqno, tp_vars->last_recv)) + payload_len = skb->len -sizeof (struct batadv_unicast_packet ); + to_ack = seqno + payload_len; +if (batadv_seq_before (to_ack, tp_vars->last_recv)) goto send_ack;/* if the packet is out of order enqueue it */ -if (ntohl (icmp->seqno) != tp_vars->last_recv) { +if (batadv_seq_before (tp_vars->last_recv, seqno)) {/* exit immediately (and do not send any ACK) if the packet has * not been enqueued correctly */ -if (!batadv_tp_handle_out_of_order (tp_vars, skb)) { +if (!batadv_tp_handle_out_of_order (tp_vars, seqno, payload_len)) {spin_unlock_bh (&tp_vars->unacked_lock); goto out; }
@@ -1529,8 +1527,7 @@ static void batadv_tp_recv_msg(struct batadv_priv *bat_priv, }/* if everything was fine count the ACKed bytes */ - packet_size = skb->len -sizeof (struct batadv_unicast_packet ); - tp_vars->last_recv += packet_size; + tp_vars->last_recv = to_ack;/* check if this ordered message filled a gap.... */ batadv_tp_ack_unordered (tp_vars);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 111/175 batman-adv: tt: dont merge change entries with different VIDs
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Sven Eckelmann <[email protected]>
commit f08e06c2d5c3e2434e7c773f2213f4a7dce6bc1e upstream.
batadv_tt_local_event() merges/cancels events for the same client which would conflict or be duplicates. The matching of the queued events only compares the MAC address - the VLAN ID stored in each event is ignored.
If a MAC would now appear on multiple VID, the two ADD change events (for VID 1 and VID 2) would be merged to a single vid event. The remote can therefore not calculate the correct TT table and desync. A full translation table exchange is required to recover from this state.
A check of VID is therefore necessary to avoid such wrong merges/cancels.
--- net/batman-adv/translation-table.c | 3 +++ 1 file changed, 3 insertions(+)
net/batman-adv/translation-table.c +3 -0
@@ -485,6 +485,9 @@ static void batadv_tt_local_event(struct batadv_priv *bat_priv,if (!batadv_compare_eth (entry->change.addr, common->addr))continue ; +if (entry->change.vid != tt_change_node->change.vid) +continue ; +/* DEL+ADD in the same orig interval have no effect and can be * removed to avoid silly behaviour on the receiver side. The * other way around (ADD+DEL) can happen in case of roaming of
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 94/175 batman-adv: tp_meter: avoid window underflow
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Sven Eckelmann <[email protected]>
commit 765947b81fb54b6ebb0bc1cfe55c0fa399e002b8 upstream.
In batadv_tp_avail(), win_left is calculated with 32-bit unsigned
arithmetic: win_left = win_limit - tp_vars->last_sent;
During Fast Recovery, cwnd is inflated and last_sent advances rapidly. When Fast Recovery ends, cwnd drops abruptly back to ss_threshold. If the newly shrunk win_limit is less than last_sent, the unsigned subtraction will underflow, wrapping to a massive positive value. Instead of returning that the window is full (unavailable), it returns that the sender can continue sending.
To handle this situation, it must be checked whether the windows end sequence number (win_limit) has to be compared with the last sent sequence number. If it would be before the last sent sequence number, then more acks are needed before the transmission can be started again.
--- net/batman-adv/tp_meter.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-)
net/batman-adv/tp_meter.c +6 -1
@@ -817,10 +817,15 @@ static void batadv_tp_recv_ack(struct batadv_priv *bat_priv,static bool batadv_tp_avail (struct batadv_tp_vars *tp_vars,size_t payload_len) { +u32 last_sent =READ_ONCE (tp_vars->last_sent);u32 win_left, win_limit; win_limit =atomic_read (&tp_vars->last_acked) + tp_vars->cwnd; - win_left = win_limit - tp_vars->last_sent; + +if (batadv_seq_before (last_sent, win_limit)) + win_left = win_limit - last_sent; +else + win_left =0 ;return win_left >= payload_len; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 112/175 batman-adv: tt: track roam count per VID
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Sven Eckelmann <[email protected]>
commit 12407d5f61c2653a64f2ff4b22f3c267f8420ef1 upstream.
batadv_tt_check_roam_count() is supposed to track roaming of a TT entry. But TT entries are for a MAC + VID. The VID was completely missed and thus leads to incorrect detection of ROAM counts when a client MAC exists in multiple VLANs.
--- net/batman-adv/translation-table.c | 9 +++++++-- net/batman-adv/types.h | 3 +++ 2 files changed, 10 insertions(+), 2 deletions(-)
net/batman-adv/translation-table.c +7 -2
@@ -3517,6 +3517,7 @@ static void batadv_tt_roam_purge(struct batadv_priv *bat_priv)* batadv_tt_check_roam_count() - check if a client has roamed too frequently * @bat_priv: the bat priv with all the soft interface information * @client: mac address of the roaming client +* @vid: VLAN identifier * * This function checks whether the client already reached the * maximum number of possible roaming phases. In this case the ROAMING_ADV
@@ -3524,7 +3525,7 @@ static void batadv_tt_roam_purge(struct batadv_priv *bat_priv)* * Return: true if the ROAMING_ADV can be sent, false otherwise */ -static bool batadv_tt_check_roam_count (struct batadv_priv *bat_priv,u8 *client) +static bool batadv_tt_check_roam_count (struct batadv_priv *bat_priv,u8 *client,u16 vid) {struct batadv_tt_roam_node *tt_roam_node;bool ret = false;
@@ -3537,6 +3538,9 @@ static bool batadv_tt_check_roam_count(struct batadv_priv *bat_priv, u8 *client)if (!batadv_compare_eth (tt_roam_node->addr, client))continue ; +if (tt_roam_node->vid != vid) +continue ; +if (batadv_has_timed_out (tt_roam_node->first_time,BATADV_ROAMING_MAX_TIME ))continue ;
@@ -3558,6 +3562,7 @@ static bool batadv_tt_check_roam_count(struct batadv_priv *bat_priv, u8 *client)atomic_set (&tt_roam_node->counter,BATADV_ROAMING_MAX_COUNT -1 );ether_addr_copy (tt_roam_node->addr, client); + tt_roam_node->vid = vid;list_add (&tt_roam_node->list, &bat_priv->tt.roam_list); ret = true;
@@ -3594,7 +3599,7 @@ static void batadv_send_roam_adv(struct batadv_priv *bat_priv, u8 *client,/* before going on we have to check whether the client has * already roamed to us too many times */ -if (!batadv_tt_check_roam_count (bat_priv, client)) +if (!batadv_tt_check_roam_count (bat_priv, client, vid)) goto out; batadv_dbg(BATADV_DBG_TT, bat_priv,
net/batman-adv/types.h +3 -0
@@ -1995,6 +1995,9 @@ struct batadv_tt_roam_node {/** @addr: mac address of the client in the roaming phase */ u8 addr[ETH_ALEN ]; +/** @vid: VLAN identifier */ +u16 vid; +/** * @counter: number of allowed roaming events per client within a single * OGM interval (changes are committed with each OGM)
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 113/175 batman-adv: dat: prevent false sharing between VLANs
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Sven Eckelmann <[email protected]>
commit 20d7658b74169f86d4ac01b9185b3eadddf71f28 upstream.
The local hash of DAT entries is supposed to be VLAN (VID) aware. But the adding to the hash and the search in the hash were not checking the VID information of the hash entries. The entries would therefore only be correctly separated when batadv_hash_dat() didn't select the same buckets for different VIDs.
--- net/batman-adv/distributed-arp-table.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-)
net/batman-adv/distributed-arp-table.c +9 -3
@@ -215,10 +215,13 @@ static void batadv_dat_purge(struct work_struct *work)*/ static bool batadv_compare_dat (const struct hlist_node *node,const void *data2) { - const void *data1 = container_of(node, struct batadv_dat_entry, - hash_entry); +const struct batadv_dat_entry *entry1; +const struct batadv_dat_entry *entry2; -return memcmp (data1, data2,sizeof (__be32)) ==0 ; + entry1 = container_of(node, struct batadv_dat_entry, hash_entry); + entry2 = data2; + +return entry1->ip == entry2->ip && entry1->vid == entry2->vid; }/**
@@ -345,6 +348,9 @@ batadv_dat_entry_hash_find(struct batadv_priv *bat_priv, __be32 ip,if (dat_entry->ip != ip)continue ; +if (dat_entry->vid != vid) +continue ; +if (!kref_get_unless_zero (&dat_entry->refcount))continue ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 114/175 batman-adv: tvlv: enforce 2-byte alignment
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Sven Eckelmann <[email protected]>
commit 32a6799255525d6ea4da0f7e9e0e521ad9560a46 upstream.
The fields of an aggregated OGM(v2) are accessed assuming (at least) 2-byte alignment, so a following OGM must start at an even offset. As the header length is even, an odd tvlv_len would misalign it and trigger unaligned accesses on strict-alignment architectures.
Such a misaligned TVLV/OGM/OGMv2 is not created by a normal participant in the mesh. Therefore, reject such malformed packets.
--- net/batman-adv/bat_iv_ogm.c | 11 ++++++++++- net/batman-adv/bat_v_ogm.c | 11 ++++++++++- net/batman-adv/tvlv.c | 6 ++++++ 3 files changed, 26 insertions(+), 2 deletions(-)
net/batman-adv/bat_iv_ogm.c +10 -1
@@ -310,14 +310,23 @@ batadv_iv_ogm_aggr_packet(int buff_pos, int packet_len, const struct batadv_ogm_packet *ogm_packet) {int next_buff_pos =0 ; +u16 tvlv_len;/* check if there is enough space for the header */ next_buff_pos += buff_pos +sizeof (*ogm_packet);if (next_buff_pos > packet_len)return false; + tvlv_len =ntohs (ogm_packet->tvlv_len); + +/* the fields of an aggregated OGM are accessed assuming (at least) +* 2-byte alignment, so a following OGM must start at an even offset. +*/ +if (tvlv_len &1 ) +return false; +/* check if there is enough space for the optional TVLV */ - next_buff_pos +=ntohs (ogm_packet->tvlv_len); + next_buff_pos += tvlv_len;return next_buff_pos <= packet_len; }
net/batman-adv/bat_v_ogm.c +10 -1
@@ -853,14 +853,23 @@ batadv_v_ogm_aggr_packet(int buff_pos, int packet_len, const struct batadv_ogm2_packet *ogm2_packet) {int next_buff_pos =0 ; +u16 tvlv_len;/* check if there is enough space for the header */ next_buff_pos += buff_pos +sizeof (*ogm2_packet);if (next_buff_pos > packet_len)return false; + tvlv_len =ntohs (ogm2_packet->tvlv_len); + +/* the fields of an aggregated OGMv2 are accessed assuming (at least) +* 2-byte alignment, so a following OGMv2 must start at an even offset. +*/ +if (tvlv_len &1 ) +return false; +/* check if there is enough space for the optional TVLV */ - next_buff_pos +=ntohs (ogm2_packet->tvlv_len); + next_buff_pos += tvlv_len;return next_buff_pos <= packet_len; }
net/batman-adv/tvlv.c +6 -0
@@ -464,6 +464,12 @@ int batadv_tvlv_containers_process(struct batadv_priv *bat_priv,if (tvlv_value_cont_len > tvlv_value_len)break ; +/* the next tvlv header is accessed assuming (at least) 2-byte +* alignment, so it must start at an even offset. +*/ +if (tvlv_value_cont_len &1 ) +break ; + tvlv_handler =batadv_tvlv_handler_get (bat_priv, tvlv_hdr->type, tvlv_hdr->version);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 115/175 batman-adv: tvlv: avoid race of cifsnotfound handler state
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Sven Eckelmann <[email protected]>
commit edb557b2ba38fea2c5eb710cf366c797e187218c upstream.
TVLV handlers can have the flag BATADV_TVLV_HANDLER_OGM_CIFNOTFND set to signal that the OGM handler should be called (with NULL for data) when the specific TVLV container was not found in the OGM. This is used by:
* DAT
* GW
* Multicast (OGM + Tracker)
The state whether the handler was executed was stored in the struct batadv_tvlv_handler. But the TVLV processing is started without any lock. Multiple parallel contexts processing TVLVs would therefore overwrite each others BATADV_TVLV_HANDLER_OGM_CALLED flag in the shared batadv_tvlv_handler.
Drop the shared BATADV_TVLV_HANDLER_OGM_CALLED flag and instead determine, per TVLV buffer, whether a matching container was present by scanning the packet's buffer.
--- net/batman-adv/tvlv.c | 63 ++++++++++++++++++++++++++++++++++++++---- net/batman-adv/types.h | 7 ----- 2 files changed, 57 insertions(+), 13 deletions(-)
net/batman-adv/tvlv.c +57 -6
@@ -398,7 +398,6 @@ static int batadv_tvlv_call_handler(struct batadv_priv *bat_priv, tvlv_handler->ogm_handler (bat_priv, orig_node,BATADV_NO_FLAGS , tvlv_value, tvlv_value_len); - tvlv_handler->flags |=BATADV_TVLV_HANDLER_OGM_CALLED ;break ;case BATADV_UNICAST_TVLV :if (!skb)
@@ -430,6 +429,48 @@ static int batadv_tvlv_call_handler(struct batadv_priv *bat_priv,return NET_RX_SUCCESS ; } +/** +* batadv_tvlv_containers_contain() - check if a tvlv buffer holds a container +* @tvlv_value: tvlv content +* @tvlv_value_len: tvlv content length +* @type: tvlv container type to look for +* @version: tvlv container version to look for +* +* Return: true if a container of the given type and version is present in the +* tvlv buffer, false otherwise. +*/ +static bool batadv_tvlv_containers_contain (void *tvlv_value, +u16 tvlv_value_len,u8 type, +u8 version) +{ +struct batadv_tvlv_hdr *tvlv_hdr; +u16 tvlv_value_cont_len; + +while (tvlv_value_len >=sizeof (*tvlv_hdr)) { + tvlv_hdr = tvlv_value; + tvlv_value_cont_len =ntohs (tvlv_hdr->len); + tvlv_value = tvlv_hdr +1 ; + tvlv_value_len -=sizeof (*tvlv_hdr); + +if (tvlv_value_cont_len > tvlv_value_len) +break ; + +/* the next tvlv header is accessed assuming (at least) 2-byte +* alignment, so it must start at an even offset. +*/ +if (tvlv_value_cont_len &1 ) +break ; + +if (tvlv_hdr->type == type && tvlv_hdr->version == version) +return true; + + tvlv_value = (u8 *)tvlv_value + tvlv_value_cont_len; + tvlv_value_len -= tvlv_value_cont_len; + } + +return false; +} +/** * batadv_tvlv_containers_process() - parse the given tvlv buffer to call the * appropriate handlers
@@ -449,7 +490,9 @@ int batadv_tvlv_containers_process(struct batadv_priv *bat_priv, struct sk_buff *skb, void *tvlv_value, u16 tvlv_value_len) { + u16 tvlv_value_start_len = tvlv_value_len;struct batadv_tvlv_handler *tvlv_handler; +void *tvlv_value_start = tvlv_value;struct batadv_tvlv_hdr *tvlv_hdr;u16 tvlv_value_cont_len;u8 cifnotfound =BATADV_TVLV_HANDLER_OGM_CIFNOTFND ;
@@ -493,12 +536,20 @@ int batadv_tvlv_containers_process(struct batadv_priv *bat_priv,if (!tvlv_handler->ogm_handler)continue ; -if ((tvlv_handler->flags &BATADV_TVLV_HANDLER_OGM_CIFNOTFND ) && - !(tvlv_handler->flags &BATADV_TVLV_HANDLER_OGM_CALLED )) - tvlv_handler->ogm_handler (bat_priv, orig_node, - cifnotfound,NULL ,0 ); +if (!(tvlv_handler->flags &BATADV_TVLV_HANDLER_OGM_CIFNOTFND )) +continue ; - tvlv_handler->flags &= ~BATADV_TVLV_HANDLER_OGM_CALLED ; +/* if the corresponding container was present then the handler +* was already called from the loop above +*/ +if (batadv_tvlv_containers_contain (tvlv_value_start, + tvlv_value_start_len, + tvlv_handler->type, + tvlv_handler->version)) +continue ; + + tvlv_handler->ogm_handler (bat_priv, orig_node, + cifnotfound,NULL ,0 ); }rcu_read_unlock ();
net/batman-adv/types.h +0 -7
@@ -2413,13 +2413,6 @@ enum batadv_tvlv_handler_flags {* will call this handler even if its type was not found (with no data) */ BATADV_TVLV_HANDLER_OGM_CIFNOTFND = BIT(1), - -/** -* @BATADV_TVLV_HANDLER_OGM_CALLED: interval tvlv handling flag - the -* API marks a handler as being called, so it won't be called if the -* BATADV_TVLV_HANDLER_OGM_CIFNOTFND flag was set -*/ - BATADV_TVLV_HANDLER_OGM_CALLED = BIT(2), };#endif /* _NET_BATMAN_ADV_TYPES_H_ */
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 116/175 ipv6: account for fraggap on the paged allocation path
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Wongi Lee <[email protected]>
commit 736b380e28d0480c7bc3e022f1950f31fe53a7c5 upstream.
In __ip6_append_data(), when the paged-allocation branch is taken (MSG_MORE / NETIF_F_SG / large fraglen), alloclen and pagedlen are computed as
alloclen = fragheaderlen + transhdrlen; pagedlen = datalen - transhdrlen;
datalen already includes fraggap (datalen = length + fraggap). When fraggap is non-zero, this is not the first skb and transhdrlen is zero. The fraggap bytes carried over from the previous skb are copied just past the fragment headers in the new skb's linear area. The linear area is therefore undersized by fraggap bytes while pagedlen is overstated by the same amount, and the copy writes past skb->end into the trailing skb_shared_info.
An unprivileged user can trigger this via a UDPv6 socket using MSG_MORE together with MSG_SPLICE_PAGES.
The bad accounting was introduced by commit 773ba4fe9104 ("ipv6:
avoid partial copy for zc"). Before commit ce650a166335 ("udp6: Fix __ip6_append_data()'s handling of MSG_SPLICE_PAGES"), the negative copy value caused -EINVAL to be returned. That later commit allowed MSG_SPLICE_PAGES to proceed in this case, making the corruption triggerable.
The non-paged branch sets alloclen to fraglen, which already accounts for fraggap because datalen does. Bring the paged branch in line by adding fraggap to alloclen and subtracting it from pagedlen.
After this adjustment, copy no longer collapses to -fraggap on the paged path, so remove the stale comment describing that old arithmetic. Since a negative copy is no longer expected for a valid MSG_SPLICE_PAGES case, remove the MSG_SPLICE_PAGES exception from the negative copy check.
--- net/ipv6/ip6_output.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-)
net/ipv6/ip6_output.c +3 -6
@@ -1633,8 +1633,8 @@ alloc_new_skb: !(rt->dst.dev->features & NETIF_F_SG))) alloclen = fraglen; else { - alloclen = fragheaderlen + transhdrlen; - pagedlen = datalen - transhdrlen; + alloclen = fragheaderlen + transhdrlen + fraggap; + pagedlen = datalen - transhdrlen - fraggap; } alloclen += alloc_extra;
@@ -1649,10 +1649,7 @@ alloc_new_skb: fraglen = datalen + fragheaderlen; copy = datalen - transhdrlen - fraggap - pagedlen; -/* [!] NOTE: copy may be negative if pagedlen>0 -* because then the equation may reduces to -fraggap. -*/ -if (copy <0 && !(flags &MSG_SPLICE_PAGES )) { +if (copy <0 ) { err = -EINVAL ; goto error; }
Greg Kroah-Hartman
maintainerPATCH 117/175 inet: add indirect call wrapper for getfrag() calls
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Eric Dumazet <[email protected]>
[ Upstream commit 5204ccbfa22358f95afd031a3f337e6d9a74baea ]
UDP send path suffers from one indirect call to ip_generic_getfrag()
We can use INDIRECT_CALL_1() to avoid it.
Stable-dep-of: eca856950f7c ("ipv4: account for fraggap on the paged allocation path")
--- net/ipv4/ip_output.c | 13 +++++++++---- net/ipv6/ip6_output.c | 13 ++++++++----- 2 files changed, 17 insertions(+), 9 deletions(-)
net/ipv4/ip_output.c +9 -4
@@ -1168,7 +1168,10 @@ static int __ip_append_data(struct sock *sk,/* [!] NOTE: copy will be negative if pagedlen>0 * because then the equation reduces to -fraggap. */ -if (copy >0 &&getfrag (from, data + transhdrlen, offset, copy, fraggap, skb) <0 ) { +if (copy >0 && +INDIRECT_CALL_1 (getfrag, ip_generic_getfrag, + from, data + transhdrlen, offset, + copy, fraggap, skb) <0 ) { err = -EFAULT ;kfree_skb (skb); goto error;
@@ -1212,8 +1215,9 @@ static int __ip_append_data(struct sock *sk,unsigned int off; off = skb->len; -if (getfrag (from,skb_put (skb, copy), - offset, copy, off, skb) <0 ) { +if (INDIRECT_CALL_1 (getfrag, ip_generic_getfrag, + from,skb_put (skb, copy), + offset, copy, off, skb) <0 ) {__skb_trim (skb, off); err = -EFAULT ; goto error;
@@ -1253,7 +1257,8 @@ static int __ip_append_data(struct sock *sk,get_page (pfrag->page); } copy =min_t (int, copy, pfrag->size - pfrag->offset); -if (getfrag (from, +if (INDIRECT_CALL_1 (getfrag, ip_generic_getfrag, + from,page_address (pfrag->page) + pfrag->offset, offset, copy, skb->len, skb) <0 ) goto error_efault;
net/ipv6/ip6_output.c +8 -5
@@ -1695,8 +1695,9 @@ static int __ip6_append_data(struct sock *sk,pskb_trim_unique (skb_prev, maxfraglen); }if (copy >0 && -getfrag (from, data + transhdrlen, offset, - copy, fraggap, skb) <0 ) { +INDIRECT_CALL_1 (getfrag, ip_generic_getfrag, + from, data + transhdrlen, offset, + copy, fraggap, skb) <0 ) { err = -EFAULT ;kfree_skb (skb); goto error;
@@ -1740,8 +1741,9 @@ static int __ip6_append_data(struct sock *sk,unsigned int off; off = skb->len; -if (getfrag (from,skb_put (skb, copy), - offset, copy, off, skb) <0 ) { +if (INDIRECT_CALL_1 (getfrag, ip_generic_getfrag, + from,skb_put (skb, copy), + offset, copy, off, skb) <0 ) {__skb_trim (skb, off); err = -EFAULT ; goto error;
@@ -1781,7 +1783,8 @@ static int __ip6_append_data(struct sock *sk,get_page (pfrag->page); } copy =min_t (int, copy, pfrag->size - pfrag->offset); -if (getfrag (from, +if (INDIRECT_CALL_1 (getfrag, ip_generic_getfrag, + from,page_address (pfrag->page) + pfrag->offset, offset, copy, skb->len, skb) <0 ) goto error_efault;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 118/175 ipv4: account for fraggap on the paged allocation path
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Wongi Lee <[email protected]>
[ Upstream commit eca856950f7cb1a221e02b99d758409f2c5cec42 ]
In __ip_append_data(), when the paged-allocation branch is taken, alloclen and pagedlen are computed as
alloclen = fragheaderlen + transhdrlen; pagedlen = datalen - transhdrlen;
datalen already includes fraggap, but the fraggap bytes carried over from the previous skb are copied into the new skb's linear area at offset transhdrlen by the subsequent skb_copy_and_csum_bits(). The linear area is therefore undersized by fraggap bytes while pagedlen is overstated by the same amount.
The non-paged branch sets alloclen to fraglen, which already accounts for fraggap because datalen does. Bring the paged branch in line by adding fraggap to alloclen and subtracting it from pagedlen.
After this adjustment, copy no longer collapses to -fraggap on the paged path, so remove the stale comment describing that old arithmetic.
--- net/ipv4/ip_output.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-)
net/ipv4/ip_output.c +2 -5
@@ -1117,8 +1117,8 @@ static int __ip_append_data(struct sock *sk, !(rt->dst.dev->features & NETIF_F_SG))) alloclen = fraglen; else { - alloclen = fragheaderlen + transhdrlen; - pagedlen = datalen - transhdrlen; + alloclen = fragheaderlen + transhdrlen + fraggap; + pagedlen = datalen - transhdrlen - fraggap; } alloclen += alloc_extra;
@@ -1165,9 +1165,6 @@ static int __ip_append_data(struct sock *sk, } copy = datalen - transhdrlen - fraggap - pagedlen; -/* [!] NOTE: copy will be negative if pagedlen>0 -* because then the equation reduces to -fraggap. -*/ if (copy >0 && INDIRECT_CALL_1(getfrag, ip_generic_getfrag, from, data + transhdrlen, offset,
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 119/175 ntfs3: reject direct userspace writes to reserved $LX* xattrs
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Konstantin Komarov <[email protected]>
commit 5b08dccecf825cbf905f348bc6ccb497507e28e2 upstream.
NTFS3 uses $LXUID, $LXGID, $LXMOD and $LXDEV as internal WSL permission metadata and reloads them into i_uid, i_gid and i_mode from ntfs_get_wsl_perm().
Because the empty-prefix xattr handler also lets file owners call setxattr() on these names directly, an unprivileged writer on a writable ntfs3 mount can plant root ownership and S_ISUID on their own file and gain euid 0 after inode reload.
Reject direct userspace writes to the reserved $LX* names. Internal ntfs3 metadata updates are unchanged because ntfs_save_wsl_perm() writes them via ntfs_set_ea() directly.
--- fs/ntfs3/xattr.c | 12 ++++++++++++ 1 file changed, 12 insertions(+)
fs/ntfs3/xattr.c +12 -0
@@ -828,6 +828,12 @@ out:return err; } +static bool ntfs_is_reserved_lxattr (const char *name) +{ +return !strcmp (name,"$LXUID" ) || !strcmp (name,"$LXGID" ) || + !strcmp (name,"$LXMOD" ) || !strcmp (name,"$LXDEV" ); +} +/* * ntfs_setxattr - inode_operations::setxattr */
@@ -932,6 +938,12 @@ set_new_fa: goto out; } +/* Do not allow non privileged users to change $LXUID/$LXGID... */ +if (ntfs_is_reserved_lxattr (name) && !capable (CAP_SYS_ADMIN )) { + err = -EPERM ; + goto out; + } +/* Deal with NTFS extended attribute. */ err =ntfs_set_ea (inode, name,strlen (name), value, size, flags,0 ,NULL );