diff mbox series

[v2,14/14] powerpc: Implement UACCESS validation on PPC32

Message ID be282f27ad808418c7475b51a00b4cb035f89a95.1687430631.git.christophe.leroy@csgroup.eu (mailing list archive)
State Superseded
Headers show
Series powerpc/objtool: uaccess validation for PPC32 (v2) | expand

Commit Message

Christophe Leroy June 22, 2023, 10:54 a.m. UTC
In order to implement UACCESS validation, objtool support
for powerpc needs to be enhanced to decode more instructions.

It also requires implementation of switch tables finding.
On PPC32 it is similar to x86, switch tables are anonymous in .rodata,
the difference is that the value is relative to its index in the table.

Then comes the UACCESS enabling/disabling instructions. On booke and
8xx it is done with a mtspr instruction. For 8xx that's in SPRN_MD_AP,
for booke that's in SPRN_PID. Annotate those instructions.

For book3s/32 that's a bit more complex and left aside for the moment.

No work has been done for ASM files, they are not used for UACCESS
so for the moment just tell objtool to ignore ASM files.

For relocable code, the .got2 relocation preceding each global
function needs to be marked as ignored because some versions of GCC
do this:

			120: R_PPC_REL32	.got2+0x7ff0

00000124 <tohex>:
     124:	94 21 ff f0 	stwu    r1,-16(r1)
     128:	7c 08 02 a6 	mflr    r0
     12c:	42 9f 00 05 	bcl     20,4*cr7+so,130 <tohex+0xc>
     130:	39 00 00 00 	li      r8,0
     134:	39 20 00 08 	li      r9,8
     138:	93 c1 00 08 	stw     r30,8(r1)
     13c:	7f c8 02 a6 	mflr    r30
     140:	90 01 00 14 	stw     r0,20(r1)
     144:	80 1e ff f0 	lwz     r0,-16(r30)
     148:	7f c0 f2 14 	add     r30,r0,r30
     14c:	81 5e 80 00 	lwz     r10,-32768(r30)
     150:	80 fe 80 04 	lwz     r7,-32764(r30)

While other versions do that:

00000120 <tohex>:
     120:	94 21 ff f0 	stwu    r1,-16(r1)
     124:	7c 08 02 a6 	mflr    r0
     128:	42 9f 00 05 	bcl     20,4*cr7+so,12c <tohex+0xc>
     12c:	39 00 00 00 	li      r8,0
     130:	39 20 00 08 	li      r9,8
     134:	93 c1 00 08 	stw     r30,8(r1)
     138:	7f c8 02 a6 	mflr    r30
     13c:	3f de 00 00 	addis   r30,r30,0
			13e: R_PPC_REL16_HA	.got2+0x8012
     140:	90 01 00 14 	stw     r0,20(r1)
     144:	3b de 00 00 	addi    r30,r30,0
			146: R_PPC_REL16_LO	.got2+0x801a
     148:	81 5e 80 00 	lwz     r10,-32768(r30)
     14c:	80 fe 80 04 	lwz     r7,-32764(r30)

Also declare longjmp() and start_secondary_resume() as global noreturn
functions, and declare __copy_tofrom_user() and __arch_clear_user()
as UACCESS safe.

Signed-off-by: Christophe Leroy <christophe.leroy@csgroup.eu>
---
 arch/powerpc/Kconfig                         |  2 +
 arch/powerpc/include/asm/kup.h               | 12 +++
 arch/powerpc/include/asm/nohash/32/kup-8xx.h |  8 +-
 arch/powerpc/include/asm/nohash/kup-booke.h  |  8 +-
 arch/powerpc/kexec/core_32.c                 |  4 +-
 tools/objtool/arch/powerpc/decode.c          | 82 ++++++++++++++++++--
 tools/objtool/arch/powerpc/special.c         | 42 +++++++++-
 tools/objtool/check.c                        |  5 ++
 8 files changed, 148 insertions(+), 15 deletions(-)

Comments

Peter Zijlstra June 22, 2023, 11:56 a.m. UTC | #1
On Thu, Jun 22, 2023 at 12:54:36PM +0200, Christophe Leroy wrote:

> diff --git a/tools/objtool/check.c b/tools/objtool/check.c
> index f850ab892ad5..8ac5711a055f 100644
> --- a/tools/objtool/check.c
> +++ b/tools/objtool/check.c
> @@ -218,6 +218,7 @@ static bool __dead_end_function(struct objtool_file *file, struct symbol *func,
>  		"kthread_exit",
>  		"kunit_try_catch_throw",
>  		"lbug_with_loc",
> +		"longjmp",
>  		"machine_real_restart",
>  		"make_task_dead",
>  		"mpt_halt_firmware",
> @@ -230,7 +231,9 @@ static bool __dead_end_function(struct objtool_file *file, struct symbol *func,
>  		"sev_es_terminate",
>  		"snp_abort",
>  		"start_kernel",
> +		"start_secondary_resume",
>  		"stop_this_cpu",
> +		"unrecoverable_exception",
>  		"usercopy_abort",
>  		"x86_64_start_kernel",
>  		"x86_64_start_reservations",

Someone went and changed all that in tip/objtool/core :-)

But perhaps, like the uaccess_safe_builtins[] array below, should we
start marking sections so we can remember where stuff comes from later?

> @@ -1335,6 +1338,8 @@ static const char *uaccess_safe_builtin[] = {
>  	"rep_stos_alternative",
>  	"rep_movs_alternative",
>  	"__copy_user_nocache",
> +	"__copy_tofrom_user",
> +	"__arch_clear_user",
>  	NULL
>  };

Do we want to rename the 'misc' sectino to 'x86' and start a 'ppc32'
section there?
kernel test robot June 22, 2023, 7:16 p.m. UTC | #2
Hi Christophe,

kernel test robot noticed the following build warnings:

[auto build test WARNING on powerpc/next]
[also build test WARNING on powerpc/fixes masahiroy-kbuild/for-next masahiroy-kbuild/fixes linus/master v6.4-rc7]
[cannot apply to next-20230622]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]

