diff mbox series

[RFC] powerpc/signal: sanitise PT_NIP and sa_handler low bits

Message ID 20211130072933.2004389-1-npiggin@gmail.com (mailing list archive)
State New
Headers show
Series [RFC] powerpc/signal: sanitise PT_NIP and sa_handler low bits | expand

Checks

Context Check Description
snowpatch_ozlabs/github-powerpc_ppctests success Successfully ran 8 jobs.
snowpatch_ozlabs/github-powerpc_selftests success Successfully ran 8 jobs.
snowpatch_ozlabs/github-powerpc_sparse success Successfully ran 4 jobs.
snowpatch_ozlabs/github-powerpc_kernel_qemu success Successfully ran 24 jobs.
snowpatch_ozlabs/github-powerpc_clang success Successfully ran 7 jobs.

Commit Message

Nicholas Piggin Nov. 30, 2021, 7:29 a.m. UTC
The bottom 2 bits of NIP are ignored when RFI returns with SRR0 = NIP,
so regs->nip does not correspond to the actual return address if either
of those bits are set. Further, these bits are reserved in SRR0 so they
should not be set. Sanitize PT_NIP from signal handlers to ensure they
can't be set by userspace, this also keeps the low 2 bit of TFHAR clear,
which are similarly reserved. 32-bit signal delivery returns directly to
the handler, so sa_handler is sanitised similarly there.

This can cause a bug when CONFIG_PPC_RFI_SRR_DEBUG=y on a processor that
does not implement the 2 low bits of SRR0 (always read back 0) because
SRR0 will not match regs->nip. This was caught by sigfuz, but a simple
reproducer follows.

  #include <stdlib.h>
  #include <signal.h>
  #include <ucontext.h>

  static void trap_signal_handler(int signo, siginfo_t *si, void *uc)
  {
      ucontext_t *ucp = uc;
      ucp->uc_mcontext.gp_regs[PT_NIP] |= 3;
  }

  int main(void)
  {
      struct sigaction trap_sa;
      trap_sa.sa_flags = SA_SIGINFO;
      trap_sa.sa_sigaction = trap_signal_handler;
      sigaction(SIGUSR1, &trap_sa, NULL);
      raise(SIGUSR1);
      exit(EXIT_SUCCESS);
  }

Reported-by: Sachin Sant <sachinp@linux.vnet.ibm.com>
Signed-off-by: Nicholas Piggin <npiggin@gmail.com>
---
I'm not entirely sure about the 32-bit / compat part. Or the 64-bit for
that matter except that it does seem to fix the bug caused by the test
program.

Thanks,
Nick

 arch/powerpc/kernel/signal_32.c | 23 ++++++++++++++++-------
 arch/powerpc/kernel/signal_64.c | 17 ++++++++++++-----
 2 files changed, 28 insertions(+), 12 deletions(-)

Comments

Sachin Sant Dec. 15, 2021, 10:49 a.m. UTC | #1
> Reported-by: Sachin Sant <sachinp@linux.vnet.ibm.com>
> Signed-off-by: Nicholas Piggin <npiggin@gmail.com>
> ---
> I'm not entirely sure about the 32-bit / compat part. Or the 64-bit for
> that matter except that it does seem to fix the bug caused by the test
> program.
> 
> Thanks,
> Nick
> 
> arch/powerpc/kernel/signal_32.c | 23 ++++++++++++++++-------
> arch/powerpc/kernel/signal_64.c | 17 ++++++++++++-----
> 2 files changed, 28 insertions(+), 12 deletions(-)

Sorry for the delayed feedback. I was observing confusing test results
so had to be sure. 

Test results are against  5.16.0-rc5-03218-g798527287598 (powerpc/merge)

I ran some extended set of kernel self tests (from powerpc/signal and
powerpc/security) on POWER8, POWER9 and POWER10 configs.

On POWER8 & POWER10 LPAR with this fix tests ran successfully.

on POWER9 PowerNV with the fix and following set of configs

