2019-05-29 07:18:00 -07:00
/* SPDX-License-Identifier: GPL-2.0-only */
2017-07-10 18:04:30 -07:00
/ *
* Copyright ( C ) 2 0 1 2 R e g e n t s o f t h e U n i v e r s i t y o f C a l i f o r n i a
* Copyright ( C ) 2 0 1 7 S i F i v e
* /
# include < l i n u x / i n i t . h >
# include < l i n u x / l i n k a g e . h >
# include < a s m / a s m . h >
# include < a s m / c s r . h >
# include < a s m / u n i s t d . h >
# include < a s m / t h r e a d _ i n f o . h >
# include < a s m / a s m - o f f s e t s . h >
2021-03-22 22:26:05 +08:00
# include < a s m / e r r a t a _ l i s t . h >
2017-07-10 18:04:30 -07:00
2020-02-27 11:15:03 -08:00
# if ! I S _ E N A B L E D ( C O N F I G _ P R E E M P T I O N )
.set resume_ k e r n e l , r e s t o r e _ a l l
# endif
2017-07-10 18:04:30 -07:00
2020-02-27 11:15:03 -08:00
ENTRY( h a n d l e _ e x c e p t i o n )
2017-07-10 18:04:30 -07:00
/ *
* If c o m i n g f r o m u s e r s p a c e , p r e s e r v e t h e u s e r t h r e a d p o i n t e r a n d l o a d
2019-10-28 13:10:32 +01:00
* the k e r n e l t h r e a d p o i n t e r . I f w e c a m e f r o m t h e k e r n e l , t h e s c r a t c h
* register w i l l c o n t a i n 0 , a n d w e s h o u l d c o n t i n u e o n t h e c u r r e n t T P .
2017-07-10 18:04:30 -07:00
* /
2019-10-28 13:10:32 +01:00
csrrw t p , C S R _ S C R A T C H , t p
2017-07-10 18:04:30 -07:00
bnez t p , _ s a v e _ c o n t e x t
_restore_kernel_tpsp :
2019-10-28 13:10:32 +01:00
csrr t p , C S R _ S C R A T C H
2017-07-10 18:04:30 -07:00
REG_ S s p , T A S K _ T I _ K E R N E L _ S P ( t p )
riscv: add VMAP_STACK overflow detection
This patch adds stack overflow detection to riscv, usable when
CONFIG_VMAP_STACK=y.
Overflow is detected in kernel exception entry(kernel/entry.S), if the
kernel stack is overflow and been detected, the overflow handler is
invoked on a per-cpu overflow stack. This approach preserves GPRs and
the original exception information.
The overflow detect is performed before any attempt is made to access
the stack and the principle of stack overflow detection: kernel stacks
are aligned to double their size, enabling overflow to be detected with
a single bit test. For example, a 16K stack is aligned to 32K, ensuring
that bit 14 of the SP must be zero. On an overflow (or underflow), this
bit is flipped. Thus, overflow (of less than the size of the stack) can
be detected by testing whether this bit is set.
This gives us a useful error message on stack overflow, as can be
trigger with the LKDTM overflow test:
[ 388.053267] lkdtm: Performing direct entry EXHAUST_STACK
[ 388.053663] lkdtm: Calling function with 1024 frame size to depth 32 ...
[ 388.054016] lkdtm: loop 32/32 ...
[ 388.054186] lkdtm: loop 31/32 ...
[ 388.054491] lkdtm: loop 30/32 ...
[ 388.054672] lkdtm: loop 29/32 ...
[ 388.054859] lkdtm: loop 28/32 ...
[ 388.055010] lkdtm: loop 27/32 ...
[ 388.055163] lkdtm: loop 26/32 ...
[ 388.055309] lkdtm: loop 25/32 ...
[ 388.055481] lkdtm: loop 24/32 ...
[ 388.055653] lkdtm: loop 23/32 ...
[ 388.055837] lkdtm: loop 22/32 ...
[ 388.056015] lkdtm: loop 21/32 ...
[ 388.056188] lkdtm: loop 20/32 ...
[ 388.058145] Insufficient stack space to handle exception!
[ 388.058153] Task stack: [0xffffffd014260000..0xffffffd014264000]
[ 388.058160] Overflow stack: [0xffffffe1f8d2c220..0xffffffe1f8d2d220]
[ 388.058168] CPU: 0 PID: 89 Comm: bash Not tainted 5.12.0-rc8-dirty #90
[ 388.058175] Hardware name: riscv-virtio,qemu (DT)
[ 388.058187] epc : number+0x32/0x2c0
[ 388.058247] ra : vsnprintf+0x2ae/0x3f0
[ 388.058255] epc : ffffffe0002d38f6 ra : ffffffe0002d814e sp : ffffffd01425ffc0
[ 388.058263] gp : ffffffe0012e4010 tp : ffffffe08014da00 t0 : ffffffd0142606e8
[ 388.058271] t1 : 0000000000000000 t2 : 0000000000000000 s0 : ffffffd014260070
[ 388.058303] s1 : ffffffd014260158 a0 : ffffffd01426015e a1 : ffffffd014260158
[ 388.058311] a2 : 0000000000000013 a3 : ffff0a01ffffff10 a4 : ffffffe000c398e0
[ 388.058319] a5 : 511b02ec65f3e300 a6 : 0000000000a1749a a7 : 0000000000000000
[ 388.058327] s2 : ffffffff000000ff s3 : 00000000ffff0a01 s4 : ffffffe0012e50a8
[ 388.058335] s5 : 0000000000ffff0a s6 : ffffffe0012e50a8 s7 : ffffffe000da1cc0
[ 388.058343] s8 : ffffffffffffffff s9 : ffffffd0142602b0 s10: ffffffd0142602a8
[ 388.058351] s11: ffffffd01426015e t3 : 00000000000f0000 t4 : ffffffffffffffff
[ 388.058359] t5 : 000000000000002f t6 : ffffffd014260158
[ 388.058366] status: 0000000000000100 badaddr: ffffffd01425fff8 cause: 000000000000000f
[ 388.058374] Kernel panic - not syncing: Kernel stack overflow
[ 388.058381] CPU: 0 PID: 89 Comm: bash Not tainted 5.12.0-rc8-dirty #90
[ 388.058387] Hardware name: riscv-virtio,qemu (DT)
[ 388.058393] Call Trace:
[ 388.058400] [<ffffffe000004944>] walk_stackframe+0x0/0xce
[ 388.058406] [<ffffffe0006f0b28>] dump_backtrace+0x38/0x46
[ 388.058412] [<ffffffe0006f0b46>] show_stack+0x10/0x18
[ 388.058418] [<ffffffe0006f3690>] dump_stack+0x74/0x8e
[ 388.058424] [<ffffffe0006f0d52>] panic+0xfc/0x2b2
[ 388.058430] [<ffffffe0006f0acc>] print_trace_address+0x0/0x24
[ 388.058436] [<ffffffe0002d814e>] vsnprintf+0x2ae/0x3f0
[ 388.058956] SMP: stopping secondary CPUs
Signed-off-by: Tong Tiangen <tongtiangen@huawei.com>
Reviewed-by: Kefeng Wang <wangkefeng.wang@huawei.com>
Signed-off-by: Palmer Dabbelt <palmerdabbelt@google.com>
2021-06-21 11:28:55 +08:00
# ifdef C O N F I G _ V M A P _ S T A C K
addi s p , s p , - ( P T _ S I Z E _ O N _ S T A C K )
srli s p , s p , T H R E A D _ S H I F T
andi s p , s p , 0 x1
bnez s p , h a n d l e _ k e r n e l _ s t a c k _ o v e r f l o w
REG_ L s p , T A S K _ T I _ K E R N E L _ S P ( t p )
# endif
2017-07-10 18:04:30 -07:00
_save_context :
REG_ S s p , T A S K _ T I _ U S E R _ S P ( t p )
REG_ L s p , T A S K _ T I _ K E R N E L _ S P ( t p )
addi s p , s p , - ( P T _ S I Z E _ O N _ S T A C K )
REG_ S x1 , P T _ R A ( s p )
REG_ S x3 , P T _ G P ( s p )
REG_ S x5 , P T _ T 0 ( s p )
REG_ S x6 , P T _ T 1 ( s p )
REG_ S x7 , P T _ T 2 ( s p )
REG_ S x8 , P T _ S 0 ( s p )
REG_ S x9 , P T _ S 1 ( s p )
REG_ S x10 , P T _ A 0 ( s p )
REG_ S x11 , P T _ A 1 ( s p )
REG_ S x12 , P T _ A 2 ( s p )
REG_ S x13 , P T _ A 3 ( s p )
REG_ S x14 , P T _ A 4 ( s p )
REG_ S x15 , P T _ A 5 ( s p )
REG_ S x16 , P T _ A 6 ( s p )
REG_ S x17 , P T _ A 7 ( s p )
REG_ S x18 , P T _ S 2 ( s p )
REG_ S x19 , P T _ S 3 ( s p )
REG_ S x20 , P T _ S 4 ( s p )
REG_ S x21 , P T _ S 5 ( s p )
REG_ S x22 , P T _ S 6 ( s p )
REG_ S x23 , P T _ S 7 ( s p )
REG_ S x24 , P T _ S 8 ( s p )
REG_ S x25 , P T _ S 9 ( s p )
REG_ S x26 , P T _ S 1 0 ( s p )
REG_ S x27 , P T _ S 1 1 ( s p )
REG_ S x28 , P T _ T 3 ( s p )
REG_ S x29 , P T _ T 4 ( s p )
REG_ S x30 , P T _ T 5 ( s p )
REG_ S x31 , P T _ T 6 ( s p )
/ *
2018-01-04 19:55:55 +01:00
* Disable u s e r - m o d e m e m o r y a c c e s s a s i t s h o u l d o n l y b e s e t i n t h e
* actual u s e r c o p y r o u t i n e s .
*
* Disable t h e F P U t o d e t e c t i l l e g a l u s a g e o f f l o a t i n g p o i n t i n k e r n e l
* space.
2017-07-10 18:04:30 -07:00
* /
2018-01-04 19:55:55 +01:00
li t 0 , S R _ S U M | S R _ F S
2017-07-10 18:04:30 -07:00
REG_ L s0 , T A S K _ T I _ U S E R _ S P ( t p )
2019-10-28 13:10:32 +01:00
csrrc s1 , C S R _ S T A T U S , t 0
csrr s2 , C S R _ E P C
csrr s3 , C S R _ T V A L
csrr s4 , C S R _ C A U S E
csrr s5 , C S R _ S C R A T C H
2017-07-10 18:04:30 -07:00
REG_ S s0 , P T _ S P ( s p )
2019-10-28 13:10:32 +01:00
REG_ S s1 , P T _ S T A T U S ( s p )
REG_ S s2 , P T _ E P C ( s p )
REG_ S s3 , P T _ B A D A D D R ( s p )
REG_ S s4 , P T _ C A U S E ( s p )
2017-07-10 18:04:30 -07:00
REG_ S s5 , P T _ T P ( s p )
/ *
2019-10-28 13:10:32 +01:00
* Set t h e s c r a t c h r e g i s t e r t o 0 , s o t h a t i f a r e c u r s i v e e x c e p t i o n
2017-07-10 18:04:30 -07:00
* occurs, t h e e x c e p t i o n v e c t o r k n o w s i t c a m e f r o m t h e k e r n e l
* /
2019-10-28 13:10:32 +01:00
csrw C S R _ S C R A T C H , x0
2017-07-10 18:04:30 -07:00
/* Load the global pointer */
.option push
.option norelax
la g p , _ _ g l o b a l _ p o i n t e r $
.option pop
2020-06-27 13:57:08 +00:00
# ifdef C O N F I G _ T R A C E _ I R Q F L A G S
call t r a c e _ h a r d i r q s _ o f f
# endif
2020-06-24 17:03:16 +08:00
# ifdef C O N F I G _ C O N T E X T _ T R A C K I N G
/* If previous state is in user mode, call context_tracking_user_exit. */
li a0 , S R _ P P
and a0 , s1 , a0
bnez a0 , s k i p _ c o n t e x t _ t r a c k i n g
call c o n t e x t _ t r a c k i n g _ u s e r _ e x i t
skip_context_tracking :
# endif
2017-07-10 18:04:30 -07:00
/ *
* MSB o f c a u s e d i f f e r e n t i a t e s b e t w e e n
* interrupts a n d e x c e p t i o n s
* /
bge s4 , z e r o , 1 f
2020-06-27 13:57:08 +00:00
la r a , r e t _ f r o m _ e x c e p t i o n
2017-07-10 18:04:30 -07:00
/* Handle interrupts */
2018-03-07 15:57:28 -08:00
move a0 , s p / * p t _ r e g s * /
2020-06-01 14:45:42 +05:30
la a1 , h a n d l e _ a r c h _ i r q
REG_ L a1 , ( a1 )
jr a1
2017-07-10 18:04:30 -07:00
1 :
2019-10-28 13:10:32 +01:00
/ *
* Exceptions r u n w i t h i n t e r r u p t s e n a b l e d o r d i s a b l e d d e p e n d i n g o n t h e
* state o f S R _ P I E i n m / s s t a t u s .
* /
andi t 0 , s1 , S R _ P I E
2019-09-16 16:47:41 +08:00
beqz t 0 , 1 f
2021-03-30 02:16:24 +08:00
/* kprobes, entered via ebreak, must have interrupts disabled. */
li t 0 , E X C _ B R E A K P O I N T
beq s4 , t 0 , 1 f
2020-12-18 16:20:51 -08:00
# ifdef C O N F I G _ T R A C E _ I R Q F L A G S
call t r a c e _ h a r d i r q s _ o n
# endif
2019-10-28 13:10:32 +01:00
csrs C S R _ S T A T U S , S R _ I E
2018-01-29 23:51:45 -08:00
2019-09-16 16:47:41 +08:00
1 :
2020-06-27 13:57:08 +00:00
la r a , r e t _ f r o m _ e x c e p t i o n
2017-07-10 18:04:30 -07:00
/* Handle syscalls */
li t 0 , E X C _ S Y S C A L L
beq s4 , t 0 , h a n d l e _ s y s c a l l
/* Handle other exceptions */
slli t 0 , s4 , R I S C V _ L G P T R
la t 1 , e x c p _ v e c t _ t a b l e
la t 2 , e x c p _ v e c t _ t a b l e _ e n d
move a0 , s p / * p t _ r e g s * /
add t 0 , t 1 , t 0
/* Check if exception code lies within bounds */
bgeu t 0 , t 2 , 1 f
REG_ L t 0 , 0 ( t 0 )
jr t 0
1 :
tail d o _ t r a p _ u n k n o w n
handle_syscall :
2020-12-13 22:50:36 +09:00
# ifdef C O N F I G _ R I S C V _ M _ M O D E
/ *
* When r u n n i n g i s M - M o d e ( n o M M U c o n f i g ) , M P I E d o e s n o t g e t s e t .
* As a r e s u l t , w e n e e d t o f o r c e e n a b l e i n t e r r u p t s h e r e b e c a u s e
* handle_ e x c e p t i o n d i d n o t d o s e t S R _ I E a s i t a l w a y s s e e s S R _ P I E
* being c l e a r e d .
* /
csrs C S R _ S T A T U S , S R _ I E
# endif
2020-06-24 17:03:16 +08:00
# if d e f i n e d ( C O N F I G _ T R A C E _ I R Q F L A G S ) | | d e f i n e d ( C O N F I G _ C O N T E X T _ T R A C K I N G )
2020-06-27 13:57:08 +00:00
/* Recover a0 - a7 for system calls */
REG_ L a0 , P T _ A 0 ( s p )
REG_ L a1 , P T _ A 1 ( s p )
REG_ L a2 , P T _ A 2 ( s p )
REG_ L a3 , P T _ A 3 ( s p )
REG_ L a4 , P T _ A 4 ( s p )
REG_ L a5 , P T _ A 5 ( s p )
REG_ L a6 , P T _ A 6 ( s p )
REG_ L a7 , P T _ A 7 ( s p )
# endif
2017-07-10 18:04:30 -07:00
/* save the initial A0 value (needed in signal handlers) */
REG_ S a0 , P T _ O R I G _ A 0 ( s p )
/ *
* Advance S E P C t o a v o i d e x e c u t i n g t h e o r i g i n a l
* scall i n s t r u c t i o n o n s r e t
* /
addi s2 , s2 , 0 x4
2019-10-28 13:10:32 +01:00
REG_ S s2 , P T _ E P C ( s p )
2017-07-10 18:04:30 -07:00
/* Trace syscalls, but only if requested by the user. */
REG_ L t 0 , T A S K _ T I _ F L A G S ( t p )
2018-10-29 11:48:53 +01:00
andi t 0 , t 0 , _ T I F _ S Y S C A L L _ W O R K
2017-07-10 18:04:30 -07:00
bnez t 0 , h a n d l e _ s y s c a l l _ t r a c e _ e n t e r
check_syscall_nr :
/* Check to make sure we don't jump to a bogus syscall number. */
li t 0 , _ _ N R _ s y s c a l l s
la s0 , s y s _ n i _ s y s c a l l
2019-10-04 17:12:22 -07:00
/ *
* Syscall n u m b e r h e l d i n a7 .
* If s y s c a l l n u m b e r i s a b o v e a l l o w e d v a l u e , r e d i r e c t t o n i _ s y s c a l l .
* /
2020-12-21 23:52:00 +01:00
bgeu a7 , t 0 , 1 f
2019-10-04 17:12:22 -07:00
/* Call syscall */
2017-07-10 18:04:30 -07:00
la s0 , s y s _ c a l l _ t a b l e
slli t 0 , a7 , R I S C V _ L G P T R
add s0 , s0 , t 0
REG_ L s0 , 0 ( s0 )
1 :
jalr s0
ret_from_syscall :
/* Set user a0 to kernel a0 */
REG_ S a0 , P T _ A 0 ( s p )
2019-10-04 17:12:22 -07:00
/ *
* We d i d n ' t e x e c u t e t h e a c t u a l s y s c a l l .
* Seccomp a l r e a d y s e t r e t u r n v a l u e f o r t h e c u r r e n t t a s k p t _ r e g s .
* ( If i t w a s c o n f i g u r e d w i t h S E C C O M P _ R E T _ E R R N O / T R A C E )
* /
ret_from_syscall_rejected :
2017-07-10 18:04:30 -07:00
/* Trace syscalls, but only if requested by the user. */
REG_ L t 0 , T A S K _ T I _ F L A G S ( t p )
2018-10-29 11:48:53 +01:00
andi t 0 , t 0 , _ T I F _ S Y S C A L L _ W O R K
2017-07-10 18:04:30 -07:00
bnez t 0 , h a n d l e _ s y s c a l l _ t r a c e _ e x i t
ret_from_exception :
2019-10-28 13:10:32 +01:00
REG_ L s0 , P T _ S T A T U S ( s p )
csrc C S R _ S T A T U S , S R _ I E
2020-06-27 13:57:08 +00:00
# ifdef C O N F I G _ T R A C E _ I R Q F L A G S
call t r a c e _ h a r d i r q s _ o f f
# endif
2019-10-28 13:10:32 +01:00
# ifdef C O N F I G _ R I S C V _ M _ M O D E
/* the MPP value is too large to be used as an immediate arg for addi */
li t 0 , S R _ M P P
and s0 , s0 , t 0
# else
2018-01-04 18:35:03 +01:00
andi s0 , s0 , S R _ S P P
2019-10-28 13:10:32 +01:00
# endif
2019-01-03 11:32:33 +08:00
bnez s0 , r e s u m e _ k e r n e l
2017-07-10 18:04:30 -07:00
resume_userspace :
/* Interrupts must be disabled here so flags are checked atomically */
REG_ L s0 , T A S K _ T I _ F L A G S ( t p ) / * c u r r e n t _ t h r e a d _ i n f o - > f l a g s * /
andi s1 , s0 , _ T I F _ W O R K _ M A S K
bnez s1 , w o r k _ p e n d i n g
2020-06-24 17:03:16 +08:00
# ifdef C O N F I G _ C O N T E X T _ T R A C K I N G
call c o n t e x t _ t r a c k i n g _ u s e r _ e n t e r
# endif
2017-07-10 18:04:30 -07:00
/* Save unwound kernel stack pointer in thread_info */
addi s0 , s p , P T _ S I Z E _ O N _ S T A C K
REG_ S s0 , T A S K _ T I _ K E R N E L _ S P ( t p )
/ *
2019-10-28 13:10:32 +01:00
* Save T P i n t o t h e s c r a t c h r e g i s t e r , s o w e c a n f i n d t h e k e r n e l d a t a
* structures a g a i n .
2017-07-10 18:04:30 -07:00
* /
2019-10-28 13:10:32 +01:00
csrw C S R _ S C R A T C H , t p
2017-07-10 18:04:30 -07:00
restore_all :
2020-06-27 13:57:08 +00:00
# ifdef C O N F I G _ T R A C E _ I R Q F L A G S
REG_ L s1 , P T _ S T A T U S ( s p )
andi t 0 , s1 , S R _ P I E
beqz t 0 , 1 f
call t r a c e _ h a r d i r q s _ o n
j 2 f
1 :
call t r a c e _ h a r d i r q s _ o f f
2 :
# endif
2020-02-27 11:15:03 -08:00
REG_ L a0 , P T _ S T A T U S ( s p )
/ *
* The c u r r e n t l o a d r e s e r v a t i o n i s e f f e c t i v e l y p a r t o f t h e p r o c e s s o r ' s
* state, i n t h e s e n s e t h a t l o a d r e s e r v a t i o n s c a n n o t b e s h a r e d b e t w e e n
* different h a r t c o n t e x t s . W e c a n ' t a c t u a l l y s a v e a n d r e s t o r e a l o a d
* reservation, s o i n s t e a d h e r e w e c l e a r a n y e x i s t i n g r e s e r v a t i o n - -
* it' s a l w a y s l e g a l f o r i m p l e m e n t a t i o n s t o c l e a r l o a d r e s e r v a t i o n s a t
* any p o i n t ( a s l o n g a s t h e f o r w a r d p r o g r e s s g u a r a n t e e i s k e p t , b u t
* we' l l i g n o r e t h a t h e r e ) .
*
* Dangling l o a d r e s e r v a t i o n s c a n b e t h e r e s u l t o f t a k i n g a t r a p i n t h e
* middle o f a n L R / S C s e q u e n c e , b u t c a n a l s o b e t h e r e s u l t o f a t a k e n
* forward b r a n c h a r o u n d a n S C - - w h i c h i s h o w w e i m p l e m e n t C A S . A s a
* result w e n e e d t o c l e a r r e s e r v a t i o n s b e t w e e n t h e l a s t C A S a n d t h e
* jump b a c k t o t h e n e w c o n t e x t . W h i l e i t i s u n l i k e l y t h e s t o r e
* completes, i m p l e m e n t a t i o n s a r e a l l o w e d t o e x p a n d r e s e r v a t i o n s t o b e
* arbitrarily l a r g e .
* /
REG_ L a2 , P T _ E P C ( s p )
REG_ S C x0 , a2 , P T _ E P C ( s p )
csrw C S R _ S T A T U S , a0
csrw C S R _ E P C , a2
REG_ L x1 , P T _ R A ( s p )
REG_ L x3 , P T _ G P ( s p )
REG_ L x4 , P T _ T P ( s p )
REG_ L x5 , P T _ T 0 ( s p )
REG_ L x6 , P T _ T 1 ( s p )
REG_ L x7 , P T _ T 2 ( s p )
REG_ L x8 , P T _ S 0 ( s p )
REG_ L x9 , P T _ S 1 ( s p )
REG_ L x10 , P T _ A 0 ( s p )
REG_ L x11 , P T _ A 1 ( s p )
REG_ L x12 , P T _ A 2 ( s p )
REG_ L x13 , P T _ A 3 ( s p )
REG_ L x14 , P T _ A 4 ( s p )
REG_ L x15 , P T _ A 5 ( s p )
REG_ L x16 , P T _ A 6 ( s p )
REG_ L x17 , P T _ A 7 ( s p )
REG_ L x18 , P T _ S 2 ( s p )
REG_ L x19 , P T _ S 3 ( s p )
REG_ L x20 , P T _ S 4 ( s p )
REG_ L x21 , P T _ S 5 ( s p )
REG_ L x22 , P T _ S 6 ( s p )
REG_ L x23 , P T _ S 7 ( s p )
REG_ L x24 , P T _ S 8 ( s p )
REG_ L x25 , P T _ S 9 ( s p )
REG_ L x26 , P T _ S 1 0 ( s p )
REG_ L x27 , P T _ S 1 1 ( s p )
REG_ L x28 , P T _ T 3 ( s p )
REG_ L x29 , P T _ T 4 ( s p )
REG_ L x30 , P T _ T 5 ( s p )
REG_ L x31 , P T _ T 6 ( s p )
REG_ L x2 , P T _ S P ( s p )
2019-10-28 13:10:32 +01:00
# ifdef C O N F I G _ R I S C V _ M _ M O D E
mret
# else
2017-07-10 18:04:30 -07:00
sret
2019-10-28 13:10:32 +01:00
# endif
2017-07-10 18:04:30 -07:00
2019-10-15 21:18:03 +02:00
# if I S _ E N A B L E D ( C O N F I G _ P R E E M P T I O N )
2019-01-03 11:32:33 +08:00
resume_kernel :
REG_ L s0 , T A S K _ T I _ P R E E M P T _ C O U N T ( t p )
bnez s0 , r e s t o r e _ a l l
REG_ L s0 , T A S K _ T I _ F L A G S ( t p )
andi s0 , s0 , _ T I F _ N E E D _ R E S C H E D
beqz s0 , r e s t o r e _ a l l
call p r e e m p t _ s c h e d u l e _ i r q
2019-09-23 15:36:17 +01:00
j r e s t o r e _ a l l
2019-01-03 11:32:33 +08:00
# endif
2017-07-10 18:04:30 -07:00
work_pending :
/* Enter slow path for supplementary processing */
la r a , r e t _ f r o m _ e x c e p t i o n
andi s1 , s0 , _ T I F _ N E E D _ R E S C H E D
bnez s1 , w o r k _ r e s c h e d
work_notifysig :
/* Handle pending signals and notify-resume requests */
2019-10-28 13:10:32 +01:00
csrs C S R _ S T A T U S , S R _ I E / * E n a b l e i n t e r r u p t s f o r d o _ n o t i f y _ r e s u m e ( ) * /
2017-07-10 18:04:30 -07:00
move a0 , s p / * p t _ r e g s * /
move a1 , s0 / * c u r r e n t _ t h r e a d _ i n f o - > f l a g s * /
tail d o _ n o t i f y _ r e s u m e
work_resched :
tail s c h e d u l e
/* Slow paths for ptrace. */
handle_syscall_trace_enter :
move a0 , s p
call d o _ s y s c a l l _ t r a c e _ e n t e r
riscv: fix seccomp reject syscall code path
If secure_computing() rejected a system call, we were previously setting
the system call number to -1, to indicate to later code that the syscall
failed. However, if something (e.g. a user notification) was sleeping, and
received a signal, we may set a0 to -ERESTARTSYS and re-try the system call
again.
In this case, seccomp "denies" the syscall (because of the signal), and we
would set a7 to -1, thus losing the value of the system call we want to
restart.
Instead, let's return -1 from do_syscall_trace_enter() to indicate that the
syscall was rejected, so we don't clobber the value in case of -ERESTARTSYS
or whatever.
This commit fixes the user_notification_signal seccomp selftest on riscv to
no longer hang. That test expects the system call to be re-issued after the
signal, and it wasn't due to the above bug. Now that it is, everything
works normally.
Note that in the ptrace (tracer) case, the tracer can set the register
values to whatever they want, so we still need to keep the code that
handles out-of-bounds syscalls. However, we can drop the comment.
We can also drop syscall_set_nr(), since it is no longer used anywhere, and
the code that re-loads the value in a7 because of it.
Reported in: https://lore.kernel.org/bpf/CAEn-LTp=ss0Dfv6J00=rCAy+N78U2AmhqJNjfqjr2FDpPYjxEQ@mail.gmail.com/
Reported-by: David Abdurachmanov <david.abdurachmanov@gmail.com>
Signed-off-by: Tycho Andersen <tycho@tycho.ws>
Reviewed-by: Kees Cook <keescook@chromium.org>
Signed-off-by: Palmer Dabbelt <palmerdabbelt@google.com>
2020-02-08 08:18:17 -07:00
move t 0 , a0
2017-07-10 18:04:30 -07:00
REG_ L a0 , P T _ A 0 ( s p )
REG_ L a1 , P T _ A 1 ( s p )
REG_ L a2 , P T _ A 2 ( s p )
REG_ L a3 , P T _ A 3 ( s p )
REG_ L a4 , P T _ A 4 ( s p )
REG_ L a5 , P T _ A 5 ( s p )
REG_ L a6 , P T _ A 6 ( s p )
REG_ L a7 , P T _ A 7 ( s p )
riscv: fix seccomp reject syscall code path
If secure_computing() rejected a system call, we were previously setting
the system call number to -1, to indicate to later code that the syscall
failed. However, if something (e.g. a user notification) was sleeping, and
received a signal, we may set a0 to -ERESTARTSYS and re-try the system call
again.
In this case, seccomp "denies" the syscall (because of the signal), and we
would set a7 to -1, thus losing the value of the system call we want to
restart.
Instead, let's return -1 from do_syscall_trace_enter() to indicate that the
syscall was rejected, so we don't clobber the value in case of -ERESTARTSYS
or whatever.
This commit fixes the user_notification_signal seccomp selftest on riscv to
no longer hang. That test expects the system call to be re-issued after the
signal, and it wasn't due to the above bug. Now that it is, everything
works normally.
Note that in the ptrace (tracer) case, the tracer can set the register
values to whatever they want, so we still need to keep the code that
handles out-of-bounds syscalls. However, we can drop the comment.
We can also drop syscall_set_nr(), since it is no longer used anywhere, and
the code that re-loads the value in a7 because of it.
Reported in: https://lore.kernel.org/bpf/CAEn-LTp=ss0Dfv6J00=rCAy+N78U2AmhqJNjfqjr2FDpPYjxEQ@mail.gmail.com/
Reported-by: David Abdurachmanov <david.abdurachmanov@gmail.com>
Signed-off-by: Tycho Andersen <tycho@tycho.ws>
Reviewed-by: Kees Cook <keescook@chromium.org>
Signed-off-by: Palmer Dabbelt <palmerdabbelt@google.com>
2020-02-08 08:18:17 -07:00
bnez t 0 , r e t _ f r o m _ s y s c a l l _ r e j e c t e d
2017-07-10 18:04:30 -07:00
j c h e c k _ s y s c a l l _ n r
handle_syscall_trace_exit :
move a0 , s p
call d o _ s y s c a l l _ t r a c e _ e x i t
j r e t _ f r o m _ e x c e p t i o n
riscv: add VMAP_STACK overflow detection
This patch adds stack overflow detection to riscv, usable when
CONFIG_VMAP_STACK=y.
Overflow is detected in kernel exception entry(kernel/entry.S), if the
kernel stack is overflow and been detected, the overflow handler is
invoked on a per-cpu overflow stack. This approach preserves GPRs and
the original exception information.
The overflow detect is performed before any attempt is made to access
the stack and the principle of stack overflow detection: kernel stacks
are aligned to double their size, enabling overflow to be detected with
a single bit test. For example, a 16K stack is aligned to 32K, ensuring
that bit 14 of the SP must be zero. On an overflow (or underflow), this
bit is flipped. Thus, overflow (of less than the size of the stack) can
be detected by testing whether this bit is set.
This gives us a useful error message on stack overflow, as can be
trigger with the LKDTM overflow test:
[ 388.053267] lkdtm: Performing direct entry EXHAUST_STACK
[ 388.053663] lkdtm: Calling function with 1024 frame size to depth 32 ...
[ 388.054016] lkdtm: loop 32/32 ...
[ 388.054186] lkdtm: loop 31/32 ...
[ 388.054491] lkdtm: loop 30/32 ...
[ 388.054672] lkdtm: loop 29/32 ...
[ 388.054859] lkdtm: loop 28/32 ...
[ 388.055010] lkdtm: loop 27/32 ...
[ 388.055163] lkdtm: loop 26/32 ...
[ 388.055309] lkdtm: loop 25/32 ...
[ 388.055481] lkdtm: loop 24/32 ...
[ 388.055653] lkdtm: loop 23/32 ...
[ 388.055837] lkdtm: loop 22/32 ...
[ 388.056015] lkdtm: loop 21/32 ...
[ 388.056188] lkdtm: loop 20/32 ...
[ 388.058145] Insufficient stack space to handle exception!
[ 388.058153] Task stack: [0xffffffd014260000..0xffffffd014264000]
[ 388.058160] Overflow stack: [0xffffffe1f8d2c220..0xffffffe1f8d2d220]
[ 388.058168] CPU: 0 PID: 89 Comm: bash Not tainted 5.12.0-rc8-dirty #90
[ 388.058175] Hardware name: riscv-virtio,qemu (DT)
[ 388.058187] epc : number+0x32/0x2c0
[ 388.058247] ra : vsnprintf+0x2ae/0x3f0
[ 388.058255] epc : ffffffe0002d38f6 ra : ffffffe0002d814e sp : ffffffd01425ffc0
[ 388.058263] gp : ffffffe0012e4010 tp : ffffffe08014da00 t0 : ffffffd0142606e8
[ 388.058271] t1 : 0000000000000000 t2 : 0000000000000000 s0 : ffffffd014260070
[ 388.058303] s1 : ffffffd014260158 a0 : ffffffd01426015e a1 : ffffffd014260158
[ 388.058311] a2 : 0000000000000013 a3 : ffff0a01ffffff10 a4 : ffffffe000c398e0
[ 388.058319] a5 : 511b02ec65f3e300 a6 : 0000000000a1749a a7 : 0000000000000000
[ 388.058327] s2 : ffffffff000000ff s3 : 00000000ffff0a01 s4 : ffffffe0012e50a8
[ 388.058335] s5 : 0000000000ffff0a s6 : ffffffe0012e50a8 s7 : ffffffe000da1cc0
[ 388.058343] s8 : ffffffffffffffff s9 : ffffffd0142602b0 s10: ffffffd0142602a8
[ 388.058351] s11: ffffffd01426015e t3 : 00000000000f0000 t4 : ffffffffffffffff
[ 388.058359] t5 : 000000000000002f t6 : ffffffd014260158
[ 388.058366] status: 0000000000000100 badaddr: ffffffd01425fff8 cause: 000000000000000f
[ 388.058374] Kernel panic - not syncing: Kernel stack overflow
[ 388.058381] CPU: 0 PID: 89 Comm: bash Not tainted 5.12.0-rc8-dirty #90
[ 388.058387] Hardware name: riscv-virtio,qemu (DT)
[ 388.058393] Call Trace:
[ 388.058400] [<ffffffe000004944>] walk_stackframe+0x0/0xce
[ 388.058406] [<ffffffe0006f0b28>] dump_backtrace+0x38/0x46
[ 388.058412] [<ffffffe0006f0b46>] show_stack+0x10/0x18
[ 388.058418] [<ffffffe0006f3690>] dump_stack+0x74/0x8e
[ 388.058424] [<ffffffe0006f0d52>] panic+0xfc/0x2b2
[ 388.058430] [<ffffffe0006f0acc>] print_trace_address+0x0/0x24
[ 388.058436] [<ffffffe0002d814e>] vsnprintf+0x2ae/0x3f0
[ 388.058956] SMP: stopping secondary CPUs
Signed-off-by: Tong Tiangen <tongtiangen@huawei.com>
Reviewed-by: Kefeng Wang <wangkefeng.wang@huawei.com>
Signed-off-by: Palmer Dabbelt <palmerdabbelt@google.com>
2021-06-21 11:28:55 +08:00
# ifdef C O N F I G _ V M A P _ S T A C K
handle_kernel_stack_overflow :
la s p , s h a d o w _ s t a c k
addi s p , s p , S H A D O W _ O V E R F L O W _ S T A C K _ S I Z E
/ / save c a l l e r r e g i s t e r t o s h a d o w s t a c k
addi s p , s p , - ( P T _ S I Z E _ O N _ S T A C K )
REG_ S x1 , P T _ R A ( s p )
REG_ S x5 , P T _ T 0 ( s p )
REG_ S x6 , P T _ T 1 ( s p )
REG_ S x7 , P T _ T 2 ( s p )
REG_ S x10 , P T _ A 0 ( s p )
REG_ S x11 , P T _ A 1 ( s p )
REG_ S x12 , P T _ A 2 ( s p )
REG_ S x13 , P T _ A 3 ( s p )
REG_ S x14 , P T _ A 4 ( s p )
REG_ S x15 , P T _ A 5 ( s p )
REG_ S x16 , P T _ A 6 ( s p )
REG_ S x17 , P T _ A 7 ( s p )
REG_ S x28 , P T _ T 3 ( s p )
REG_ S x29 , P T _ T 4 ( s p )
REG_ S x30 , P T _ T 5 ( s p )
REG_ S x31 , P T _ T 6 ( s p )
la r a , r e s t o r e _ c a l l e r _ r e g
tail g e t _ o v e r f l o w _ s t a c k
restore_caller_reg :
/ / save p e r - c p u o v e r f l o w s t a c k
REG_ S a0 , - 8 ( s p )
/ / restore c a l l e r r e g i s t e r f r o m s h a d o w _ s t a c k
REG_ L x1 , P T _ R A ( s p )
REG_ L x5 , P T _ T 0 ( s p )
REG_ L x6 , P T _ T 1 ( s p )
REG_ L x7 , P T _ T 2 ( s p )
REG_ L x10 , P T _ A 0 ( s p )
REG_ L x11 , P T _ A 1 ( s p )
REG_ L x12 , P T _ A 2 ( s p )
REG_ L x13 , P T _ A 3 ( s p )
REG_ L x14 , P T _ A 4 ( s p )
REG_ L x15 , P T _ A 5 ( s p )
REG_ L x16 , P T _ A 6 ( s p )
REG_ L x17 , P T _ A 7 ( s p )
REG_ L x28 , P T _ T 3 ( s p )
REG_ L x29 , P T _ T 4 ( s p )
REG_ L x30 , P T _ T 5 ( s p )
REG_ L x31 , P T _ T 6 ( s p )
/ / load p e r - c p u o v e r f l o w s t a c k
REG_ L s p , - 8 ( s p )
addi s p , s p , - ( P T _ S I Z E _ O N _ S T A C K )
/ / save c o n t e x t t o o v e r f l o w s t a c k
REG_ S x1 , P T _ R A ( s p )
REG_ S x3 , P T _ G P ( s p )
REG_ S x5 , P T _ T 0 ( s p )
REG_ S x6 , P T _ T 1 ( s p )
REG_ S x7 , P T _ T 2 ( s p )
REG_ S x8 , P T _ S 0 ( s p )
REG_ S x9 , P T _ S 1 ( s p )
REG_ S x10 , P T _ A 0 ( s p )
REG_ S x11 , P T _ A 1 ( s p )
REG_ S x12 , P T _ A 2 ( s p )
REG_ S x13 , P T _ A 3 ( s p )
REG_ S x14 , P T _ A 4 ( s p )
REG_ S x15 , P T _ A 5 ( s p )
REG_ S x16 , P T _ A 6 ( s p )
REG_ S x17 , P T _ A 7 ( s p )
REG_ S x18 , P T _ S 2 ( s p )
REG_ S x19 , P T _ S 3 ( s p )
REG_ S x20 , P T _ S 4 ( s p )
REG_ S x21 , P T _ S 5 ( s p )
REG_ S x22 , P T _ S 6 ( s p )
REG_ S x23 , P T _ S 7 ( s p )
REG_ S x24 , P T _ S 8 ( s p )
REG_ S x25 , P T _ S 9 ( s p )
REG_ S x26 , P T _ S 1 0 ( s p )
REG_ S x27 , P T _ S 1 1 ( s p )
REG_ S x28 , P T _ T 3 ( s p )
REG_ S x29 , P T _ T 4 ( s p )
REG_ S x30 , P T _ T 5 ( s p )
REG_ S x31 , P T _ T 6 ( s p )
REG_ L s0 , T A S K _ T I _ K E R N E L _ S P ( t p )
csrr s1 , C S R _ S T A T U S
csrr s2 , C S R _ E P C
csrr s3 , C S R _ T V A L
csrr s4 , C S R _ C A U S E
csrr s5 , C S R _ S C R A T C H
REG_ S s0 , P T _ S P ( s p )
REG_ S s1 , P T _ S T A T U S ( s p )
REG_ S s2 , P T _ E P C ( s p )
REG_ S s3 , P T _ B A D A D D R ( s p )
REG_ S s4 , P T _ C A U S E ( s p )
REG_ S s5 , P T _ T P ( s p )
move a0 , s p
tail h a n d l e _ b a d _ s t a c k
# endif
2017-07-10 18:04:30 -07:00
END( h a n d l e _ e x c e p t i o n )
ENTRY( r e t _ f r o m _ f o r k )
la r a , r e t _ f r o m _ e x c e p t i o n
tail s c h e d u l e _ t a i l
ENDPROC( r e t _ f r o m _ f o r k )
ENTRY( r e t _ f r o m _ k e r n e l _ t h r e a d )
call s c h e d u l e _ t a i l
/* Call fn(arg) */
la r a , r e t _ f r o m _ e x c e p t i o n
move a0 , s1
jr s0
ENDPROC( r e t _ f r o m _ k e r n e l _ t h r e a d )
/ *
* Integer r e g i s t e r c o n t e x t s w i t c h
* The c a l l e e - s a v e d r e g i s t e r s m u s t b e s a v e d a n d r e s t o r e d .
*
* a0 : previous t a s k _ s t r u c t ( m u s t b e p r e s e r v e d a c r o s s t h e s w i t c h )
* a1 : next t a s k _ s t r u c t
*
* The v a l u e o f a0 a n d a1 m u s t b e p r e s e r v e d b y t h i s f u n c t i o n , a s t h a t ' s h o w
* arguments a r e p a s s e d t o s c h e d u l e _ t a i l .
* /
ENTRY( _ _ s w i t c h _ t o )
/* Save context into prev->thread */
li a4 , T A S K _ T H R E A D _ R A
add a3 , a0 , a4
add a4 , a1 , a4
REG_ S r a , T A S K _ T H R E A D _ R A _ R A ( a3 )
REG_ S s p , T A S K _ T H R E A D _ S P _ R A ( a3 )
REG_ S s0 , T A S K _ T H R E A D _ S 0 _ R A ( a3 )
REG_ S s1 , T A S K _ T H R E A D _ S 1 _ R A ( a3 )
REG_ S s2 , T A S K _ T H R E A D _ S 2 _ R A ( a3 )
REG_ S s3 , T A S K _ T H R E A D _ S 3 _ R A ( a3 )
REG_ S s4 , T A S K _ T H R E A D _ S 4 _ R A ( a3 )
REG_ S s5 , T A S K _ T H R E A D _ S 5 _ R A ( a3 )
REG_ S s6 , T A S K _ T H R E A D _ S 6 _ R A ( a3 )
REG_ S s7 , T A S K _ T H R E A D _ S 7 _ R A ( a3 )
REG_ S s8 , T A S K _ T H R E A D _ S 8 _ R A ( a3 )
REG_ S s9 , T A S K _ T H R E A D _ S 9 _ R A ( a3 )
REG_ S s10 , T A S K _ T H R E A D _ S 1 0 _ R A ( a3 )
REG_ S s11 , T A S K _ T H R E A D _ S 1 1 _ R A ( a3 )
/* Restore context from next->thread */
REG_ L r a , T A S K _ T H R E A D _ R A _ R A ( a4 )
REG_ L s p , T A S K _ T H R E A D _ S P _ R A ( a4 )
REG_ L s0 , T A S K _ T H R E A D _ S 0 _ R A ( a4 )
REG_ L s1 , T A S K _ T H R E A D _ S 1 _ R A ( a4 )
REG_ L s2 , T A S K _ T H R E A D _ S 2 _ R A ( a4 )
REG_ L s3 , T A S K _ T H R E A D _ S 3 _ R A ( a4 )
REG_ L s4 , T A S K _ T H R E A D _ S 4 _ R A ( a4 )
REG_ L s5 , T A S K _ T H R E A D _ S 5 _ R A ( a4 )
REG_ L s6 , T A S K _ T H R E A D _ S 6 _ R A ( a4 )
REG_ L s7 , T A S K _ T H R E A D _ S 7 _ R A ( a4 )
REG_ L s8 , T A S K _ T H R E A D _ S 8 _ R A ( a4 )
REG_ L s9 , T A S K _ T H R E A D _ S 9 _ R A ( a4 )
REG_ L s10 , T A S K _ T H R E A D _ S 1 0 _ R A ( a4 )
REG_ L s11 , T A S K _ T H R E A D _ S 1 1 _ R A ( a4 )
/* Swap the CPU entry around. */
lw a3 , T A S K _ T I _ C P U ( a0 )
lw a4 , T A S K _ T I _ C P U ( a1 )
sw a3 , T A S K _ T I _ C P U ( a1 )
sw a4 , T A S K _ T I _ C P U ( a0 )
2020-07-12 13:41:49 +00:00
/* The offset of thread_info in task_struct is zero. */
2017-07-10 18:04:30 -07:00
move t p , a1
ret
ENDPROC( _ _ s w i t c h _ t o )
2019-10-28 13:10:41 +01:00
# ifndef C O N F I G _ M M U
# define d o _ p a g e _ f a u l t d o _ t r a p _ u n k n o w n
# endif
2017-07-10 18:04:30 -07:00
.section " .rodata "
2021-03-17 16:17:25 +08:00
.align LGREG
2017-07-10 18:04:30 -07:00
/* Exception vector table */
ENTRY( e x c p _ v e c t _ t a b l e )
RISCV_ P T R d o _ t r a p _ i n s n _ m i s a l i g n e d
2021-03-22 22:26:05 +08:00
ALT_ I N S N _ F A U L T ( R I S C V _ P T R d o _ t r a p _ i n s n _ f a u l t )
2017-07-10 18:04:30 -07:00
RISCV_ P T R d o _ t r a p _ i n s n _ i l l e g a l
RISCV_ P T R d o _ t r a p _ b r e a k
RISCV_ P T R d o _ t r a p _ l o a d _ m i s a l i g n e d
RISCV_ P T R d o _ t r a p _ l o a d _ f a u l t
RISCV_ P T R d o _ t r a p _ s t o r e _ m i s a l i g n e d
RISCV_ P T R d o _ t r a p _ s t o r e _ f a u l t
RISCV_ P T R d o _ t r a p _ e c a l l _ u / * s y s t e m c a l l , g e t s i n t e r c e p t e d * /
RISCV_ P T R d o _ t r a p _ e c a l l _ s
RISCV_ P T R d o _ t r a p _ u n k n o w n
RISCV_ P T R d o _ t r a p _ e c a l l _ m
2021-03-22 22:26:05 +08:00
/* instruciton page fault */
ALT_ P A G E _ F A U L T ( R I S C V _ P T R d o _ p a g e _ f a u l t )
2017-07-10 18:04:30 -07:00
RISCV_ P T R d o _ p a g e _ f a u l t / * l o a d p a g e f a u l t * /
RISCV_ P T R d o _ t r a p _ u n k n o w n
RISCV_ P T R d o _ p a g e _ f a u l t / * s t o r e p a g e f a u l t * /
excp_vect_table_end :
END( e x c p _ v e c t _ t a b l e )
2019-10-28 13:10:41 +01:00
# ifndef C O N F I G _ M M U
ENTRY( _ _ u s e r _ r t _ s i g r e t u r n )
li a7 , _ _ N R _ r t _ s i g r e t u r n
scall
END( _ _ u s e r _ r t _ s i g r e t u r n )
# endif