Patch "MIPS: Prevent unaligned accesses during stack unwinding" has been added to the 4.4-stable tree
Subsystems (2)
This is a note to let you know that I've just added the patch titled
MIPS: Prevent unaligned accesses during stack unwinding
to the 4.4-stable tree which can be found at:
http://www.kernel.org/git/?p=linux/kernel/git/stable/stable-queue.git;a=summary
The filename of the patch is:
mips-prevent-unaligned-accesses-during-stack-unwinding.patch
and it can be found in the queue-4.4 subdirectory.
If you, or anyone else, feels it should not be added to the stable tree, please let <[email protected]> know about it.
Quoted 1 line
From
a3552dace7d1d0cabf573e88fc3025cb90c4a601Mon Sep 17 00:00:00 2001
From: Paul Burton <[email protected]>
Date: Mon, 7 Nov 2016 15:07:03 +0000
Subject: MIPS: Prevent unaligned accesses during stack unwinding
From: Paul Burton <[email protected]>
commit a3552dace7d1d0cabf573e88fc3025cb90c4a601 upstream.
During stack unwinding we call a number of functions to determine what type of instruction we're looking at. The union mips_instruction pointer provided to them may be pointing at a 2 byte, but not 4 byte, aligned address & we thus cannot directly access the 4 byte wide members of the union mips_instruction. To avoid this is_ra_save_ins() copies the required half-words of the microMIPS instruction to a correctly aligned union mips_instruction on the stack, which it can then access safely. The is_jump_ins() & is_sp_move_ins() functions do not correctly perform this temporary copy, and instead attempt to directly dereference 4 byte fields which may be misaligned and lead to an address exception.
Fix this by copying the instruction halfwords to a temporary union mips_instruction in get_frame_info() such that we can provide a 4 byte aligned union mips_instruction to the is_*_ins() functions and they do not need to deal with misalignment themselves.
Patchwork: https://patchwork.linux-mips.org/patch/14529/
--- arch/mips/kernel/process.c | 70 ++++++++++++++++++++++----------------------- 1 file changed, 35 insertions(+), 35 deletions(-)
arch/mips/kernel/process.c +35 -35
@@ -194,8 +194,6 @@ struct mips_frame_info {static inline int is_ra_save_ins (union mips_instruction *ip) {#ifdef CONFIG_CPU_MICROMIPS -union mips_instruction mmi; -/* * swsp ra,offset * swm16 reglist,offset(sp)
@@ -205,23 +203,20 @@ static inline int is_ra_save_ins(union m* * microMIPS is way more fun... */ -if (mm_insn_16bit (ip->halfword[0 ])) { - mmi.word = (ip->halfword[0 ] <<16 ); -return (mmi.mm16_r5_format.opcode == mm_swsp16_op && - mmi.mm16_r5_format.rt ==31 ) || - (mmi.mm16_m_format.opcode == mm_pool16c_op && - mmi.mm16_m_format.func == mm_swm16_op); +if (mm_insn_16bit (ip->halfword[1 ])) { +return (ip->mm16_r5_format.opcode == mm_swsp16_op && + ip->mm16_r5_format.rt ==31 ) || + (ip->mm16_m_format.opcode == mm_pool16c_op && + ip->mm16_m_format.func == mm_swm16_op); }else { - mmi.halfword[0 ] = ip->halfword[1 ]; - mmi.halfword[1 ] = ip->halfword[0 ]; -return (mmi.mm_m_format.opcode == mm_pool32b_op && - mmi.mm_m_format.rd >9 && - mmi.mm_m_format.base ==29 && - mmi.mm_m_format.func == mm_swm32_func) || - (mmi.i_format.opcode == mm_sw32_op && - mmi.i_format.rs ==29 && - mmi.i_format.rt ==31 ); +return (ip->mm_m_format.opcode == mm_pool32b_op && + ip->mm_m_format.rd >9 && + ip->mm_m_format.base ==29 && + ip->mm_m_format.func == mm_swm32_func) || + (ip->i_format.opcode == mm_sw32_op && + ip->i_format.rs ==29 && + ip->i_format.rt ==31 ); }#else /* sw / sd $ra, offset($sp) */
@@ -242,12 +237,8 @@ static inline int is_jump_ins(union mips* * microMIPS is kind of more fun... */ -union mips_instruction mmi; - - mmi.word = (ip->halfword[0 ] <<16 ); - -if ((mmi.mm16_r5_format.opcode == mm_pool16c_op && - (mmi.mm16_r5_format.rt & mm_jr16_op) == mm_jr16_op) || +if ((ip->mm16_r5_format.opcode == mm_pool16c_op && + (ip->mm16_r5_format.rt & mm_jr16_op) == mm_jr16_op) || ip->j_format.opcode == mm_jal32_op)return 1 ; if (ip->r_format.opcode != mm_pool32a_op ||
@@ -276,15 +267,13 @@ static inline int is_sp_move_ins(union m* * microMIPS is not more fun... */ -if (mm_insn_16bit (ip->halfword[0 ])) { -union mips_instruction mmi; - - mmi.word = (ip->halfword[0 ] <<16 ); -return (mmi.mm16_r3_format.opcode == mm_pool16d_op && - mmi.mm16_r3_format.simmediate && mm_addiusp_func) || - (mmi.mm16_r5_format.opcode == mm_pool16d_op && - mmi.mm16_r5_format.rt ==29 ); +if (mm_insn_16bit (ip->halfword[1 ])) { +return (ip->mm16_r3_format.opcode == mm_pool16d_op && + ip->mm16_r3_format.simmediate && mm_addiusp_func) || + (ip->mm16_r5_format.opcode == mm_pool16d_op && + ip->mm16_r5_format.rt ==29 ); } +return ip->mm_i_format.opcode == mm_addiu32_op && ip->mm_i_format.rt ==29 && ip->mm_i_format.rs ==29 ;#else
@@ -299,7 +288,8 @@ static inline int is_sp_move_ins(union mstatic int get_frame_info (struct mips_frame_info *info) { -union mips_instruction *ip; +bool is_mmips =IS_ENABLED (CONFIG_CPU_MICROMIPS ); +union mips_instruction insn, *ip;unsigned max_insns = info->func_size /sizeof (union mips_instruction );unsigned i;
@@ -315,11 +305,21 @@ static int get_frame_info(struct mips_fr max_insns =min (128U , max_insns);for (i =0 ; i < max_insns; i++, ip++) { +if (is_mmips &&mm_insn_16bit (ip->halfword[0 ])) { + insn.halfword[0 ] =0 ; + insn.halfword[1 ] = ip->halfword[0 ]; + }else if (is_mmips) { + insn.halfword[0 ] = ip->halfword[1 ]; + insn.halfword[1 ] = ip->halfword[0 ]; + }else { + insn.word = ip->word; + } -if (is_jump_ins (ip)) +if (is_jump_ins (&insn))break ; +if (!info->frame_size) { -if (is_sp_move_ins (ip)) +if (is_sp_move_ins (&insn)) {#ifdef CONFIG_CPU_MICROMIPS if (mm_insn_16bit (ip->halfword[0 ]))
@@ -342,7 +342,7 @@ static int get_frame_info(struct mips_fr }continue ; } -if (info->pc_offset ==-1 &&is_ra_save_ins (ip)) { +if (info->pc_offset ==-1 &&is_ra_save_ins (&insn)) { info->pc_offset = ip->i_format.simmediate /sizeof (long );break ;
Patches currently in stable-queue which might be from [email protected] are
queue-4.4/mips-calculate-micromips-ra-properly-when-unwinding-the-stack.patch queue-4.4/mips-fix-get_frame_info-handling-of-micromips-function-size.patch queue-4.4/mips-handle-micromips-jumps-in-the-same-way-as-mips32-mips64-jumps.patch queue-4.4/mips-fix-is_jump_ins-handling-of-16b-micromips-instructions.patch queue-4.4/mips-clear-isa-bit-correctly-in-get_frame_info.patch queue-4.4/mips-prevent-unaligned-accesses-during-stack-unwinding.patch