Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit ad4f9576 authored by David S. Miller's avatar David S. Miller
Browse files

[SPARC64]: Fix user accesses in regset code.



If target is not current we need to use access_process_vm().

Noticed by Roland McGrath.

Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 7c3cce97
Loading
Loading
Loading
Loading
+115 −21
Original line number Diff line number Diff line
@@ -138,8 +138,17 @@ static int genregs64_get(struct task_struct *target,
			(regs->u_regs[UREG_I6] + STACK_BIAS);
		unsigned long window[16];

		if (target == current) {
			if (copy_from_user(window, reg_window, sizeof(window)))
				return -EFAULT;
		} else {
			if (access_process_vm(target,
					      (unsigned long) reg_window,
					      window,
					      sizeof(window), 0) !=
			    sizeof(window))
				return -EFAULT;
		}

		ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
					  window,
@@ -190,17 +199,38 @@ static int genregs64_set(struct task_struct *target,
			(regs->u_regs[UREG_I6] + STACK_BIAS);
		unsigned long window[16];

		if (target == current) {
			if (copy_from_user(window, reg_window, sizeof(window)))
				return -EFAULT;
		} else {
			if (access_process_vm(target,
					      (unsigned long) reg_window,
					      window,
					      sizeof(window), 0) !=
			    sizeof(window))
				return -EFAULT;
		}

		ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
					 window,
					 16 * sizeof(u64),
					 32 * sizeof(u64));
		if (!ret &&
		    copy_to_user(reg_window, window, sizeof(window)))
		if (!ret) {
			if (target == current) {
				if (copy_to_user(reg_window, window,
						 sizeof(window)))
					return -EFAULT;
			} else {
				if (access_process_vm(target,
						      (unsigned long)
						      reg_window,
						      window,
						      sizeof(window), 1) !=
				    sizeof(window))
					return -EFAULT;
			}
		}
	}

	if (!ret && count > 0) {
		unsigned long tstate;
@@ -412,10 +442,23 @@ static int genregs32_get(struct task_struct *target,
			*k++ = regs->u_regs[pos++];

		reg_window = (compat_ulong_t __user *) regs->u_regs[UREG_I6];
		if (target == current) {
			for (; count > 0 && pos < 32; count--) {
				if (get_user(*k++, &reg_window[pos++]))
					return -EFAULT;
			}
		} else {
			for (; count > 0 && pos < 32; count--) {
				if (access_process_vm(target,
						      (unsigned long)
						      &reg_window[pos],
						      k, sizeof(*k), 0)
				    != sizeof(*k))
					return -EFAULT;
				k++;
				pos++;
			}
		}
	} else {
		for (; count > 0 && pos < 16; count--) {
			if (put_user((compat_ulong_t) regs->u_regs[pos++], u++))
@@ -423,11 +466,29 @@ static int genregs32_get(struct task_struct *target,
		}

		reg_window = (compat_ulong_t __user *) regs->u_regs[UREG_I6];
		if (target == current) {
			for (; count > 0 && pos < 32; count--) {
				if (get_user(reg, &reg_window[pos++]) ||
				    put_user(reg, u++))
					return -EFAULT;
			}
		} else {
			for (; count > 0 && pos < 32; count--) {
				if (access_process_vm(target,
						      (unsigned long)
						      &reg_window[pos],
						      &reg, sizeof(reg), 0)
				    != sizeof(reg))
					return -EFAULT;
				if (access_process_vm(target,
						      (unsigned long) u,
						      &reg, sizeof(reg), 1)
				    != sizeof(reg))
					return -EFAULT;
				pos++;
				u++;
			}
		}
	}
	while (count > 0) {
		switch (pos) {
@@ -488,10 +549,24 @@ static int genregs32_set(struct task_struct *target,
			regs->u_regs[pos++] = *k++;

		reg_window = (compat_ulong_t __user *) regs->u_regs[UREG_I6];
		if (target == current) {
			for (; count > 0 && pos < 32; count--) {
				if (put_user(*k++, &reg_window[pos++]))
					return -EFAULT;
			}
		} else {
			for (; count > 0 && pos < 32; count--) {
				if (access_process_vm(target,
						      (unsigned long)
						      &reg_window[pos],
						      (void *) k,
						      sizeof(*k), 1)
				    != sizeof(*k))
					return -EFAULT;
				k++;
				pos++;
			}
		}
	} else {
		for (; count > 0 && pos < 16; count--) {
			if (get_user(reg, u++))
@@ -500,11 +575,30 @@ static int genregs32_set(struct task_struct *target,
		}

		reg_window = (compat_ulong_t __user *) regs->u_regs[UREG_I6];
		if (target == current) {
			for (; count > 0 && pos < 32; count--) {
				if (get_user(reg, u++) ||
				    put_user(reg, &reg_window[pos++]))
					return -EFAULT;
			}
		} else {
			for (; count > 0 && pos < 32; count--) {
				if (access_process_vm(target,
						      (unsigned long)
						      u,
						      &reg, sizeof(reg), 0)
				    != sizeof(reg))
					return -EFAULT;
				if (access_process_vm(target,
						      (unsigned long)
						      &reg_window[pos],
						      &reg, sizeof(reg), 1)
				    != sizeof(reg))
					return -EFAULT;
				pos++;
				u++;
			}
		}
	}
	while (count > 0) {
		unsigned long tstate;