Commit 19b39c38 authored by Linus Torvalds's avatar Linus Torvalds
Browse files
Pull ptrace regset updates from Al Viro:
 "Internal regset API changes:

   - regularize copy_regset_{to,from}_user() callers

   - switch to saner calling conventions for ->get()

   - kill user_regset_copyout()

  The ->put() side of things will have to wait for the next cycle,
  unfortunately.

  The balance is about -1KLoC and replacements for ->get() instances are
  a lot saner"

* 'work.regset' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs: (41 commits)
  regset: kill user_regset_copyout{,_zero}()
  regset(): kill ->get_size()
  regset: kill ->get()
  csky: switch to ->regset_get()
  xtensa: switch to ->regset_get()
  parisc: switch to ->regset_get()
  nds32: switch to ->regset_get()
  nios2: switch to ->regset_get()
  hexagon: switch to ->regset_get()
  h8300: switch to ->regset_get()
  openrisc: switch to ->regset_get()
  riscv: switch to ->regset_get()
  c6x: switch to ->regset_get()
  ia64: switch to ->regset_get()
  arc: switch to ->regset_get()
  arm: switch to ->regset_get()
  sh: convert to ->regset_get()
  arm64: switch to ->regset_get()
  mips: switch to ->regset_get()
  sparc: switch to ->regset_get()
  ...
parents 995909a4 ce327e1c
Loading
Loading
Loading
Loading
+58 −90
Original line number Diff line number Diff line
@@ -18,76 +18,52 @@ static struct callee_regs *task_callee_regs(struct task_struct *tsk)

static int genregs_get(struct task_struct *target,
		       const struct user_regset *regset,
		       unsigned int pos, unsigned int count,
		       void *kbuf, void __user *ubuf)
		       struct membuf to)
{
	const struct pt_regs *ptregs = task_pt_regs(target);
	const struct callee_regs *cregs = task_callee_regs(target);
	int ret = 0;
	unsigned int stop_pc_val;

#define REG_O_CHUNK(START, END, PTR)	\
	if (!ret)	\
		ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, PTR, \
			offsetof(struct user_regs_struct, START), \
			offsetof(struct user_regs_struct, END));

#define REG_O_ONE(LOC, PTR)	\
	if (!ret)		\
		ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, PTR, \
			offsetof(struct user_regs_struct, LOC), \
			offsetof(struct user_regs_struct, LOC) + 4);