url:    https://github.com/intel-lab-lkp/linux/commits/Christophe-Leroy/powerpc-kuap-Avoid-unnecessary-reads-of-MD_AP/20230622-185950
base:   https://git.kernel.org/pub/scm/linux/kernel/git/powerpc/linux.git next
patch link:    https://lore.kernel.org/r/be282f27ad808418c7475b51a00b4cb035f89a95.1687430631.git.christophe.leroy%40csgroup.eu
patch subject: [PATCH v2 14/14] powerpc: Implement UACCESS validation on PPC32
config: powerpc-randconfig-r025-20230622 (https://download.01.org/0day-ci/archive/20230623/202306230353.iPqv57lK-lkp@intel.com/config)
compiler: powerpc-linux-gcc (GCC) 12.3.0
reproduce: (https://download.01.org/0day-ci/archive/20230623/202306230353.iPqv57lK-lkp@intel.com/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202306230353.iPqv57lK-lkp@intel.com/

All warnings (new ones prefixed by >>):

   lib/ubsan.c:307:6: warning: no previous prototype for '__ubsan_handle_type_mismatch' [-Wmissing-prototypes]
     307 | void __ubsan_handle_type_mismatch(struct type_mismatch_data *data,
         |      ^~~~~~~~~~~~~~~~~~~~~~~~~~~~
>> lib/ubsan.o: warning: objtool: ubsan_type_mismatch_common+0x24: UACCESS-safe disables UACCESS
   lib/ubsan.o: warning: objtool: __ubsan_handle_type_mismatch+0x54: call to _restgpr_30_x() with UACCESS enabled
   lib/ubsan.o: warning: objtool: __ubsan_handle_type_mismatch_v1+0x5c: call to _restgpr_30_x() with UACCESS enabled
   lib/ubsan.o: warning: objtool: __ubsan_handle_load_invalid_value+0x28: call to memset() with UACCESS enabled
   lib/ubsan.o: warning: objtool: __ubsan_handle_shift_out_of_bounds+0x34: call to memset() with UACCESS enabled
--
>> arch/powerpc/kernel/ptrace/ptrace-view.o: warning: objtool: gpr32_set_common+0x2b8: redundant UACCESS disable


objdump-func vmlinux.o ubsan_type_mismatch_common:
0000 00000000 <ubsan_type_mismatch_common>:
0000    0:	94 21 ff e0 	stwu    r1,-32(r1)
0004    4:	7c 08 02 a6 	mflr    r0
0008    8:	bf 61 00 0c 	stmw    r27,12(r1)
000c    c:	7c 7f 1b 78 	mr      r31,r3
0010   10:	90 01 00 24 	stw     r0,36(r1)
0014   14:	7c 9e 23 78 	mr      r30,r4
0018   18:	48 00 00 01 	bl      18 <ubsan_type_mismatch_common+0x18>	18: R_PPC_REL24	__sanitizer_cov_trace_pc
001c   1c:	7f 90 0a a6 	mfpid   r28
0020   20:	39 20 00 00 	li      r9,0
0024   24:	7d 30 0b a6 	mtpid   r9
0028   28:	4c 00 01 2c 	isync
002c   2c:	2c 1e 00 00 	cmpwi   r30,0
0030   30:	40 e2 00 58 	bne+    88 <ubsan_type_mismatch_common+0x88>
0034   34:	48 00 00 01 	bl      34 <ubsan_type_mismatch_common+0x34>	34: R_PPC_REL24	__sanitizer_cov_trace_pc
0038   38:	80 7f 00 00 	lwz     r3,0(r31)
003c   3c:	48 00 00 01 	bl      3c <ubsan_type_mismatch_common+0x3c>	3c: R_PPC_REL24	.text.suppress_report
0040   40:	2c 03 00 00 	cmpwi   r3,0
0044   44:	40 e2 01 30 	bne+    174 <ubsan_type_mismatch_common+0x174>
0048   48:	48 00 00 01 	bl      48 <ubsan_type_mismatch_common+0x48>	48: R_PPC_REL24	__sanitizer_cov_trace_pc
004c   4c:	80 7f 00 00 	lwz     r3,0(r31)
0050   50:	3c 80 00 00 	lis     r4,0	52: R_PPC_ADDR16_HA	.rodata.ubsan_type_mismatch_common.str1.1
0054   54:	38 84 00 00 	addi    r4,r4,0	56: R_PPC_ADDR16_LO	.rodata.ubsan_type_mismatch_common.str1.1
0058   58:	48 00 00 01 	bl      58 <ubsan_type_mismatch_common+0x58>	58: R_PPC_REL24	.text.unlikely.ubsan_prologue
005c   5c:	89 3f 00 0c 	lbz     r9,12(r31)
0060   60:	3d 40 00 00 	lis     r10,0	62: R_PPC_ADDR16_HA	.rodata.type_check_kinds
0064   64:	80 bf 00 04 	lwz     r5,4(r31)
0068   68:	39 4a 00 00 	addi    r10,r10,0	6a: R_PPC_ADDR16_LO	.rodata.type_check_kinds
006c   6c:	55 29 10 3a 	slwi    r9,r9,2
0070   70:	7c 8a 48 2e 	lwzx    r4,r10,r9
0074   74:	3c 60 00 00 	lis     r3,0	76: R_PPC_ADDR16_HA	.rodata.ubsan_type_mismatch_common.str1.1+0xf
0078   78:	38 a5 00 04 	addi    r5,r5,4
007c   7c:	38 63 00 00 	addi    r3,r3,0	7e: R_PPC_ADDR16_LO	.rodata.ubsan_type_mismatch_common.str1.1+0xf
0080   80:	48 00 00 01 	bl      80 <ubsan_type_mismatch_common+0x80>	80: R_PPC_REL24	_printk
0084   84:	48 00 00 ec 	b       170 <ubsan_type_mismatch_common+0x170>
0088   88:	48 00 00 01 	bl      88 <ubsan_type_mismatch_common+0x88>	88: R_PPC_REL24	__sanitizer_cov_trace_pc
008c   8c:	83 bf 00 08 	lwz     r29,8(r31)
0090   90:	83 7f 00 00 	lwz     r27,0(r31)
0094   94:	2c 1d 00 00 	cmpwi   r29,0
0098   98:	41 c2 00 78 	beq-    110 <ubsan_type_mismatch_common+0x110>
009c   9c:	3b bd ff ff 	addi    r29,r29,-1
00a0   a0:	48 00 00 01 	bl      a0 <ubsan_type_mismatch_common+0xa0>	a0: R_PPC_REL24	__sanitizer_cov_trace_pc
00a4   a4:	7f bd f0 39 	and.    r29,r29,r30
00a8   a8:	41 e2 00 68 	beq+    110 <ubsan_type_mismatch_common+0x110>
00ac   ac:	48 00 00 01 	bl      ac <ubsan_type_mismatch_common+0xac>	ac: R_PPC_REL24	__sanitizer_cov_trace_pc
00b0   b0:	7f 63 db 78 	mr      r3,r27
00b4   b4:	48 00 00 01 	bl      b4 <ubsan_type_mismatch_common+0xb4>	b4: R_PPC_REL24	.text.suppress_report
00b8   b8:	2c 03 00 00 	cmpwi   r3,0
00bc   bc:	40 e2 00 b8 	bne+    174 <ubsan_type_mismatch_common+0x174>
00c0   c0:	48 00 00 01 	bl      c0 <ubsan_type_mismatch_common+0xc0>	c0: R_PPC_REL24	__sanitizer_cov_trace_pc
00c4   c4:	80 7f 00 00 	lwz     r3,0(r31)
00c8   c8:	3c 80 00 00 	lis     r4,0	ca: R_PPC_ADDR16_HA	.rodata.ubsan_type_mismatch_common.str1.1+0x2d
00cc   cc:	38 84 00 00 	addi    r4,r4,0	ce: R_PPC_ADDR16_LO	.rodata.ubsan_type_mismatch_common.str1.1+0x2d
00d0   d0:	48 00 00 01 	bl      d0 <ubsan_type_mismatch_common+0xd0>	d0: R_PPC_REL24	.text.unlikely.ubsan_prologue
00d4   d4:	89 3f 00 0c 	lbz     r9,12(r31)
00d8   d8:	3d 40 00 00 	lis     r10,0	da: R_PPC_ADDR16_HA	.rodata.type_check_kinds
00dc   dc:	80 df 00 04 	lwz     r6,4(r31)
00e0   e0:	39 4a 00 00 	addi    r10,r10,0	e2: R_PPC_ADDR16_LO	.rodata.type_check_kinds
00e4   e4:	55 29 10 3a 	slwi    r9,r9,2
00e8   e8:	7c 8a 48 2e 	lwzx    r4,r10,r9
00ec   ec:	3c 60 00 00 	lis     r3,0	ee: R_PPC_ADDR16_HA	.rodata.ubsan_type_mismatch_common.str1.1+0x3f
00f0   f0:	38 c6 00 04 	addi    r6,r6,4
00f4   f4:	7f c5 f3 78 	mr      r5,r30
00f8   f8:	38 63 00 00 	addi    r3,r3,0	fa: R_PPC_ADDR16_LO	.rodata.ubsan_type_mismatch_common.str1.1+0x3f
00fc   fc:	48 00 00 01 	bl      fc <ubsan_type_mismatch_common+0xfc>	fc: R_PPC_REL24	_printk
0100  100:	3c 60 00 00 	lis     r3,0	102: R_PPC_ADDR16_HA	.rodata.ubsan_type_mismatch_common.str1.1+0x67
0104  104:	80 9f 00 08 	lwz     r4,8(r31)
0108  108:	38 63 00 00 	addi    r3,r3,0	10a: R_PPC_ADDR16_LO	.rodata.ubsan_type_mismatch_common.str1.1+0x67
010c  10c:	48 00 00 60 	b       16c <ubsan_type_mismatch_common+0x16c>
0110  110:	48 00 00 01 	bl      110 <ubsan_type_mismatch_common+0x110>	110: R_PPC_REL24	__sanitizer_cov_trace_pc
0114  114:	7f 63 db 78 	mr      r3,r27
0118  118:	48 00 00 01 	bl      118 <ubsan_type_mismatch_common+0x118>	118: R_PPC_REL24	.text.suppress_report
011c  11c:	2c 03 00 00 	cmpwi   r3,0
0120  120:	40 e2 00 54 	bne+    174 <ubsan_type_mismatch_common+0x174>
0124  124:	48 00 00 01 	bl      124 <ubsan_type_mismatch_common+0x124>	124: R_PPC_REL24	__sanitizer_cov_trace_pc
0128  128:	80 7f 00 00 	lwz     r3,0(r31)
012c  12c:	3c 80 00 00 	lis     r4,0	12e: R_PPC_ADDR16_HA	.rodata.ubsan_type_mismatch_common.str1.1+0x8c
0130  130:	38 84 00 00 	addi    r4,r4,0	132: R_PPC_ADDR16_LO	.rodata.ubsan_type_mismatch_common.str1.1+0x8c
0134  134:	48 00 00 01 	bl      134 <ubsan_type_mismatch_common+0x134>	134: R_PPC_REL24	.text.unlikely.ubsan_prologue
0138  138:	89 3f 00 0c 	lbz     r9,12(r31)
013c  13c:	3d 40 00 00 	lis     r10,0	13e: R_PPC_ADDR16_HA	.rodata.type_check_kinds
0140  140:	39 4a 00 00 	addi    r10,r10,0	142: R_PPC_ADDR16_LO	.rodata.type_check_kinds
0144  144:	55 29 10 3a 	slwi    r9,r9,2
0148  148:	3c 60 00 00 	lis     r3,0	14a: R_PPC_ADDR16_HA	.rodata.ubsan_type_mismatch_common.str1.1+0xa1
014c  14c:	7c 8a 48 2e 	lwzx    r4,r10,r9
0150  150:	7f c5 f3 78 	mr      r5,r30
0154  154:	38 63 00 00 	addi    r3,r3,0	156: R_PPC_ADDR16_LO	.rodata.ubsan_type_mismatch_common.str1.1+0xa1
0158  158:	48 00 00 01 	bl      158 <ubsan_type_mismatch_common+0x158>	158: R_PPC_REL24	_printk
015c  15c:	80 9f 00 04 	lwz     r4,4(r31)
0160  160:	3c 60 00 00 	lis     r3,0	162: R_PPC_ADDR16_HA	.rodata.ubsan_type_mismatch_common.str1.1+0xca
0164  164:	38 63 00 00 	addi    r3,r3,0	166: R_PPC_ADDR16_LO	.rodata.ubsan_type_mismatch_common.str1.1+0xca
0168  168:	38 84 00 04 	addi    r4,r4,4
016c  16c:	48 00 00 01 	bl      16c <ubsan_type_mismatch_common+0x16c>	16c: R_PPC_REL24	_printk
0170  170:	48 00 00 01 	bl      170 <ubsan_type_mismatch_common+0x170>	170: R_PPC_REL24	.text.unlikely.ubsan_epilogue
0174  174:	48 00 00 01 	bl      174 <ubsan_type_mismatch_common+0x174>	174: R_PPC_REL24	__sanitizer_cov_trace_pc
0178  178:	2c 1c 00 00 	cmpwi   r28,0
017c  17c:	41 e2 00 14 	beq+    190 <ubsan_type_mismatch_common+0x190>
0180  180:	48 00 00 01 	bl      180 <ubsan_type_mismatch_common+0x180>	180: R_PPC_REL24	__sanitizer_cov_trace_pc
0184  184:	81 22 0e b4 	lwz     r9,3764(r2)
0188  188:	7d 30 0b a6 	mtpid   r9
018c  18c:	4c 00 01 2c 	isync
0190  190:	80 01 00 24 	lwz     r0,36(r1)
0194  194:	83 61 00 0c 	lwz     r27,12(r1)
0198  198:	83 81 00 10 	lwz     r28,16(r1)
019c  19c:	83 a1 00 14 	lwz     r29,20(r1)
01a0  1a0:	7c 08 03 a6 	mtlr    r0
01a4  1a4:	83 c1 00 18 	lwz     r30,24(r1)
01a8  1a8:	83 e1 00 1c 	lwz     r31,28(r1)
01ac  1ac:	38 21 00 20 	addi    r1,r1,32
01b0  1b0:	48 00 00 00 	b       1b0 <ubsan_type_mismatch_common+0x1b0>	1b0: R_PPC_REL24	__sanitizer_cov_trace_pc
kernel test robot June 22, 2023, 8:07 p.m. UTC | #3
Hi Christophe,

kernel test robot noticed the following build warnings:

[auto build test WARNING on powerpc/next]
[also build test WARNING on powerpc/fixes masahiroy-kbuild/for-next masahiroy-kbuild/fixes linus/master v6.4-rc7]
[cannot apply to next-20230622]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]

url:    https://github.com/intel-lab-lkp/linux/commits/Christophe-Leroy/powerpc-kuap-Avoid-unnecessary-reads-of-MD_AP/20230622-185950
base:   https://git.kernel.org/pub/scm/linux/kernel/git/powerpc/linux.git next
patch link:    https://lore.kernel.org/r/be282f27ad808418c7475b51a00b4cb035f89a95.1687430631.git.christophe.leroy%40csgroup.eu
patch subject: [PATCH v2 14/14] powerpc: Implement UACCESS validation on PPC32
config: powerpc-allmodconfig (https://download.01.org/0day-ci/archive/20230623/202306230351.SpwvWyz3-lkp@intel.com/config)
compiler: powerpc-linux-gcc (GCC) 12.3.0
reproduce: (https://download.01.org/0day-ci/archive/20230623/202306230351.SpwvWyz3-lkp@intel.com/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202306230351.SpwvWyz3-lkp@intel.com/

All warnings (new ones prefixed by >>):

   arch/powerpc/platforms/powermac/smp.c:416:13: warning: no previous prototype for 'smp_psurge_take_timebase' [-Wmissing-prototypes]
     416 | void __init smp_psurge_take_timebase(void)
         |             ^~~~~~~~~~~~~~~~~~~~~~~~
   arch/powerpc/platforms/powermac/smp.c:432:13: warning: no previous prototype for 'smp_psurge_give_timebase' [-Wmissing-prototypes]
     432 | void __init smp_psurge_give_timebase(void)
         |             ^~~~~~~~~~~~~~~~~~~~~~~~
>> arch/powerpc/platforms/powermac/smp.o: warning: objtool: .text.pmac_cpu_offline_self: unexpected end of section
Christophe Leroy June 23, 2023, 4:03 p.m. UTC | #4
Le 22/06/2023 à 13:56, Peter Zijlstra a écrit :
> On Thu, Jun 22, 2023 at 12:54:36PM +0200, Christophe Leroy wrote:
> 
>> diff --git a/tools/objtool/check.c b/tools/objtool/check.c
>> index f850ab892ad5..8ac5711a055f 100644
>> --- a/tools/objtool/check.c
>> +++ b/tools/objtool/check.c
>> @@ -218,6 +218,7 @@ static bool __dead_end_function(struct objtool_file *file, struct symbol *func,
>>   		"kthread_exit",
>>   		"kunit_try_catch_throw",
>>   		"lbug_with_loc",
>> +		"longjmp",
>>   		"machine_real_restart",
>>   		"make_task_dead",
>>   		"mpt_halt_firmware",
>> @@ -230,7 +231,9 @@ static bool __dead_end_function(struct objtool_file *file, struct symbol *func,
>>   		"sev_es_terminate",
>>   		"snp_abort",
>>   		"start_kernel",
>> +		"start_secondary_resume",
>>   		"stop_this_cpu",
>> +		"unrecoverable_exception",
>>   		"usercopy_abort",
>>   		"x86_64_start_kernel",
>>   		"x86_64_start_reservations",
> 
> Someone went and changed all that in tip/objtool/core :-)
> 
> But perhaps, like the uaccess_safe_builtins[] array below, should we
> start marking sections so we can remember where stuff comes from later?

Or, now that it is a H file, maybe each arch could have its own H file 
for arch specific functions ? Then we'd get:

diff --git a/tools/objtool/arch/powerpc/include/arch/noreturns.h 
b/tools/objtool/arch/powerpc/include/arch/noreturns.h
new file mode 100644
index 000000000000..664f17d39026
--- /dev/null
+++ b/tools/objtool/arch/powerpc/include/arch/noreturns.h
@@ -0,0 +1,11 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+/*
+ * This is a (sorted!) list of all known __noreturn functions in 
arch/powerpc.
+ * It's needed for objtool to properly reverse-engineer the control 
flow graph.
+ *
+ * Yes, this is unfortunate.  A better solution is in the works.
+ */
+NORETURN(longjmp)
+NORETURN(start_secondary_resume)
+NORETURN(unrecoverable_exception)
diff --git a/tools/objtool/noreturns.h b/tools/objtool/noreturns.h
index 1514e84d5cc4..f725ed37532d 100644
--- a/tools/objtool/noreturns.h
+++ b/tools/objtool/noreturns.h
@@ -1,5 +1,7 @@
  /* SPDX-License-Identifier: GPL-2.0 */

+#include <arch/noreturns.h>
+
  /*
   * This is a (sorted!) list of all known __noreturn functions in the 
kernel.
   * It's needed for objtool to properly reverse-engineer the control 
flow graph.


> 
>> @@ -1335,6 +1338,8 @@ static const char *uaccess_safe_builtin[] = {
>>   	"rep_stos_alternative",
>>   	"rep_movs_alternative",
>>   	"__copy_user_nocache",
>> +	"__copy_tofrom_user",
>> +	"__arch_clear_user",
>>   	NULL
>>   };
> 
> Do we want to rename the 'misc' sectino to 'x86' and start a 'ppc32'
> section there?
> 

Sure.

Then that would look like:

diff --git a/tools/objtool/check.c b/tools/objtool/check.c
index 2b61f8180bea..2d564d0e2ae1 100644
--- a/tools/objtool/check.c
+++ b/tools/objtool/check.c
@@ -1259,13 +1259,15 @@ static const char *uaccess_safe_builtin[] = {
  	"stackleak_track_stack",
  	/* misc */
  	"csum_partial_copy_generic",
+	"ftrace_likely_update", /* CONFIG_TRACE_BRANCH_PROFILING */
+	/* misc x86 */
  	"copy_mc_fragile",
  	"copy_mc_fragile_handle_tail",
  	"copy_mc_enhanced_fast_string",
-	"ftrace_likely_update", /* CONFIG_TRACE_BRANCH_PROFILING */
  	"rep_stos_alternative",
  	"rep_movs_alternative",
  	"__copy_user_nocache",
+	/* misc powerpc */
  	"__copy_tofrom_user",
  	"__arch_clear_user",
  	NULL
diff mbox series

Patch

diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig
index 8b955bc7b59f..8b613e520143 100644
--- a/arch/powerpc/Kconfig
+++ b/arch/powerpc/Kconfig
@@ -160,6 +160,7 @@  config PPC
 	select ARCH_KEEP_MEMBLOCK
 	select ARCH_MIGHT_HAVE_PC_PARPORT
 	select ARCH_MIGHT_HAVE_PC_SERIO
+	select ARCH_OBJTOOL_SKIP_ASM
 	select ARCH_OPTIONAL_KERNEL_RWX		if ARCH_HAS_STRICT_KERNEL_RWX
 	select ARCH_OPTIONAL_KERNEL_RWX_DEFAULT
 	select ARCH_SPLIT_ARG64			if PPC32
@@ -258,6 +259,7 @@  config PPC
 	select HAVE_OPTPROBES
 	select HAVE_OBJTOOL			if PPC32 || MPROFILE_KERNEL
 	select HAVE_OBJTOOL_MCOUNT		if HAVE_OBJTOOL
+	select HAVE_UACCESS_VALIDATION		if HAVE_OBJTOOL && PPC_KUAP && PPC32
 	select HAVE_PERF_EVENTS
 	select HAVE_PERF_EVENTS_NMI		if PPC64
 	select HAVE_PERF_REGS
diff --git a/arch/powerpc/include/asm/kup.h b/arch/powerpc/include/asm/kup.h
index 132f1c7e1064..9f824cb93d8a 100644
--- a/arch/powerpc/include/asm/kup.h
+++ b/arch/powerpc/include/asm/kup.h
@@ -10,6 +10,8 @@ 
 #include <linux/types.h>
 
 static __always_inline bool kuap_is_disabled(void);
+static __always_inline void mtspr_uaccess_begin(int rn, unsigned long val);
+static __always_inline void mtspr_uaccess_end(int rn, unsigned long val);
 #endif
 
 #ifdef CONFIG_PPC_BOOK3S_64
@@ -222,6 +224,16 @@  static __always_inline void prevent_current_write_to_user(void)
 	prevent_user_access(KUAP_WRITE);
 }
 
+static __always_inline void mtspr_uaccess_begin(int rn, unsigned long val)
+{
+	asm(ASM_UACCESS_BEGIN "mtspr %0, %1\n\t" : : "i"(rn), "r"(val) : "memory");
+}
+
+static __always_inline void mtspr_uaccess_end(int rn, unsigned long val)
+{
+	asm(ASM_UACCESS_END "mtspr %0, %1\n\t" : : "i"(rn), "r"(val) : "memory");
+}
+
 #endif /* !__ASSEMBLY__ */
 
 #endif /* _ASM_POWERPC_KUAP_H_ */
diff --git a/arch/powerpc/include/asm/nohash/32/kup-8xx.h b/arch/powerpc/include/asm/nohash/32/kup-8xx.h
index 61067e4c8f22..9b59231d87c9 100644
--- a/arch/powerpc/include/asm/nohash/32/kup-8xx.h
+++ b/arch/powerpc/include/asm/nohash/32/kup-8xx.h
@@ -42,12 +42,12 @@  static __always_inline unsigned long __kuap_get_and_assert_locked(void)
 static __always_inline void __allow_user_access(void __user *to, const void __user *from,
 						unsigned long size, unsigned long dir)
 {
-	mtspr(SPRN_MD_AP, MD_APG_INIT);
+	mtspr_uaccess_begin(SPRN_MD_AP, MD_APG_INIT);
 }
 
 static __always_inline void __prevent_user_access(unsigned long dir)
 {
-	mtspr(SPRN_MD_AP, MD_APG_KUAP);
+	mtspr_uaccess_end(SPRN_MD_AP, MD_APG_KUAP);
 }
 
 static __always_inline unsigned long __prevent_user_access_return(void)
@@ -56,14 +56,14 @@  static __always_inline unsigned long __prevent_user_access_return(void)
 
 	flags = mfspr(SPRN_MD_AP);
 
-	mtspr(SPRN_MD_AP, MD_APG_KUAP);
+	mtspr_uaccess_end(SPRN_MD_AP, MD_APG_KUAP);
 
 	return flags;
 }
 
 static __always_inline void __restore_user_access(unsigned long flags)
 {
-	mtspr(SPRN_MD_AP, flags);
+	mtspr_uaccess_begin(SPRN_MD_AP, flags);
 }
 
 static __always_inline bool
diff --git a/arch/powerpc/include/asm/nohash/kup-booke.h b/arch/powerpc/include/asm/nohash/kup-booke.h
index 416f3e0897d5..2967501c434e 100644
--- a/arch/powerpc/include/asm/nohash/kup-booke.h
+++ b/arch/powerpc/include/asm/nohash/kup-booke.h
@@ -64,13 +64,13 @@  static __always_inline unsigned long __kuap_get_and_assert_locked(void)
 static __always_inline void __allow_user_access(void __user *to, const void __user *from,
 						unsigned long size, unsigned long dir)
 {
-	mtspr(SPRN_PID, current->thread.pid);
+	mtspr_uaccess_begin(SPRN_PID, current->thread.pid);
 	isync();
 }
 
 static __always_inline void __prevent_user_access(unsigned long dir)
 {
-	mtspr(SPRN_PID, 0);
+	mtspr_uaccess_end(SPRN_PID, 0);
 	isync();
 }
 
@@ -78,7 +78,7 @@  static __always_inline unsigned long __prevent_user_access_return(void)
 {
 	unsigned long flags = mfspr(SPRN_PID);
 
-	mtspr(SPRN_PID, 0);
+	mtspr_uaccess_end(SPRN_PID, 0);
 	isync();
 
 	return flags;
@@ -87,7 +87,7 @@  static __always_inline unsigned long __prevent_user_access_return(void)
 static __always_inline void __restore_user_access(unsigned long flags)
 {
 	if (flags) {
-		mtspr(SPRN_PID, current->thread.pid);
+		mtspr_uaccess_begin(SPRN_PID, current->thread.pid);
 		isync();
 	}
 }
diff --git a/arch/powerpc/kexec/core_32.c b/arch/powerpc/kexec/core_32.c
index c95f96850c9e..6e955f32e7c3 100644
--- a/arch/powerpc/kexec/core_32.c
+++ b/arch/powerpc/kexec/core_32.c
@@ -17,7 +17,7 @@ 
 typedef void (*relocate_new_kernel_t)(
 				unsigned long indirection_page,
 				unsigned long reboot_code_buffer,
-				unsigned long start_address) __noreturn;
+				unsigned long start_address);
 
 /*
  * This is a generic machine_kexec function suitable at least for
@@ -61,6 +61,8 @@  void default_machine_kexec(struct kimage *image)
 	/* now call it */
 	rnk = (relocate_new_kernel_t) reboot_code_buffer;
 	(*rnk)(page_list, reboot_code_buffer_phys, image->start);
+
+	unreachable();	/* For objtool */
 }
 
 int machine_kexec_prepare(struct kimage *image)
diff --git a/tools/objtool/arch/powerpc/decode.c b/tools/objtool/arch/powerpc/decode.c
index 53b55690f320..2ed5241eb7be 100644
--- a/tools/objtool/arch/powerpc/decode.c
+++ b/tools/objtool/arch/powerpc/decode.c
@@ -43,24 +43,94 @@  int arch_decode_instruction(struct objtool_file *file, const struct section *sec
 			    unsigned long offset, unsigned int maxlen,
 			    struct instruction *insn)
 {
-	unsigned int opcode;
+	unsigned int opcode, xop;
+	unsigned int rs, ra, rb, bo, bi, to, uimm, simm, lk, aa;
 	enum insn_type typ;
 	unsigned long imm;
 	u32 ins;
 
+	if (file->elf->ehdr.e_flags & EF_PPC_RELOCATABLE_LIB) {
+		struct reloc *reloc;
+
+		reloc = find_reloc_by_dest_range(file->elf, insn->sec, insn->offset, 4);
+
+		if (reloc && reloc->type == R_PPC_REL32 &&
+		    !strncmp(reloc->sym->sec->name, ".got2", 5)) {
+			insn->type = INSN_OTHER;
+			insn->ignore = true;
+			insn->len = 4;
+
+			return 0;
+		}
+	}
+
 	ins = bswap_if_needed(file->elf, *(u32 *)(sec->data->d_buf + offset));
 	opcode = ins >> 26;
-	typ = INSN_OTHER;
-	imm = 0;
+	xop = (ins >> 1) & 0x3ff;
+	rs = bo = to = (ins >> 21) & 0x1f;
+	ra = bi = (ins >> 16) & 0x1f;
+	rb = (ins >> 11) & 0x1f;
+	uimm = simm = (ins >> 0) & 0xffff;
+	aa = ins & 2;
+	lk = ins & 1;
 
 	switch (opcode) {
+	case 3:
+		if (to == 31 && ra == 0 && simm == 0) /* twi 31, r0, 0 */
+			typ = INSN_BUG;
+		else
+			typ = INSN_OTHER;
+		break;
+	case 16: /* bc[l][a] */
+		if (lk)	/* bcl[a] */
+			typ = INSN_OTHER;
+		else		/* bc[a] */
+			typ = INSN_JUMP_CONDITIONAL;
+
+		imm = ins & 0xfffc;
+		if (imm & 0x8000)
+			imm -= 0x10000;
+		insn->immediate = imm | aa;
+		break;
 	case 18: /* b[l][a] */
-		if ((ins & 3) == 1) /* bl */
+		if (lk)	/* bl[a] */
 			typ = INSN_CALL;
+		else		/* b[a] */
+			typ = INSN_JUMP_UNCONDITIONAL;
 
 		imm = ins & 0x3fffffc;
 		if (imm & 0x2000000)
 			imm -= 0x4000000;
+		insn->immediate = imm | aa;
+		break;
+	case 19:
+		if (xop == 16 && bo == 20 && bi == 0)	/* blr */
+			typ = INSN_RETURN;
+		else if (xop == 16)	/* bclr */
+			typ = INSN_RETURN_CONDITIONAL;
+		else if (xop == 50)	/* rfi */
+			typ = INSN_JUMP_DYNAMIC;
+		else if (xop == 528 && bo == 20 && bi == 0 && !lk)	/* bctr */
+			typ = INSN_JUMP_DYNAMIC;
+		else if (xop == 528 && bo == 20 && bi == 0 && lk)	/* bctrl */
+			typ = INSN_CALL_DYNAMIC;
+		else
+			typ = INSN_OTHER;
+		break;
+	case 24:
+		if (rs == 0 && ra == 0 && uimm == 0)
+			typ = INSN_NOP;
+		else
+			typ = INSN_OTHER;
+		break;
+	case 31:
+		if (xop == 4 && to == 31 && ra == 0 && rb == 0) /* trap */
+			typ = INSN_BUG;
+		else
+			typ = INSN_OTHER;
+		break;
+	default:
+		typ = INSN_OTHER;
 		break;
 	}
 
@@ -70,13 +140,15 @@  int arch_decode_instruction(struct objtool_file *file, const struct section *sec
 		insn->len = 4;
 
 	insn->type = typ;
-	insn->immediate = imm;
 
 	return 0;
 }
 
 unsigned long arch_jump_destination(struct instruction *insn)
 {
+	if (insn->immediate & 2)
+		return insn->immediate & ~2;
+
 	return insn->offset + insn->immediate;
 }
 
diff --git a/tools/objtool/arch/powerpc/special.c b/tools/objtool/arch/powerpc/special.c
index 979b555b16ea..be37f4b455dc 100644
--- a/tools/objtool/arch/powerpc/special.c
+++ b/tools/objtool/arch/powerpc/special.c
@@ -15,5 +15,45 @@  bool arch_support_alt_relocation(struct special_alt *special_alt,
 struct reloc *arch_find_switch_table(struct objtool_file *file,
 				     struct instruction *insn, bool *is_rel)
 {
-	exit(-1);
+	struct reloc  *text_reloc, *rodata_reloc;
+	struct section *table_sec;
+	unsigned long table_offset;
+
+	/* look for a relocation which references .rodata */
+	text_reloc = find_reloc_by_dest_range(file->elf, insn->sec,
+					      insn->offset, insn->len);
+	if (!text_reloc || text_reloc->sym->type != STT_SECTION ||
+	    !text_reloc->sym->sec->rodata)
+		return NULL;
+
+	table_offset = text_reloc->addend;
+	table_sec = text_reloc->sym->sec;
+
+	/*
+	 * Make sure the .rodata address isn't associated with a
+	 * symbol.  GCC jump tables are anonymous data.
+	 *
+	 * Also support C jump tables which are in the same format as
+	 * switch jump tables.  For objtool to recognize them, they
+	 * need to be placed in the C_JUMP_TABLE_SECTION section.  They
+	 * have symbols associated with them.
+	 */
+	if (find_symbol_containing(table_sec, table_offset)) {
+		if (strcmp(table_sec->name, C_JUMP_TABLE_SECTION))
+			return NULL;
+		*is_rel = false;
+	} else {
+		*is_rel = true;
+	}
+
+	/*
+	 * Each table entry has a rela associated with it.  The rela
+	 * should reference text in the same function as the original
+	 * instruction.
+	 */
+	rodata_reloc = find_reloc_by_dest(file->elf, table_sec, table_offset);
+	if (!rodata_reloc)
+		return NULL;
+
+	return rodata_reloc;
 }
diff --git a/tools/objtool/check.c b/tools/objtool/check.c
index f850ab892ad5..8ac5711a055f 100644
--- a/tools/objtool/check.c
+++ b/tools/objtool/check.c
@@ -218,6 +218,7 @@  static bool __dead_end_function(struct objtool_file *file, struct symbol *func,
 		"kthread_exit",
 		"kunit_try_catch_throw",
 		"lbug_with_loc",
+		"longjmp",
 		"machine_real_restart",
 		"make_task_dead",
 		"mpt_halt_firmware",
@@ -230,7 +231,9 @@  static bool __dead_end_function(struct objtool_file *file, struct symbol *func,
 		"sev_es_terminate",
 		"snp_abort",
 		"start_kernel",
+		"start_secondary_resume",
 		"stop_this_cpu",
+		"unrecoverable_exception",
 		"usercopy_abort",
 		"x86_64_start_kernel",
 		"x86_64_start_reservations",
@@ -1335,6 +1338,8 @@  static const char *uaccess_safe_builtin[] = {
 	"rep_stos_alternative",
 	"rep_movs_alternative",
 	"__copy_user_nocache",
+	"__copy_tofrom_user",
+	"__arch_clear_user",
 	NULL
 };