diff options
Diffstat (limited to 'tools')
45 files changed, 1129 insertions, 374 deletions
diff --git a/tools/arch/s390/include/uapi/asm/kvm.h b/tools/arch/s390/include/uapi/asm/kvm.h index 69d09c39bbcd..cd7359e23d86 100644 --- a/tools/arch/s390/include/uapi/asm/kvm.h +++ b/tools/arch/s390/include/uapi/asm/kvm.h @@ -88,6 +88,12 @@ struct kvm_s390_io_adapter_req {  /* kvm attributes for KVM_S390_VM_TOD */  #define KVM_S390_VM_TOD_LOW		0  #define KVM_S390_VM_TOD_HIGH		1 +#define KVM_S390_VM_TOD_EXT		2 + +struct kvm_s390_vm_tod_clock { +	__u8  epoch_idx; +	__u64 tod; +};  /* kvm attributes for KVM_S390_VM_CPU_MODEL */  /* processor related attributes are r/w */ diff --git a/tools/arch/x86/include/asm/cpufeatures.h b/tools/arch/x86/include/asm/cpufeatures.h index 8ea315a11fe0..2519c6c801c9 100644 --- a/tools/arch/x86/include/asm/cpufeatures.h +++ b/tools/arch/x86/include/asm/cpufeatures.h @@ -196,6 +196,7 @@  #define X86_FEATURE_HW_PSTATE	( 7*32+ 8) /* AMD HW-PState */  #define X86_FEATURE_PROC_FEEDBACK ( 7*32+ 9) /* AMD ProcFeedbackInterface */ +#define X86_FEATURE_SME		( 7*32+10) /* AMD Secure Memory Encryption */  #define X86_FEATURE_INTEL_PPIN	( 7*32+14) /* Intel Processor Inventory Number */  #define X86_FEATURE_INTEL_PT	( 7*32+15) /* Intel Processor Trace */ @@ -287,6 +288,7 @@  #define X86_FEATURE_PFTHRESHOLD (15*32+12) /* pause filter threshold */  #define X86_FEATURE_AVIC	(15*32+13) /* Virtual Interrupt Controller */  #define X86_FEATURE_V_VMSAVE_VMLOAD (15*32+15) /* Virtual VMSAVE VMLOAD */ +#define X86_FEATURE_VGIF	(15*32+16) /* Virtual GIF */  /* Intel-defined CPU features, CPUID level 0x00000007:0 (ecx), word 16 */  #define X86_FEATURE_AVX512VBMI  (16*32+ 1) /* AVX512 Vector Bit Manipulation instructions*/ diff --git a/tools/arch/x86/include/asm/disabled-features.h b/tools/arch/x86/include/asm/disabled-features.h index 5dff775af7cd..c10c9128f54e 100644 --- a/tools/arch/x86/include/asm/disabled-features.h +++ b/tools/arch/x86/include/asm/disabled-features.h @@ -21,11 +21,13 @@  # define DISABLE_K6_MTRR	(1<<(X86_FEATURE_K6_MTRR & 31))  # define DISABLE_CYRIX_ARR	(1<<(X86_FEATURE_CYRIX_ARR & 31))  # define DISABLE_CENTAUR_MCR	(1<<(X86_FEATURE_CENTAUR_MCR & 31)) +# define DISABLE_PCID		0  #else  # define DISABLE_VME		0  # define DISABLE_K6_MTRR	0  # define DISABLE_CYRIX_ARR	0  # define DISABLE_CENTAUR_MCR	0 +# define DISABLE_PCID		(1<<(X86_FEATURE_PCID & 31))  #endif /* CONFIG_X86_64 */  #ifdef CONFIG_X86_INTEL_MEMORY_PROTECTION_KEYS @@ -49,7 +51,7 @@  #define DISABLED_MASK1	0  #define DISABLED_MASK2	0  #define DISABLED_MASK3	(DISABLE_CYRIX_ARR|DISABLE_CENTAUR_MCR|DISABLE_K6_MTRR) -#define DISABLED_MASK4	0 +#define DISABLED_MASK4	(DISABLE_PCID)  #define DISABLED_MASK5	0  #define DISABLED_MASK6	0  #define DISABLED_MASK7	0 diff --git a/tools/include/asm-generic/hugetlb_encode.h b/tools/include/asm-generic/hugetlb_encode.h new file mode 100644 index 000000000000..e4732d3c2998 --- /dev/null +++ b/tools/include/asm-generic/hugetlb_encode.h @@ -0,0 +1,34 @@ +#ifndef _ASM_GENERIC_HUGETLB_ENCODE_H_ +#define _ASM_GENERIC_HUGETLB_ENCODE_H_ + +/* + * Several system calls take a flag to request "hugetlb" huge pages. + * Without further specification, these system calls will use the + * system's default huge page size.  If a system supports multiple + * huge page sizes, the desired huge page size can be specified in + * bits [26:31] of the flag arguments.  The value in these 6 bits + * will encode the log2 of the huge page size. + * + * The following definitions are associated with this huge page size + * encoding in flag arguments.  System call specific header files + * that use this encoding should include this file.  They can then + * provide definitions based on these with their own specific prefix. + * for example: + * #define MAP_HUGE_SHIFT HUGETLB_FLAG_ENCODE_SHIFT + */ + +#define HUGETLB_FLAG_ENCODE_SHIFT	26 +#define HUGETLB_FLAG_ENCODE_MASK	0x3f + +#define HUGETLB_FLAG_ENCODE_64KB	(16 << HUGETLB_FLAG_ENCODE_SHIFT) +#define HUGETLB_FLAG_ENCODE_512KB	(19 << HUGETLB_FLAG_ENCODE_SHIFT) +#define HUGETLB_FLAG_ENCODE_1MB		(20 << HUGETLB_FLAG_ENCODE_SHIFT) +#define HUGETLB_FLAG_ENCODE_2MB		(21 << HUGETLB_FLAG_ENCODE_SHIFT) +#define HUGETLB_FLAG_ENCODE_8MB		(23 << HUGETLB_FLAG_ENCODE_SHIFT) +#define HUGETLB_FLAG_ENCODE_16MB	(24 << HUGETLB_FLAG_ENCODE_SHIFT) +#define HUGETLB_FLAG_ENCODE_256MB	(28 << HUGETLB_FLAG_ENCODE_SHIFT) +#define HUGETLB_FLAG_ENCODE_1GB		(30 << HUGETLB_FLAG_ENCODE_SHIFT) +#define HUGETLB_FLAG_ENCODE_2GB		(31 << HUGETLB_FLAG_ENCODE_SHIFT) +#define HUGETLB_FLAG_ENCODE_16GB	(34 << HUGETLB_FLAG_ENCODE_SHIFT) + +#endif /* _ASM_GENERIC_HUGETLB_ENCODE_H_ */ diff --git a/tools/include/uapi/asm-generic/mman-common.h b/tools/include/uapi/asm-generic/mman-common.h index 8c27db0c5c08..203268f9231e 100644 --- a/tools/include/uapi/asm-generic/mman-common.h +++ b/tools/include/uapi/asm-generic/mman-common.h @@ -58,20 +58,12 @@  					   overrides the coredump filter bits */  #define MADV_DODUMP	17		/* Clear the MADV_DONTDUMP flag */ +#define MADV_WIPEONFORK 18		/* Zero memory on fork, child only */ +#define MADV_KEEPONFORK 19		/* Undo MADV_WIPEONFORK */ +  /* compatibility flags */  #define MAP_FILE	0 -/* - * When MAP_HUGETLB is set bits [26:31] encode the log2 of the huge page size. - * This gives us 6 bits, which is enough until someone invents 128 bit address - * spaces. - * - * Assume these are all power of twos. - * When 0 use the default page size. - */ -#define MAP_HUGE_SHIFT	26 -#define MAP_HUGE_MASK	0x3f -  #define PKEY_DISABLE_ACCESS	0x1  #define PKEY_DISABLE_WRITE	0x2  #define PKEY_ACCESS_MASK	(PKEY_DISABLE_ACCESS |\ diff --git a/tools/include/uapi/drm/drm.h b/tools/include/uapi/drm/drm.h index 101593ab10ac..97677cd6964d 100644 --- a/tools/include/uapi/drm/drm.h +++ b/tools/include/uapi/drm/drm.h @@ -700,6 +700,7 @@ struct drm_prime_handle {  struct drm_syncobj_create {  	__u32 handle; +#define DRM_SYNCOBJ_CREATE_SIGNALED (1 << 0)  	__u32 flags;  }; @@ -718,6 +719,24 @@ struct drm_syncobj_handle {  	__u32 pad;  }; +#define DRM_SYNCOBJ_WAIT_FLAGS_WAIT_ALL (1 << 0) +#define DRM_SYNCOBJ_WAIT_FLAGS_WAIT_FOR_SUBMIT (1 << 1) +struct drm_syncobj_wait { +	__u64 handles; +	/* absolute timeout */ +	__s64 timeout_nsec; +	__u32 count_handles; +	__u32 flags; +	__u32 first_signaled; /* only valid when not waiting all */ +	__u32 pad; +}; + +struct drm_syncobj_array { +	__u64 handles; +	__u32 count_handles; +	__u32 pad; +}; +  #if defined(__cplusplus)  }  #endif @@ -840,6 +859,9 @@ extern "C" {  #define DRM_IOCTL_SYNCOBJ_DESTROY	DRM_IOWR(0xC0, struct drm_syncobj_destroy)  #define DRM_IOCTL_SYNCOBJ_HANDLE_TO_FD	DRM_IOWR(0xC1, struct drm_syncobj_handle)  #define DRM_IOCTL_SYNCOBJ_FD_TO_HANDLE	DRM_IOWR(0xC2, struct drm_syncobj_handle) +#define DRM_IOCTL_SYNCOBJ_WAIT		DRM_IOWR(0xC3, struct drm_syncobj_wait) +#define DRM_IOCTL_SYNCOBJ_RESET		DRM_IOWR(0xC4, struct drm_syncobj_array) +#define DRM_IOCTL_SYNCOBJ_SIGNAL	DRM_IOWR(0xC5, struct drm_syncobj_array)  /**   * Device specific ioctls should only be in their respective headers diff --git a/tools/include/uapi/drm/i915_drm.h b/tools/include/uapi/drm/i915_drm.h index 7ccbd6a2bbe0..6598fb76d2c2 100644 --- a/tools/include/uapi/drm/i915_drm.h +++ b/tools/include/uapi/drm/i915_drm.h @@ -260,6 +260,8 @@ typedef struct _drm_i915_sarea {  #define DRM_I915_GEM_CONTEXT_GETPARAM	0x34  #define DRM_I915_GEM_CONTEXT_SETPARAM	0x35  #define DRM_I915_PERF_OPEN		0x36 +#define DRM_I915_PERF_ADD_CONFIG	0x37 +#define DRM_I915_PERF_REMOVE_CONFIG	0x38  #define DRM_IOCTL_I915_INIT		DRM_IOW( DRM_COMMAND_BASE + DRM_I915_INIT, drm_i915_init_t)  #define DRM_IOCTL_I915_FLUSH		DRM_IO ( DRM_COMMAND_BASE + DRM_I915_FLUSH) @@ -315,6 +317,8 @@ typedef struct _drm_i915_sarea {  #define DRM_IOCTL_I915_GEM_CONTEXT_GETPARAM	DRM_IOWR (DRM_COMMAND_BASE + DRM_I915_GEM_CONTEXT_GETPARAM, struct drm_i915_gem_context_param)  #define DRM_IOCTL_I915_GEM_CONTEXT_SETPARAM	DRM_IOWR (DRM_COMMAND_BASE + DRM_I915_GEM_CONTEXT_SETPARAM, struct drm_i915_gem_context_param)  #define DRM_IOCTL_I915_PERF_OPEN	DRM_IOW(DRM_COMMAND_BASE + DRM_I915_PERF_OPEN, struct drm_i915_perf_open_param) +#define DRM_IOCTL_I915_PERF_ADD_CONFIG	DRM_IOW(DRM_COMMAND_BASE + DRM_I915_PERF_ADD_CONFIG, struct drm_i915_perf_oa_config) +#define DRM_IOCTL_I915_PERF_REMOVE_CONFIG	DRM_IOW(DRM_COMMAND_BASE + DRM_I915_PERF_REMOVE_CONFIG, __u64)  /* Allow drivers to submit batchbuffers directly to hardware, relying   * on the security mechanisms provided by hardware. @@ -431,6 +435,11 @@ typedef struct drm_i915_irq_wait {   */  #define I915_PARAM_HAS_EXEC_BATCH_FIRST	 48 +/* Query whether DRM_I915_GEM_EXECBUFFER2 supports supplying an array of + * drm_i915_gem_exec_fence structures.  See I915_EXEC_FENCE_ARRAY. + */ +#define I915_PARAM_HAS_EXEC_FENCE_ARRAY  49 +  typedef struct drm_i915_getparam {  	__s32 param;  	/* @@ -812,6 +821,17 @@ struct drm_i915_gem_exec_object2 {  	__u64 rsvd2;  }; +struct drm_i915_gem_exec_fence { +	/** +	 * User's handle for a drm_syncobj to wait on or signal. +	 */ +	__u32 handle; + +#define I915_EXEC_FENCE_WAIT            (1<<0) +#define I915_EXEC_FENCE_SIGNAL          (1<<1) +	__u32 flags; +}; +  struct drm_i915_gem_execbuffer2 {  	/**  	 * List of gem_exec_object2 structs @@ -826,7 +846,11 @@ struct drm_i915_gem_execbuffer2 {  	__u32 DR1;  	__u32 DR4;  	__u32 num_cliprects; -	/** This is a struct drm_clip_rect *cliprects */ +	/** +	 * This is a struct drm_clip_rect *cliprects if I915_EXEC_FENCE_ARRAY +	 * is not set.  If I915_EXEC_FENCE_ARRAY is set, then this is a +	 * struct drm_i915_gem_exec_fence *fences. +	 */  	__u64 cliprects_ptr;  #define I915_EXEC_RING_MASK              (7<<0)  #define I915_EXEC_DEFAULT                (0<<0) @@ -927,7 +951,14 @@ struct drm_i915_gem_execbuffer2 {   * element).   */  #define I915_EXEC_BATCH_FIRST		(1<<18) -#define __I915_EXEC_UNKNOWN_FLAGS (-(I915_EXEC_BATCH_FIRST<<1)) + +/* Setting I915_FENCE_ARRAY implies that num_cliprects and cliprects_ptr + * define an array of i915_gem_exec_fence structures which specify a set of + * dma fences to wait upon or signal. + */ +#define I915_EXEC_FENCE_ARRAY   (1<<19) + +#define __I915_EXEC_UNKNOWN_FLAGS (-(I915_EXEC_FENCE_ARRAY<<1))  #define I915_EXEC_CONTEXT_ID_MASK	(0xffffffff)  #define i915_execbuffer2_set_context_id(eb2, context) \ @@ -1467,6 +1498,22 @@ enum drm_i915_perf_record_type {  	DRM_I915_PERF_RECORD_MAX /* non-ABI */  }; +/** + * Structure to upload perf dynamic configuration into the kernel. + */ +struct drm_i915_perf_oa_config { +	/** String formatted like "%08x-%04x-%04x-%04x-%012x" */ +	char uuid[36]; + +	__u32 n_mux_regs; +	__u32 n_boolean_regs; +	__u32 n_flex_regs; + +	__u64 __user mux_regs_ptr; +	__u64 __user boolean_regs_ptr; +	__u64 __user flex_regs_ptr; +}; +  #if defined(__cplusplus)  }  #endif diff --git a/tools/include/uapi/linux/bpf.h b/tools/include/uapi/linux/bpf.h index 461811e57140..43ab5c402f98 100644 --- a/tools/include/uapi/linux/bpf.h +++ b/tools/include/uapi/linux/bpf.h @@ -143,12 +143,6 @@ enum bpf_attach_type {  #define MAX_BPF_ATTACH_TYPE __MAX_BPF_ATTACH_TYPE -enum bpf_sockmap_flags { -	BPF_SOCKMAP_UNSPEC, -	BPF_SOCKMAP_STRPARSER, -	__MAX_BPF_SOCKMAP_FLAG -}; -  /* If BPF_F_ALLOW_OVERRIDE flag is used in BPF_PROG_ATTACH command   * to the given target_fd cgroup the descendent cgroup will be able to   * override effective bpf program that was inherited from this cgroup @@ -368,9 +362,20 @@ union bpf_attr {   * int bpf_redirect(ifindex, flags)   *     redirect to another netdev   *     @ifindex: ifindex of the net device - *     @flags: bit 0 - if set, redirect to ingress instead of egress - *             other bits - reserved - *     Return: TC_ACT_REDIRECT + *     @flags: + *	  cls_bpf: + *          bit 0 - if set, redirect to ingress instead of egress + *          other bits - reserved + *	  xdp_bpf: + *	    all bits - reserved + *     Return: cls_bpf: TC_ACT_REDIRECT on success or TC_ACT_SHOT on error + *	       xdp_bfp: XDP_REDIRECT on success or XDP_ABORT on error + * int bpf_redirect_map(map, key, flags) + *     redirect to endpoint in map + *     @map: pointer to dev map + *     @key: index in map to lookup + *     @flags: -- + *     Return: XDP_REDIRECT on success or XDP_ABORT on error   *   * u32 bpf_get_route_realm(skb)   *     retrieve a dst's tclassid @@ -632,7 +637,7 @@ union bpf_attr {  	FN(skb_adjust_room),		\  	FN(redirect_map),		\  	FN(sk_redirect_map),		\ -	FN(sock_map_update), +	FN(sock_map_update),		\  /* integer value in 'imm' field of BPF_CALL instruction selects which helper   * function eBPF program intends to call @@ -753,20 +758,23 @@ struct bpf_sock {  	__u32 family;  	__u32 type;  	__u32 protocol; +	__u32 mark; +	__u32 priority;  };  #define XDP_PACKET_HEADROOM 256  /* User return codes for XDP prog type.   * A valid XDP program must return one of these defined values. All other - * return codes are reserved for future use. Unknown return codes will result - * in packet drop. + * return codes are reserved for future use. Unknown return codes will + * result in packet drops and a warning via bpf_warn_invalid_xdp_action().   */  enum xdp_action {  	XDP_ABORTED = 0,  	XDP_DROP,  	XDP_PASS,  	XDP_TX, +	XDP_REDIRECT,  };  /* user accessible metadata for XDP packet hook diff --git a/tools/include/uapi/linux/kvm.h b/tools/include/uapi/linux/kvm.h index 6cd63c18708a..838887587411 100644 --- a/tools/include/uapi/linux/kvm.h +++ b/tools/include/uapi/linux/kvm.h @@ -711,7 +711,8 @@ struct kvm_ppc_one_seg_page_size {  struct kvm_ppc_smmu_info {  	__u64 flags;  	__u32 slb_size; -	__u32 pad; +	__u16 data_keys;	/* # storage keys supported for data */ +	__u16 instr_keys;	/* # storage keys supported for instructions */  	struct kvm_ppc_one_seg_page_size sps[KVM_PPC_PAGE_SIZES_MAX_SZ];  }; diff --git a/tools/include/uapi/linux/mman.h b/tools/include/uapi/linux/mman.h index 81d8edf11789..a937480d7cd3 100644 --- a/tools/include/uapi/linux/mman.h +++ b/tools/include/uapi/linux/mman.h @@ -1,7 +1,8 @@  #ifndef _UAPI_LINUX_MMAN_H  #define _UAPI_LINUX_MMAN_H -#include <uapi/asm/mman.h> +#include <asm/mman.h> +#include <asm-generic/hugetlb_encode.h>  #define MREMAP_MAYMOVE	1  #define MREMAP_FIXED	2 @@ -10,4 +11,25 @@  #define OVERCOMMIT_ALWAYS		1  #define OVERCOMMIT_NEVER		2 +/* + * Huge page size encoding when MAP_HUGETLB is specified, and a huge page + * size other than the default is desired.  See hugetlb_encode.h. + * All known huge page size encodings are provided here.  It is the + * responsibility of the application to know which sizes are supported on + * the running system.  See mmap(2) man page for details. + */ +#define MAP_HUGE_SHIFT	HUGETLB_FLAG_ENCODE_SHIFT +#define MAP_HUGE_MASK	HUGETLB_FLAG_ENCODE_MASK + +#define MAP_HUGE_64KB	HUGETLB_FLAG_ENCODE_64KB +#define MAP_HUGE_512KB	HUGETLB_FLAG_ENCODE_512KB +#define MAP_HUGE_1MB	HUGETLB_FLAG_ENCODE_1MB +#define MAP_HUGE_2MB	HUGETLB_FLAG_ENCODE_2MB +#define MAP_HUGE_8MB	HUGETLB_FLAG_ENCODE_8MB +#define MAP_HUGE_16MB	HUGETLB_FLAG_ENCODE_16MB +#define MAP_HUGE_256MB	HUGETLB_FLAG_ENCODE_256MB +#define MAP_HUGE_1GB	HUGETLB_FLAG_ENCODE_1GB +#define MAP_HUGE_2GB	HUGETLB_FLAG_ENCODE_2GB +#define MAP_HUGE_16GB	HUGETLB_FLAG_ENCODE_16GB +  #endif /* _UAPI_LINUX_MMAN_H */ diff --git a/tools/objtool/Documentation/stack-validation.txt b/tools/objtool/Documentation/stack-validation.txt index 6a1af43862df..3995735a878f 100644 --- a/tools/objtool/Documentation/stack-validation.txt +++ b/tools/objtool/Documentation/stack-validation.txt @@ -194,10 +194,10 @@ they mean, and suggestions for how to fix them.     If it's a GCC-compiled .c file, the error may be because the function     uses an inline asm() statement which has a "call" instruction.  An     asm() statement with a call instruction must declare the use of the -   stack pointer in its output operand.  For example, on x86_64: +   stack pointer in its output operand.  On x86_64, this means adding +   the ASM_CALL_CONSTRAINT as an output constraint: -     register void *__sp asm("rsp"); -     asm volatile("call func" : "+r" (__sp)); +     asm volatile("call func" : ASM_CALL_CONSTRAINT);     Otherwise the stack frame may not get created before the call. diff --git a/tools/objtool/arch/x86/decode.c b/tools/objtool/arch/x86/decode.c index 0e8c8ec4fd4e..34a579f806e3 100644 --- a/tools/objtool/arch/x86/decode.c +++ b/tools/objtool/arch/x86/decode.c @@ -208,14 +208,14 @@ int arch_decode_instruction(struct elf *elf, struct section *sec,  		break;  	case 0x89: -		if (rex == 0x48 && modrm == 0xe5) { +		if (rex_w && !rex_r && modrm_mod == 3 && modrm_reg == 4) { -			/* mov %rsp, %rbp */ +			/* mov %rsp, reg */  			*type = INSN_STACK;  			op->src.type = OP_SRC_REG;  			op->src.reg = CFI_SP;  			op->dest.type = OP_DEST_REG; -			op->dest.reg = CFI_BP; +			op->dest.reg = op_to_cfi_reg[modrm_rm][rex_b];  			break;  		} @@ -284,11 +284,16 @@ int arch_decode_instruction(struct elf *elf, struct section *sec,  	case 0x8d:  		if (sib == 0x24 && rex_w && !rex_b && !rex_x) { -			/* lea disp(%rsp), reg */  			*type = INSN_STACK; -			op->src.type = OP_SRC_ADD; +			if (!insn.displacement.value) { +				/* lea (%rsp), reg */ +				op->src.type = OP_SRC_REG; +			} else { +				/* lea disp(%rsp), reg */ +				op->src.type = OP_SRC_ADD; +				op->src.offset = insn.displacement.value; +			}  			op->src.reg = CFI_SP; -			op->src.offset = insn.displacement.value;  			op->dest.type = OP_DEST_REG;  			op->dest.reg = op_to_cfi_reg[modrm_reg][rex_r]; diff --git a/tools/objtool/check.c b/tools/objtool/check.c index f744617c9946..a0c518ecf085 100644 --- a/tools/objtool/check.c +++ b/tools/objtool/check.c @@ -1203,24 +1203,39 @@ static int update_insn_state(struct instruction *insn, struct insn_state *state)  		switch (op->src.type) {  		case OP_SRC_REG: -			if (op->src.reg == CFI_SP && op->dest.reg == CFI_BP) { +			if (op->src.reg == CFI_SP && op->dest.reg == CFI_BP && +			    cfa->base == CFI_SP && +			    regs[CFI_BP].base == CFI_CFA && +			    regs[CFI_BP].offset == -cfa->offset) { + +				/* mov %rsp, %rbp */ +				cfa->base = op->dest.reg; +				state->bp_scratch = false; +			} -				if (cfa->base == CFI_SP && -				    regs[CFI_BP].base == CFI_CFA && -				    regs[CFI_BP].offset == -cfa->offset) { +			else if (op->src.reg == CFI_SP && +				 op->dest.reg == CFI_BP && state->drap) { -					/* mov %rsp, %rbp */ -					cfa->base = op->dest.reg; -					state->bp_scratch = false; -				} +				/* drap: mov %rsp, %rbp */ +				regs[CFI_BP].base = CFI_BP; +				regs[CFI_BP].offset = -state->stack_size; +				state->bp_scratch = false; +			} -				else if (state->drap) { +			else if (op->src.reg == CFI_SP && cfa->base == CFI_SP) { -					/* drap: mov %rsp, %rbp */ -					regs[CFI_BP].base = CFI_BP; -					regs[CFI_BP].offset = -state->stack_size; -					state->bp_scratch = false; -				} +				/* +				 * mov %rsp, %reg +				 * +				 * This is needed for the rare case where GCC +				 * does: +				 * +				 *   mov    %rsp, %rax +				 *   ... +				 *   mov    %rax, %rsp +				 */ +				state->vals[op->dest.reg].base = CFI_CFA; +				state->vals[op->dest.reg].offset = -state->stack_size;  			}  			else if (op->dest.reg == cfa->base) { diff --git a/tools/objtool/elf.c b/tools/objtool/elf.c index 6e9f980a7d26..24460155c82c 100644 --- a/tools/objtool/elf.c +++ b/tools/objtool/elf.c @@ -175,19 +175,20 @@ static int read_sections(struct elf *elf)  			return -1;  		} -		sec->data = elf_getdata(s, NULL); -		if (!sec->data) { -			WARN_ELF("elf_getdata"); -			return -1; -		} - -		if (sec->data->d_off != 0 || -		    sec->data->d_size != sec->sh.sh_size) { -			WARN("unexpected data attributes for %s", sec->name); -			return -1; +		if (sec->sh.sh_size != 0) { +			sec->data = elf_getdata(s, NULL); +			if (!sec->data) { +				WARN_ELF("elf_getdata"); +				return -1; +			} +			if (sec->data->d_off != 0 || +			    sec->data->d_size != sec->sh.sh_size) { +				WARN("unexpected data attributes for %s", +				     sec->name); +				return -1; +			}  		} - -		sec->len = sec->data->d_size; +		sec->len = sec->sh.sh_size;  	}  	/* sanity check, one more call to elf_nextscn() should return NULL */ @@ -508,6 +509,7 @@ struct section *elf_create_rela_section(struct elf *elf, struct section *base)  	strcat(relaname, base->name);  	sec = elf_create_section(elf, relaname, sizeof(GElf_Rela), 0); +	free(relaname);  	if (!sec)  		return NULL; @@ -561,6 +563,7 @@ int elf_write(struct elf *elf)  	struct section *sec;  	Elf_Scn *s; +	/* Update section headers for changed sections: */  	list_for_each_entry(sec, &elf->sections, list) {  		if (sec->changed) {  			s = elf_getscn(elf->elf, sec->idx); @@ -568,13 +571,17 @@ int elf_write(struct elf *elf)  				WARN_ELF("elf_getscn");  				return -1;  			} -			if (!gelf_update_shdr (s, &sec->sh)) { +			if (!gelf_update_shdr(s, &sec->sh)) {  				WARN_ELF("gelf_update_shdr");  				return -1;  			}  		}  	} +	/* Make sure the new section header entries get updated properly. */ +	elf_flagelf(elf->elf, ELF_C_SET, ELF_F_DIRTY); + +	/* Write all changes to the file. */  	if (elf_update(elf->elf, ELF_C_WRITE) < 0) {  		WARN_ELF("elf_update");  		return -1; diff --git a/tools/perf/MANIFEST b/tools/perf/MANIFEST index 62072822dc85..627b7cada144 100644 --- a/tools/perf/MANIFEST +++ b/tools/perf/MANIFEST @@ -1,34 +1,8 @@  tools/perf -tools/arch/alpha/include/asm/barrier.h -tools/arch/arm/include/asm/barrier.h -tools/arch/arm64/include/asm/barrier.h -tools/arch/ia64/include/asm/barrier.h -tools/arch/mips/include/asm/barrier.h -tools/arch/powerpc/include/asm/barrier.h -tools/arch/s390/include/asm/barrier.h -tools/arch/sh/include/asm/barrier.h -tools/arch/sparc/include/asm/barrier.h -tools/arch/sparc/include/asm/barrier_32.h -tools/arch/sparc/include/asm/barrier_64.h -tools/arch/tile/include/asm/barrier.h -tools/arch/x86/include/asm/barrier.h -tools/arch/x86/include/asm/cmpxchg.h -tools/arch/x86/include/asm/cpufeatures.h -tools/arch/x86/include/asm/disabled-features.h -tools/arch/x86/include/asm/required-features.h -tools/arch/x86/include/uapi/asm/svm.h -tools/arch/x86/include/uapi/asm/vmx.h -tools/arch/x86/include/uapi/asm/kvm.h -tools/arch/x86/include/uapi/asm/kvm_perf.h -tools/arch/x86/lib/memcpy_64.S -tools/arch/x86/lib/memset_64.S -tools/arch/s390/include/uapi/asm/kvm_perf.h -tools/arch/s390/include/uapi/asm/sie.h -tools/arch/xtensa/include/asm/barrier.h +tools/arch  tools/scripts  tools/build -tools/arch/x86/include/asm/atomic.h -tools/arch/x86/include/asm/rmwcc.h +tools/include  tools/lib/traceevent  tools/lib/api  tools/lib/bpf @@ -42,60 +16,3 @@ tools/lib/find_bit.c  tools/lib/bitmap.c  tools/lib/str_error_r.c  tools/lib/vsprintf.c -tools/include/asm/alternative-asm.h -tools/include/asm/atomic.h -tools/include/asm/barrier.h -tools/include/asm/bug.h -tools/include/asm-generic/atomic-gcc.h -tools/include/asm-generic/barrier.h -tools/include/asm-generic/bitops/arch_hweight.h -tools/include/asm-generic/bitops/atomic.h -tools/include/asm-generic/bitops/const_hweight.h -tools/include/asm-generic/bitops/__ffs.h -tools/include/asm-generic/bitops/__ffz.h -tools/include/asm-generic/bitops/__fls.h -tools/include/asm-generic/bitops/find.h -tools/include/asm-generic/bitops/fls64.h -tools/include/asm-generic/bitops/fls.h -tools/include/asm-generic/bitops/hweight.h -tools/include/asm-generic/bitops.h -tools/include/linux/atomic.h -tools/include/linux/bitops.h -tools/include/linux/compiler.h -tools/include/linux/compiler-gcc.h -tools/include/linux/coresight-pmu.h -tools/include/linux/bug.h -tools/include/linux/filter.h -tools/include/linux/hash.h -tools/include/linux/kernel.h -tools/include/linux/list.h -tools/include/linux/log2.h -tools/include/uapi/asm-generic/fcntl.h -tools/include/uapi/asm-generic/ioctls.h -tools/include/uapi/asm-generic/mman-common.h -tools/include/uapi/asm-generic/mman.h -tools/include/uapi/drm/drm.h -tools/include/uapi/drm/i915_drm.h -tools/include/uapi/linux/bpf.h -tools/include/uapi/linux/bpf_common.h -tools/include/uapi/linux/fcntl.h -tools/include/uapi/linux/hw_breakpoint.h -tools/include/uapi/linux/kvm.h -tools/include/uapi/linux/mman.h -tools/include/uapi/linux/perf_event.h -tools/include/uapi/linux/sched.h -tools/include/uapi/linux/stat.h -tools/include/uapi/linux/vhost.h -tools/include/uapi/sound/asound.h -tools/include/linux/poison.h -tools/include/linux/rbtree.h -tools/include/linux/rbtree_augmented.h -tools/include/linux/refcount.h -tools/include/linux/string.h -tools/include/linux/stringify.h -tools/include/linux/types.h -tools/include/linux/err.h -tools/include/linux/bitmap.h -tools/include/linux/time64.h -tools/arch/*/include/uapi/asm/mman.h -tools/arch/*/include/uapi/asm/perf_regs.h diff --git a/tools/perf/arch/s390/util/Build b/tools/perf/arch/s390/util/Build index bd518b623d7a..5bd7b9260cc0 100644 --- a/tools/perf/arch/s390/util/Build +++ b/tools/perf/arch/s390/util/Build @@ -1,5 +1,4 @@  libperf-y += header.o -libperf-y += sym-handling.o  libperf-y += kvm-stat.o  libperf-$(CONFIG_DWARF) += dwarf-regs.o diff --git a/tools/perf/arch/s390/util/sym-handling.c b/tools/perf/arch/s390/util/sym-handling.c deleted file mode 100644 index e103f6e46afe..000000000000 --- a/tools/perf/arch/s390/util/sym-handling.c +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Architecture specific ELF symbol handling and relocation mapping. - * - * Copyright 2017 IBM Corp. - * Author(s): Thomas Richter <tmricht@linux.vnet.ibm.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License (version 2 only) - * as published by the Free Software Foundation. - */ - -#include "symbol.h" - -#ifdef HAVE_LIBELF_SUPPORT -bool elf__needs_adjust_symbols(GElf_Ehdr ehdr) -{ -	if (ehdr.e_type == ET_EXEC) -		return false; -	return ehdr.e_type == ET_REL || ehdr.e_type == ET_DYN; -} - -void arch__adjust_sym_map_offset(GElf_Sym *sym, -				 GElf_Shdr *shdr __maybe_unused, -				 struct map *map) -{ -	if (map->type == MAP__FUNCTION) -		sym->st_value += map->start; -} -#endif diff --git a/tools/perf/util/callchain.c b/tools/perf/util/callchain.c index 510b513e0f01..be09d77cade0 100644 --- a/tools/perf/util/callchain.c +++ b/tools/perf/util/callchain.c @@ -65,8 +65,6 @@ static int parse_callchain_mode(const char *value)  		callchain_param.mode = CHAIN_FOLDED;  		return 0;  	} - -	pr_err("Invalid callchain mode: %s\n", value);  	return -1;  } @@ -82,8 +80,6 @@ static int parse_callchain_order(const char *value)  		callchain_param.order_set = true;  		return 0;  	} - -	pr_err("Invalid callchain order: %s\n", value);  	return -1;  } @@ -105,8 +101,6 @@ static int parse_callchain_sort_key(const char *value)  		callchain_param.branch_callstack = 1;  		return 0;  	} - -	pr_err("Invalid callchain sort key: %s\n", value);  	return -1;  } @@ -124,8 +118,6 @@ static int parse_callchain_value(const char *value)  		callchain_param.value = CCVAL_COUNT;  		return 0;  	} - -	pr_err("Invalid callchain config key: %s\n", value);  	return -1;  } @@ -319,12 +311,27 @@ int perf_callchain_config(const char *var, const char *value)  		return ret;  	} -	if (!strcmp(var, "print-type")) -		return parse_callchain_mode(value); -	if (!strcmp(var, "order")) -		return parse_callchain_order(value); -	if (!strcmp(var, "sort-key")) -		return parse_callchain_sort_key(value); +	if (!strcmp(var, "print-type")){ +		int ret; +		ret = parse_callchain_mode(value); +		if (ret == -1) +			pr_err("Invalid callchain mode: %s\n", value); +		return ret; +	} +	if (!strcmp(var, "order")){ +		int ret; +		ret = parse_callchain_order(value); +		if (ret == -1) +			pr_err("Invalid callchain order: %s\n", value); +		return ret; +	} +	if (!strcmp(var, "sort-key")){ +		int ret; +		ret = parse_callchain_sort_key(value); +		if (ret == -1) +			pr_err("Invalid callchain sort key: %s\n", value); +		return ret; +	}  	if (!strcmp(var, "threshold")) {  		callchain_param.min_percent = strtod(value, &endptr);  		if (value == endptr) { diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c index 4bb89373eb52..0dccdb89572c 100644 --- a/tools/perf/util/evsel.c +++ b/tools/perf/util/evsel.c @@ -271,12 +271,17 @@ struct perf_evsel *perf_evsel__new_idx(struct perf_event_attr *attr, int idx)  	return evsel;  } +static bool perf_event_can_profile_kernel(void) +{ +	return geteuid() == 0 || perf_event_paranoid() == -1; +} +  struct perf_evsel *perf_evsel__new_cycles(bool precise)  {  	struct perf_event_attr attr = {  		.type	= PERF_TYPE_HARDWARE,  		.config	= PERF_COUNT_HW_CPU_CYCLES, -		.exclude_kernel	= geteuid() != 0, +		.exclude_kernel	= !perf_event_can_profile_kernel(),  	};  	struct perf_evsel *evsel; diff --git a/tools/perf/util/symbol-elf.c b/tools/perf/util/symbol-elf.c index 5c39f420111e..9cf781f0d8a2 100644 --- a/tools/perf/util/symbol-elf.c +++ b/tools/perf/util/symbol-elf.c @@ -810,12 +810,6 @@ static u64 ref_reloc(struct kmap *kmap)  void __weak arch__sym_update(struct symbol *s __maybe_unused,  		GElf_Sym *sym __maybe_unused) { } -void __weak arch__adjust_sym_map_offset(GElf_Sym *sym, GElf_Shdr *shdr, -				       struct map *map __maybe_unused) -{ -	sym->st_value -= shdr->sh_addr - shdr->sh_offset; -} -  int dso__load_sym(struct dso *dso, struct map *map, struct symsrc *syms_ss,  		  struct symsrc *runtime_ss, int kmodule)  { @@ -996,7 +990,7 @@ int dso__load_sym(struct dso *dso, struct map *map, struct symsrc *syms_ss,  			/* Adjust symbol to map to file offset */  			if (adjust_kernel_syms) -				arch__adjust_sym_map_offset(&sym, &shdr, map); +				sym.st_value -= shdr.sh_addr - shdr.sh_offset;  			if (strcmp(section_name,  				   (curr_dso->short_name + diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h index 2bd6a1f01a1c..aad99e7e179b 100644 --- a/tools/perf/util/symbol.h +++ b/tools/perf/util/symbol.h @@ -344,9 +344,6 @@ int setup_intlist(struct intlist **list, const char *list_str,  #ifdef HAVE_LIBELF_SUPPORT  bool elf__needs_adjust_symbols(GElf_Ehdr ehdr);  void arch__sym_update(struct symbol *s, GElf_Sym *sym); -void arch__adjust_sym_map_offset(GElf_Sym *sym, -				 GElf_Shdr *shdr __maybe_unused, -				 struct map *map __maybe_unused);  #endif  #define SYMBOL_A 0 diff --git a/tools/perf/util/syscalltbl.c b/tools/perf/util/syscalltbl.c index 19e5db90394c..6eea7cff3d4e 100644 --- a/tools/perf/util/syscalltbl.c +++ b/tools/perf/util/syscalltbl.c @@ -15,9 +15,9 @@  #include "syscalltbl.h"  #include <stdlib.h> +#include <linux/compiler.h>  #ifdef HAVE_SYSCALL_TABLE -#include <linux/compiler.h>  #include <string.h>  #include "string2.h"  #include "util.h" diff --git a/tools/testing/nvdimm/test/nfit.c b/tools/testing/nvdimm/test/nfit.c index d20791c3f499..bef419d4266d 100644 --- a/tools/testing/nvdimm/test/nfit.c +++ b/tools/testing/nvdimm/test/nfit.c @@ -1527,9 +1527,6 @@ static void nfit_test1_setup(struct nfit_test *t)  	set_bit(ND_CMD_ARS_START, &acpi_desc->bus_cmd_force_en);  	set_bit(ND_CMD_ARS_STATUS, &acpi_desc->bus_cmd_force_en);  	set_bit(ND_CMD_CLEAR_ERROR, &acpi_desc->bus_cmd_force_en); -	set_bit(ND_CMD_GET_CONFIG_SIZE, &acpi_desc->dimm_cmd_force_en); -	set_bit(ND_CMD_GET_CONFIG_DATA, &acpi_desc->dimm_cmd_force_en); -	set_bit(ND_CMD_SET_CONFIG_DATA, &acpi_desc->dimm_cmd_force_en);  }  static int nfit_test_blk_do_io(struct nd_blk_region *ndbr, resource_size_t dpa, diff --git a/tools/testing/selftests/Makefile b/tools/testing/selftests/Makefile index 26ce4f7168be..ff805643b5f7 100644 --- a/tools/testing/selftests/Makefile +++ b/tools/testing/selftests/Makefile @@ -52,6 +52,10 @@ override LDFLAGS =  override MAKEFLAGS =  endif +ifneq ($(KBUILD_SRC),) +override LDFLAGS = +endif +  BUILD := $(O)  ifndef BUILD    BUILD := $(KBUILD_OUTPUT) @@ -62,32 +66,32 @@ endif  export BUILD  all: -	for TARGET in $(TARGETS); do		\ +	@for TARGET in $(TARGETS); do		\  		BUILD_TARGET=$$BUILD/$$TARGET;	\  		mkdir $$BUILD_TARGET  -p;	\  		make OUTPUT=$$BUILD_TARGET -C $$TARGET;\  	done;  run_tests: all -	for TARGET in $(TARGETS); do \ +	@for TARGET in $(TARGETS); do \  		BUILD_TARGET=$$BUILD/$$TARGET;	\  		make OUTPUT=$$BUILD_TARGET -C $$TARGET run_tests;\  	done;  hotplug: -	for TARGET in $(TARGETS_HOTPLUG); do \ +	@for TARGET in $(TARGETS_HOTPLUG); do \  		BUILD_TARGET=$$BUILD/$$TARGET;	\  		make OUTPUT=$$BUILD_TARGET -C $$TARGET;\  	done;  run_hotplug: hotplug -	for TARGET in $(TARGETS_HOTPLUG); do \ +	@for TARGET in $(TARGETS_HOTPLUG); do \  		BUILD_TARGET=$$BUILD/$$TARGET;	\  		make OUTPUT=$$BUILD_TARGET -C $$TARGET run_full_test;\  	done;  clean_hotplug: -	for TARGET in $(TARGETS_HOTPLUG); do \ +	@for TARGET in $(TARGETS_HOTPLUG); do \  		BUILD_TARGET=$$BUILD/$$TARGET;	\  		make OUTPUT=$$BUILD_TARGET -C $$TARGET clean;\  	done; @@ -103,7 +107,7 @@ install:  ifdef INSTALL_PATH  	@# Ask all targets to install their files  	mkdir -p $(INSTALL_PATH) -	for TARGET in $(TARGETS); do \ +	@for TARGET in $(TARGETS); do \  		BUILD_TARGET=$$BUILD/$$TARGET;	\  		make OUTPUT=$$BUILD_TARGET -C $$TARGET INSTALL_PATH=$(INSTALL_PATH)/$$TARGET install; \  	done; @@ -128,7 +132,7 @@ else  endif  clean: -	for TARGET in $(TARGETS); do \ +	@for TARGET in $(TARGETS); do \  		BUILD_TARGET=$$BUILD/$$TARGET;	\  		make OUTPUT=$$BUILD_TARGET -C $$TARGET clean;\  	done; diff --git a/tools/testing/selftests/bpf/bpf_util.h b/tools/testing/selftests/bpf/bpf_util.h index 20ecbaa0d85d..6c53a8906eff 100644 --- a/tools/testing/selftests/bpf/bpf_util.h +++ b/tools/testing/selftests/bpf/bpf_util.h @@ -12,6 +12,7 @@ static inline unsigned int bpf_num_possible_cpus(void)  	unsigned int start, end, possible_cpus = 0;  	char buff[128];  	FILE *fp; +	int n;  	fp = fopen(fcpu, "r");  	if (!fp) { @@ -20,17 +21,17 @@ static inline unsigned int bpf_num_possible_cpus(void)  	}  	while (fgets(buff, sizeof(buff), fp)) { -		if (sscanf(buff, "%u-%u", &start, &end) == 2) { -			possible_cpus = start == 0 ? end + 1 : 0; -			break; +		n = sscanf(buff, "%u-%u", &start, &end); +		if (n == 0) { +			printf("Failed to retrieve # possible CPUs!\n"); +			exit(1); +		} else if (n == 1) { +			end = start;  		} +		possible_cpus = start == 0 ? end + 1 : 0; +		break;  	} -  	fclose(fp); -	if (!possible_cpus) { -		printf("Failed to retrieve # possible CPUs!\n"); -		exit(1); -	}  	return possible_cpus;  } diff --git a/tools/testing/selftests/breakpoints/Makefile b/tools/testing/selftests/breakpoints/Makefile index 6b214b7b10fb..247b0a1899d7 100644 --- a/tools/testing/selftests/breakpoints/Makefile +++ b/tools/testing/selftests/breakpoints/Makefile @@ -2,14 +2,14 @@  uname_M := $(shell uname -m 2>/dev/null || echo not)  ARCH ?= $(shell echo $(uname_M) | sed -e s/i.86/x86/ -e s/x86_64/x86/) +TEST_GEN_PROGS := step_after_suspend_test +  ifeq ($(ARCH),x86) -TEST_GEN_PROGS := breakpoint_test +TEST_GEN_PROGS += breakpoint_test  endif  ifneq (,$(filter $(ARCH),aarch64 arm64)) -TEST_GEN_PROGS := breakpoint_test_arm64 +TEST_GEN_PROGS += breakpoint_test_arm64  endif -TEST_GEN_PROGS += step_after_suspend_test -  include ../lib.mk diff --git a/tools/testing/selftests/ftrace/test.d/kprobe/multiple_kprobes.tc b/tools/testing/selftests/ftrace/test.d/kprobe/multiple_kprobes.tc index 2a1cb9908746..a4fd4c851a5b 100644 --- a/tools/testing/selftests/ftrace/test.d/kprobe/multiple_kprobes.tc +++ b/tools/testing/selftests/ftrace/test.d/kprobe/multiple_kprobes.tc @@ -1,6 +1,8 @@  #!/bin/sh  # description: Register/unregister many kprobe events +[ -f kprobe_events ] || exit_unsupported # this is configurable +  # ftrace fentry skip size depends on the machine architecture.  # Currently HAVE_KPROBES_ON_FTRACE defined on x86 and powerpc64le  case `uname -m` in diff --git a/tools/testing/selftests/futex/Makefile b/tools/testing/selftests/futex/Makefile index 7c647f619d63..f0c0369ccb79 100644 --- a/tools/testing/selftests/futex/Makefile +++ b/tools/testing/selftests/futex/Makefile @@ -7,14 +7,17 @@ TEST_PROGS := run.sh  include ../lib.mk  all: -	for DIR in $(SUBDIRS); do		\ +	@for DIR in $(SUBDIRS); do		\  		BUILD_TARGET=$(OUTPUT)/$$DIR;	\  		mkdir $$BUILD_TARGET  -p;	\  		make OUTPUT=$$BUILD_TARGET -C $$DIR $@;\ +		if [ -e $$DIR/$(TEST_PROGS) ]; then +			rsync -a $$DIR/$(TEST_PROGS) $$BUILD_TARGET/; +		fi  	done  override define RUN_TESTS -	$(OUTPUT)/run.sh +	@cd $(OUTPUT); ./run.sh  endef  override define INSTALL_RULE @@ -33,7 +36,7 @@ override define EMIT_TESTS  endef  override define CLEAN -	for DIR in $(SUBDIRS); do		\ +	@for DIR in $(SUBDIRS); do		\  		BUILD_TARGET=$(OUTPUT)/$$DIR;	\  		mkdir $$BUILD_TARGET  -p;	\  		make OUTPUT=$$BUILD_TARGET -C $$DIR $@;\ diff --git a/tools/testing/selftests/intel_pstate/Makefile b/tools/testing/selftests/intel_pstate/Makefile index 849a90ffe8dd..a97e24edde39 100644 --- a/tools/testing/selftests/intel_pstate/Makefile +++ b/tools/testing/selftests/intel_pstate/Makefile @@ -1,7 +1,9 @@  CFLAGS := $(CFLAGS) -Wall -D_GNU_SOURCE  LDLIBS := $(LDLIBS) -lm +ifeq (,$(filter $(ARCH),x86))  TEST_GEN_FILES := msr aperf +endif  TEST_PROGS := run.sh diff --git a/tools/testing/selftests/intel_pstate/run.sh b/tools/testing/selftests/intel_pstate/run.sh index 7868c106b8b1..d3ab48f91cd6 100755 --- a/tools/testing/selftests/intel_pstate/run.sh +++ b/tools/testing/selftests/intel_pstate/run.sh @@ -29,13 +29,12 @@  EVALUATE_ONLY=0 -max_cpus=$(($(nproc)-1)) +if ! uname -m | sed -e s/i.86/x86/ -e s/x86_64/x86/ | grep -q x86; then +	echo "$0 # Skipped: Test can only run on x86 architectures." +	exit 0 +fi -# compile programs -gcc aperf.c -Wall -D_GNU_SOURCE -o aperf  -lm -[ $? -ne 0 ] && echo "Problem compiling aperf.c." && exit 1 -gcc -o msr msr.c -lm -[ $? -ne 0 ] && echo "Problem compiling msr.c." && exit 1 +max_cpus=$(($(nproc)-1))  function run_test () { diff --git a/tools/testing/selftests/lib.mk b/tools/testing/selftests/lib.mk index 693616651da5..f65886af7c0c 100644 --- a/tools/testing/selftests/lib.mk +++ b/tools/testing/selftests/lib.mk @@ -6,7 +6,14 @@ ifeq (0,$(MAKELEVEL))  OUTPUT := $(shell pwd)  endif +# The following are built by lib.mk common compile rules. +# TEST_CUSTOM_PROGS should be used by tests that require +# custom build rule and prevent common build rule use. +# TEST_PROGS are for test shell scripts. +# TEST_CUSTOM_PROGS and TEST_PROGS will be run by common run_tests +# and install targets. Common clean doesn't touch them.  TEST_GEN_PROGS := $(patsubst %,$(OUTPUT)/%,$(TEST_GEN_PROGS)) +TEST_GEN_PROGS_EXTENDED := $(patsubst %,$(OUTPUT)/%,$(TEST_GEN_PROGS_EXTENDED))  TEST_GEN_FILES := $(patsubst %,$(OUTPUT)/%,$(TEST_GEN_FILES))  all: $(TEST_GEN_PROGS) $(TEST_GEN_PROGS_EXTENDED) $(TEST_GEN_FILES) @@ -20,17 +27,28 @@ define RUN_TESTS  		test_num=`echo $$test_num+1 | bc`;	\  		echo "selftests: $$BASENAME_TEST";	\  		echo "========================================";	\ -		if [ ! -x $$BASENAME_TEST ]; then	\ +		if [ ! -x $$TEST ]; then	\  			echo "selftests: Warning: file $$BASENAME_TEST is not executable, correct this.";\  			echo "not ok 1..$$test_num selftests: $$BASENAME_TEST [FAIL]"; \  		else					\ -			cd `dirname $$TEST` > /dev/null; (./$$BASENAME_TEST && echo "ok 1..$$test_num selftests: $$BASENAME_TEST [PASS]") || echo "not ok 1..$$test_num selftests:  $$BASENAME_TEST [FAIL]"; cd - > /dev/null;\ +			cd `dirname $$TEST` > /dev/null; (./$$BASENAME_TEST > /tmp/$$BASENAME_TEST 2>&1 && echo "ok 1..$$test_num selftests: $$BASENAME_TEST [PASS]") || echo "not ok 1..$$test_num selftests:  $$BASENAME_TEST [FAIL]"; cd - > /dev/null;\  		fi;					\  	done;  endef  run_tests: all -	$(call RUN_TESTS, $(TEST_GEN_PROGS) $(TEST_PROGS)) +ifneq ($(KBUILD_SRC),) +	@if [ "X$(TEST_PROGS) $(TEST_PROGS_EXTENDED) $(TEST_FILES)" != "X" ]; then +		@rsync -aq $(TEST_PROGS) $(TEST_PROGS_EXTENDED) $(TEST_FILES) $(OUTPUT) +	fi +	@if [ "X$(TEST_PROGS)" != "X" ]; then +		$(call RUN_TESTS, $(TEST_GEN_PROGS) $(TEST_CUSTOM_PROGS) $(OUTPUT)/$(TEST_PROGS)) +	else +		$(call RUN_TESTS, $(TEST_GEN_PROGS) $(TEST_CUSTOM_PROGS)) +	fi +else +	$(call RUN_TESTS, $(TEST_GEN_PROGS) $(TEST_CUSTOM_PROGS) $(TEST_PROGS)) +endif  define INSTALL_RULE  	@if [ "X$(TEST_PROGS)$(TEST_PROGS_EXTENDED)$(TEST_FILES)" != "X" ]; then					\ @@ -38,10 +56,10 @@ define INSTALL_RULE  		echo "rsync -a $(TEST_PROGS) $(TEST_PROGS_EXTENDED) $(TEST_FILES) $(INSTALL_PATH)/";	\  		rsync -a $(TEST_PROGS) $(TEST_PROGS_EXTENDED) $(TEST_FILES) $(INSTALL_PATH)/;		\  	fi -	@if [ "X$(TEST_GEN_PROGS)$(TEST_GEN_PROGS_EXTENDED)$(TEST_GEN_FILES)" != "X" ]; then					\ +	@if [ "X$(TEST_GEN_PROGS)$(TEST_CUSTOM_PROGS)$(TEST_GEN_PROGS_EXTENDED)$(TEST_GEN_FILES)" != "X" ]; then					\  		mkdir -p ${INSTALL_PATH};										\ -		echo "rsync -a $(TEST_GEN_PROGS) $(TEST_GEN_PROGS_EXTENDED) $(TEST_GEN_FILES) $(INSTALL_PATH)/";	\ -		rsync -a $(TEST_GEN_PROGS) $(TEST_GEN_PROGS_EXTENDED) $(TEST_GEN_FILES) $(INSTALL_PATH)/;		\ +		echo "rsync -a $(TEST_GEN_PROGS) $(TEST_CUSTOM_PROGS) $(TEST_GEN_PROGS_EXTENDED) $(TEST_GEN_FILES) $(INSTALL_PATH)/";	\ +		rsync -a $(TEST_GEN_PROGS) $(TEST_CUSTOM_PROGS) $(TEST_GEN_PROGS_EXTENDED) $(TEST_GEN_FILES) $(INSTALL_PATH)/;		\  	fi  endef @@ -53,15 +71,20 @@ else  endif  define EMIT_TESTS -	@for TEST in $(TEST_GEN_PROGS) $(TEST_PROGS); do \ +	@for TEST in $(TEST_GEN_PROGS) $(TEST_CUSTOM_PROGS) $(TEST_PROGS); do \  		BASENAME_TEST=`basename $$TEST`;	\ -		echo "(./$$BASENAME_TEST && echo \"selftests: $$BASENAME_TEST [PASS]\") || echo \"selftests: $$BASENAME_TEST [FAIL]\""; \ +		echo "(./$$BASENAME_TEST > /tmp/$$BASENAME_TEST 2>&1 && echo \"selftests: $$BASENAME_TEST [PASS]\") || echo \"selftests: $$BASENAME_TEST [FAIL]\""; \  	done;  endef  emit_tests:  	$(EMIT_TESTS) +# define if isn't already. It is undefined in make O= case. +ifeq ($(RM),) +RM := rm -f +endif +  define CLEAN  	$(RM) -r $(TEST_GEN_PROGS) $(TEST_GEN_PROGS_EXTENDED) $(TEST_GEN_FILES) $(EXTRA_CLEAN)  endef @@ -69,6 +92,15 @@ endef  clean:  	$(CLEAN) +# When make O= with kselftest target from main level +# the following aren't defined. +# +ifneq ($(KBUILD_SRC),) +LINK.c = $(CC) $(CFLAGS) $(CPPFLAGS) $(LDFLAGS) $(TARGET_ARCH) +COMPILE.S = $(CC) $(ASFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c +LINK.S = $(CC) $(ASFLAGS) $(CPPFLAGS) $(LDFLAGS) $(TARGET_ARCH) +endif +  $(OUTPUT)/%:%.c  	$(LINK.c) $^ $(LDLIBS) -o $@ diff --git a/tools/testing/selftests/memfd/run_tests.sh b/tools/testing/selftests/memfd/run_tests.sh index daabb350697c..daabb350697c 100644..100755 --- a/tools/testing/selftests/memfd/run_tests.sh +++ b/tools/testing/selftests/memfd/run_tests.sh diff --git a/tools/testing/selftests/mqueue/Makefile b/tools/testing/selftests/mqueue/Makefile index 79a664aeb8d7..0f5e347b068d 100644 --- a/tools/testing/selftests/mqueue/Makefile +++ b/tools/testing/selftests/mqueue/Makefile @@ -5,8 +5,8 @@ TEST_GEN_PROGS := mq_open_tests mq_perf_tests  include ../lib.mk  override define RUN_TESTS -	@./mq_open_tests /test1 || echo "selftests: mq_open_tests [FAIL]" -	@./mq_perf_tests || echo "selftests: mq_perf_tests [FAIL]" +	$(OUTPUT)/mq_open_tests /test1 || echo "selftests: mq_open_tests [FAIL]" +	$(OUTPUT)//mq_perf_tests || echo "selftests: mq_perf_tests [FAIL]"  endef  override define EMIT_TESTS diff --git a/tools/testing/selftests/net/.gitignore b/tools/testing/selftests/net/.gitignore index 9801253e4802..c612d6e38c62 100644 --- a/tools/testing/selftests/net/.gitignore +++ b/tools/testing/selftests/net/.gitignore @@ -6,3 +6,4 @@ reuseport_bpf  reuseport_bpf_cpu  reuseport_bpf_numa  reuseport_dualstack +reuseaddr_conflict diff --git a/tools/testing/selftests/net/Makefile b/tools/testing/selftests/net/Makefile index de1f5772b878..d86bca991f45 100644 --- a/tools/testing/selftests/net/Makefile +++ b/tools/testing/selftests/net/Makefile @@ -5,9 +5,9 @@ CFLAGS += -I../../../../usr/include/  TEST_PROGS := run_netsocktests run_afpackettests test_bpf.sh netdevice.sh rtnetlink.sh  TEST_GEN_FILES =  socket -TEST_GEN_FILES += psock_fanout psock_tpacket -TEST_GEN_FILES += reuseport_bpf reuseport_bpf_cpu reuseport_bpf_numa -TEST_GEN_FILES += reuseport_dualstack msg_zerocopy +TEST_GEN_FILES += psock_fanout psock_tpacket msg_zerocopy +TEST_GEN_PROGS = reuseport_bpf reuseport_bpf_cpu reuseport_bpf_numa +TEST_GEN_PROGS += reuseport_dualstack reuseaddr_conflict  include ../lib.mk diff --git a/tools/testing/selftests/net/msg_zerocopy.c b/tools/testing/selftests/net/msg_zerocopy.c index 40232af5b023..3ab6ec403905 100644 --- a/tools/testing/selftests/net/msg_zerocopy.c +++ b/tools/testing/selftests/net/msg_zerocopy.c @@ -55,7 +55,7 @@  #include <unistd.h>  #ifndef SO_EE_ORIGIN_ZEROCOPY -#define SO_EE_ORIGIN_ZEROCOPY		SO_EE_ORIGIN_UPAGE +#define SO_EE_ORIGIN_ZEROCOPY		5  #endif  #ifndef SO_ZEROCOPY diff --git a/tools/testing/selftests/net/netdevice.sh b/tools/testing/selftests/net/netdevice.sh index 4e00568d70c2..90cb903c3381 100755 --- a/tools/testing/selftests/net/netdevice.sh +++ b/tools/testing/selftests/net/netdevice.sh @@ -178,7 +178,7 @@ if [ "$(id -u)" -ne 0 ];then  	exit 0  fi -ip -Version 2>/dev/null >/dev/null +ip link show 2>/dev/null >/dev/null  if [ $? -ne 0 ];then  	echo "SKIP: Could not run test without the ip tool"  	exit 0 diff --git a/tools/testing/selftests/net/reuseaddr_conflict.c b/tools/testing/selftests/net/reuseaddr_conflict.c new file mode 100644 index 000000000000..7c5b12664b03 --- /dev/null +++ b/tools/testing/selftests/net/reuseaddr_conflict.c @@ -0,0 +1,114 @@ +/* + * Test for the regression introduced by + * + * b9470c27607b ("inet: kill smallest_size and smallest_port") + * + * If we open an ipv4 socket on a port with reuseaddr we shouldn't reset the tb + * when we open the ipv6 conterpart, which is what was happening previously. + */ +#include <errno.h> +#include <error.h> +#include <arpa/inet.h> +#include <netinet/in.h> +#include <stdbool.h> +#include <stdio.h> +#include <sys/socket.h> +#include <sys/types.h> +#include <unistd.h> + +#define PORT 9999 + +int open_port(int ipv6, int any) +{ +	int fd = -1; +	int reuseaddr = 1; +	int v6only = 1; +	int addrlen; +	int ret = -1; +	struct sockaddr *addr; +	int family = ipv6 ? AF_INET6 : AF_INET; + +	struct sockaddr_in6 addr6 = { +		.sin6_family = AF_INET6, +		.sin6_port = htons(PORT), +		.sin6_addr = in6addr_any +	}; +	struct sockaddr_in addr4 = { +		.sin_family = AF_INET, +		.sin_port = htons(PORT), +		.sin_addr.s_addr = any ? htonl(INADDR_ANY) : inet_addr("127.0.0.1"), +	}; + + +	if (ipv6) { +		addr = (struct sockaddr*)&addr6; +		addrlen = sizeof(addr6); +	} else { +		addr = (struct sockaddr*)&addr4; +		addrlen = sizeof(addr4); +	} + +	if ((fd = socket(family, SOCK_STREAM, IPPROTO_TCP)) < 0) { +		perror("socket"); +		goto out; +	} + +	if (ipv6 && setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, (void*)&v6only, +			       sizeof(v6only)) < 0) { +		perror("setsockopt IPV6_V6ONLY"); +		goto out; +	} + +	if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &reuseaddr, +		       sizeof(reuseaddr)) < 0) { +		perror("setsockopt SO_REUSEADDR"); +		goto out; +	} + +	if (bind(fd, addr, addrlen) < 0) { +		perror("bind"); +		goto out; +	} + +	if (any) +		return fd; + +	if (listen(fd, 1) < 0) { +		perror("listen"); +		goto out; +	} +	return fd; +out: +	close(fd); +	return ret; +} + +int main(void) +{ +	int listenfd; +	int fd1, fd2; + +	fprintf(stderr, "Opening 127.0.0.1:%d\n", PORT); +	listenfd = open_port(0, 0); +	if (listenfd < 0) +		error(1, errno, "Couldn't open listen socket"); +	fprintf(stderr, "Opening INADDR_ANY:%d\n", PORT); +	fd1 = open_port(0, 1); +	if (fd1 >= 0) +		error(1, 0, "Was allowed to create an ipv4 reuseport on a already bound non-reuseport socket"); +	fprintf(stderr, "Opening in6addr_any:%d\n", PORT); +	fd1 = open_port(1, 1); +	if (fd1 < 0) +		error(1, errno, "Couldn't open ipv6 reuseport"); +	fprintf(stderr, "Opening INADDR_ANY:%d\n", PORT); +	fd2 = open_port(0, 1); +	if (fd2 >= 0) +		error(1, 0, "Was allowed to create an ipv4 reuseport on a already bound non-reuseport socket"); +	close(fd1); +	fprintf(stderr, "Opening INADDR_ANY:%d after closing ipv6 socket\n", PORT); +	fd1 = open_port(0, 1); +	if (fd1 >= 0) +		error(1, 0, "Was allowed to create an ipv4 reuseport on an already bound non-reuseport socket with no ipv6"); +	fprintf(stderr, "Success"); +	return 0; +} diff --git a/tools/testing/selftests/seccomp/Makefile b/tools/testing/selftests/seccomp/Makefile index aeb0c805f3ca..553d870b4ca9 100644 --- a/tools/testing/selftests/seccomp/Makefile +++ b/tools/testing/selftests/seccomp/Makefile @@ -1,8 +1,16 @@ -TEST_GEN_PROGS := seccomp_bpf -CFLAGS += -Wl,-no-as-needed -Wall -LDFLAGS += -lpthread +all:  include ../lib.mk -$(TEST_GEN_PROGS): seccomp_bpf.c ../kselftest_harness.h -	$(CC) $(CFLAGS) $(LDFLAGS) $< -o $@ +.PHONY: all clean + +BINARIES := seccomp_bpf seccomp_benchmark +CFLAGS += -Wl,-no-as-needed -Wall + +seccomp_bpf: seccomp_bpf.c ../kselftest_harness.h +	$(CC) $(CFLAGS) $(LDFLAGS) -lpthread $< -o $@ + +TEST_PROGS += $(BINARIES) +EXTRA_CLEAN := $(BINARIES) + +all: $(BINARIES) diff --git a/tools/testing/selftests/seccomp/seccomp_benchmark.c b/tools/testing/selftests/seccomp/seccomp_benchmark.c new file mode 100644 index 000000000000..5838c8697ec3 --- /dev/null +++ b/tools/testing/selftests/seccomp/seccomp_benchmark.c @@ -0,0 +1,99 @@ +/* + * Strictly speaking, this is not a test. But it can report during test + * runs so relative performace can be measured. + */ +#define _GNU_SOURCE +#include <assert.h> +#include <stdio.h> +#include <stdlib.h> +#include <time.h> +#include <unistd.h> +#include <linux/filter.h> +#include <linux/seccomp.h> +#include <sys/prctl.h> +#include <sys/syscall.h> +#include <sys/types.h> + +#define ARRAY_SIZE(a)    (sizeof(a) / sizeof(a[0])) + +unsigned long long timing(clockid_t clk_id, unsigned long long samples) +{ +	pid_t pid, ret; +	unsigned long long i; +	struct timespec start, finish; + +	pid = getpid(); +	assert(clock_gettime(clk_id, &start) == 0); +	for (i = 0; i < samples; i++) { +		ret = syscall(__NR_getpid); +		assert(pid == ret); +	} +	assert(clock_gettime(clk_id, &finish) == 0); + +	i = finish.tv_sec - start.tv_sec; +	i *= 1000000000; +	i += finish.tv_nsec - start.tv_nsec; + +	printf("%lu.%09lu - %lu.%09lu = %llu\n", +		finish.tv_sec, finish.tv_nsec, +		start.tv_sec, start.tv_nsec, +		i); + +	return i; +} + +unsigned long long calibrate(void) +{ +	unsigned long long i; + +	printf("Calibrating reasonable sample size...\n"); + +	for (i = 5; ; i++) { +		unsigned long long samples = 1 << i; + +		/* Find something that takes more than 5 seconds to run. */ +		if (timing(CLOCK_REALTIME, samples) / 1000000000ULL > 5) +			return samples; +	} +} + +int main(int argc, char *argv[]) +{ +	struct sock_filter filter[] = { +		BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_ALLOW), +	}; +	struct sock_fprog prog = { +		.len = (unsigned short)ARRAY_SIZE(filter), +		.filter = filter, +	}; +	long ret; +	unsigned long long samples; +	unsigned long long native, filtered; + +	if (argc > 1) +		samples = strtoull(argv[1], NULL, 0); +	else +		samples = calibrate(); + +	printf("Benchmarking %llu samples...\n", samples); + +	native = timing(CLOCK_PROCESS_CPUTIME_ID, samples) / samples; +	printf("getpid native: %llu ns\n", native); + +	ret = prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0); +	assert(ret == 0); + +	ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog); +	assert(ret == 0); + +	filtered = timing(CLOCK_PROCESS_CPUTIME_ID, samples) / samples; +	printf("getpid RET_ALLOW: %llu ns\n", filtered); + +	printf("Estimated seccomp overhead per syscall: %llu ns\n", +		filtered - native); + +	if (filtered == native) +		printf("Trying running again with more samples.\n"); + +	return 0; +} diff --git a/tools/testing/selftests/seccomp/seccomp_bpf.c b/tools/testing/selftests/seccomp/seccomp_bpf.c index 4d6f92a9df6b..24dbf634e2dd 100644 --- a/tools/testing/selftests/seccomp/seccomp_bpf.c +++ b/tools/testing/selftests/seccomp/seccomp_bpf.c @@ -6,10 +6,18 @@   */  #include <sys/types.h> -#include <asm/siginfo.h> -#define __have_siginfo_t 1 -#define __have_sigval_t 1 -#define __have_sigevent_t 1 + +/* + * glibc 2.26 and later have SIGSYS in siginfo_t. Before that, + * we need to use the kernel's siginfo.h file and trick glibc + * into accepting it. + */ +#if !__GLIBC_PREREQ(2, 26) +# include <asm/siginfo.h> +# define __have_siginfo_t 1 +# define __have_sigval_t 1 +# define __have_sigevent_t 1 +#endif  #include <errno.h>  #include <linux/filter.h> @@ -68,17 +76,7 @@  #define SECCOMP_MODE_FILTER 2  #endif -#ifndef SECCOMP_RET_KILL -#define SECCOMP_RET_KILL        0x00000000U /* kill the task immediately */ -#define SECCOMP_RET_TRAP        0x00030000U /* disallow and force a SIGSYS */ -#define SECCOMP_RET_ERRNO       0x00050000U /* returns an errno */ -#define SECCOMP_RET_TRACE       0x7ff00000U /* pass to a tracer or disallow */ -#define SECCOMP_RET_ALLOW       0x7fff0000U /* allow */ - -/* Masks for the return value sections. */ -#define SECCOMP_RET_ACTION      0x7fff0000U -#define SECCOMP_RET_DATA        0x0000ffffU - +#ifndef SECCOMP_RET_ALLOW  struct seccomp_data {  	int nr;  	__u32 arch; @@ -87,6 +85,70 @@ struct seccomp_data {  };  #endif +#ifndef SECCOMP_RET_KILL_PROCESS +#define SECCOMP_RET_KILL_PROCESS 0x80000000U /* kill the process */ +#define SECCOMP_RET_KILL_THREAD	 0x00000000U /* kill the thread */ +#endif +#ifndef SECCOMP_RET_KILL +#define SECCOMP_RET_KILL	 SECCOMP_RET_KILL_THREAD +#define SECCOMP_RET_TRAP	 0x00030000U /* disallow and force a SIGSYS */ +#define SECCOMP_RET_ERRNO	 0x00050000U /* returns an errno */ +#define SECCOMP_RET_TRACE	 0x7ff00000U /* pass to a tracer or disallow */ +#define SECCOMP_RET_ALLOW	 0x7fff0000U /* allow */ +#endif +#ifndef SECCOMP_RET_LOG +#define SECCOMP_RET_LOG		 0x7ffc0000U /* allow after logging */ +#endif + +#ifndef __NR_seccomp +# if defined(__i386__) +#  define __NR_seccomp 354 +# elif defined(__x86_64__) +#  define __NR_seccomp 317 +# elif defined(__arm__) +#  define __NR_seccomp 383 +# elif defined(__aarch64__) +#  define __NR_seccomp 277 +# elif defined(__hppa__) +#  define __NR_seccomp 338 +# elif defined(__powerpc__) +#  define __NR_seccomp 358 +# elif defined(__s390__) +#  define __NR_seccomp 348 +# else +#  warning "seccomp syscall number unknown for this architecture" +#  define __NR_seccomp 0xffff +# endif +#endif + +#ifndef SECCOMP_SET_MODE_STRICT +#define SECCOMP_SET_MODE_STRICT 0 +#endif + +#ifndef SECCOMP_SET_MODE_FILTER +#define SECCOMP_SET_MODE_FILTER 1 +#endif + +#ifndef SECCOMP_GET_ACTION_AVAIL +#define SECCOMP_GET_ACTION_AVAIL 2 +#endif + +#ifndef SECCOMP_FILTER_FLAG_TSYNC +#define SECCOMP_FILTER_FLAG_TSYNC 1 +#endif + +#ifndef SECCOMP_FILTER_FLAG_LOG +#define SECCOMP_FILTER_FLAG_LOG 2 +#endif + +#ifndef seccomp +int seccomp(unsigned int op, unsigned int flags, void *args) +{ +	errno = 0; +	return syscall(__NR_seccomp, op, flags, args); +} +#endif +  #if __BYTE_ORDER == __LITTLE_ENDIAN  #define syscall_arg(_n) (offsetof(struct seccomp_data, args[_n]))  #elif __BYTE_ORDER == __BIG_ENDIAN @@ -136,7 +198,7 @@ TEST(no_new_privs_support)  	}  } -/* Tests kernel support by checking for a copy_from_user() fault on * NULL. */ +/* Tests kernel support by checking for a copy_from_user() fault on NULL. */  TEST(mode_filter_support)  {  	long ret; @@ -342,6 +404,28 @@ TEST(empty_prog)  	EXPECT_EQ(EINVAL, errno);  } +TEST(log_all) +{ +	struct sock_filter filter[] = { +		BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_LOG), +	}; +	struct sock_fprog prog = { +		.len = (unsigned short)ARRAY_SIZE(filter), +		.filter = filter, +	}; +	long ret; +	pid_t parent = getppid(); + +	ret = prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0); +	ASSERT_EQ(0, ret); + +	ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog); +	ASSERT_EQ(0, ret); + +	/* getppid() should succeed and be logged (no check for logging) */ +	EXPECT_EQ(parent, syscall(__NR_getppid)); +} +  TEST_SIGNAL(unknown_ret_is_kill_inside, SIGSYS)  {  	struct sock_filter filter[] = { @@ -520,6 +604,117 @@ TEST_SIGNAL(KILL_one_arg_six, SIGSYS)  	close(fd);  } +/* This is a thread task to die via seccomp filter violation. */ +void *kill_thread(void *data) +{ +	bool die = (bool)data; + +	if (die) { +		prctl(PR_GET_SECCOMP, 0, 0, 0, 0); +		return (void *)SIBLING_EXIT_FAILURE; +	} + +	return (void *)SIBLING_EXIT_UNKILLED; +} + +/* Prepare a thread that will kill itself or both of us. */ +void kill_thread_or_group(struct __test_metadata *_metadata, bool kill_process) +{ +	pthread_t thread; +	void *status; +	/* Kill only when calling __NR_prctl. */ +	struct sock_filter filter_thread[] = { +		BPF_STMT(BPF_LD|BPF_W|BPF_ABS, +			offsetof(struct seccomp_data, nr)), +		BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, __NR_prctl, 0, 1), +		BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_KILL_THREAD), +		BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_ALLOW), +	}; +	struct sock_fprog prog_thread = { +		.len = (unsigned short)ARRAY_SIZE(filter_thread), +		.filter = filter_thread, +	}; +	struct sock_filter filter_process[] = { +		BPF_STMT(BPF_LD|BPF_W|BPF_ABS, +			offsetof(struct seccomp_data, nr)), +		BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, __NR_prctl, 0, 1), +		BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_KILL_PROCESS), +		BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_ALLOW), +	}; +	struct sock_fprog prog_process = { +		.len = (unsigned short)ARRAY_SIZE(filter_process), +		.filter = filter_process, +	}; + +	ASSERT_EQ(0, prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0)) { +		TH_LOG("Kernel does not support PR_SET_NO_NEW_PRIVS!"); +	} + +	ASSERT_EQ(0, seccomp(SECCOMP_SET_MODE_FILTER, 0, +			     kill_process ? &prog_process : &prog_thread)); + +	/* +	 * Add the KILL_THREAD rule again to make sure that the KILL_PROCESS +	 * flag cannot be downgraded by a new filter. +	 */ +	ASSERT_EQ(0, seccomp(SECCOMP_SET_MODE_FILTER, 0, &prog_thread)); + +	/* Start a thread that will exit immediately. */ +	ASSERT_EQ(0, pthread_create(&thread, NULL, kill_thread, (void *)false)); +	ASSERT_EQ(0, pthread_join(thread, &status)); +	ASSERT_EQ(SIBLING_EXIT_UNKILLED, (unsigned long)status); + +	/* Start a thread that will die immediately. */ +	ASSERT_EQ(0, pthread_create(&thread, NULL, kill_thread, (void *)true)); +	ASSERT_EQ(0, pthread_join(thread, &status)); +	ASSERT_NE(SIBLING_EXIT_FAILURE, (unsigned long)status); + +	/* +	 * If we get here, only the spawned thread died. Let the parent know +	 * the whole process didn't die (i.e. this thread, the spawner, +	 * stayed running). +	 */ +	exit(42); +} + +TEST(KILL_thread) +{ +	int status; +	pid_t child_pid; + +	child_pid = fork(); +	ASSERT_LE(0, child_pid); +	if (child_pid == 0) { +		kill_thread_or_group(_metadata, false); +		_exit(38); +	} + +	ASSERT_EQ(child_pid, waitpid(child_pid, &status, 0)); + +	/* If only the thread was killed, we'll see exit 42. */ +	ASSERT_TRUE(WIFEXITED(status)); +	ASSERT_EQ(42, WEXITSTATUS(status)); +} + +TEST(KILL_process) +{ +	int status; +	pid_t child_pid; + +	child_pid = fork(); +	ASSERT_LE(0, child_pid); +	if (child_pid == 0) { +		kill_thread_or_group(_metadata, true); +		_exit(38); +	} + +	ASSERT_EQ(child_pid, waitpid(child_pid, &status, 0)); + +	/* If the entire process was killed, we'll see SIGSYS. */ +	ASSERT_TRUE(WIFSIGNALED(status)); +	ASSERT_EQ(SIGSYS, WTERMSIG(status)); +} +  /* TODO(wad) add 64-bit versus 32-bit arg tests. */  TEST(arg_out_of_range)  { @@ -541,26 +736,30 @@ TEST(arg_out_of_range)  	EXPECT_EQ(EINVAL, errno);  } +#define ERRNO_FILTER(name, errno)					\ +	struct sock_filter _read_filter_##name[] = {			\ +		BPF_STMT(BPF_LD|BPF_W|BPF_ABS,				\ +			offsetof(struct seccomp_data, nr)),		\ +		BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, __NR_read, 0, 1),	\ +		BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_ERRNO | errno),	\ +		BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_ALLOW),		\ +	};								\ +	struct sock_fprog prog_##name = {				\ +		.len = (unsigned short)ARRAY_SIZE(_read_filter_##name),	\ +		.filter = _read_filter_##name,				\ +	} + +/* Make sure basic errno values are correctly passed through a filter. */  TEST(ERRNO_valid)  { -	struct sock_filter filter[] = { -		BPF_STMT(BPF_LD|BPF_W|BPF_ABS, -			offsetof(struct seccomp_data, nr)), -		BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, __NR_read, 0, 1), -		BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_ERRNO | E2BIG), -		BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_ALLOW), -	}; -	struct sock_fprog prog = { -		.len = (unsigned short)ARRAY_SIZE(filter), -		.filter = filter, -	}; +	ERRNO_FILTER(valid, E2BIG);  	long ret;  	pid_t parent = getppid();  	ret = prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0);  	ASSERT_EQ(0, ret); -	ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog); +	ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog_valid);  	ASSERT_EQ(0, ret);  	EXPECT_EQ(parent, syscall(__NR_getppid)); @@ -568,26 +767,17 @@ TEST(ERRNO_valid)  	EXPECT_EQ(E2BIG, errno);  } +/* Make sure an errno of zero is correctly handled by the arch code. */  TEST(ERRNO_zero)  { -	struct sock_filter filter[] = { -		BPF_STMT(BPF_LD|BPF_W|BPF_ABS, -			offsetof(struct seccomp_data, nr)), -		BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, __NR_read, 0, 1), -		BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_ERRNO | 0), -		BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_ALLOW), -	}; -	struct sock_fprog prog = { -		.len = (unsigned short)ARRAY_SIZE(filter), -		.filter = filter, -	}; +	ERRNO_FILTER(zero, 0);  	long ret;  	pid_t parent = getppid();  	ret = prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0);  	ASSERT_EQ(0, ret); -	ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog); +	ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog_zero);  	ASSERT_EQ(0, ret);  	EXPECT_EQ(parent, syscall(__NR_getppid)); @@ -595,26 +785,21 @@ TEST(ERRNO_zero)  	EXPECT_EQ(0, read(0, NULL, 0));  } +/* + * The SECCOMP_RET_DATA mask is 16 bits wide, but errno is smaller. + * This tests that the errno value gets capped correctly, fixed by + * 580c57f10768 ("seccomp: cap SECCOMP_RET_ERRNO data to MAX_ERRNO"). + */  TEST(ERRNO_capped)  { -	struct sock_filter filter[] = { -		BPF_STMT(BPF_LD|BPF_W|BPF_ABS, -			offsetof(struct seccomp_data, nr)), -		BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, __NR_read, 0, 1), -		BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_ERRNO | 4096), -		BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_ALLOW), -	}; -	struct sock_fprog prog = { -		.len = (unsigned short)ARRAY_SIZE(filter), -		.filter = filter, -	}; +	ERRNO_FILTER(capped, 4096);  	long ret;  	pid_t parent = getppid();  	ret = prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0);  	ASSERT_EQ(0, ret); -	ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog); +	ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog_capped);  	ASSERT_EQ(0, ret);  	EXPECT_EQ(parent, syscall(__NR_getppid)); @@ -622,6 +807,37 @@ TEST(ERRNO_capped)  	EXPECT_EQ(4095, errno);  } +/* + * Filters are processed in reverse order: last applied is executed first. + * Since only the SECCOMP_RET_ACTION mask is tested for return values, the + * SECCOMP_RET_DATA mask results will follow the most recently applied + * matching filter return (and not the lowest or highest value). + */ +TEST(ERRNO_order) +{ +	ERRNO_FILTER(first,  11); +	ERRNO_FILTER(second, 13); +	ERRNO_FILTER(third,  12); +	long ret; +	pid_t parent = getppid(); + +	ret = prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0); +	ASSERT_EQ(0, ret); + +	ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog_first); +	ASSERT_EQ(0, ret); + +	ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog_second); +	ASSERT_EQ(0, ret); + +	ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog_third); +	ASSERT_EQ(0, ret); + +	EXPECT_EQ(parent, syscall(__NR_getppid)); +	EXPECT_EQ(-1, read(0, NULL, 0)); +	EXPECT_EQ(12, errno); +} +  FIXTURE_DATA(TRAP) {  	struct sock_fprog prog;  }; @@ -676,7 +892,7 @@ TEST_F_SIGNAL(TRAP, ign, SIGSYS)  	syscall(__NR_getpid);  } -static struct siginfo TRAP_info; +static siginfo_t TRAP_info;  static volatile int TRAP_nr;  static void TRAP_action(int nr, siginfo_t *info, void *void_context)  { @@ -735,6 +951,7 @@ TEST_F(TRAP, handler)  FIXTURE_DATA(precedence) {  	struct sock_fprog allow; +	struct sock_fprog log;  	struct sock_fprog trace;  	struct sock_fprog error;  	struct sock_fprog trap; @@ -746,6 +963,13 @@ FIXTURE_SETUP(precedence)  	struct sock_filter allow_insns[] = {  		BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_ALLOW),  	}; +	struct sock_filter log_insns[] = { +		BPF_STMT(BPF_LD|BPF_W|BPF_ABS, +			offsetof(struct seccomp_data, nr)), +		BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, __NR_getpid, 1, 0), +		BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_ALLOW), +		BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_LOG), +	};  	struct sock_filter trace_insns[] = {  		BPF_STMT(BPF_LD|BPF_W|BPF_ABS,  			offsetof(struct seccomp_data, nr)), @@ -782,6 +1006,7 @@ FIXTURE_SETUP(precedence)  	memcpy(self->_x.filter, &_x##_insns, sizeof(_x##_insns)); \  	self->_x.len = (unsigned short)ARRAY_SIZE(_x##_insns)  	FILTER_ALLOC(allow); +	FILTER_ALLOC(log);  	FILTER_ALLOC(trace);  	FILTER_ALLOC(error);  	FILTER_ALLOC(trap); @@ -792,6 +1017,7 @@ FIXTURE_TEARDOWN(precedence)  {  #define FILTER_FREE(_x) if (self->_x.filter) free(self->_x.filter)  	FILTER_FREE(allow); +	FILTER_FREE(log);  	FILTER_FREE(trace);  	FILTER_FREE(error);  	FILTER_FREE(trap); @@ -809,6 +1035,8 @@ TEST_F(precedence, allow_ok)  	ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &self->allow);  	ASSERT_EQ(0, ret); +	ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &self->log); +	ASSERT_EQ(0, ret);  	ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &self->trace);  	ASSERT_EQ(0, ret);  	ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &self->error); @@ -833,6 +1061,8 @@ TEST_F_SIGNAL(precedence, kill_is_highest, SIGSYS)  	ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &self->allow);  	ASSERT_EQ(0, ret); +	ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &self->log); +	ASSERT_EQ(0, ret);  	ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &self->trace);  	ASSERT_EQ(0, ret);  	ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &self->error); @@ -864,6 +1094,8 @@ TEST_F_SIGNAL(precedence, kill_is_highest_in_any_order, SIGSYS)  	ASSERT_EQ(0, ret);  	ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &self->error);  	ASSERT_EQ(0, ret); +	ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &self->log); +	ASSERT_EQ(0, ret);  	ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &self->trace);  	ASSERT_EQ(0, ret);  	ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &self->trap); @@ -885,6 +1117,8 @@ TEST_F_SIGNAL(precedence, trap_is_second, SIGSYS)  	ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &self->allow);  	ASSERT_EQ(0, ret); +	ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &self->log); +	ASSERT_EQ(0, ret);  	ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &self->trace);  	ASSERT_EQ(0, ret);  	ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &self->error); @@ -910,6 +1144,8 @@ TEST_F_SIGNAL(precedence, trap_is_second_in_any_order, SIGSYS)  	ASSERT_EQ(0, ret);  	ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &self->trap);  	ASSERT_EQ(0, ret); +	ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &self->log); +	ASSERT_EQ(0, ret);  	ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &self->trace);  	ASSERT_EQ(0, ret);  	ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &self->error); @@ -931,6 +1167,8 @@ TEST_F(precedence, errno_is_third)  	ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &self->allow);  	ASSERT_EQ(0, ret); +	ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &self->log); +	ASSERT_EQ(0, ret);  	ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &self->trace);  	ASSERT_EQ(0, ret);  	ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &self->error); @@ -949,6 +1187,8 @@ TEST_F(precedence, errno_is_third_in_any_order)  	ret = prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0);  	ASSERT_EQ(0, ret); +	ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &self->log); +	ASSERT_EQ(0, ret);  	ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &self->error);  	ASSERT_EQ(0, ret);  	ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &self->trace); @@ -971,6 +1211,8 @@ TEST_F(precedence, trace_is_fourth)  	ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &self->allow);  	ASSERT_EQ(0, ret); +	ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &self->log); +	ASSERT_EQ(0, ret);  	ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &self->trace);  	ASSERT_EQ(0, ret);  	/* Should work just fine. */ @@ -992,12 +1234,54 @@ TEST_F(precedence, trace_is_fourth_in_any_order)  	ASSERT_EQ(0, ret);  	ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &self->allow);  	ASSERT_EQ(0, ret); +	ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &self->log); +	ASSERT_EQ(0, ret);  	/* Should work just fine. */  	EXPECT_EQ(parent, syscall(__NR_getppid));  	/* No ptracer */  	EXPECT_EQ(-1, syscall(__NR_getpid));  } +TEST_F(precedence, log_is_fifth) +{ +	pid_t mypid, parent; +	long ret; + +	mypid = getpid(); +	parent = getppid(); +	ret = prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0); +	ASSERT_EQ(0, ret); + +	ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &self->allow); +	ASSERT_EQ(0, ret); +	ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &self->log); +	ASSERT_EQ(0, ret); +	/* Should work just fine. */ +	EXPECT_EQ(parent, syscall(__NR_getppid)); +	/* Should also work just fine */ +	EXPECT_EQ(mypid, syscall(__NR_getpid)); +} + +TEST_F(precedence, log_is_fifth_in_any_order) +{ +	pid_t mypid, parent; +	long ret; + +	mypid = getpid(); +	parent = getppid(); +	ret = prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0); +	ASSERT_EQ(0, ret); + +	ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &self->log); +	ASSERT_EQ(0, ret); +	ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &self->allow); +	ASSERT_EQ(0, ret); +	/* Should work just fine. */ +	EXPECT_EQ(parent, syscall(__NR_getppid)); +	/* Should also work just fine */ +	EXPECT_EQ(mypid, syscall(__NR_getpid)); +} +  #ifndef PTRACE_O_TRACESECCOMP  #define PTRACE_O_TRACESECCOMP	0x00000080  #endif @@ -1262,6 +1546,13 @@ TEST_F(TRACE_poke, getpid_runs_normally)  # error "Do not know how to find your architecture's registers and syscalls"  #endif +/* When the syscall return can't be changed, stub out the tests for it. */ +#ifdef SYSCALL_NUM_RET_SHARE_REG +# define EXPECT_SYSCALL_RETURN(val, action)	EXPECT_EQ(-1, action) +#else +# define EXPECT_SYSCALL_RETURN(val, action)	EXPECT_EQ(val, action) +#endif +  /* Use PTRACE_GETREGS and PTRACE_SETREGS when available. This is useful for   * architectures without HAVE_ARCH_TRACEHOOK (e.g. User-mode Linux).   */ @@ -1357,7 +1648,7 @@ void change_syscall(struct __test_metadata *_metadata,  #ifdef SYSCALL_NUM_RET_SHARE_REG  		TH_LOG("Can't modify syscall return on this architecture");  #else -		regs.SYSCALL_RET = 1; +		regs.SYSCALL_RET = EPERM;  #endif  #ifdef HAVE_GETREGS @@ -1426,6 +1717,8 @@ void tracer_ptrace(struct __test_metadata *_metadata, pid_t tracee,  	if (nr == __NR_getpid)  		change_syscall(_metadata, tracee, __NR_getppid); +	if (nr == __NR_open) +		change_syscall(_metadata, tracee, -1);  }  FIXTURE_DATA(TRACE_syscall) { @@ -1480,6 +1773,28 @@ FIXTURE_TEARDOWN(TRACE_syscall)  		free(self->prog.filter);  } +TEST_F(TRACE_syscall, ptrace_syscall_redirected) +{ +	/* Swap SECCOMP_RET_TRACE tracer for PTRACE_SYSCALL tracer. */ +	teardown_trace_fixture(_metadata, self->tracer); +	self->tracer = setup_trace_fixture(_metadata, tracer_ptrace, NULL, +					   true); + +	/* Tracer will redirect getpid to getppid. */ +	EXPECT_NE(self->mypid, syscall(__NR_getpid)); +} + +TEST_F(TRACE_syscall, ptrace_syscall_dropped) +{ +	/* Swap SECCOMP_RET_TRACE tracer for PTRACE_SYSCALL tracer. */ +	teardown_trace_fixture(_metadata, self->tracer); +	self->tracer = setup_trace_fixture(_metadata, tracer_ptrace, NULL, +					   true); + +	/* Tracer should skip the open syscall, resulting in EPERM. */ +	EXPECT_SYSCALL_RETURN(EPERM, syscall(__NR_open)); +} +  TEST_F(TRACE_syscall, syscall_allowed)  {  	long ret; @@ -1520,13 +1835,8 @@ TEST_F(TRACE_syscall, syscall_dropped)  	ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &self->prog, 0, 0);  	ASSERT_EQ(0, ret); -#ifdef SYSCALL_NUM_RET_SHARE_REG -	/* gettid has been skipped */ -	EXPECT_EQ(-1, syscall(__NR_gettid)); -#else  	/* gettid has been skipped and an altered return value stored. */ -	EXPECT_EQ(1, syscall(__NR_gettid)); -#endif +	EXPECT_SYSCALL_RETURN(EPERM, syscall(__NR_gettid));  	EXPECT_NE(self->mytid, syscall(__NR_gettid));  } @@ -1557,6 +1867,7 @@ TEST_F(TRACE_syscall, skip_after_RET_TRACE)  	ASSERT_EQ(0, ret);  	/* Tracer will redirect getpid to getppid, and we should see EPERM. */ +	errno = 0;  	EXPECT_EQ(-1, syscall(__NR_getpid));  	EXPECT_EQ(EPERM, errno);  } @@ -1654,47 +1965,6 @@ TEST_F_SIGNAL(TRACE_syscall, kill_after_ptrace, SIGSYS)  	EXPECT_NE(self->mypid, syscall(__NR_getpid));  } -#ifndef __NR_seccomp -# if defined(__i386__) -#  define __NR_seccomp 354 -# elif defined(__x86_64__) -#  define __NR_seccomp 317 -# elif defined(__arm__) -#  define __NR_seccomp 383 -# elif defined(__aarch64__) -#  define __NR_seccomp 277 -# elif defined(__hppa__) -#  define __NR_seccomp 338 -# elif defined(__powerpc__) -#  define __NR_seccomp 358 -# elif defined(__s390__) -#  define __NR_seccomp 348 -# else -#  warning "seccomp syscall number unknown for this architecture" -#  define __NR_seccomp 0xffff -# endif -#endif - -#ifndef SECCOMP_SET_MODE_STRICT -#define SECCOMP_SET_MODE_STRICT 0 -#endif - -#ifndef SECCOMP_SET_MODE_FILTER -#define SECCOMP_SET_MODE_FILTER 1 -#endif - -#ifndef SECCOMP_FILTER_FLAG_TSYNC -#define SECCOMP_FILTER_FLAG_TSYNC 1 -#endif - -#ifndef seccomp -int seccomp(unsigned int op, unsigned int flags, void *args) -{ -	errno = 0; -	return syscall(__NR_seccomp, op, flags, args); -} -#endif -  TEST(seccomp_syscall)  {  	struct sock_filter filter[] = { @@ -1783,6 +2053,67 @@ TEST(seccomp_syscall_mode_lock)  	}  } +/* + * Test detection of known and unknown filter flags. Userspace needs to be able + * to check if a filter flag is supported by the current kernel and a good way + * of doing that is by attempting to enter filter mode, with the flag bit in + * question set, and a NULL pointer for the _args_ parameter. EFAULT indicates + * that the flag is valid and EINVAL indicates that the flag is invalid. + */ +TEST(detect_seccomp_filter_flags) +{ +	unsigned int flags[] = { SECCOMP_FILTER_FLAG_TSYNC, +				 SECCOMP_FILTER_FLAG_LOG }; +	unsigned int flag, all_flags; +	int i; +	long ret; + +	/* Test detection of known-good filter flags */ +	for (i = 0, all_flags = 0; i < ARRAY_SIZE(flags); i++) { +		flag = flags[i]; +		ret = seccomp(SECCOMP_SET_MODE_FILTER, flag, NULL); +		ASSERT_NE(ENOSYS, errno) { +			TH_LOG("Kernel does not support seccomp syscall!"); +		} +		EXPECT_EQ(-1, ret); +		EXPECT_EQ(EFAULT, errno) { +			TH_LOG("Failed to detect that a known-good filter flag (0x%X) is supported!", +			       flag); +		} + +		all_flags |= flag; +	} + +	/* Test detection of all known-good filter flags */ +	ret = seccomp(SECCOMP_SET_MODE_FILTER, all_flags, NULL); +	EXPECT_EQ(-1, ret); +	EXPECT_EQ(EFAULT, errno) { +		TH_LOG("Failed to detect that all known-good filter flags (0x%X) are supported!", +		       all_flags); +	} + +	/* Test detection of an unknown filter flag */ +	flag = -1; +	ret = seccomp(SECCOMP_SET_MODE_FILTER, flag, NULL); +	EXPECT_EQ(-1, ret); +	EXPECT_EQ(EINVAL, errno) { +		TH_LOG("Failed to detect that an unknown filter flag (0x%X) is unsupported!", +		       flag); +	} + +	/* +	 * Test detection of an unknown filter flag that may simply need to be +	 * added to this test +	 */ +	flag = flags[ARRAY_SIZE(flags) - 1] << 1; +	ret = seccomp(SECCOMP_SET_MODE_FILTER, flag, NULL); +	EXPECT_EQ(-1, ret); +	EXPECT_EQ(EINVAL, errno) { +		TH_LOG("Failed to detect that an unknown filter flag (0x%X) is unsupported! Does a new flag need to be added to this test?", +		       flag); +	} +} +  TEST(TSYNC_first)  {  	struct sock_filter filter[] = { @@ -2421,6 +2752,99 @@ TEST(syscall_restart)  		_metadata->passed = 0;  } +TEST_SIGNAL(filter_flag_log, SIGSYS) +{ +	struct sock_filter allow_filter[] = { +		BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_ALLOW), +	}; +	struct sock_filter kill_filter[] = { +		BPF_STMT(BPF_LD|BPF_W|BPF_ABS, +			offsetof(struct seccomp_data, nr)), +		BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, __NR_getpid, 0, 1), +		BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_KILL), +		BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_ALLOW), +	}; +	struct sock_fprog allow_prog = { +		.len = (unsigned short)ARRAY_SIZE(allow_filter), +		.filter = allow_filter, +	}; +	struct sock_fprog kill_prog = { +		.len = (unsigned short)ARRAY_SIZE(kill_filter), +		.filter = kill_filter, +	}; +	long ret; +	pid_t parent = getppid(); + +	ret = prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0); +	ASSERT_EQ(0, ret); + +	/* Verify that the FILTER_FLAG_LOG flag isn't accepted in strict mode */ +	ret = seccomp(SECCOMP_SET_MODE_STRICT, SECCOMP_FILTER_FLAG_LOG, +		      &allow_prog); +	ASSERT_NE(ENOSYS, errno) { +		TH_LOG("Kernel does not support seccomp syscall!"); +	} +	EXPECT_NE(0, ret) { +		TH_LOG("Kernel accepted FILTER_FLAG_LOG flag in strict mode!"); +	} +	EXPECT_EQ(EINVAL, errno) { +		TH_LOG("Kernel returned unexpected errno for FILTER_FLAG_LOG flag in strict mode!"); +	} + +	/* Verify that a simple, permissive filter can be added with no flags */ +	ret = seccomp(SECCOMP_SET_MODE_FILTER, 0, &allow_prog); +	EXPECT_EQ(0, ret); + +	/* See if the same filter can be added with the FILTER_FLAG_LOG flag */ +	ret = seccomp(SECCOMP_SET_MODE_FILTER, SECCOMP_FILTER_FLAG_LOG, +		      &allow_prog); +	ASSERT_NE(EINVAL, errno) { +		TH_LOG("Kernel does not support the FILTER_FLAG_LOG flag!"); +	} +	EXPECT_EQ(0, ret); + +	/* Ensure that the kill filter works with the FILTER_FLAG_LOG flag */ +	ret = seccomp(SECCOMP_SET_MODE_FILTER, SECCOMP_FILTER_FLAG_LOG, +		      &kill_prog); +	EXPECT_EQ(0, ret); + +	EXPECT_EQ(parent, syscall(__NR_getppid)); +	/* getpid() should never return. */ +	EXPECT_EQ(0, syscall(__NR_getpid)); +} + +TEST(get_action_avail) +{ +	__u32 actions[] = { SECCOMP_RET_KILL_THREAD, SECCOMP_RET_TRAP, +			    SECCOMP_RET_ERRNO, SECCOMP_RET_TRACE, +			    SECCOMP_RET_LOG,   SECCOMP_RET_ALLOW }; +	__u32 unknown_action = 0x10000000U; +	int i; +	long ret; + +	ret = seccomp(SECCOMP_GET_ACTION_AVAIL, 0, &actions[0]); +	ASSERT_NE(ENOSYS, errno) { +		TH_LOG("Kernel does not support seccomp syscall!"); +	} +	ASSERT_NE(EINVAL, errno) { +		TH_LOG("Kernel does not support SECCOMP_GET_ACTION_AVAIL operation!"); +	} +	EXPECT_EQ(ret, 0); + +	for (i = 0; i < ARRAY_SIZE(actions); i++) { +		ret = seccomp(SECCOMP_GET_ACTION_AVAIL, 0, &actions[i]); +		EXPECT_EQ(ret, 0) { +			TH_LOG("Expected action (0x%X) not available!", +			       actions[i]); +		} +	} + +	/* Check that an unknown action is handled properly (EOPNOTSUPP) */ +	ret = seccomp(SECCOMP_GET_ACTION_AVAIL, 0, &unknown_action); +	EXPECT_EQ(ret, -1); +	EXPECT_EQ(errno, EOPNOTSUPP); +} +  /*   * TODO:   * - add microbenchmarks @@ -2429,6 +2853,8 @@ TEST(syscall_restart)   * - endianness checking when appropriate   * - 64-bit arg prodding   * - arch value testing (x86 modes especially) + * - verify that FILTER_FLAG_LOG filters generate log messages + * - verify that RET_LOG generates log messages   * - ...   */ diff --git a/tools/testing/selftests/sigaltstack/sas.c b/tools/testing/selftests/sigaltstack/sas.c index 7d406c3973ba..97bb150837df 100644 --- a/tools/testing/selftests/sigaltstack/sas.c +++ b/tools/testing/selftests/sigaltstack/sas.c @@ -39,7 +39,11 @@ void my_usr1(int sig, siginfo_t *si, void *u)  	stack_t stk;  	struct stk_data *p; +#if __s390x__ +	register unsigned long sp asm("%15"); +#else  	register unsigned long sp asm("sp"); +#endif  	if (sp < (unsigned long)sstack ||  			sp >= (unsigned long)sstack + SIGSTKSZ) { diff --git a/tools/testing/selftests/sync/Makefile b/tools/testing/selftests/sync/Makefile index 4981c6b6d050..8e04d0afcbd7 100644 --- a/tools/testing/selftests/sync/Makefile +++ b/tools/testing/selftests/sync/Makefile @@ -2,12 +2,16 @@ CFLAGS += -O2 -g -std=gnu89 -pthread -Wall -Wextra  CFLAGS += -I../../../../usr/include/  LDFLAGS += -pthread -TEST_PROGS = sync_test - -all: $(TEST_PROGS) +.PHONY: all clean  include ../lib.mk +# lib.mk TEST_CUSTOM_PROGS var is for custom tests that need special +# build rules. lib.mk will run and install them. + +TEST_CUSTOM_PROGS := $(OUTPUT)/sync_test +all: $(TEST_CUSTOM_PROGS) +  OBJS = sync_test.o sync.o  TESTS += sync_alloc.o @@ -18,6 +22,16 @@ TESTS += sync_stress_parallelism.o  TESTS += sync_stress_consumer.o  TESTS += sync_stress_merge.o -sync_test: $(OBJS) $(TESTS) +OBJS := $(patsubst %,$(OUTPUT)/%,$(OBJS)) +TESTS := $(patsubst %,$(OUTPUT)/%,$(TESTS)) + +$(TEST_CUSTOM_PROGS): $(TESTS) $(OBJS) +	$(CC) -o $(TEST_CUSTOM_PROGS) $(OBJS) $(TESTS) $(CFLAGS) $(LDFLAGS) + +$(OBJS): $(OUTPUT)/%.o: %.c +	$(CC) -c $^ -o $@ + +$(TESTS): $(OUTPUT)/%.o: %.c +	$(CC) -c $^ -o $@ -EXTRA_CLEAN := sync_test $(OBJS) $(TESTS) +EXTRA_CLEAN := $(TEST_CUSTOM_PROGS) $(OBJS) $(TESTS) diff --git a/tools/testing/selftests/timers/set-timer-lat.c b/tools/testing/selftests/timers/set-timer-lat.c index 9c92b7bd5641..50da45437daa 100644 --- a/tools/testing/selftests/timers/set-timer-lat.c +++ b/tools/testing/selftests/timers/set-timer-lat.c @@ -143,7 +143,8 @@ int setup_timer(int clock_id, int flags, int interval, timer_t *tm1)  			printf("%-22s %s missing CAP_WAKE_ALARM?    : [UNSUPPORTED]\n",  					clockstring(clock_id),  					flags ? "ABSTIME":"RELTIME"); -			return 0; +			/* Indicate timer isn't set, so caller doesn't wait */ +			return 1;  		}  		printf("%s - timer_create() failed\n", clockstring(clock_id));  		return -1; @@ -213,8 +214,9 @@ int do_timer(int clock_id, int flags)  	int err;  	err = setup_timer(clock_id, flags, interval, &tm1); +	/* Unsupported case - return 0 to not fail the test */  	if (err) -		return err; +		return err == 1 ? 0 : err;  	while (alarmcount < 5)  		sleep(1); @@ -228,18 +230,17 @@ int do_timer_oneshot(int clock_id, int flags)  	timer_t tm1;  	const int interval = 0;  	struct timeval timeout; -	fd_set fds;  	int err;  	err = setup_timer(clock_id, flags, interval, &tm1); +	/* Unsupported case - return 0 to not fail the test */  	if (err) -		return err; +		return err == 1 ? 0 : err;  	memset(&timeout, 0, sizeof(timeout));  	timeout.tv_sec = 5; -	FD_ZERO(&fds);  	do { -		err = select(FD_SETSIZE, &fds, NULL, NULL, &timeout); +		err = select(0, NULL, NULL, NULL, &timeout);  	} while (err == -1 && errno == EINTR);  	timer_delete(tm1); diff --git a/tools/testing/selftests/watchdog/Makefile b/tools/testing/selftests/watchdog/Makefile index f863c664e3d1..ee068511fd0b 100644 --- a/tools/testing/selftests/watchdog/Makefile +++ b/tools/testing/selftests/watchdog/Makefile @@ -1,8 +1,3 @@ -TEST_PROGS := watchdog-test - -all: $(TEST_PROGS) +TEST_GEN_PROGS := watchdog-test  include ../lib.mk - -clean: -	rm -fr $(TEST_PROGS)  | 