#define REG_O_ZERO(LOC)		\
	if (!ret)		\
		ret = user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf, \
			offsetof(struct user_regs_struct, LOC), \
			offsetof(struct user_regs_struct, LOC) + 4);
	membuf_zero(&to, 4);	// pad
	membuf_store(&to, ptregs->bta);
	membuf_store(&to, ptregs->lp_start);
	membuf_store(&to, ptregs->lp_end);
	membuf_store(&to, ptregs->lp_count);
	membuf_store(&to, ptregs->status32);
	membuf_store(&to, ptregs->ret);
	membuf_store(&to, ptregs->blink);
	membuf_store(&to, ptregs->fp);
	membuf_store(&to, ptregs->r26);	// gp
	membuf_store(&to, ptregs->r12);
	membuf_store(&to, ptregs->r11);
	membuf_store(&to, ptregs->r10);
	membuf_store(&to, ptregs->r9);
	membuf_store(&to, ptregs->r8);
	membuf_store(&to, ptregs->r7);
	membuf_store(&to, ptregs->r6);
	membuf_store(&to, ptregs->r5);
	membuf_store(&to, ptregs->r4);
	membuf_store(&to, ptregs->r3);
	membuf_store(&to, ptregs->r2);
	membuf_store(&to, ptregs->r1);
	membuf_store(&to, ptregs->r0);
	membuf_store(&to, ptregs->sp);
	membuf_zero(&to, 4);	// pad2
	membuf_store(&to, cregs->r25);
	membuf_store(&to, cregs->r24);
	membuf_store(&to, cregs->r23);
	membuf_store(&to, cregs->r22);
	membuf_store(&to, cregs->r21);
	membuf_store(&to, cregs->r20);
	membuf_store(&to, cregs->r19);
	membuf_store(&to, cregs->r18);
	membuf_store(&to, cregs->r17);
	membuf_store(&to, cregs->r16);
	membuf_store(&to, cregs->r15);
	membuf_store(&to, cregs->r14);
	membuf_store(&to, cregs->r13);
	membuf_store(&to, target->thread.fault_address); // efa

	REG_O_ZERO(pad);
	REG_O_ONE(scratch.bta, &ptregs->bta);
	REG_O_ONE(scratch.lp_start, &ptregs->lp_start);
	REG_O_ONE(scratch.lp_end, &ptregs->lp_end);
	REG_O_ONE(scratch.lp_count, &ptregs->lp_count);
	REG_O_ONE(scratch.status32, &ptregs->status32);
	REG_O_ONE(scratch.ret, &ptregs->ret);
	REG_O_ONE(scratch.blink, &ptregs->blink);
	REG_O_ONE(scratch.fp, &ptregs->fp);
	REG_O_ONE(scratch.gp, &ptregs->r26);
	REG_O_ONE(scratch.r12, &ptregs->r12);
	REG_O_ONE(scratch.r11, &ptregs->r11);
	REG_O_ONE(scratch.r10, &ptregs->r10);
	REG_O_ONE(scratch.r9, &ptregs->r9);
	REG_O_ONE(scratch.r8, &ptregs->r8);
	REG_O_ONE(scratch.r7, &ptregs->r7);
	REG_O_ONE(scratch.r6, &ptregs->r6);
	REG_O_ONE(scratch.r5, &ptregs->r5);
	REG_O_ONE(scratch.r4, &ptregs->r4);
	REG_O_ONE(scratch.r3, &ptregs->r3);
	REG_O_ONE(scratch.r2, &ptregs->r2);
	REG_O_ONE(scratch.r1, &ptregs->r1);
	REG_O_ONE(scratch.r0, &ptregs->r0);
	REG_O_ONE(scratch.sp, &ptregs->sp);

	REG_O_ZERO(pad2);

	REG_O_ONE(callee.r25, &cregs->r25);
	REG_O_ONE(callee.r24, &cregs->r24);
	REG_O_ONE(callee.r23, &cregs->r23);
	REG_O_ONE(callee.r22, &cregs->r22);
	REG_O_ONE(callee.r21, &cregs->r21);
	REG_O_ONE(callee.r20, &cregs->r20);
	REG_O_ONE(callee.r19, &cregs->r19);
	REG_O_ONE(callee.r18, &cregs->r18);
	REG_O_ONE(callee.r17, &cregs->r17);
	REG_O_ONE(callee.r16, &cregs->r16);
	REG_O_ONE(callee.r15, &cregs->r15);
	REG_O_ONE(callee.r14, &cregs->r14);
	REG_O_ONE(callee.r13, &cregs->r13);

	REG_O_ONE(efa, &target->thread.fault_address);

	if (!ret) {
	if (in_brkpt_trap(ptregs)) {
		stop_pc_val = target->thread.fault_address;
		pr_debug("\t\tstop_pc (brk-pt)\n");
@@ -96,10 +72,7 @@ static int genregs_get(struct task_struct *target,
		pr_debug("\t\tstop_pc (others)\n");
	}

		REG_O_ONE(stop_pc, &stop_pc_val);
	}

	return ret;
	return membuf_store(&to, stop_pc_val); // stop_pc
}

static int genregs_set(struct task_struct *target,
@@ -184,25 +157,20 @@ static int genregs_set(struct task_struct *target,
#ifdef CONFIG_ISA_ARCV2
static int arcv2regs_get(struct task_struct *target,
		       const struct user_regset *regset,
		       unsigned int pos, unsigned int count,
		       void *kbuf, void __user *ubuf)
		       struct membuf to)
{
	const struct pt_regs *regs = task_pt_regs(target);
	int ret, copy_sz;

	if (IS_ENABLED(CONFIG_ARC_HAS_ACCL_REGS))
		copy_sz = sizeof(struct user_regs_arcv2);
	else
		copy_sz = 4;	/* r30 only */

		/*
		 * itemized copy not needed like above as layout of regs (r30,r58,r59)
		 * is exactly same in kernel (pt_regs) and userspace (user_regs_arcv2)
		 */
	ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, &regs->r30,
				  0, copy_sz);
		return membuf_write(&to, &regs->r30, sizeof(struct user_regs_arcv2));

	return ret;

	membuf_write(&to, &regs->r30, 4); /* r30 only */
	return membuf_zero(&to, sizeof(struct user_regs_arcv2) - 4);
}

static int arcv2regs_set(struct task_struct *target,
@@ -237,7 +205,7 @@ static const struct user_regset arc_regsets[] = {
	       .n = ELF_NGREG,
	       .size = sizeof(unsigned long),
	       .align = sizeof(unsigned long),
	       .get = genregs_get,
	       .regset_get = genregs_get,
	       .set = genregs_set,
	},
#ifdef CONFIG_ISA_ARCV2
@@ -246,7 +214,7 @@ static const struct user_regset arc_regsets[] = {
	       .n = ELF_ARCV2REG,
	       .size = sizeof(unsigned long),
	       .align = sizeof(unsigned long),
	       .get = arcv2regs_get,
	       .regset_get = arcv2regs_get,
	       .set = arcv2regs_set,
	},
#endif
+12 −40
Original line number Diff line number Diff line
@@ -569,14 +569,9 @@ out:

static int gpr_get(struct task_struct *target,
		   const struct user_regset *regset,
		   unsigned int pos, unsigned int count,
		   void *kbuf, void __user *ubuf)
		   struct membuf to)
{
	struct pt_regs *regs = task_pt_regs(target);