CONFIG_PPC_IRQ_SOFT_MASK_DEBUG=y
CONFIG_PPC_RFI_SRR_DEBUG=y

the tests ran successfully.

But with the fix and following set of configs

CONFIG_PPC_IRQ_SOFT_MASK_DEBUG=y
CONFIG_PPC_RFI_SRR_DEBUG=n

I still a warning and then a crash:

[  550.568588] count-cache-flush: hardware flush enabled.
[  550.568593] link-stack-flush: software flush enabled.
[  550.569604] ------------[ cut here ]------------
[  550.569611] WARNING: CPU: 21 PID: 3784 at arch/powerpc/kernel/irq.c:288 arch_local_irq_restore+0x22c/0x230
[  550.569625] Modules linked in: nft_ct nf_conntrack nf_defrag_ipv6 nf_defrag_ipv4 ip_set nf_tables rfkill libcrc32c nfnetlink i2c_dev rpcrdma sunrpc ib_umad rdma_ucm ib_srpt ib_isert iscsi_target_mod target_core_mod ib_ipoib ib_iser rdma_cm iw_cm libiscsi ib_cm scsi_transport_iscsi mlx5_ib ib_uverbs dm_mod ib_core ses enclosure tpm_i2c_nuvoton i2c_opal ipmi_powernv xts ipmi_devintf uio_pdrv_genirq vmx_crypto ipmi_msghandler i2c_core opal_prd uio ibmpowernv leds_powernv powernv_op_panel sch_fq_codel ip_tables ext4 mbcache jbd2 mlx5_core sd_mod t10_pi sg mpt3sas ipr tg3 libata mlxfw psample raid_class ptp scsi_transport_sas pps_core fuse
[  550.569752] CPU: 21 PID: 3784 Comm: NetworkManager Kdump: loaded Not tainted 5.16.0-rc5-03218-g798527287598 #8
[  550.569765] NIP:  c0000000000171dc LR: c000000000033240 CTR: c000000000cf1260
[  550.569774] REGS: c000000ae08bbab0 TRAP: 0700   Not tainted  (5.16.0-rc5-03218-g798527287598)
[  550.569784] MSR:  9000000000021031 <SF,HV,ME,IR,DR,LE>  CR: 28004444  XER: 20040000
[  550.569802] CFAR: c00000000001704c IRQMASK: 1
[  550.569802] GPR00: c000000000033240 c000000ae08bbd50 c000000002a10600 0000000000000000
[  550.569802] GPR04: c000000ae08bbe80 00007fffaea1ece0 0000000000000000 0000000000000000
[  550.569802] GPR08: 0000000000000002 0000000000000000 0000000000000002 0000000001f3fb0c
[  550.569802] GPR12: 0000000000004000 c000005fff7c9080 0000000000000000 0000000000000000
[  550.569802] GPR16: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
[  550.569802] GPR20: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
[  550.569802] GPR24: 0000000000000002 0000000000000001 0000000002002000 0000000002802000
[  550.569802] GPR28: 0000000000000000 0000000000000800 c000000ae08bbe80 0000000000040080
[  550.569899] NIP [c0000000000171dc] arch_local_irq_restore+0x22c/0x230
[  550.569909] LR [c000000000033240] interrupt_exit_user_prepare_main+0x150/0x260
[  550.569919] Call Trace:
[  550.569925] [c000000ae08bbd80] [c000000000033240] interrupt_exit_user_prepare_main+0x150/0x260
[  550.569937] [c000000ae08bbde0] [c000000000033744] syscall_exit_prepare+0x74/0x150
[  550.569948] [c000000ae08bbe10] [c00000000000c758] system_call_common+0xf8/0x268
[  550.569960] --- interrupt: c00 at 0x7fffaea1ece0
[  550.569968] NIP:  00007fffaea1ece0 LR: 00007fffaea1ecc4 CTR: 0000000000000000
[  550.569977] REGS: c000000ae08bbe80 TRAP: 0c00   Not tainted  (5.16.0-rc5-03218-g798527287598)
[  550.569987] MSR:  900000000280f033 <SF,HV,VEC,VSX,EE,PR,FP,ME,IR,DR,RI,LE>  CR: 24004448  XER: 00000000
[  550.570012] IRQMASK: 0
[  550.570012] GPR00: 00000000000000a7 00007fffeea71ce0 00007fffaeb07300 0000000000000001
[  550.570012] GPR04: 0000000000000007 0000000000013eed 0000000000000000 0000000000000002
[  550.570012] GPR08: 00007fffad6c7ea8 0000000000000000 0000000000000000 0000000000000000
[  550.570012] GPR12: 0000000000000000 00007fffad6cf510 0000000000000000 0000000000000000
[  550.570012] GPR16: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
[  550.570012] GPR20: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
[  550.570012] GPR24: 0000000000000000 0000000000000001 0000000000013eed 00007fffeea71da4
[  550.570012] GPR28: 0000000000000000 0000000000000007 000000013a1ae810 0000000000013eed
[  550.570105] NIP [00007fffaea1ece0] 0x7fffaea1ece0
[  550.570112] LR [00007fffaea1ecc4] 0x7fffaea1ecc4
[  550.570119] --- interrupt: c00
[  550.570124] Instruction dump:
[  550.570130] f8010040 0fe00000 4bfffff0 60000000 60000000 0fe00000 60000000 60000000
[  550.570148] 60000000 39200002 7d210164 4bfffec4 <0fe00000> 3c4c02a0 38429420 7c0802a6
[  550.570165] ---[ end trace b8833ddd6f9d2d40 ]---
[  550.570174] Unrecoverable exception 700 at c000000000017050 (msr=9000000000021031)
[  550.570184] Oops: Unrecoverable exception, sig: 6 [#1]
[  550.570191] LE PAGE_SIZE=64K MMU=Radix SMP NR_CPUS=2048 NUMA PowerNV
[  550.570200] Modules linked in: nft_ct nf_conntrack nf_defrag_ipv6 nf_defrag_ipv4 ip_set nf_tables rfkill libcrc32c nfnetlink i2c_dev rpcrdma sunrpc ib_umad rdma_ucm ib_srpt ib_isert iscsi_target_mod target_core_mod ib_ipoib ib_iser rdma_cm iw_cm libiscsi ib_cm scsi_transport_iscsi mlx5_ib ib_uverbs dm_mod ib_core ses enclosure tpm_i2c_nuvoton i2c_opal ipmi_powernv xts ipmi_devintf uio_pdrv_genirq vmx_crypto ipmi_msghandler i2c_core opal_prd uio ibmpowernv leds_powernv powernv_op_panel sch_fq_codel ip_tables ext4 mbcache jbd2 mlx5_core sd_mod t10_pi sg mpt3sas ipr tg3 libata mlxfw psample raid_class ptp scsi_transport_sas pps_core fuse
[  550.570313] CPU: 21 PID: 3784 Comm: NetworkManager Kdump: loaded Tainted: G        W         5.16.0-rc5-03218-g798527287598 #8
[  550.570326] NIP:  c000000000017050 LR: c000000000033240 CTR: c000000000cf1260
[  550.570335] REGS: c000000ae08bbab0 TRAP: 0700   Tainted: G        W          (5.16.0-rc5-03218-g798527287598)
[  550.570346] MSR:  9000000000021031 <SF,HV,ME,IR,DR,LE>  CR: 28004444  XER: 20040000
[  550.570363] CFAR: c00000000001704c IRQMASK: 1
[  550.570363] GPR00: c000000000033240 c000000ae08bbd50 c000000002a10600 0000000000000000
[  550.570363] GPR04: c000000ae08bbe80 00007fffaea1ece0 0000000000000000 0000000000000000
[  550.570363] GPR08: 0000000000000002 0000000000000000 0000000000000002 0000000001f3fb0c
[  550.570363] GPR12: 0000000000004000 c000005fff7c9080 0000000000000000 0000000000000000
[  550.570363] GPR16: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
[  550.570363] GPR20: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
[  550.570363] GPR24: 0000000000000002 0000000000000001 0000000002002000 0000000002802000
[  550.570363] GPR28: 0000000000000000 0000000000000800 c000000ae08bbe80 0000000000040080
……..

Not sure if the above problem is related to the previous one I reported
or a different one.

Thanks
-Sachin
Nicholas Piggin Dec. 20, 2021, 5:28 a.m. UTC | #2
Excerpts from Sachin Sant's message of December 15, 2021 8:49 pm:
> 
>> Reported-by: Sachin Sant <sachinp@linux.vnet.ibm.com>
>> Signed-off-by: Nicholas Piggin <npiggin@gmail.com>
>> ---
>> I'm not entirely sure about the 32-bit / compat part. Or the 64-bit for
>> that matter except that it does seem to fix the bug caused by the test
>> program.
>> 
>> Thanks,
>> Nick
>> 
>> arch/powerpc/kernel/signal_32.c | 23 ++++++++++++++++-------
>> arch/powerpc/kernel/signal_64.c | 17 ++++++++++++-----
>> 2 files changed, 28 insertions(+), 12 deletions(-)
> 
> Sorry for the delayed feedback. I was observing confusing test results
> so had to be sure. 
> 
> Test results are against  5.16.0-rc5-03218-g798527287598 (powerpc/merge)
> 
> I ran some extended set of kernel self tests (from powerpc/signal and
> powerpc/security) on POWER8, POWER9 and POWER10 configs.
> 
> On POWER8 & POWER10 LPAR with this fix tests ran successfully.
> 
> on POWER9 PowerNV with the fix and following set of configs
> 
> CONFIG_PPC_IRQ_SOFT_MASK_DEBUG=y
> CONFIG_PPC_RFI_SRR_DEBUG=y
> 
> the tests ran successfully.
> 
> But with the fix and following set of configs
> 
> CONFIG_PPC_IRQ_SOFT_MASK_DEBUG=y
> CONFIG_PPC_RFI_SRR_DEBUG=n
> 
> I still a warning and then a crash:
> 
> [  550.568588] count-cache-flush: hardware flush enabled.
> [  550.568593] link-stack-flush: software flush enabled.
> [  550.569604] ------------[ cut here ]------------
> [  550.569611] WARNING: CPU: 21 PID: 3784 at arch/powerpc/kernel/irq.c:288 arch_local_irq_restore+0x22c/0x230
> [  550.569625] Modules linked in: nft_ct nf_conntrack nf_defrag_ipv6 nf_defrag_ipv4 ip_set nf_tables rfkill libcrc32c nfnetlink i2c_dev rpcrdma sunrpc ib_umad rdma_ucm ib_srpt ib_isert iscsi_target_mod target_core_mod ib_ipoib ib_iser rdma_cm iw_cm libiscsi ib_cm scsi_transport_iscsi mlx5_ib ib_uverbs dm_mod ib_core ses enclosure tpm_i2c_nuvoton i2c_opal ipmi_powernv xts ipmi_devintf uio_pdrv_genirq vmx_crypto ipmi_msghandler i2c_core opal_prd uio ibmpowernv leds_powernv powernv_op_panel sch_fq_codel ip_tables ext4 mbcache jbd2 mlx5_core sd_mod t10_pi sg mpt3sas ipr tg3 libata mlxfw psample raid_class ptp scsi_transport_sas pps_core fuse
> [  550.569752] CPU: 21 PID: 3784 Comm: NetworkManager Kdump: loaded Not tainted 5.16.0-rc5-03218-g798527287598 #8
> [  550.569765] NIP:  c0000000000171dc LR: c000000000033240 CTR: c000000000cf1260
> [  550.569774] REGS: c000000ae08bbab0 TRAP: 0700   Not tainted  (5.16.0-rc5-03218-g798527287598)
> [  550.569784] MSR:  9000000000021031 <SF,HV,ME,IR,DR,LE>  CR: 28004444  XER: 20040000
> [  550.569802] CFAR: c00000000001704c IRQMASK: 1
> [  550.569802] GPR00: c000000000033240 c000000ae08bbd50 c000000002a10600 0000000000000000
> [  550.569802] GPR04: c000000ae08bbe80 00007fffaea1ece0 0000000000000000 0000000000000000
> [  550.569802] GPR08: 0000000000000002 0000000000000000 0000000000000002 0000000001f3fb0c
> [  550.569802] GPR12: 0000000000004000 c000005fff7c9080 0000000000000000 0000000000000000
> [  550.569802] GPR16: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
> [  550.569802] GPR20: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
> [  550.569802] GPR24: 0000000000000002 0000000000000001 0000000002002000 0000000002802000
> [  550.569802] GPR28: 0000000000000000 0000000000000800 c000000ae08bbe80 0000000000040080
> [  550.569899] NIP [c0000000000171dc] arch_local_irq_restore+0x22c/0x230
> [  550.569909] LR [c000000000033240] interrupt_exit_user_prepare_main+0x150/0x260
> [  550.569919] Call Trace:
> [  550.569925] [c000000ae08bbd80] [c000000000033240] interrupt_exit_user_prepare_main+0x150/0x260
> [  550.569937] [c000000ae08bbde0] [c000000000033744] syscall_exit_prepare+0x74/0x150
> [  550.569948] [c000000ae08bbe10] [c00000000000c758] system_call_common+0xf8/0x268

Yeah this looks like a different issue. Is there a test running which 
flips the security mitigations rapidly? There is a race window with
the the static branch causing exit_must_hard_disable() returning two
different values.

We should update they key while single threaded AFAIKS.

Thanks,
Nick
---

diff --git a/arch/powerpc/lib/feature-fixups.c b/arch/powerpc/lib/feature-fixups.c
index 57c6bb802f6c..a7cb317e7039 100644
--- a/arch/powerpc/lib/feature-fixups.c
+++ b/arch/powerpc/lib/feature-fixups.c
@@ -232,11 +232,22 @@ static DEFINE_MUTEX(exit_flush_lock);
 
 static int __do_stf_barrier_fixups(void *data)
 {
-	enum stf_barrier_type *types = data;
+	enum stf_barrier_type types = *(enum stf_barrier_type *)data;
 
 	do_stf_entry_barrier_fixups(*types);
 	do_stf_exit_barrier_fixups(*types);
 
+	if ((types & STF_BARRIER_FALLBACK) || (types & STF_BARRIER_SYNC_ORI))
+		stf_exit_reentrant = false;
+	else
+		stf_exit_reentrant = true;
+
+	if (stf_exit_reentrant && rfi_exit_reentrant)
+		static_branch_disable(&interrupt_exit_not_reentrant);
+	else
+		static_branch_enable(&interrupt_exit_not_reentrant);
+
+
 	return 0;
 }
 
@@ -257,18 +268,9 @@ void do_stf_barrier_fixups(enum stf_barrier_type types)
 
 	// Prevent static key update races with do_rfi_flush_fixups()
 	mutex_lock(&exit_flush_lock);
-	static_branch_enable(&interrupt_exit_not_reentrant);
 
 	stop_machine(__do_stf_barrier_fixups, &types, NULL);
 
-	if ((types & STF_BARRIER_FALLBACK) || (types & STF_BARRIER_SYNC_ORI))
-		stf_exit_reentrant = false;
-	else
-		stf_exit_reentrant = true;
-
-	if (stf_exit_reentrant && rfi_exit_reentrant)
-		static_branch_disable(&interrupt_exit_not_reentrant);
-
 	mutex_unlock(&exit_flush_lock);
 }
 
