Commit ad4a4d3a authored by Catalin Marinas's avatar Catalin Marinas
Browse files

Merge branch 'for-next/signal' into for-next/core

* for-next/signal:
  : Signal handling cleanups
  arm64/signal: Only read new data when parsing the ZT context
  arm64/signal: Only read new data when parsing the ZA context
  arm64/signal: Only read new data when parsing the SVE context
  arm64/signal: Avoid rereading context frame sizes
  arm64/signal: Make interface for restore_fpsimd_context() consistent
  arm64/signal: Remove redundant size validation from parse_user_sigframe()
  arm64/signal: Don't redundantly verify FPSIMD magic
parents 96004636 ad678be4
Loading
Loading
Loading
Loading
+61 −60
Original line number Diff line number Diff line
@@ -170,6 +170,19 @@ static void __user *apply_user_offset(
	return base + offset;
}

struct user_ctxs {
	struct fpsimd_context __user *fpsimd;
	u32 fpsimd_size;
	struct sve_context __user *sve;
	u32 sve_size;
	struct tpidr2_context __user *tpidr2;
	u32 tpidr2_size;
	struct za_context __user *za;
	u32 za_size;
	struct zt_context __user *zt;
	u32 zt_size;
};

static int preserve_fpsimd_context(struct fpsimd_context __user *ctx)
{
	struct user_fpsimd_state const *fpsimd =
@@ -188,25 +201,20 @@ static int preserve_fpsimd_context(struct fpsimd_context __user *ctx)
	return err ? -EFAULT : 0;
}