	return user_regset_copyout(&pos, &count, &kbuf, &ubuf,
				   regs,
				   0, sizeof(*regs));
	return membuf_write(&to, task_pt_regs(target), sizeof(struct pt_regs));
}

static int gpr_set(struct task_struct *target,
@@ -602,12 +597,10 @@ static int gpr_set(struct task_struct *target,

static int fpa_get(struct task_struct *target,
		   const struct user_regset *regset,
		   unsigned int pos, unsigned int count,
		   void *kbuf, void __user *ubuf)
		   struct membuf to)
{
	return user_regset_copyout(&pos, &count, &kbuf, &ubuf,
				   &task_thread_info(target)->fpstate,
				   0, sizeof(struct user_fp));
	return membuf_write(&to, &task_thread_info(target)->fpstate,
				 sizeof(struct user_fp));
}

static int fpa_set(struct task_struct *target,
@@ -642,41 +635,20 @@ static int fpa_set(struct task_struct *target,
 *	vfp_set() ignores this chunk
 *
 * 1 word for the FPSCR
 *
 * The bounds-checking logic built into user_regset_copyout and friends
 * means that we can make a simple sequence of calls to map the relevant data
 * to/from the specified slice of the user regset structure.
 */
static int vfp_get(struct task_struct *target,
		   const struct user_regset *regset,
		   unsigned int pos, unsigned int count,
		   void *kbuf, void __user *ubuf)
		   struct membuf to)
{
	int ret;
	struct thread_info *thread = task_thread_info(target);
	struct vfp_hard_struct const *vfp = &thread->vfpstate.hard;
	const size_t user_fpregs_offset = offsetof(struct user_vfp, fpregs);
	const size_t user_fpscr_offset = offsetof(struct user_vfp, fpscr);

	vfp_sync_hwstate(thread);

	ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
				  &vfp->fpregs,
				  user_fpregs_offset,
				  user_fpregs_offset + sizeof(vfp->fpregs));
	if (ret)
		return ret;

	ret = user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf,
				       user_fpregs_offset + sizeof(vfp->fpregs),
				       user_fpscr_offset);
	if (ret)
		return ret;

	return user_regset_copyout(&pos, &count, &kbuf, &ubuf,
				   &vfp->fpscr,
				   user_fpscr_offset,
				   user_fpscr_offset + sizeof(vfp->fpscr));
	membuf_write(&to, vfp->fpregs, sizeof(vfp->fpregs));
	membuf_zero(&to, user_fpscr_offset - sizeof(vfp->fpregs));
	return membuf_store(&to, vfp->fpscr);
}

/*
@@ -739,7 +711,7 @@ static const struct user_regset arm_regsets[] = {
		.n = ELF_NGREG,
		.size = sizeof(u32),
		.align = sizeof(u32),
		.get = gpr_get,
		.regset_get = gpr_get,
		.set = gpr_set
	},
	[REGSET_FPR] = {
@@ -751,7 +723,7 @@ static const struct user_regset arm_regsets[] = {
		.n = sizeof(struct user_fp) / sizeof(u32),
		.size = sizeof(u32),
		.align = sizeof(u32),
		.get = fpa_get,
		.regset_get = fpa_get,
		.set = fpa_set
	},
#ifdef CONFIG_VFP
@@ -764,7 +736,7 @@ static const struct user_regset arm_regsets[] = {
		.n = ARM_VFPREGS_SIZE / sizeof(u32),
		.size = sizeof(u32),
		.align = sizeof(u32),
		.get = vfp_get,
		.regset_get = vfp_get,
		.set = vfp_set
	},
#endif /* CONFIG_VFP */
+99 −204
Original line number Diff line number Diff line
@@ -474,11 +474,10 @@ static int ptrace_hbp_set_addr(unsigned int note_type,

static int hw_break_get(struct task_struct *target,
			const struct user_regset *regset,
			unsigned int pos, unsigned int count,
			void *kbuf, void __user *ubuf)
			struct membuf to)
{
	unsigned int note_type = regset->core_note_type;
	int ret, idx = 0, offset, limit;
	int ret, idx = 0;
	u32 info, ctrl;
	u64 addr;

@@ -487,49 +486,21 @@ static int hw_break_get(struct task_struct *target,
	if (ret)
		return ret;

	ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, &info, 0,
				  sizeof(info));
	if (ret)
		return ret;