@@ -472,6 +474,16 @@ static int __do_rfi_flush_fixups(void *data)
 		patch_instruction(dest + 2, ppc_inst(instrs[2]));
 	}
 
+	if (types & L1D_FLUSH_FALLBACK)
+		rfi_exit_reentrant = false;
+	else
+		rfi_exit_reentrant = true;
+
+	if (stf_exit_reentrant && rfi_exit_reentrant)
+		static_branch_disable(&interrupt_exit_not_reentrant);
+	else
+		static_branch_enable(&interrupt_exit_not_reentrant);
+
 	printk(KERN_DEBUG "rfi-flush: patched %d locations (%s flush)\n", i,
 		(types == L1D_FLUSH_NONE)       ? "no" :
 		(types == L1D_FLUSH_FALLBACK)   ? "fallback displacement" :
@@ -495,18 +507,9 @@ void do_rfi_flush_fixups(enum l1d_flush_type types)
 
 	// Prevent static key update races with do_stf_barrier_fixups()
 	mutex_lock(&exit_flush_lock);
-	static_branch_enable(&interrupt_exit_not_reentrant);
 
 	stop_machine(__do_rfi_flush_fixups, &types, NULL);
 
-	if (types & L1D_FLUSH_FALLBACK)
-		rfi_exit_reentrant = false;
-	else
-		rfi_exit_reentrant = true;
-
-	if (stf_exit_reentrant && rfi_exit_reentrant)
-		static_branch_disable(&interrupt_exit_not_reentrant);
-
 	mutex_unlock(&exit_flush_lock);
 }
