Merge 72fda6c8e5 ("Merge tag 'execve-v6.11-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/kees/linux") into android-mainline

Steps on the way to v6.11-rc1

Change-Id: I838e4df23bfa37e4025d6c9007b8eae05d6f4281
Signed-off-by: Tudor Ambarus <tudordana@google.com>
This commit is contained in:
Tudor Ambarus
2024-08-08 18:23:53 +00:00
41 changed files with 642 additions and 346 deletions
@@ -7439,17 +7439,18 @@
Crash from Xen panic notifier, without executing late
panic() code such as dumping handler.
xen_mc_debug [X86,XEN,EARLY]
Enable multicall debugging when running as a Xen PV guest.
Enabling this feature will reduce performance a little
bit, so it should only be enabled for obtaining extended
debug data in case of multicall errors.
xen_msr_safe= [X86,XEN,EARLY]
Format: <bool>
Select whether to always use non-faulting (safe) MSR
access functions when running as Xen PV guest. The
default value is controlled by CONFIG_XEN_PV_MSR_SAFE.
xen_nopvspin [X86,XEN,EARLY]
Disables the qspinlock slowpath using Xen PV optimizations.
This parameter is obsoleted by "nopvspin" parameter, which
has equivalent effect for XEN platform.
xen_nopv [X86]
Disables the PV optimizations forcing the HVM guest to
run as generic HVM guest with no PV drivers.
+2
View File
@@ -8285,7 +8285,9 @@ S: Supported
T: git git://git.kernel.org/pub/scm/linux/kernel/git/kees/linux.git for-next/execve
F: Documentation/userspace-api/ELF.rst
F: fs/*binfmt_*.c
F: fs/Kconfig.binfmt
F: fs/exec.c
F: fs/exec_test.c
F: include/linux/binfmts.h
F: include/linux/elf.h
F: include/uapi/linux/binfmts.h
+1 -1
View File
@@ -109,7 +109,7 @@ int set_foreign_p2m_mapping(struct gnttab_map_grant_ref *map_ops,
* immediate unmapping.
*/
map_ops[i].status = GNTST_general_error;
unmap.host_addr = map_ops[i].host_addr,
unmap.host_addr = map_ops[i].host_addr;
unmap.handle = map_ops[i].handle;
map_ops[i].handle = INVALID_GRANT_HANDLE;
if (map_ops[i].flags & GNTMAP_device_map)
-2
View File
@@ -10,8 +10,6 @@
#include <xen/xen.h>
#include <xen/interface/physdev.h>
#include "xen-ops.h"
#include "pmu.h"
#include "smp.h"
static unsigned int xen_io_apic_read(unsigned apic, unsigned reg)
{
+1 -1
View File
@@ -3,7 +3,7 @@
#include <linux/debugfs.h>
#include <linux/slab.h>
#include "debugfs.h"
#include "xen-ops.h"
static struct dentry *d_xen_debug;
-7
View File
@@ -1,7 +0,0 @@
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef _XEN_DEBUGFS_H
#define _XEN_DEBUGFS_H
struct dentry * __init xen_init_debugfs(void);
#endif /* _XEN_DEBUGFS_H */
-2
View File
@@ -20,8 +20,6 @@
#include <asm/setup.h>
#include "xen-ops.h"
#include "smp.h"
#include "pmu.h"
EXPORT_SYMBOL_GPL(hypercall_page);
-2
View File
@@ -28,8 +28,6 @@
#include <asm/xen/page.h>
#include "xen-ops.h"
#include "mmu.h"
#include "smp.h"
static unsigned long shared_info_pfn;
-4
View File
@@ -85,10 +85,6 @@
#endif
#include "xen-ops.h"
#include "mmu.h"
#include "smp.h"
#include "multicalls.h"
#include "pmu.h"
#include "../kernel/cpu/cpu.h" /* get_cpu_cap() */
+1 -2
View File
@@ -5,8 +5,7 @@
#include <asm/xen/hypercall.h>
#include <xen/interface/memory.h>
#include "multicalls.h"
#include "mmu.h"
#include "xen-ops.h"
unsigned long arbitrary_virt_to_mfn(void *vaddr)
{
-28
View File
@@ -1,28 +0,0 @@
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef _XEN_MMU_H
#include <linux/linkage.h>
#include <asm/page.h>
enum pt_level {
PT_PGD,
PT_P4D,
PT_PUD,
PT_PMD,
PT_PTE
};
bool __set_phys_to_machine(unsigned long pfn, unsigned long mfn);
void set_pte_mfn(unsigned long vaddr, unsigned long pfn, pgprot_t flags);
pte_t xen_ptep_modify_prot_start(struct vm_area_struct *vma, unsigned long addr, pte_t *ptep);
void xen_ptep_modify_prot_commit(struct vm_area_struct *vma, unsigned long addr,
pte_t *ptep, pte_t pte);
unsigned long xen_read_cr2_direct(void);
extern void xen_init_mmu_ops(void);
extern void xen_hvm_init_mmu_ops(void);
#endif /* _XEN_MMU_H */
+1 -1
View File
@@ -5,7 +5,7 @@
#include <xen/interface/xen.h>
#include <xen/hvm.h>
#include "mmu.h"
#include "xen-ops.h"
#ifdef CONFIG_PROC_VMCORE
/*
+7 -8
View File
@@ -82,9 +82,7 @@
#include <xen/hvc-console.h>
#include <xen/swiotlb-xen.h>
#include "multicalls.h"
#include "mmu.h"
#include "debugfs.h"
#include "xen-ops.h"
/*
* Prototypes for functions called via PV_CALLEE_SAVE_REGS_THUNK() in order
@@ -128,7 +126,7 @@ static DEFINE_SPINLOCK(xen_reservation_lock);
* looking at another vcpu's cr3 value, it should use this variable.
*/
DEFINE_PER_CPU(unsigned long, xen_cr3); /* cr3 stored as physaddr */
DEFINE_PER_CPU(unsigned long, xen_current_cr3); /* actual vcpu cr3 */
static DEFINE_PER_CPU(unsigned long, xen_current_cr3); /* actual vcpu cr3 */
static phys_addr_t xen_pt_base, xen_pt_size __initdata;
@@ -305,16 +303,17 @@ static void xen_set_pte(pte_t *ptep, pte_t pteval)
__xen_set_pte(ptep, pteval);
}
pte_t xen_ptep_modify_prot_start(struct vm_area_struct *vma,
unsigned long addr, pte_t *ptep)
static pte_t xen_ptep_modify_prot_start(struct vm_area_struct *vma,
unsigned long addr, pte_t *ptep)
{
/* Just return the pte as-is. We preserve the bits on commit */
trace_xen_mmu_ptep_modify_prot_start(vma->vm_mm, addr, ptep, *ptep);
return *ptep;
}
void xen_ptep_modify_prot_commit(struct vm_area_struct *vma, unsigned long addr,
pte_t *ptep, pte_t pte)
static void xen_ptep_modify_prot_commit(struct vm_area_struct *vma,
unsigned long addr,
pte_t *ptep, pte_t pte)
{
struct mmu_update u;
+103 -25
View File
@@ -23,26 +23,21 @@
#include <linux/percpu.h>
#include <linux/hardirq.h>
#include <linux/debugfs.h>
#include <linux/jump_label.h>
#include <linux/printk.h>
#include <asm/xen/hypercall.h>
#include "multicalls.h"
#include "debugfs.h"
#include "xen-ops.h"
#define MC_BATCH 32
#define MC_DEBUG 0
#define MC_ARGS (MC_BATCH * 16)
struct mc_buffer {
unsigned mcidx, argidx, cbidx;
struct multicall_entry entries[MC_BATCH];
#if MC_DEBUG
struct multicall_entry debug[MC_BATCH];
void *caller[MC_BATCH];
#endif
unsigned char args[MC_ARGS];
struct callback {
void (*fn)(void *);
@@ -50,13 +45,98 @@ struct mc_buffer {
} callbacks[MC_BATCH];
};
struct mc_debug_data {
struct multicall_entry entries[MC_BATCH];
void *caller[MC_BATCH];
size_t argsz[MC_BATCH];
unsigned long *args[MC_BATCH];
};
static DEFINE_PER_CPU(struct mc_buffer, mc_buffer);
static struct mc_debug_data mc_debug_data_early __initdata;
static struct mc_debug_data __percpu *mc_debug_data __refdata =
&mc_debug_data_early;
DEFINE_PER_CPU(unsigned long, xen_mc_irq_flags);
static struct static_key mc_debug __ro_after_init;
static bool mc_debug_enabled __initdata;
static int __init xen_parse_mc_debug(char *arg)
{
mc_debug_enabled = true;
static_key_slow_inc(&mc_debug);
return 0;
}
early_param("xen_mc_debug", xen_parse_mc_debug);
static int __init mc_debug_enable(void)
{
struct mc_debug_data __percpu *mcdb;
unsigned long flags;
if (!mc_debug_enabled)
return 0;
mcdb = alloc_percpu(struct mc_debug_data);
if (!mcdb) {
pr_err("xen_mc_debug inactive\n");
static_key_slow_dec(&mc_debug);
return -ENOMEM;
}
/* Be careful when switching to percpu debug data. */
local_irq_save(flags);
xen_mc_flush();
mc_debug_data = mcdb;
local_irq_restore(flags);
pr_info("xen_mc_debug active\n");
return 0;
}
early_initcall(mc_debug_enable);
/* Number of parameters of hypercalls used via multicalls. */
static const uint8_t hpcpars[] = {
[__HYPERVISOR_mmu_update] = 4,
[__HYPERVISOR_stack_switch] = 2,
[__HYPERVISOR_fpu_taskswitch] = 1,
[__HYPERVISOR_update_descriptor] = 2,
[__HYPERVISOR_update_va_mapping] = 3,
[__HYPERVISOR_mmuext_op] = 4,
};
static void print_debug_data(struct mc_buffer *b, struct mc_debug_data *mcdb,
int idx)
{
unsigned int arg;
unsigned int opidx = mcdb->entries[idx].op & 0xff;
unsigned int pars = 0;
pr_err(" call %2d: op=%lu result=%ld caller=%pS ", idx + 1,
mcdb->entries[idx].op, b->entries[idx].result,
mcdb->caller[idx]);
if (opidx < ARRAY_SIZE(hpcpars))
pars = hpcpars[opidx];
if (pars) {
pr_cont("pars=");
for (arg = 0; arg < pars; arg++)
pr_cont("%lx ", mcdb->entries[idx].args[arg]);
}
if (mcdb->argsz[idx]) {
pr_cont("args=");
for (arg = 0; arg < mcdb->argsz[idx] / 8; arg++)
pr_cont("%lx ", mcdb->args[idx][arg]);
}
pr_cont("\n");
}
void xen_mc_flush(void)
{
struct mc_buffer *b = this_cpu_ptr(&mc_buffer);
struct multicall_entry *mc;
struct mc_debug_data *mcdb = NULL;
int ret = 0;
unsigned long flags;
int i;
@@ -69,10 +149,11 @@ void xen_mc_flush(void)
trace_xen_mc_flush(b->mcidx, b->argidx, b->cbidx);
#if MC_DEBUG
memcpy(b->debug, b->entries,
b->mcidx * sizeof(struct multicall_entry));
#endif
if (static_key_false(&mc_debug)) {
mcdb = this_cpu_ptr(mc_debug_data);
memcpy(mcdb->entries, b->entries,
b->mcidx * sizeof(struct multicall_entry));
}
switch (b->mcidx) {
case 0:
@@ -103,21 +184,14 @@ void xen_mc_flush(void)
pr_err("%d of %d multicall(s) failed: cpu %d\n",
ret, b->mcidx, smp_processor_id());
for (i = 0; i < b->mcidx; i++) {
if (b->entries[i].result < 0) {
#if MC_DEBUG
pr_err(" call %2d: op=%lu arg=[%lx] result=%ld\t%pS\n",
i + 1,
b->debug[i].op,
b->debug[i].args[0],
b->entries[i].result,
b->caller[i]);
#else
if (static_key_false(&mc_debug)) {
print_debug_data(b, mcdb, i);
} else if (b->entries[i].result < 0) {
pr_err(" call %2d: op=%lu arg=[%lx] result=%ld\n",
i + 1,
b->entries[i].op,
b->entries[i].args[0],
b->entries[i].result);
#endif
}
}
}
@@ -155,9 +229,13 @@ struct multicall_space __xen_mc_entry(size_t args)
}
ret.mc = &b->entries[b->mcidx];
#if MC_DEBUG
b->caller[b->mcidx] = __builtin_return_address(0);
#endif
if (static_key_false(&mc_debug)) {
struct mc_debug_data *mcdb = this_cpu_ptr(mc_debug_data);
mcdb->caller[b->mcidx] = __builtin_return_address(0);
mcdb->argsz[b->mcidx] = args;
mcdb->args[b->mcidx] = (unsigned long *)(&b->args[argidx]);
}
b->mcidx++;
ret.args = &b->args[argidx];
b->argidx = argidx + args;
-69
View File
@@ -1,69 +0,0 @@
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef _XEN_MULTICALLS_H
#define _XEN_MULTICALLS_H
#include <trace/events/xen.h>
#include "xen-ops.h"
/* Multicalls */
struct multicall_space
{
struct multicall_entry *mc;
void *args;
};
/* Allocate room for a multicall and its args */
struct multicall_space __xen_mc_entry(size_t args);
DECLARE_PER_CPU(unsigned long, xen_mc_irq_flags);
/* Call to start a batch of multiple __xen_mc_entry()s. Must be
paired with xen_mc_issue() */
static inline void xen_mc_batch(void)
{
unsigned long flags;
/* need to disable interrupts until this entry is complete */
local_irq_save(flags);
trace_xen_mc_batch(xen_get_lazy_mode());
__this_cpu_write(xen_mc_irq_flags, flags);
}
static inline struct multicall_space xen_mc_entry(size_t args)
{
xen_mc_batch();
return __xen_mc_entry(args);
}
/* Flush all pending multicalls */
void xen_mc_flush(void);
/* Issue a multicall if we're not in a lazy mode */
static inline void xen_mc_issue(unsigned mode)
{
trace_xen_mc_issue(mode);
if ((xen_get_lazy_mode() & mode) == 0)
xen_mc_flush();
/* restore flags saved in xen_mc_batch */
local_irq_restore(this_cpu_read(xen_mc_irq_flags));
}
/* Set up a callback to be called when the current batch is flushed */
void xen_mc_callback(void (*fn)(void *), void *data);
/*
* Try to extend the arguments of the previous multicall command. The
* previous command's op must match. If it does, then it attempts to
* extend the argument space allocated to the multicall entry by
* arg_size bytes.
*
* The returned multicall_space will return with mc pointing to the
* command on success, or NULL on failure, and args pointing to the
* newly allocated space.
*/
struct multicall_space xen_mc_extend_args(unsigned long op, size_t arg_size);
#endif /* _XEN_MULTICALLS_H */
+2 -4
View File
@@ -81,7 +81,6 @@
#include <xen/balloon.h>
#include <xen/grant_table.h>
#include "multicalls.h"
#include "xen-ops.h"
#define P2M_MID_PER_PAGE (PAGE_SIZE / sizeof(unsigned long *))
@@ -730,7 +729,7 @@ int set_foreign_p2m_mapping(struct gnttab_map_grant_ref *map_ops,
* immediate unmapping.
*/
map_ops[i].status = GNTST_general_error;
unmap[0].host_addr = map_ops[i].host_addr,
unmap[0].host_addr = map_ops[i].host_addr;
unmap[0].handle = map_ops[i].handle;
map_ops[i].handle = INVALID_GRANT_HANDLE;
if (map_ops[i].flags & GNTMAP_device_map)
@@ -740,7 +739,7 @@ int set_foreign_p2m_mapping(struct gnttab_map_grant_ref *map_ops,
if (kmap_ops) {
kmap_ops[i].status = GNTST_general_error;
unmap[1].host_addr = kmap_ops[i].host_addr,
unmap[1].host_addr = kmap_ops[i].host_addr;
unmap[1].handle = kmap_ops[i].handle;
kmap_ops[i].handle = INVALID_GRANT_HANDLE;
if (kmap_ops[i].flags & GNTMAP_device_map)
@@ -795,7 +794,6 @@ int clear_foreign_p2m_mapping(struct gnttab_unmap_grant_ref *unmap_ops,
#ifdef CONFIG_XEN_DEBUG_FS
#include <linux/debugfs.h>
#include "debugfs.h"
static int p2m_dump_show(struct seq_file *m, void *v)
{
static const char * const type_name[] = {
-1
View File
@@ -10,7 +10,6 @@
#include <xen/interface/xenpmu.h>
#include "xen-ops.h"
#include "pmu.h"
/* x86_pmu.handle_irq definition */
#include "../events/perf_event.h"
-22
View File
@@ -1,22 +0,0 @@
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef __XEN_PMU_H
#define __XEN_PMU_H
#include <xen/interface/xenpmu.h>
extern bool is_xen_pmu;
irqreturn_t xen_pmu_irq_handler(int irq, void *dev_id);
#ifdef CONFIG_XEN_HAVE_VPMU
void xen_pmu_init(int cpu);
void xen_pmu_finish(int cpu);
#else
static inline void xen_pmu_init(int cpu) {}
static inline void xen_pmu_finish(int cpu) {}
#endif
bool pmu_msr_read(unsigned int msr, uint64_t *val, int *err);
bool pmu_msr_write(unsigned int msr, uint32_t low, uint32_t high, int *err);
int pmu_apic_update(uint32_t reg);
unsigned long long xen_read_pmc(int counter);
#endif /* __XEN_PMU_H */
-1
View File
@@ -34,7 +34,6 @@
#include <xen/features.h>
#include <xen/hvc-console.h>
#include "xen-ops.h"
#include "mmu.h"
#define GB(x) ((uint64_t)(x) * 1024 * 1024 * 1024)
-1
View File
@@ -9,7 +9,6 @@
#include <xen/hvc-console.h>
#include "xen-ops.h"
#include "smp.h"
static DEFINE_PER_CPU(struct xen_common_irq, xen_resched_irq) = { .irq = -1 };
static DEFINE_PER_CPU(struct xen_common_irq, xen_callfunc_irq) = { .irq = -1 };
-51
View File
@@ -1,51 +0,0 @@
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef _XEN_SMP_H
#ifdef CONFIG_SMP
void asm_cpu_bringup_and_idle(void);
asmlinkage void cpu_bringup_and_idle(void);
extern void xen_send_IPI_mask(const struct cpumask *mask,
int vector);
extern void xen_send_IPI_mask_allbutself(const struct cpumask *mask,
int vector);
extern void xen_send_IPI_allbutself(int vector);
extern void xen_send_IPI_all(int vector);
extern void xen_send_IPI_self(int vector);
extern int xen_smp_intr_init(unsigned int cpu);
extern void xen_smp_intr_free(unsigned int cpu);
int xen_smp_intr_init_pv(unsigned int cpu);
void xen_smp_intr_free_pv(unsigned int cpu);
void xen_smp_count_cpus(void);
void xen_smp_cpus_done(unsigned int max_cpus);
void xen_smp_send_reschedule(int cpu);
void xen_smp_send_call_function_ipi(const struct cpumask *mask);
void xen_smp_send_call_function_single_ipi(int cpu);
void __noreturn xen_cpu_bringup_again(unsigned long stack);
struct xen_common_irq {
int irq;
char *name;
};
#else /* CONFIG_SMP */
static inline int xen_smp_intr_init(unsigned int cpu)
{
return 0;
}
static inline void xen_smp_intr_free(unsigned int cpu) {}
static inline int xen_smp_intr_init_pv(unsigned int cpu)
{
return 0;
}
static inline void xen_smp_intr_free_pv(unsigned int cpu) {}
static inline void xen_smp_count_cpus(void) { }
#endif /* CONFIG_SMP */
#endif
-2
View File
@@ -5,8 +5,6 @@
#include <xen/events.h>
#include "xen-ops.h"
#include "smp.h"
static void __init xen_hvm_smp_prepare_boot_cpu(void)
{
-3
View File
@@ -46,9 +46,6 @@
#include <xen/hvc-console.h>
#include "xen-ops.h"
#include "mmu.h"
#include "smp.h"
#include "pmu.h"
cpumask_var_t xen_cpu_initialized_map;
+5 -15
View File
@@ -18,7 +18,6 @@
static DEFINE_PER_CPU(int, lock_kicker_irq) = -1;
static DEFINE_PER_CPU(char *, irq_name);
static DEFINE_PER_CPU(atomic_t, xen_qlock_wait_nest);
static bool xen_pvspin = true;
static void xen_qlock_kick(int cpu)
{
@@ -68,7 +67,7 @@ void xen_init_lock_cpu(int cpu)
int irq;
char *name;
if (!xen_pvspin)
if (nopvspin)
return;
WARN(per_cpu(lock_kicker_irq, cpu) >= 0, "spinlock on CPU%d exists on IRQ%d!\n",
@@ -95,7 +94,7 @@ void xen_uninit_lock_cpu(int cpu)
{
int irq;
if (!xen_pvspin)
if (nopvspin)
return;
kfree(per_cpu(irq_name, cpu));
@@ -125,10 +124,10 @@ PV_CALLEE_SAVE_REGS_THUNK(xen_vcpu_stolen);
void __init xen_init_spinlocks(void)
{
/* Don't need to use pvqspinlock code if there is only 1 vCPU. */
if (num_possible_cpus() == 1 || nopvspin)
xen_pvspin = false;
if (num_possible_cpus() == 1)
nopvspin = true;
if (!xen_pvspin) {
if (nopvspin) {
printk(KERN_DEBUG "xen: PV spinlocks disabled\n");
static_branch_disable(&virt_spin_lock_key);
return;
@@ -143,12 +142,3 @@ void __init xen_init_spinlocks(void)
pv_ops.lock.kick = xen_qlock_kick;
pv_ops.lock.vcpu_is_preempted = PV_CALLEE_SAVE(xen_vcpu_stolen);
}
static __init int xen_parse_nopvspin(char *arg)
{
pr_notice("\"xen_nopvspin\" is deprecated, please use \"nopvspin\" instead\n");
xen_pvspin = false;
return 0;
}
early_param("xen_nopvspin", xen_parse_nopvspin);
-2
View File
@@ -15,8 +15,6 @@
#include <asm/fixmap.h>
#include "xen-ops.h"
#include "mmu.h"
#include "pmu.h"
static DEFINE_PER_CPU(u64, spec_ctrl);
+1 -1
View File
@@ -30,7 +30,7 @@
#include "xen-ops.h"
/* Minimum amount of time until next clock event fires */
#define TIMER_SLOP 100000
#define TIMER_SLOP 1
static u64 xen_sched_clock_offset __read_mostly;
+145 -3
View File
@@ -5,8 +5,15 @@
#include <linux/init.h>
#include <linux/clocksource.h>
#include <linux/irqreturn.h>
#include <linux/linkage.h>
#include <xen/interface/xenpmu.h>
#include <xen/xen-ops.h>
#include <asm/page.h>
#include <trace/events/xen.h>
/* These are code, but not functions. Defined in entry.S */
extern const char xen_failsafe_callback[];
@@ -23,14 +30,11 @@ void xen_copy_trap_info(struct trap_info *traps);
DECLARE_PER_CPU_ALIGNED(struct vcpu_info, xen_vcpu_info);
DECLARE_PER_CPU(unsigned long, xen_cr3);
DECLARE_PER_CPU(unsigned long, xen_current_cr3);
extern struct start_info *xen_start_info;
extern struct shared_info xen_dummy_shared_info;
extern struct shared_info *HYPERVISOR_shared_info;
extern bool xen_fifo_events;
void xen_setup_mfn_list_list(void);
void xen_build_mfn_list_list(void);
void xen_setup_machphys_mapping(void);
@@ -177,4 +181,142 @@ static inline void xen_hvm_post_suspend(int suspend_cancelled) {}
void xen_add_extra_mem(unsigned long start_pfn, unsigned long n_pfns);
struct dentry * __init xen_init_debugfs(void);
enum pt_level {
PT_PGD,
PT_P4D,
PT_PUD,
PT_PMD,
PT_PTE
};
bool __set_phys_to_machine(unsigned long pfn, unsigned long mfn);
void set_pte_mfn(unsigned long vaddr, unsigned long pfn, pgprot_t flags);
unsigned long xen_read_cr2_direct(void);
void xen_init_mmu_ops(void);
void xen_hvm_init_mmu_ops(void);
/* Multicalls */
struct multicall_space
{
struct multicall_entry *mc;
void *args;
};
/* Allocate room for a multicall and its args */
struct multicall_space __xen_mc_entry(size_t args);
DECLARE_PER_CPU(unsigned long, xen_mc_irq_flags);
/* Call to start a batch of multiple __xen_mc_entry()s. Must be
paired with xen_mc_issue() */
static inline void xen_mc_batch(void)
{
unsigned long flags;
/* need to disable interrupts until this entry is complete */
local_irq_save(flags);
trace_xen_mc_batch(xen_get_lazy_mode());
__this_cpu_write(xen_mc_irq_flags, flags);
}
static inline struct multicall_space xen_mc_entry(size_t args)
{
xen_mc_batch();
return __xen_mc_entry(args);
}
/* Flush all pending multicalls */
void xen_mc_flush(void);
/* Issue a multicall if we're not in a lazy mode */
static inline void xen_mc_issue(unsigned mode)
{
trace_xen_mc_issue(mode);
if ((xen_get_lazy_mode() & mode) == 0)
xen_mc_flush();
/* restore flags saved in xen_mc_batch */
local_irq_restore(this_cpu_read(xen_mc_irq_flags));
}
/* Set up a callback to be called when the current batch is flushed */
void xen_mc_callback(void (*fn)(void *), void *data);
/*
* Try to extend the arguments of the previous multicall command. The
* previous command's op must match. If it does, then it attempts to
* extend the argument space allocated to the multicall entry by
* arg_size bytes.
*
* The returned multicall_space will return with mc pointing to the
* command on success, or NULL on failure, and args pointing to the
* newly allocated space.
*/
struct multicall_space xen_mc_extend_args(unsigned long op, size_t arg_size);
extern bool is_xen_pmu;
irqreturn_t xen_pmu_irq_handler(int irq, void *dev_id);
#ifdef CONFIG_XEN_HAVE_VPMU
void xen_pmu_init(int cpu);
void xen_pmu_finish(int cpu);
#else
static inline void xen_pmu_init(int cpu) {}
static inline void xen_pmu_finish(int cpu) {}
#endif
bool pmu_msr_read(unsigned int msr, uint64_t *val, int *err);
bool pmu_msr_write(unsigned int msr, uint32_t low, uint32_t high, int *err);
int pmu_apic_update(uint32_t reg);
unsigned long long xen_read_pmc(int counter);
#ifdef CONFIG_SMP
void asm_cpu_bringup_and_idle(void);
asmlinkage void cpu_bringup_and_idle(void);
extern void xen_send_IPI_mask(const struct cpumask *mask,
int vector);
extern void xen_send_IPI_mask_allbutself(const struct cpumask *mask,
int vector);
extern void xen_send_IPI_allbutself(int vector);
extern void xen_send_IPI_all(int vector);
extern void xen_send_IPI_self(int vector);
extern int xen_smp_intr_init(unsigned int cpu);
extern void xen_smp_intr_free(unsigned int cpu);
int xen_smp_intr_init_pv(unsigned int cpu);
void xen_smp_intr_free_pv(unsigned int cpu);
void xen_smp_count_cpus(void);
void xen_smp_cpus_done(unsigned int max_cpus);
void xen_smp_send_reschedule(int cpu);
void xen_smp_send_call_function_ipi(const struct cpumask *mask);
void xen_smp_send_call_function_single_ipi(int cpu);
void __noreturn xen_cpu_bringup_again(unsigned long stack);
struct xen_common_irq {
int irq;
char *name;
};
#else /* CONFIG_SMP */
static inline int xen_smp_intr_init(unsigned int cpu)
{
return 0;
}
static inline void xen_smp_intr_free(unsigned int cpu) {}
static inline int xen_smp_intr_init_pv(unsigned int cpu)
{
return 0;
}
static inline void xen_smp_intr_free_pv(unsigned int cpu) {}
static inline void xen_smp_count_cpus(void) { }
#endif /* CONFIG_SMP */
#endif /* XEN_OPS_H */
+1
View File
@@ -729,4 +729,5 @@ static void __exit evtchn_cleanup(void)
module_init(evtchn_init);
module_exit(evtchn_cleanup);
MODULE_DESCRIPTION("Xen /dev/xen/evtchn device driver");
MODULE_LICENSE("GPL");
+1 -1
View File
@@ -208,7 +208,7 @@ static void do_reboot(void)
orderly_reboot();
}
static struct shutdown_handler shutdown_handlers[] = {
static const struct shutdown_handler shutdown_handlers[] = {
{ "poweroff", true, do_poweroff },
{ "halt", false, do_poweroff },
{ "reboot", true, do_reboot },
+1
View File
@@ -19,6 +19,7 @@
#include "privcmd.h"
MODULE_DESCRIPTION("Xen Mmap of hypercall buffers");
MODULE_LICENSE("GPL");
struct privcmd_buf_private {
+25 -11
View File
@@ -17,6 +17,7 @@
#include <linux/poll.h>
#include <linux/sched.h>
#include <linux/slab.h>
#include <linux/srcu.h>
#include <linux/string.h>
#include <linux/workqueue.h>
#include <linux/errno.h>
@@ -48,6 +49,7 @@
#include "privcmd.h"
MODULE_DESCRIPTION("Xen hypercall passthrough driver");
MODULE_LICENSE("GPL");
#define PRIV_VMA_LOCKED ((void *)1)
@@ -845,7 +847,8 @@ out:
#ifdef CONFIG_XEN_PRIVCMD_EVENTFD
/* Irqfd support */
static struct workqueue_struct *irqfd_cleanup_wq;
static DEFINE_MUTEX(irqfds_lock);
static DEFINE_SPINLOCK(irqfds_lock);
DEFINE_STATIC_SRCU(irqfds_srcu);
static LIST_HEAD(irqfds_list);
struct privcmd_kernel_irqfd {
@@ -873,6 +876,9 @@ static void irqfd_shutdown(struct work_struct *work)
container_of(work, struct privcmd_kernel_irqfd, shutdown);
u64 cnt;
/* Make sure irqfd has been initialized in assign path */
synchronize_srcu(&irqfds_srcu);
eventfd_ctx_remove_wait_queue(kirqfd->eventfd, &kirqfd->wait, &cnt);
eventfd_ctx_put(kirqfd->eventfd);
kfree(kirqfd);
@@ -909,9 +915,11 @@ irqfd_wakeup(wait_queue_entry_t *wait, unsigned int mode, int sync, void *key)
irqfd_inject(kirqfd);
if (flags & EPOLLHUP) {
mutex_lock(&irqfds_lock);
unsigned long flags;
spin_lock_irqsave(&irqfds_lock, flags);
irqfd_deactivate(kirqfd);
mutex_unlock(&irqfds_lock);
spin_unlock_irqrestore(&irqfds_lock, flags);
}
return 0;
@@ -929,10 +937,11 @@ irqfd_poll_func(struct file *file, wait_queue_head_t *wqh, poll_table *pt)
static int privcmd_irqfd_assign(struct privcmd_irqfd *irqfd)
{
struct privcmd_kernel_irqfd *kirqfd, *tmp;
unsigned long flags;
__poll_t events;
struct fd f;
void *dm_op;
int ret;
int ret, idx;
kirqfd = kzalloc(sizeof(*kirqfd) + irqfd->size, GFP_KERNEL);
if (!kirqfd)
@@ -968,18 +977,19 @@ static int privcmd_irqfd_assign(struct privcmd_irqfd *irqfd)
init_waitqueue_func_entry(&kirqfd->wait, irqfd_wakeup);
init_poll_funcptr(&kirqfd->pt, irqfd_poll_func);
mutex_lock(&irqfds_lock);
spin_lock_irqsave(&irqfds_lock, flags);
list_for_each_entry(tmp, &irqfds_list, list) {
if (kirqfd->eventfd == tmp->eventfd) {
ret = -EBUSY;
mutex_unlock(&irqfds_lock);
spin_unlock_irqrestore(&irqfds_lock, flags);
goto error_eventfd;
}
}
idx = srcu_read_lock(&irqfds_srcu);
list_add_tail(&kirqfd->list, &irqfds_list);
mutex_unlock(&irqfds_lock);
spin_unlock_irqrestore(&irqfds_lock, flags);
/*
* Check if there was an event already pending on the eventfd before we
@@ -989,6 +999,8 @@ static int privcmd_irqfd_assign(struct privcmd_irqfd *irqfd)
if (events & EPOLLIN)
irqfd_inject(kirqfd);
srcu_read_unlock(&irqfds_srcu, idx);
/*
* Do not drop the file until the kirqfd is fully initialized, otherwise
* we might race against the EPOLLHUP.
@@ -1011,12 +1023,13 @@ static int privcmd_irqfd_deassign(struct privcmd_irqfd *irqfd)
{
struct privcmd_kernel_irqfd *kirqfd;
struct eventfd_ctx *eventfd;
unsigned long flags;
eventfd = eventfd_ctx_fdget(irqfd->fd);
if (IS_ERR(eventfd))
return PTR_ERR(eventfd);
mutex_lock(&irqfds_lock);
spin_lock_irqsave(&irqfds_lock, flags);
list_for_each_entry(kirqfd, &irqfds_list, list) {
if (kirqfd->eventfd == eventfd) {
@@ -1025,7 +1038,7 @@ static int privcmd_irqfd_deassign(struct privcmd_irqfd *irqfd)
}
}
mutex_unlock(&irqfds_lock);
spin_unlock_irqrestore(&irqfds_lock, flags);
eventfd_ctx_put(eventfd);
@@ -1073,13 +1086,14 @@ static int privcmd_irqfd_init(void)
static void privcmd_irqfd_exit(void)
{
struct privcmd_kernel_irqfd *kirqfd, *tmp;
unsigned long flags;
mutex_lock(&irqfds_lock);
spin_lock_irqsave(&irqfds_lock, flags);
list_for_each_entry_safe(kirqfd, tmp, &irqfds_list, list)
irqfd_deactivate(kirqfd);
mutex_unlock(&irqfds_lock);
spin_unlock_irqrestore(&irqfds_lock, flags);
destroy_workqueue(irqfd_cleanup_wq);
}
+1
View File
@@ -1708,5 +1708,6 @@ static void __exit xen_pcibk_cleanup(void)
module_init(xen_pcibk_init);
module_exit(xen_pcibk_cleanup);
MODULE_DESCRIPTION("Xen PCI-device stub driver");
MODULE_LICENSE("Dual BSD/GPL");
MODULE_ALIAS("xen-backend:pci");
+8
View File
@@ -176,4 +176,12 @@ config COREDUMP
certainly want to say Y here. Not necessary on systems that never
need debugging or only ever run flawless code.
config EXEC_KUNIT_TEST
bool "Build execve tests" if !KUNIT_ALL_TESTS
depends on KUNIT=y
default KUNIT_ALL_TESTS
help
This builds the exec KUnit tests, which tests boundary conditions
of various aspects of the exec internals.
endmenu
+77 -42
View File
@@ -1003,7 +1003,8 @@ out_free_interp:
if (elf_read_implies_exec(*elf_ex, executable_stack))
current->personality |= READ_IMPLIES_EXEC;
if (!(current->personality & ADDR_NO_RANDOMIZE) && randomize_va_space)
const int snapshot_randomize_va_space = READ_ONCE(randomize_va_space);
if (!(current->personality & ADDR_NO_RANDOMIZE) && snapshot_randomize_va_space)
current->flags |= PF_RANDOMIZE;
setup_new_exec(bprm);
@@ -1061,47 +1062,7 @@ out_free_interp:
* Header for ET_DYN binaries to calculate the
* randomization (load_bias) for all the LOAD
* Program Headers.
*
* There are effectively two types of ET_DYN
* binaries: programs (i.e. PIE: ET_DYN with INTERP)
* and loaders (ET_DYN without INTERP, since they
* _are_ the ELF interpreter). The loaders must
* be loaded away from programs since the program
* may otherwise collide with the loader (especially
* for ET_EXEC which does not have a randomized
* position). For example to handle invocations of
* "./ld.so someprog" to test out a new version of
* the loader, the subsequent program that the
* loader loads must avoid the loader itself, so
* they cannot share the same load range. Sufficient
* room for the brk must be allocated with the
* loader as well, since brk must be available with
* the loader.
*
* Therefore, programs are loaded offset from
* ELF_ET_DYN_BASE and loaders are loaded into the
* independently randomized mmap region (0 load_bias
* without MAP_FIXED nor MAP_FIXED_NOREPLACE).
*/
if (interpreter) {
load_bias = ELF_ET_DYN_BASE;
if (current->flags & PF_RANDOMIZE)
load_bias += arch_mmap_rnd();
alignment = maximum_alignment(elf_phdata, elf_ex->e_phnum);
if (alignment)
load_bias &= ~(alignment - 1);
elf_flags |= MAP_FIXED_NOREPLACE;
} else
load_bias = 0;
/*
* Since load_bias is used for all subsequent loading
* calculations, we must lower it by the first vaddr
* so that the remaining calculations based on the
* ELF vaddrs will be correctly offset. The result
* is then page aligned.
*/
load_bias = ELF_PAGESTART(load_bias - vaddr);
/*
* Calculate the entire size of the ELF mapping
@@ -1127,6 +1088,80 @@ out_free_interp:
retval = -EINVAL;
goto out_free_dentry;
}
/* Calculate any requested alignment. */
alignment = maximum_alignment(elf_phdata, elf_ex->e_phnum);
/*
* There are effectively two types of ET_DYN
* binaries: programs (i.e. PIE: ET_DYN with PT_INTERP)
* and loaders (ET_DYN without PT_INTERP, since they
* _are_ the ELF interpreter). The loaders must
* be loaded away from programs since the program
* may otherwise collide with the loader (especially
* for ET_EXEC which does not have a randomized
* position). For example to handle invocations of
* "./ld.so someprog" to test out a new version of
* the loader, the subsequent program that the
* loader loads must avoid the loader itself, so
* they cannot share the same load range. Sufficient
* room for the brk must be allocated with the
* loader as well, since brk must be available with
* the loader.
*
* Therefore, programs are loaded offset from
* ELF_ET_DYN_BASE and loaders are loaded into the
* independently randomized mmap region (0 load_bias
* without MAP_FIXED nor MAP_FIXED_NOREPLACE).
*/
if (interpreter) {
/* On ET_DYN with PT_INTERP, we do the ASLR. */
load_bias = ELF_ET_DYN_BASE;
if (current->flags & PF_RANDOMIZE)
load_bias += arch_mmap_rnd();
/* Adjust alignment as requested. */
if (alignment)
load_bias &= ~(alignment - 1);
elf_flags |= MAP_FIXED_NOREPLACE;
} else {
/*
* For ET_DYN without PT_INTERP, we rely on
* the architectures's (potentially ASLR) mmap
* base address (via a load_bias of 0).
*
* When a large alignment is requested, we
* must do the allocation at address "0" right
* now to discover where things will load so
* that we can adjust the resulting alignment.
* In this case (load_bias != 0), we can use
* MAP_FIXED_NOREPLACE to make sure the mapping
* doesn't collide with anything.
*/
if (alignment > ELF_MIN_ALIGN) {
load_bias = elf_load(bprm->file, 0, elf_ppnt,
elf_prot, elf_flags, total_size);
if (BAD_ADDR(load_bias)) {
retval = IS_ERR_VALUE(load_bias) ?
PTR_ERR((void*)load_bias) : -EINVAL;
goto out_free_dentry;
}
vm_munmap(load_bias, total_size);
/* Adjust alignment as requested. */
if (alignment)
load_bias &= ~(alignment - 1);
elf_flags |= MAP_FIXED_NOREPLACE;
} else
load_bias = 0;
}
/*
* Since load_bias is used for all subsequent loading
* calculations, we must lower it by the first vaddr
* so that the remaining calculations based on the
* ELF vaddrs will be correctly offset. The result
* is then page aligned.
*/
load_bias = ELF_PAGESTART(load_bias - vaddr);
}
error = elf_load(bprm->file, load_bias + vaddr, elf_ppnt,
@@ -1251,7 +1286,7 @@ out_free_interp:
mm->end_data = end_data;
mm->start_stack = bprm->p;
if ((current->flags & PF_RANDOMIZE) && (randomize_va_space > 1)) {
if ((current->flags & PF_RANDOMIZE) && (snapshot_randomize_va_space > 1)) {
/*
* For architectures with ELF randomization, when executing
* a loader directly (i.e. no interpreter listed in ELF
+42 -7
View File
@@ -486,6 +486,35 @@ static int count_strings_kernel(const char *const *argv)
return i;
}
static inline int bprm_set_stack_limit(struct linux_binprm *bprm,
unsigned long limit)
{
#ifdef CONFIG_MMU
/* Avoid a pathological bprm->p. */
if (bprm->p < limit)
return -E2BIG;
bprm->argmin = bprm->p - limit;
#endif
return 0;
}
static inline bool bprm_hit_stack_limit(struct linux_binprm *bprm)
{
#ifdef CONFIG_MMU
return bprm->p < bprm->argmin;
#else
return false;
#endif
}
/*
* Calculate bprm->argmin from:
* - _STK_LIM
* - ARG_MAX
* - bprm->rlim_stack.rlim_cur
* - bprm->argc
* - bprm->envc
* - bprm->p
*/
static int bprm_stack_limits(struct linux_binprm *bprm)
{
unsigned long limit, ptr_size;
@@ -505,6 +534,9 @@ static int bprm_stack_limits(struct linux_binprm *bprm)
* of argument strings even with small stacks
*/
limit = max_t(unsigned long, limit, ARG_MAX);
/* Reject totally pathological counts. */
if (bprm->argc < 0 || bprm->envc < 0)
return -E2BIG;
/*
* We must account for the size of all the argv and envp pointers to
* the argv and envp strings, since they will also take up space in
@@ -518,13 +550,14 @@ static int bprm_stack_limits(struct linux_binprm *bprm)
* argc can never be 0, to keep them from walking envp by accident.
* See do_execveat_common().
*/
ptr_size = (max(bprm->argc, 1) + bprm->envc) * sizeof(void *);
if (check_add_overflow(max(bprm->argc, 1), bprm->envc, &ptr_size) ||
check_mul_overflow(ptr_size, sizeof(void *), &ptr_size))
return -E2BIG;
if (limit <= ptr_size)
return -E2BIG;
limit -= ptr_size;
bprm->argmin = bprm->p - limit;
return 0;
return bprm_set_stack_limit(bprm, limit);
}
/*
@@ -562,10 +595,8 @@ static int copy_strings(int argc, struct user_arg_ptr argv,
pos = bprm->p;
str += len;
bprm->p -= len;
#ifdef CONFIG_MMU
if (bprm->p < bprm->argmin)
if (bprm_hit_stack_limit(bprm))
goto out;
#endif
while (len > 0) {
int offset, bytes_to_copy;
@@ -640,7 +671,7 @@ int copy_string_kernel(const char *arg, struct linux_binprm *bprm)
/* We're going to work our way backwards. */
arg += len;
bprm->p -= len;
if (IS_ENABLED(CONFIG_MMU) && bprm->p < bprm->argmin)
if (bprm_hit_stack_limit(bprm))
return -E2BIG;
while (len > 0) {
@@ -2211,3 +2242,7 @@ static int __init init_fs_exec_sysctls(void)
fs_initcall(init_fs_exec_sysctls);
#endif /* CONFIG_SYSCTL */
#ifdef CONFIG_EXEC_KUNIT_TEST
#include "exec_test.c"
#endif
+141
View File
@@ -0,0 +1,141 @@
// SPDX-License-Identifier: GPL-2.0-only
#include <kunit/test.h>
struct bprm_stack_limits_result {
struct linux_binprm bprm;
int expected_rc;
unsigned long expected_argmin;
};
static const struct bprm_stack_limits_result bprm_stack_limits_results[] = {
/* Negative argc/envc counts produce -E2BIG */
{ { .p = ULONG_MAX, .rlim_stack.rlim_cur = ULONG_MAX,
.argc = INT_MIN, .envc = INT_MIN }, .expected_rc = -E2BIG },
{ { .p = ULONG_MAX, .rlim_stack.rlim_cur = ULONG_MAX,
.argc = 5, .envc = -1 }, .expected_rc = -E2BIG },
{ { .p = ULONG_MAX, .rlim_stack.rlim_cur = ULONG_MAX,
.argc = -1, .envc = 10 }, .expected_rc = -E2BIG },
/* The max value of argc or envc is MAX_ARG_STRINGS. */
{ { .p = ULONG_MAX, .rlim_stack.rlim_cur = ULONG_MAX,
.argc = INT_MAX, .envc = INT_MAX }, .expected_rc = -E2BIG },
{ { .p = ULONG_MAX, .rlim_stack.rlim_cur = ULONG_MAX,
.argc = MAX_ARG_STRINGS, .envc = MAX_ARG_STRINGS }, .expected_rc = -E2BIG },
{ { .p = ULONG_MAX, .rlim_stack.rlim_cur = ULONG_MAX,
.argc = 0, .envc = MAX_ARG_STRINGS }, .expected_rc = -E2BIG },
{ { .p = ULONG_MAX, .rlim_stack.rlim_cur = ULONG_MAX,
.argc = MAX_ARG_STRINGS, .envc = 0 }, .expected_rc = -E2BIG },
/*
* On 32-bit system these argc and envc counts, while likely impossible
* to represent within the associated TASK_SIZE, could overflow the
* limit calculation, and bypass the ptr_size <= limit check.
*/
{ { .p = ULONG_MAX, .rlim_stack.rlim_cur = ULONG_MAX,
.argc = 0x20000001, .envc = 0x20000001 }, .expected_rc = -E2BIG },
#ifdef CONFIG_MMU
/* Make sure a pathological bprm->p doesn't cause an overflow. */
{ { .p = sizeof(void *), .rlim_stack.rlim_cur = ULONG_MAX,
.argc = 10, .envc = 10 }, .expected_rc = -E2BIG },
#endif
/*
* 0 rlim_stack will get raised to ARG_MAX. With 1 string pointer,
* we should see p - ARG_MAX + sizeof(void *).
*/
{ { .p = ULONG_MAX, .rlim_stack.rlim_cur = 0,
.argc = 1, .envc = 0 }, .expected_argmin = ULONG_MAX - ARG_MAX + sizeof(void *)},
/* Validate that argc is always raised to a minimum of 1. */
{ { .p = ULONG_MAX, .rlim_stack.rlim_cur = 0,
.argc = 0, .envc = 0 }, .expected_argmin = ULONG_MAX - ARG_MAX + sizeof(void *)},
/*
* 0 rlim_stack will get raised to ARG_MAX. With pointers filling ARG_MAX,
* we should see -E2BIG. (Note argc is always raised to at least 1.)
*/
{ { .p = ULONG_MAX, .rlim_stack.rlim_cur = 0,
.argc = ARG_MAX / sizeof(void *), .envc = 0 }, .expected_rc = -E2BIG },
{ { .p = ULONG_MAX, .rlim_stack.rlim_cur = 0,
.argc = 0, .envc = ARG_MAX / sizeof(void *) - 1 }, .expected_rc = -E2BIG },
{ { .p = ULONG_MAX, .rlim_stack.rlim_cur = 0,
.argc = ARG_MAX / sizeof(void *) + 1, .envc = 0 }, .expected_rc = -E2BIG },
{ { .p = ULONG_MAX, .rlim_stack.rlim_cur = 0,
.argc = 0, .envc = ARG_MAX / sizeof(void *) }, .expected_rc = -E2BIG },
/* And with one less, we see space for exactly 1 pointer. */
{ { .p = ULONG_MAX, .rlim_stack.rlim_cur = 0,
.argc = (ARG_MAX / sizeof(void *)) - 1, .envc = 0 },
.expected_argmin = ULONG_MAX - sizeof(void *) },
{ { .p = ULONG_MAX, .rlim_stack.rlim_cur = 0,
.argc = 0, .envc = (ARG_MAX / sizeof(void *)) - 2, },
.expected_argmin = ULONG_MAX - sizeof(void *) },
/* If we raise rlim_stack / 4 to exactly ARG_MAX, nothing changes. */
{ { .p = ULONG_MAX, .rlim_stack.rlim_cur = ARG_MAX * 4,
.argc = ARG_MAX / sizeof(void *), .envc = 0 }, .expected_rc = -E2BIG },
{ { .p = ULONG_MAX, .rlim_stack.rlim_cur = ARG_MAX * 4,
.argc = 0, .envc = ARG_MAX / sizeof(void *) - 1 }, .expected_rc = -E2BIG },
{ { .p = ULONG_MAX, .rlim_stack.rlim_cur = ARG_MAX * 4,
.argc = ARG_MAX / sizeof(void *) + 1, .envc = 0 }, .expected_rc = -E2BIG },
{ { .p = ULONG_MAX, .rlim_stack.rlim_cur = ARG_MAX * 4,
.argc = 0, .envc = ARG_MAX / sizeof(void *) }, .expected_rc = -E2BIG },
{ { .p = ULONG_MAX, .rlim_stack.rlim_cur = ARG_MAX * 4,
.argc = (ARG_MAX / sizeof(void *)) - 1, .envc = 0 },
.expected_argmin = ULONG_MAX - sizeof(void *) },
{ { .p = ULONG_MAX, .rlim_stack.rlim_cur = ARG_MAX * 4,
.argc = 0, .envc = (ARG_MAX / sizeof(void *)) - 2, },
.expected_argmin = ULONG_MAX - sizeof(void *) },
/* But raising it another pointer * 4 will provide space for 1 more pointer. */
{ { .p = ULONG_MAX, .rlim_stack.rlim_cur = (ARG_MAX + sizeof(void *)) * 4,
.argc = ARG_MAX / sizeof(void *), .envc = 0 },
.expected_argmin = ULONG_MAX - sizeof(void *) },
{ { .p = ULONG_MAX, .rlim_stack.rlim_cur = (ARG_MAX + sizeof(void *)) * 4,
.argc = 0, .envc = ARG_MAX / sizeof(void *) - 1 },
.expected_argmin = ULONG_MAX - sizeof(void *) },
/* Raising rlim_stack / 4 to _STK_LIM / 4 * 3 will see more space. */
{ { .p = ULONG_MAX, .rlim_stack.rlim_cur = 4 * (_STK_LIM / 4 * 3),
.argc = 0, .envc = 0 },
.expected_argmin = ULONG_MAX - (_STK_LIM / 4 * 3) + sizeof(void *) },
{ { .p = ULONG_MAX, .rlim_stack.rlim_cur = 4 * (_STK_LIM / 4 * 3),
.argc = 0, .envc = 0 },
.expected_argmin = ULONG_MAX - (_STK_LIM / 4 * 3) + sizeof(void *) },
/* But raising it any further will see no increase. */
{ { .p = ULONG_MAX, .rlim_stack.rlim_cur = 4 * (_STK_LIM / 4 * 3 + sizeof(void *)),
.argc = 0, .envc = 0 },
.expected_argmin = ULONG_MAX - (_STK_LIM / 4 * 3) + sizeof(void *) },
{ { .p = ULONG_MAX, .rlim_stack.rlim_cur = 4 * (_STK_LIM / 4 * + sizeof(void *)),
.argc = 0, .envc = 0 },
.expected_argmin = ULONG_MAX - (_STK_LIM / 4 * 3) + sizeof(void *) },
{ { .p = ULONG_MAX, .rlim_stack.rlim_cur = 4 * _STK_LIM,
.argc = 0, .envc = 0 },
.expected_argmin = ULONG_MAX - (_STK_LIM / 4 * 3) + sizeof(void *) },
{ { .p = ULONG_MAX, .rlim_stack.rlim_cur = 4 * _STK_LIM,
.argc = 0, .envc = 0 },
.expected_argmin = ULONG_MAX - (_STK_LIM / 4 * 3) + sizeof(void *) },
};
static void exec_test_bprm_stack_limits(struct kunit *test)
{
/* Double-check the constants. */
KUNIT_EXPECT_EQ(test, _STK_LIM, SZ_8M);
KUNIT_EXPECT_EQ(test, ARG_MAX, 32 * SZ_4K);
KUNIT_EXPECT_EQ(test, MAX_ARG_STRINGS, 0x7FFFFFFF);
for (int i = 0; i < ARRAY_SIZE(bprm_stack_limits_results); i++) {
const struct bprm_stack_limits_result *result = &bprm_stack_limits_results[i];
struct linux_binprm bprm = result->bprm;
int rc;
rc = bprm_stack_limits(&bprm);
KUNIT_EXPECT_EQ_MSG(test, rc, result->expected_rc, "on loop %d", i);
#ifdef CONFIG_MMU
KUNIT_EXPECT_EQ_MSG(test, bprm.argmin, result->expected_argmin, "on loop %d", i);
#endif
}
}
static struct kunit_case exec_test_cases[] = {
KUNIT_CASE(exec_test_bprm_stack_limits),
{},
};
static struct kunit_suite exec_test_suite = {
.name = "exec",
.test_cases = exec_test_cases,
};
kunit_test_suite(exec_test_suite);
+1 -1
View File
@@ -19,13 +19,13 @@ struct linux_binprm {
#ifdef CONFIG_MMU
struct vm_area_struct *vma;
unsigned long vma_pages;
unsigned long argmin; /* rlimit marker for copy_strings() */
#else
# define MAX_ARG_PAGES 32
struct page *page[MAX_ARG_PAGES];
#endif
struct mm_struct *mm;
unsigned long p; /* current top of mem */
unsigned long argmin; /* rlimit marker for copy_strings() */
unsigned int
/* Should an execfd be passed to userspace? */
have_execfd:1,
+2
View File
@@ -144,4 +144,6 @@ static inline void xen_evtchn_close(evtchn_port_t port)
BUG();
}
extern bool xen_fifo_events;
#endif /* _XEN_EVENTS_H */
+1 -1
View File
@@ -583,7 +583,7 @@ EXPORT_SYMBOL(queued_spin_lock_slowpath);
#include "qspinlock_paravirt.h"
#include "qspinlock.c"
bool nopvspin __initdata;
bool nopvspin;
static __init int parse_nopvspin(char *arg)
{
nopvspin = true;
+12 -7
View File
@@ -3,8 +3,13 @@ CFLAGS = -Wall
CFLAGS += -Wno-nonnull
CFLAGS += -D_GNU_SOURCE
ALIGNS := 0x1000 0x200000 0x1000000
ALIGN_PIES := $(patsubst %,load_address.%,$(ALIGNS))
ALIGN_STATIC_PIES := $(patsubst %,load_address.static.%,$(ALIGNS))
ALIGNMENT_TESTS := $(ALIGN_PIES) $(ALIGN_STATIC_PIES)
TEST_PROGS := binfmt_script.py
TEST_GEN_PROGS := execveat load_address_4096 load_address_2097152 load_address_16777216 non-regular
TEST_GEN_PROGS := execveat non-regular $(ALIGNMENT_TESTS)
TEST_GEN_FILES := execveat.symlink execveat.denatured script subdir
# Makefile is a run-time dependency, since it's accessed by the execveat test
TEST_FILES := Makefile
@@ -28,9 +33,9 @@ $(OUTPUT)/execveat.symlink: $(OUTPUT)/execveat
$(OUTPUT)/execveat.denatured: $(OUTPUT)/execveat
cp $< $@
chmod -x $@
$(OUTPUT)/load_address_4096: load_address.c
$(CC) $(CFLAGS) $(LDFLAGS) -Wl,-z,max-page-size=0x1000 -pie -static $< -o $@
$(OUTPUT)/load_address_2097152: load_address.c
$(CC) $(CFLAGS) $(LDFLAGS) -Wl,-z,max-page-size=0x200000 -pie -static $< -o $@
$(OUTPUT)/load_address_16777216: load_address.c
$(CC) $(CFLAGS) $(LDFLAGS) -Wl,-z,max-page-size=0x1000000 -pie -static $< -o $@
$(OUTPUT)/load_address.0x%: load_address.c
$(CC) $(CFLAGS) $(LDFLAGS) -Wl,-z,max-page-size=$(lastword $(subst ., ,$@)) \
-fPIE -pie $< -o $@
$(OUTPUT)/load_address.static.0x%: load_address.c
$(CC) $(CFLAGS) $(LDFLAGS) -Wl,-z,max-page-size=$(lastword $(subst ., ,$@)) \
-fPIE -static-pie $< -o $@
+54 -13
View File
@@ -5,11 +5,13 @@
#include <link.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include "../kselftest.h"
struct Statistics {
unsigned long long load_address;
unsigned long long alignment;
bool interp;
};
int ExtractStatistics(struct dl_phdr_info *info, size_t size, void *data)
@@ -26,11 +28,20 @@ int ExtractStatistics(struct dl_phdr_info *info, size_t size, void *data)
stats->alignment = 0;
for (i = 0; i < info->dlpi_phnum; i++) {
unsigned long long align;
if (info->dlpi_phdr[i].p_type == PT_INTERP) {
stats->interp = true;
continue;
}
if (info->dlpi_phdr[i].p_type != PT_LOAD)
continue;
if (info->dlpi_phdr[i].p_align > stats->alignment)
stats->alignment = info->dlpi_phdr[i].p_align;
align = info->dlpi_phdr[i].p_align;
if (align > stats->alignment)
stats->alignment = align;
}
return 1; // Terminate dl_iterate_phdr.
@@ -38,27 +49,57 @@ int ExtractStatistics(struct dl_phdr_info *info, size_t size, void *data)
int main(int argc, char **argv)
{
struct Statistics extracted;
unsigned long long misalign;
struct Statistics extracted = { };
unsigned long long misalign, pow2;
bool interp_needed;
char buf[1024];
FILE *maps;
int ret;
ksft_print_header();
ksft_set_plan(1);
ksft_set_plan(4);
/* Dump maps file for debugging reference. */
maps = fopen("/proc/self/maps", "r");
if (!maps)
ksft_exit_fail_msg("FAILED: /proc/self/maps: %s\n", strerror(errno));
while (fgets(buf, sizeof(buf), maps)) {
ksft_print_msg("%s", buf);
}
fclose(maps);
/* Walk the program headers. */
ret = dl_iterate_phdr(ExtractStatistics, &extracted);
if (ret != 1)
ksft_exit_fail_msg("FAILED: dl_iterate_phdr\n");
if (extracted.alignment == 0)
ksft_exit_fail_msg("FAILED: No alignment found\n");
else if (extracted.alignment & (extracted.alignment - 1))
ksft_exit_fail_msg("FAILED: Alignment is not a power of 2\n");
/* Report our findings. */
ksft_print_msg("load_address=%#llx alignment=%#llx\n",
extracted.load_address, extracted.alignment);
/* If we're named with ".static." we expect no INTERP. */
interp_needed = strstr(argv[0], ".static.") == NULL;
/* Were we built as expected? */
ksft_test_result(interp_needed == extracted.interp,
"%s INTERP program header %s\n",
interp_needed ? "Wanted" : "Unwanted",
extracted.interp ? "seen" : "missing");
/* Did we find an alignment? */
ksft_test_result(extracted.alignment != 0,
"Alignment%s found\n", extracted.alignment ? "" : " NOT");
/* Is the alignment sane? */
pow2 = extracted.alignment & (extracted.alignment - 1);
ksft_test_result(pow2 == 0,
"Alignment is%s a power of 2: %#llx\n",
pow2 == 0 ? "" : " NOT", extracted.alignment);
/* Is the load address aligned? */
misalign = extracted.load_address & (extracted.alignment - 1);
if (misalign)
ksft_exit_fail_msg("FAILED: alignment = %llu, load_address = %llu\n",
extracted.alignment, extracted.load_address);
ksft_test_result(misalign == 0, "Load Address is %saligned (%#llx)\n",
misalign ? "MIS" : "", misalign);
ksft_test_result_pass("Completed\n");
ksft_finished();
}