	/* Pad */
	offset = offsetof(struct user_hwdebug_state, pad);
	ret = user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf, offset,
				       offset + PTRACE_HBP_PAD_SZ);
	if (ret)
		return ret;

	membuf_write(&to, &info, sizeof(info));
	membuf_zero(&to, sizeof(u32));
	/* (address, ctrl) registers */
	offset = offsetof(struct user_hwdebug_state, dbg_regs);
	limit = regset->n * regset->size;
	while (count && offset < limit) {
	while (to.left) {
		ret = ptrace_hbp_get_addr(note_type, target, idx, &addr);
		if (ret)
			return ret;
		ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, &addr,
					  offset, offset + PTRACE_HBP_ADDR_SZ);
		if (ret)
			return ret;
		offset += PTRACE_HBP_ADDR_SZ;

		ret = ptrace_hbp_get_ctrl(note_type, target, idx, &ctrl);
		if (ret)
			return ret;
		ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, &ctrl,
					  offset, offset + PTRACE_HBP_CTRL_SZ);
		if (ret)
			return ret;
		offset += PTRACE_HBP_CTRL_SZ;

		ret = user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf,
					       offset,
					       offset + PTRACE_HBP_PAD_SZ);
		if (ret)
			return ret;
		offset += PTRACE_HBP_PAD_SZ;
		membuf_store(&to, addr);
		membuf_store(&to, ctrl);
		membuf_zero(&to, sizeof(u32));
		idx++;
	}

	return 0;
}

@@ -589,11 +560,10 @@ static int hw_break_set(struct task_struct *target,

static int gpr_get(struct task_struct *target,
		   const struct user_regset *regset,
		   unsigned int pos, unsigned int count,
		   void *kbuf, void __user *ubuf)
		   struct membuf to)
{
	struct user_pt_regs *uregs = &task_pt_regs(target)->user_regs;
	return user_regset_copyout(&pos, &count, &kbuf, &ubuf, uregs, 0, -1);
	return membuf_write(&to, uregs, sizeof(*uregs));
}

static int gpr_set(struct task_struct *target, const struct user_regset *regset,
@@ -626,8 +596,7 @@ static int fpr_active(struct task_struct *target, const struct user_regset *regs
 */
static int __fpr_get(struct task_struct *target,
		     const struct user_regset *regset,
		     unsigned int pos, unsigned int count,
		     void *kbuf, void __user *ubuf, unsigned int start_pos)
		     struct membuf to)
{
	struct user_fpsimd_state *uregs;

@@ -635,13 +604,11 @@ static int __fpr_get(struct task_struct *target,

	uregs = &target->thread.uw.fpsimd_state;

	return user_regset_copyout(&pos, &count, &kbuf, &ubuf, uregs,
				   start_pos, start_pos + sizeof(*uregs));
	return membuf_write(&to, uregs, sizeof(*uregs));
}

static int fpr_get(struct task_struct *target, const struct user_regset *regset,
		   unsigned int pos, unsigned int count,
		   void *kbuf, void __user *ubuf)
		   struct membuf to)
{
	if (!system_supports_fpsimd())
		return -EINVAL;
@@ -649,7 +616,7 @@ static int fpr_get(struct task_struct *target, const struct user_regset *regset,
	if (target == current)
		fpsimd_preserve_current_state();

	return __fpr_get(target, regset, pos, count, kbuf, ubuf, 0);
	return __fpr_get(target, regset, to);
}

static int __fpr_set(struct task_struct *target,
@@ -699,15 +666,12 @@ static int fpr_set(struct task_struct *target, const struct user_regset *regset,
}

static int tls_get(struct task_struct *target, const struct user_regset *regset,
		   unsigned int pos, unsigned int count,
		   void *kbuf, void __user *ubuf)
		   struct membuf to)
{
	unsigned long *tls = &target->thread.uw.tp_value;

	if (target == current)
		tls_preserve_current_state();

	return user_regset_copyout(&pos, &count, &kbuf, &ubuf, tls, 0, -1);
	return membuf_store(&to, target->thread.uw.tp_value);
}

static int tls_set(struct task_struct *target, const struct user_regset *regset,
@@ -727,13 +691,9 @@ static int tls_set(struct task_struct *target, const struct user_regset *regset,

static int system_call_get(struct task_struct *target,
			   const struct user_regset *regset,
			   unsigned int pos, unsigned int count,
			   void *kbuf, void __user *ubuf)
			   struct membuf to)
{
	int syscallno = task_pt_regs(target)->syscallno;

	return user_regset_copyout(&pos, &count, &kbuf, &ubuf,
				   &syscallno, 0, -1);
	return membuf_store(&to, task_pt_regs(target)->syscallno);
}

static int system_call_set(struct task_struct *target,
@@ -780,24 +740,10 @@ static unsigned int sve_size_from_header(struct user_sve_header const *header)
	return ALIGN(header->size, SVE_VQ_BYTES);
}

static unsigned int sve_get_size(struct task_struct *target,
				 const struct user_regset *regset)
{
	struct user_sve_header header;

	if (!system_supports_sve())
		return 0;

	sve_init_header_from_task(&header, target);
	return sve_size_from_header(&header);
}

static int sve_get(struct task_struct *target,
		   const struct user_regset *regset,
		   unsigned int pos, unsigned int count,
		   void *kbuf, void __user *ubuf)
		   struct membuf to)
{
	int ret;
	struct user_sve_header header;
	unsigned int vq;
	unsigned long start, end;
@@ -809,10 +755,7 @@ static int sve_get(struct task_struct *target,
	sve_init_header_from_task(&header, target);
	vq = sve_vq_from_vl(header.vl);

	ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, &header,
				  0, sizeof(header));
	if (ret)
		return ret;
	membuf_write(&to, &header, sizeof(header));

	if (target == current)
		fpsimd_preserve_current_state();
@@ -821,26 +764,18 @@ static int sve_get(struct task_struct *target,

	BUILD_BUG_ON(SVE_PT_FPSIMD_OFFSET != sizeof(header));
	if ((header.flags & SVE_PT_REGS_MASK) == SVE_PT_REGS_FPSIMD)
		return __fpr_get(target, regset, pos, count, kbuf, ubuf,
				 SVE_PT_FPSIMD_OFFSET);
		return __fpr_get(target, regset, to);

	/* Otherwise: full SVE case */

	BUILD_BUG_ON(SVE_PT_SVE_OFFSET != sizeof(header));
	start = SVE_PT_SVE_OFFSET;
	end = SVE_PT_SVE_FFR_OFFSET(vq) + SVE_PT_SVE_FFR_SIZE(vq);
	ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
				  target->thread.sve_state,
				  start, end);
	if (ret)
		return ret;
	membuf_write(&to, target->thread.sve_state, end - start);

	start = end;
	end = SVE_PT_SVE_FPSR_OFFSET(vq);
	ret = user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf,
				       start, end);
	if (ret)
		return ret;
	membuf_zero(&to, end - start);

	/*
	 * Copy fpsr, and fpcr which must follow contiguously in
@@ -848,16 +783,11 @@ static int sve_get(struct task_struct *target,
	 */
	start = end;
	end = SVE_PT_SVE_FPCR_OFFSET(vq) + SVE_PT_SVE_FPCR_SIZE;
	ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
				  &target->thread.uw.fpsimd_state.fpsr,
				  start, end);
	if (ret)
		return ret;
	membuf_write(&to, &target->thread.uw.fpsimd_state.fpsr, end - start);

	start = end;
	end = sve_size_from_header(&header);
	return user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf,
					start, end);
	return membuf_zero(&to, end - start);
}