Sachin Sant Dec. 20, 2021, 7:11 a.m. UTC | #3
>> [  550.569802] GPR16: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
>> [  550.569802] GPR20: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
>> [  550.569802] GPR24: 0000000000000002 0000000000000001 0000000002002000 0000000002802000
>> [  550.569802] GPR28: 0000000000000000 0000000000000800 c000000ae08bbe80 0000000000040080
>> [  550.569899] NIP [c0000000000171dc] arch_local_irq_restore+0x22c/0x230
>> [  550.569909] LR [c000000000033240] interrupt_exit_user_prepare_main+0x150/0x260
>> [  550.569919] Call Trace:
>> [  550.569925] [c000000ae08bbd80] [c000000000033240] interrupt_exit_user_prepare_main+0x150/0x260
>> [  550.569937] [c000000ae08bbde0] [c000000000033744] syscall_exit_prepare+0x74/0x150
>> [  550.569948] [c000000ae08bbe10] [c00000000000c758] system_call_common+0xf8/0x268
> 
> Yeah this looks like a different issue. Is there a test running which 
> flips the security mitigations rapidly? There is a race window with
Yes, powerpc/security/mitigation-patching.sh. This test enables/disables
various supported mitigations (parallel execution).

> the the static branch causing exit_must_hard_disable() returning two
> different values.
> 
> We should update they key while single threaded AFAIKS.