static int restore_fpsimd_context(struct fpsimd_context __user *ctx)
static int restore_fpsimd_context(struct user_ctxs *user)
{
	struct user_fpsimd_state fpsimd;
	__u32 magic, size;
	int err = 0;

	/* check the magic/size information */
	__get_user_error(magic, &ctx->head.magic, err);
	__get_user_error(size, &ctx->head.size, err);
	if (err)
		return -EFAULT;
	if (magic != FPSIMD_MAGIC || size != sizeof(struct fpsimd_context))
	/* check the size information */
	if (user->fpsimd_size != sizeof(struct fpsimd_context))
		return -EINVAL;

	/* copy the FP and status/control registers */
	err = __copy_from_user(fpsimd.vregs, ctx->vregs,
	err = __copy_from_user(fpsimd.vregs, &(user->fpsimd->vregs),
			       sizeof(fpsimd.vregs));
	__get_user_error(fpsimd.fpsr, &ctx->fpsr, err);
	__get_user_error(fpsimd.fpcr, &ctx->fpcr, err);
	__get_user_error(fpsimd.fpsr, &(user->fpsimd->fpsr), err);
	__get_user_error(fpsimd.fpcr, &(user->fpsimd->fpcr), err);

	clear_thread_flag(TIF_SVE);
	current->thread.fp_type = FP_STATE_FPSIMD;
@@ -219,14 +227,6 @@ static int restore_fpsimd_context(struct fpsimd_context __user *ctx)
}


struct user_ctxs {
	struct fpsimd_context __user *fpsimd;
	struct sve_context __user *sve;
	struct tpidr2_context __user *tpidr2;
	struct za_context __user *za;
	struct zt_context __user *zt;
};

#ifdef CONFIG_ARM64_SVE

static int preserve_sve_context(struct sve_context __user *ctx)
@@ -271,15 +271,20 @@ static int preserve_sve_context(struct sve_context __user *ctx)

static int restore_sve_fpsimd_context(struct user_ctxs *user)
{
	int err;
	int err = 0;
	unsigned int vl, vq;
	struct user_fpsimd_state fpsimd;
	struct sve_context sve;
	u16 user_vl, flags;

	if (__copy_from_user(&sve, user->sve, sizeof(sve)))
		return -EFAULT;
	if (user->sve_size < sizeof(*user->sve))
		return -EINVAL;

	__get_user_error(user_vl, &(user->sve->vl), err);
	__get_user_error(flags, &(user->sve->flags), err);
	if (err)
		return err;

	if (sve.flags & SVE_SIG_FLAG_SM) {
	if (flags & SVE_SIG_FLAG_SM) {
		if (!system_supports_sme())
			return -EINVAL;

@@ -291,19 +296,19 @@ static int restore_sve_fpsimd_context(struct user_ctxs *user)
		vl = task_get_sve_vl(current);
	}

	if (sve.vl != vl)
	if (user_vl != vl)
		return -EINVAL;

	if (sve.head.size <= sizeof(*user->sve)) {
	if (user->sve_size == sizeof(*user->sve)) {
		clear_thread_flag(TIF_SVE);
		current->thread.svcr &= ~SVCR_SM_MASK;
		current->thread.fp_type = FP_STATE_FPSIMD;
		goto fpsimd_only;
	}

	vq = sve_vq_from_vl(sve.vl);
	vq = sve_vq_from_vl(vl);

	if (sve.head.size < SVE_SIG_CONTEXT_SIZE(vq))
	if (user->sve_size < SVE_SIG_CONTEXT_SIZE(vq))
		return -EINVAL;

	/*
@@ -329,7 +334,7 @@ static int restore_sve_fpsimd_context(struct user_ctxs *user)
	if (err)
		return -EFAULT;

	if (sve.flags & SVE_SIG_FLAG_SM)
	if (flags & SVE_SIG_FLAG_SM)
		current->thread.svcr |= SVCR_SM_MASK;
	else
		set_thread_flag(TIF_SVE);
@@ -383,7 +388,9 @@ static int restore_tpidr2_context(struct user_ctxs *user)
	u64 tpidr2_el0;
	int err = 0;

	/* Magic and size were validated deciding to call this function */
	if (user->tpidr2_size != sizeof(*user->tpidr2))
		return -EINVAL;

	__get_user_error(tpidr2_el0, &user->tpidr2->tpidr2, err);
	if (!err)
		current->thread.tpidr2_el0 = tpidr2_el0;
@@ -428,24 +435,28 @@ static int preserve_za_context(struct za_context __user *ctx)

static int restore_za_context(struct user_ctxs *user)
{
	int err;
	int err = 0;
	unsigned int vq;
	struct za_context za;
	u16 user_vl;

	if (__copy_from_user(&za, user->za, sizeof(za)))
		return -EFAULT;
	if (user->za_size < sizeof(*user->za))
		return -EINVAL;

	__get_user_error(user_vl, &(user->za->vl), err);
	if (err)
		return err;

	if (za.vl != task_get_sme_vl(current))
	if (user_vl != task_get_sme_vl(current))
		return -EINVAL;

	if (za.head.size <= sizeof(*user->za)) {
	if (user->za_size == sizeof(*user->za)) {
		current->thread.svcr &= ~SVCR_ZA_MASK;
		return 0;
	}

	vq = sve_vq_from_vl(za.vl);
	vq = sve_vq_from_vl(user_vl);

	if (za.head.size < ZA_SIG_CONTEXT_SIZE(vq))
	if (user->za_size < ZA_SIG_CONTEXT_SIZE(vq))
		return -EINVAL;

	/*
@@ -510,19 +521,19 @@ static int preserve_zt_context(struct zt_context __user *ctx)
static int restore_zt_context(struct user_ctxs *user)
{
	int err;
	struct zt_context zt;
	u16 nregs;

	/* ZA must be restored first for this check to be valid */
	if (!thread_za_enabled(&current->thread))
		return -EINVAL;

	if (__copy_from_user(&zt, user->zt, sizeof(zt)))
		return -EFAULT;

	if (zt.nregs != 1)
	if (user->zt_size != ZT_SIG_CONTEXT_SIZE(1))
		return -EINVAL;

	if (zt.head.size != ZT_SIG_CONTEXT_SIZE(zt.nregs))
	if (__copy_from_user(&nregs, &(user->zt->nregs), sizeof(nregs)))
		return -EFAULT;

	if (nregs != 1)
		return -EINVAL;

	/*
@@ -615,10 +626,8 @@ static int parse_user_sigframe(struct user_ctxs *user,
			if (user->fpsimd)
				goto invalid;

			if (size < sizeof(*user->fpsimd))
				goto invalid;

			user->fpsimd = (struct fpsimd_context __user *)head;
			user->fpsimd_size = size;
			break;

		case ESR_MAGIC:
@@ -632,10 +641,8 @@ static int parse_user_sigframe(struct user_ctxs *user,
			if (user->sve)
				goto invalid;

			if (size < sizeof(*user->sve))
				goto invalid;

			user->sve = (struct sve_context __user *)head;
			user->sve_size = size;
			break;

		case TPIDR2_MAGIC:
@@ -645,10 +652,8 @@ static int parse_user_sigframe(struct user_ctxs *user,
			if (user->tpidr2)
				goto invalid;

			if (size != sizeof(*user->tpidr2))
				goto invalid;

			user->tpidr2 = (struct tpidr2_context __user *)head;
			user->tpidr2_size = size;
			break;

		case ZA_MAGIC:
@@ -658,10 +663,8 @@ static int parse_user_sigframe(struct user_ctxs *user,
			if (user->za)
				goto invalid;

			if (size < sizeof(*user->za))
				goto invalid;

			user->za = (struct za_context __user *)head;
			user->za_size = size;
			break;

		case ZT_MAGIC:
@@ -671,10 +674,8 @@ static int parse_user_sigframe(struct user_ctxs *user,
			if (user->zt)
				goto invalid;

			if (size < sizeof(*user->zt))
				goto invalid;

			user->zt = (struct zt_context __user *)head;
			user->zt_size = size;
			break;

		case EXTRA_MAGIC:
@@ -793,7 +794,7 @@ static int restore_sigframe(struct pt_regs *regs,
		if (user.sve)
			err = restore_sve_fpsimd_context(&user);
		else
			err = restore_fpsimd_context(user.fpsimd);
			err = restore_fpsimd_context(&user);
	}

	if (err == 0 && system_supports_sme() && user.tpidr2)