static int sve_set(struct task_struct *target,
@@ -961,8 +891,7 @@ out:
#ifdef CONFIG_ARM64_PTR_AUTH
static int pac_mask_get(struct task_struct *target,
			const struct user_regset *regset,
			unsigned int pos, unsigned int count,
			void *kbuf, void __user *ubuf)
			struct membuf to)
{
	/*
	 * The PAC bits can differ across data and instruction pointers
@@ -978,7 +907,7 @@ static int pac_mask_get(struct task_struct *target,
	if (!system_supports_address_auth())
		return -EINVAL;

	return user_regset_copyout(&pos, &count, &kbuf, &ubuf, &uregs, 0, -1);
	return membuf_write(&to, &uregs, sizeof(uregs));
}

#ifdef CONFIG_CHECKPOINT_RESTORE
@@ -1017,8 +946,7 @@ static void pac_address_keys_from_user(struct ptrauth_keys_user *keys,

static int pac_address_keys_get(struct task_struct *target,
				const struct user_regset *regset,
				unsigned int pos, unsigned int count,
				void *kbuf, void __user *ubuf)
				struct membuf to)
{
	struct ptrauth_keys_user *keys = &target->thread.keys_user;
	struct user_pac_address_keys user_keys;
@@ -1028,8 +956,7 @@ static int pac_address_keys_get(struct task_struct *target,

	pac_address_keys_to_user(&user_keys, keys);

	return user_regset_copyout(&pos, &count, &kbuf, &ubuf,
				   &user_keys, 0, -1);
	return membuf_write(&to, &user_keys, sizeof(user_keys));
}

static int pac_address_keys_set(struct task_struct *target,
@@ -1068,8 +995,7 @@ static void pac_generic_keys_from_user(struct ptrauth_keys_user *keys,

static int pac_generic_keys_get(struct task_struct *target,
				const struct user_regset *regset,
				unsigned int pos, unsigned int count,
				void *kbuf, void __user *ubuf)
				struct membuf to)
{
	struct ptrauth_keys_user *keys = &target->thread.keys_user;
	struct user_pac_generic_keys user_keys;
@@ -1079,8 +1005,7 @@ static int pac_generic_keys_get(struct task_struct *target,

	pac_generic_keys_to_user(&user_keys, keys);

	return user_regset_copyout(&pos, &count, &kbuf, &ubuf,
				   &user_keys, 0, -1);
	return membuf_write(&to, &user_keys, sizeof(user_keys));
}

static int pac_generic_keys_set(struct task_struct *target,
@@ -1134,7 +1059,7 @@ static const struct user_regset aarch64_regsets[] = {
		.n = sizeof(struct user_pt_regs) / sizeof(u64),
		.size = sizeof(u64),
		.align = sizeof(u64),
		.get = gpr_get,
		.regset_get = gpr_get,
		.set = gpr_set
	},
	[REGSET_FPR] = {
@@ -1147,7 +1072,7 @@ static const struct user_regset aarch64_regsets[] = {
		.size = sizeof(u32),
		.align = sizeof(u32),
		.active = fpr_active,
		.get = fpr_get,
		.regset_get = fpr_get,
		.set = fpr_set
	},
	[REGSET_TLS] = {
@@ -1155,7 +1080,7 @@ static const struct user_regset aarch64_regsets[] = {
		.n = 1,
		.size = sizeof(void *),
		.align = sizeof(void *),
		.get = tls_get,
		.regset_get = tls_get,
		.set = tls_set,
	},
#ifdef CONFIG_HAVE_HW_BREAKPOINT
@@ -1164,7 +1089,7 @@ static const struct user_regset aarch64_regsets[] = {
		.n = sizeof(struct user_hwdebug_state) / sizeof(u32),
		.size = sizeof(u32),
		.align = sizeof(u32),
		.get = hw_break_get,
		.regset_get = hw_break_get,
		.set = hw_break_set,
	},
	[REGSET_HW_WATCH] = {
@@ -1172,7 +1097,7 @@ static const struct user_regset aarch64_regsets[] = {
		.n = sizeof(struct user_hwdebug_state) / sizeof(u32),
		.size = sizeof(u32),
		.align = sizeof(u32),
		.get = hw_break_get,
		.regset_get = hw_break_get,
		.set = hw_break_set,
	},
#endif
@@ -1181,7 +1106,7 @@ static const struct user_regset aarch64_regsets[] = {
		.n = 1,
		.size = sizeof(int),
		.align = sizeof(int),
		.get = system_call_get,
		.regset_get = system_call_get,
		.set = system_call_set,
	},
#ifdef CONFIG_ARM64_SVE
@@ -1191,9 +1116,8 @@ static const struct user_regset aarch64_regsets[] = {
				  SVE_VQ_BYTES),
		.size = SVE_VQ_BYTES,
		.align = SVE_VQ_BYTES,
		.get = sve_get,
		.regset_get = sve_get,
		.set = sve_set,
		.get_size = sve_get_size,
	},
#endif
#ifdef CONFIG_ARM64_PTR_AUTH
@@ -1202,7 +1126,7 @@ static const struct user_regset aarch64_regsets[] = {
		.n = sizeof(struct user_pac_mask) / sizeof(u64),
		.size = sizeof(u64),
		.align = sizeof(u64),
		.get = pac_mask_get,
		.regset_get = pac_mask_get,
		/* this cannot be set dynamically */
	},