Thanks. I tested with this fix. The test ran correctly without a crash.

> diff --git a/arch/powerpc/lib/feature-fixups.c b/arch/powerpc/lib/feature-fixups.c
> index 57c6bb802f6c..a7cb317e7039 100644
> --- a/arch/powerpc/lib/feature-fixups.c
> +++ b/arch/powerpc/lib/feature-fixups.c
> @@ -232,11 +232,22 @@ static DEFINE_MUTEX(exit_flush_lock);
> 
> static int __do_stf_barrier_fixups(void *data)
> {
> -	enum stf_barrier_type *types = data;
> +	enum stf_barrier_type types = *(enum stf_barrier_type *)data;
> 
> 	do_stf_entry_barrier_fixups(*types);
> 	do_stf_exit_barrier_fixups(*types);
> 
*types should be changed to “types” to avoid build failure.
diff mbox series

Patch

diff --git a/arch/powerpc/kernel/signal_32.c b/arch/powerpc/kernel/signal_32.c
index 3e053e2fd6b6..5379bece8072 100644
--- a/arch/powerpc/kernel/signal_32.c
+++ b/arch/powerpc/kernel/signal_32.c
@@ -116,7 +116,7 @@  __unsafe_restore_general_regs(struct pt_regs *regs, struct mcontext __user *sr)
 	int i;
 
 	for (i = 0; i <= PT_RESULT; i++) {
-		if ((i == PT_MSR) || (i == PT_SOFTE))
+		if ((i == PT_NIP) || (i == PT_MSR) || (i == PT_SOFTE))
 			continue;
 		unsafe_get_user(gregs[i], &sr->mc_gregs[i], failed);
 	}
@@ -156,7 +156,7 @@  static __always_inline
 int __unsafe_restore_general_regs(struct pt_regs *regs, struct mcontext __user *sr)
 {
 	/* copy up to but not including MSR */
-	unsafe_copy_from_user(regs, &sr->mc_gregs, PT_MSR * sizeof(elf_greg_t), failed);
+	unsafe_copy_from_user(regs, &sr->mc_gregs, PT_NIP * sizeof(elf_greg_t), failed);
 
 	/* copy from orig_r3 (the word after the MSR) up to the end */
 	unsafe_copy_from_user(&regs->orig_gpr3, &sr->mc_gregs[PT_ORIG_R3],
@@ -458,7 +458,7 @@  static long restore_user_regs(struct pt_regs *regs,
 			      struct mcontext __user *sr, int sig)
 {
 	unsigned int save_r2 = 0;
-	unsigned long msr;
+	unsigned long nip, msr;
 #ifdef CONFIG_VSX
 	int i;
 #endif
@@ -473,6 +473,9 @@  static long restore_user_regs(struct pt_regs *regs,
 		save_r2 = (unsigned int)regs->gpr[2];
 	unsafe_restore_general_regs(regs, sr, failed);
 	set_trap_norestart(regs);
+	unsafe_get_user(nip, &sr->mc_gregs[PT_NIP], failed);
+	nip &= ~3UL;
+	regs_set_return_ip(regs, nip);
 	unsafe_get_user(msr, &sr->mc_gregs[PT_MSR], failed);
 	if (!sig)
 		regs->gpr[2] = (unsigned long) save_r2;
@@ -560,7 +563,7 @@  static long restore_tm_user_regs(struct pt_regs *regs,
 				 struct mcontext __user *sr,
 				 struct mcontext __user *tm_sr)
 {
-	unsigned long msr, msr_hi;
+	unsigned long nip, msr, msr_hi;
 	int i;
 
 	if (tm_suspend_disabled)
@@ -576,7 +579,9 @@  static long restore_tm_user_regs(struct pt_regs *regs,
 		return 1;
 
 	unsafe_restore_general_regs(&current->thread.ckpt_regs, sr, failed);
-	unsafe_get_user(current->thread.tm_tfhar, &sr->mc_gregs[PT_NIP], failed);
+	unsafe_get_user(nip, &sr->mc_gregs[PT_NIP], failed);
+	nip &= ~3UL;
+	current->thread.tm_tfhar = nip;
 	unsafe_get_user(msr, &sr->mc_gregs[PT_MSR], failed);
 
 	/* Restore the previous little-endian mode */
@@ -646,6 +651,10 @@  static long restore_tm_user_regs(struct pt_regs *regs,
 		current->thread.used_vsr = true;
 	}
 
+	unsafe_get_user(nip, &tm_sr->mc_gregs[PT_NIP], failed);
+	nip &= ~3UL;
+	regs_set_return_ip(regs, nip);
+
 	/* Get the top half of the MSR from the user context */
 	unsafe_get_user(msr_hi, &tm_sr->mc_gregs[PT_MSR], failed);
 	msr_hi <<= 32;
@@ -801,7 +810,7 @@  int handle_rt_signal32(struct ksignal *ksig, sigset_t *oldset,
 	regs->gpr[4] = (unsigned long)&frame->info;
 	regs->gpr[5] = (unsigned long)&frame->uc;
 	regs->gpr[6] = (unsigned long)frame;
-	regs_set_return_ip(regs, (unsigned long) ksig->ka.sa.sa_handler);
+	regs_set_return_ip(regs, (unsigned long) ksig->ka.sa.sa_handler & ~3UL);
 	/* enter the signal handler in native-endian mode */
 	regs_set_return_msr(regs, (regs->msr & ~MSR_LE) | (MSR_KERNEL & MSR_LE));
 
@@ -889,7 +898,7 @@  int handle_signal32(struct ksignal *ksig, sigset_t *oldset,
 	regs->gpr[1] = newsp;
 	regs->gpr[3] = ksig->sig;
 	regs->gpr[4] = (unsigned long) sc;
-	regs_set_return_ip(regs, (unsigned long) ksig->ka.sa.sa_handler);
+	regs_set_return_ip(regs, (unsigned long) ksig->ka.sa.sa_handler & ~3UL);
 	/* enter the signal handler in native-endian mode */
 	regs_set_return_msr(regs, (regs->msr & ~MSR_LE) | (MSR_KERNEL & MSR_LE));
 
diff --git a/arch/powerpc/kernel/signal_64.c b/arch/powerpc/kernel/signal_64.c
index d1e1fc0acbea..5ef24adb9803 100644
--- a/arch/powerpc/kernel/signal_64.c
+++ b/arch/powerpc/kernel/signal_64.c
@@ -336,7 +336,7 @@  static long notrace __unsafe_restore_sigcontext(struct task_struct *tsk, sigset_
 	elf_vrreg_t __user *v_regs;
 #endif
 	unsigned long save_r13 = 0;
-	unsigned long msr;
+	unsigned long nip, msr;
 	struct pt_regs *regs = tsk->thread.regs;
 #ifdef CONFIG_VSX
 	int i;
@@ -350,7 +350,9 @@  static long notrace __unsafe_restore_sigcontext(struct task_struct *tsk, sigset_
 
 	/* copy the GPRs */
 	unsafe_copy_from_user(regs->gpr, sc->gp_regs, sizeof(regs->gpr), efault_out);
-	unsafe_get_user(regs->nip, &sc->gp_regs[PT_NIP], efault_out);
+	unsafe_get_user(nip, &sc->gp_regs[PT_NIP], efault_out);
+	nip &= ~3UL;
+	regs_set_return_ip(regs, nip);
 	/* get MSR separately, transfer the LE bit if doing signal return */
 	unsafe_get_user(msr, &sc->gp_regs[PT_MSR], efault_out);
 	if (sig)
@@ -434,7 +436,7 @@  static long restore_tm_sigcontexts(struct task_struct *tsk,
 	elf_vrreg_t __user *v_regs, *tm_v_regs;
 #endif
 	unsigned long err = 0;
-	unsigned long msr;
+	unsigned long nip, msr;
 	struct pt_regs *regs = tsk->thread.regs;
 #ifdef CONFIG_VSX
 	int i;
@@ -458,8 +460,13 @@  static long restore_tm_sigcontexts(struct task_struct *tsk,
 	 * For the case of getting a signal and simply returning from it,
 	 * we don't need to re-copy them here.
 	 */
-	err |= __get_user(regs->nip, &tm_sc->gp_regs[PT_NIP]);
-	err |= __get_user(tsk->thread.tm_tfhar, &sc->gp_regs[PT_NIP]);
+	err |= __get_user(nip, &tm_sc->gp_regs[PT_NIP]);
+	nip &= ~3UL;
+	regs_set_return_ip(regs, nip);
+
+	err |= __get_user(nip, &sc->gp_regs[PT_NIP]);
+	nip &= ~3UL;
+	tsk->thread.tm_tfhar = nip;
 
 	/* get MSR separately, transfer the LE bit if doing signal return */
 	err |= __get_user(msr, &sc->gp_regs[PT_MSR]);