#ifdef CONFIG_CHECKPOINT_RESTORE
@@ -1211,7 +1135,7 @@ static const struct user_regset aarch64_regsets[] = {
		.n = sizeof(struct user_pac_address_keys) / sizeof(__uint128_t),
		.size = sizeof(__uint128_t),
		.align = sizeof(__uint128_t),
		.get = pac_address_keys_get,
		.regset_get = pac_address_keys_get,
		.set = pac_address_keys_set,
	},
	[REGSET_PACG_KEYS] = {
@@ -1219,7 +1143,7 @@ static const struct user_regset aarch64_regsets[] = {
		.n = sizeof(struct user_pac_generic_keys) / sizeof(__uint128_t),
		.size = sizeof(__uint128_t),
		.align = sizeof(__uint128_t),
		.get = pac_generic_keys_get,
		.regset_get = pac_generic_keys_get,
		.set = pac_generic_keys_set,
	},
#endif
@@ -1237,57 +1161,31 @@ enum compat_regset {
	REGSET_COMPAT_VFP,
};

static int compat_gpr_get(struct task_struct *target,
			  const struct user_regset *regset,
			  unsigned int pos, unsigned int count,
			  void *kbuf, void __user *ubuf)
static inline compat_ulong_t compat_get_user_reg(struct task_struct *task, int idx)
{
	int ret = 0;
	unsigned int i, start, num_regs;

	/* Calculate the number of AArch32 registers contained in count */
	num_regs = count / regset->size;

	/* Convert pos into an register number */
	start = pos / regset->size;

	if (start + num_regs > regset->n)
		return -EIO;

	for (i = 0; i < num_regs; ++i) {
		unsigned int idx = start + i;
		compat_ulong_t reg;
	struct pt_regs *regs = task_pt_regs(task);

	switch (idx) {
	case 15:
			reg = task_pt_regs(target)->pc;
			break;
		return regs->pc;
	case 16:
			reg = task_pt_regs(target)->pstate;
			reg = pstate_to_compat_psr(reg);
			break;
		return pstate_to_compat_psr(regs->pstate);
	case 17:
			reg = task_pt_regs(target)->orig_x0;
			break;
		return regs->orig_x0;
	default:
			reg = task_pt_regs(target)->regs[idx];
		return regs->regs[idx];
	}

		if (kbuf) {
			memcpy(kbuf, &reg, sizeof(reg));
			kbuf += sizeof(reg);
		} else {
			ret = copy_to_user(ubuf, &reg, sizeof(reg));
			if (ret) {
				ret = -EFAULT;
				break;
}

			ubuf += sizeof(reg);
		}
	}
static int compat_gpr_get(struct task_struct *target,
			  const struct user_regset *regset,
			  struct membuf to)
{
	int i = 0;

	return ret;
	while (to.left)
		membuf_store(&to, compat_get_user_reg(target, i++));
	return 0;
}

static int compat_gpr_set(struct task_struct *target,
@@ -1354,12 +1252,10 @@ static int compat_gpr_set(struct task_struct *target,

static int compat_vfp_get(struct task_struct *target,
			  const struct user_regset *regset,
			  unsigned int pos, unsigned int count,
			  void *kbuf, void __user *ubuf)
			  struct membuf to)
{
	struct user_fpsimd_state *uregs;
	compat_ulong_t fpscr;
	int ret, vregs_end_pos;

	if (!system_supports_fpsimd())
		return -EINVAL;
@@ -1373,19 +1269,10 @@ static int compat_vfp_get(struct task_struct *target,
	 * The VFP registers are packed into the fpsimd_state, so they all sit
	 * nicely together for us. We just need to create the fpscr separately.
	 */
	vregs_end_pos = VFP_STATE_SIZE - sizeof(compat_ulong_t);
	ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, uregs,
				  0, vregs_end_pos);

	if (count && !ret) {
	membuf_write(&to, uregs, VFP_STATE_SIZE - sizeof(compat_ulong_t));
	fpscr = (uregs->fpsr & VFP_FPSCR_STAT_MASK) |
		(uregs->fpcr & VFP_FPSCR_CTRL_MASK);

		ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, &fpscr,
					  vregs_end_pos, VFP_STATE_SIZE);
	}

	return ret;
	return membuf_store(&to, fpscr);
}

static int compat_vfp_set(struct task_struct *target,
@@ -1420,11 +1307,10 @@ static int compat_vfp_set(struct task_struct *target,
}

static int compat_tls_get(struct task_struct *target,
			  const struct user_regset *regset, unsigned int pos,
			  unsigned int count, void *kbuf, void __user *ubuf)
			  const struct user_regset *regset,
			  struct membuf to)
{
	compat_ulong_t tls = (compat_ulong_t)target->thread.uw.tp_value;
	return user_regset_copyout(&pos, &count, &kbuf, &ubuf, &tls, 0, -1);
	return membuf_store(&to, (compat_ulong_t)target->thread.uw.tp_value);
}

static int compat_tls_set(struct task_struct *target,
@@ -1449,7 +1335,7 @@ static const struct user_regset aarch32_regsets[] = {
		.n = COMPAT_ELF_NGREG,
		.size = sizeof(compat_elf_greg_t),
		.align = sizeof(compat_elf_greg_t),
		.get = compat_gpr_get,
		.regset_get = compat_gpr_get,
		.set = compat_gpr_set
	},
	[REGSET_COMPAT_VFP] = {
@@ -1458,7 +1344,7 @@ static const struct user_regset aarch32_regsets[] = {
		.size = sizeof(compat_ulong_t),
		.align = sizeof(compat_ulong_t),
		.active = fpr_active,
		.get = compat_vfp_get,
		.regset_get = compat_vfp_get,
		.set = compat_vfp_set
	},
};
@@ -1474,7 +1360,7 @@ static const struct user_regset aarch32_ptrace_regsets[] = {
		.n = COMPAT_ELF_NGREG,
		.size = sizeof(compat_elf_greg_t),
		.align = sizeof(compat_elf_greg_t),
		.get = compat_gpr_get,
		.regset_get = compat_gpr_get,
		.set = compat_gpr_set
	},
	[REGSET_FPR] = {
@@ -1482,7 +1368,7 @@ static const struct user_regset aarch32_ptrace_regsets[] = {
		.n = VFP_STATE_SIZE / sizeof(compat_ulong_t),
		.size = sizeof(compat_ulong_t),
		.align = sizeof(compat_ulong_t),
		.get = compat_vfp_get,
		.regset_get = compat_vfp_get,
		.set = compat_vfp_set
	},
	[REGSET_TLS] = {
@@ -1490,7 +1376,7 @@ static const struct user_regset aarch32_ptrace_regsets[] = {
		.n = 1,
		.size = sizeof(compat_ulong_t),
		.align = sizeof(compat_ulong_t),
		.get = compat_tls_get,
		.regset_get = compat_tls_get,
		.set = compat_tls_set,
	},
#ifdef CONFIG_HAVE_HW_BREAKPOINT
@@ -1499,7 +1385,7 @@ static const struct user_regset aarch32_ptrace_regsets[] = {
		.n = sizeof(struct user_hwdebug_state) / sizeof(u32),
		.size = sizeof(u32),
		.align = sizeof(u32),
		.get = hw_break_get,
		.regset_get = hw_break_get,
		.set = hw_break_set,
	},
	[REGSET_HW_WATCH] = {
@@ -1507,7 +1393,7 @@ static const struct user_regset aarch32_ptrace_regsets[] = {
		.n = sizeof(struct user_hwdebug_state) / sizeof(u32),
		.size = sizeof(u32),
		.align = sizeof(u32),
		.get = hw_break_get,
		.regset_get = hw_break_get,
		.set = hw_break_set,
	},
#endif
@@ -1516,7 +1402,7 @@ static const struct user_regset aarch32_ptrace_regsets[] = {
		.n = 1,
		.size = sizeof(int),
		.align = sizeof(int),
		.get = system_call_get,
		.regset_get = system_call_get,
		.set = system_call_set,
	},
};
@@ -1541,9 +1427,7 @@ static int compat_ptrace_read_user(struct task_struct *tsk, compat_ulong_t off,
	else if (off == COMPAT_PT_TEXT_END_ADDR)
		tmp = tsk->mm->end_code;
	else if (off < sizeof(compat_elf_gregset_t))
		return copy_regset_to_user(tsk, &user_aarch32_view,
					   REGSET_COMPAT_GPR, off,
					   sizeof(compat_ulong_t), ret);
		tmp = compat_get_user_reg(tsk, off >> 2);
	else if (off >= COMPAT_USER_SZ)
		return -EIO;
	else
@@ -1555,8 +1439,8 @@ static int compat_ptrace_read_user(struct task_struct *tsk, compat_ulong_t off,
static int compat_ptrace_write_user(struct task_struct *tsk, compat_ulong_t off,
				    compat_ulong_t val)
{
	int ret;
	mm_segment_t old_fs = get_fs();
	struct pt_regs newregs = *task_pt_regs(tsk);
	unsigned int idx = off / 4;

	if (off & 3 || off >= COMPAT_USER_SZ)
		return -EIO;
@@ -1564,14 +1448,25 @@ static int compat_ptrace_write_user(struct task_struct *tsk, compat_ulong_t off,
	if (off >= sizeof(compat_elf_gregset_t))
		return 0;

	set_fs(KERNEL_DS);
	ret = copy_regset_from_user(tsk, &user_aarch32_view,
				    REGSET_COMPAT_GPR, off,
				    sizeof(compat_ulong_t),
				    &val);
	set_fs(old_fs);
	switch (idx) {
	case 15:
		newregs.pc = val;
		break;
	case 16:
		newregs.pstate = compat_psr_to_pstate(val);
		break;
	case 17:
		newregs.orig_x0 = val;
		break;
	default:
		newregs.regs[idx] = val;
	}

	if (!valid_user_regs(&newregs.user_regs, tsk))
		return -EINVAL;

	return ret;
	*task_pt_regs(tsk) = newregs;
	return 0;
}

#ifdef CONFIG_HAVE_HW_BREAKPOINT
+3 −8
Original line number Diff line number Diff line
@@ -57,14 +57,9 @@ static inline int put_reg(struct task_struct *task,

static int gpr_get(struct task_struct *target,
		   const struct user_regset *regset,
		   unsigned int pos, unsigned int count,
		   void *kbuf, void __user *ubuf)
		   struct membuf to)
{
	struct pt_regs *regs = task_pt_regs(target);

	return user_regset_copyout(&pos, &count, &kbuf, &ubuf,
				   regs,
				   0, sizeof(*regs));
	return membuf_write(&to, task_pt_regs(target), sizeof(struct pt_regs));
}

enum c6x_regset {
@@ -77,7 +72,7 @@ static const struct user_regset c6x_regsets[] = {
		.n = ELF_NGREG,
		.size = sizeof(u32),
		.align = sizeof(u32),
		.get = gpr_get,
		.regset_get = gpr_get,
	},
};

+10 −14

File changed.

Preview size limit exceeded, changes collapsed.

Loading