Skip to content

Commit 35126a4

Browse files
committed
Add shstk access type for special permission of shadow stack page
1 parent 7116249 commit 35126a4

File tree

9 files changed

+85
-21
lines changed

9 files changed

+85
-21
lines changed

riscv/insns/c_sspopchk_x5.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,9 @@ if (!xSSE) {
2222
uint64_t ss_addr;
2323

2424
if (xlen == 32)
25-
ss_addr = MMU.load<uint32_t>(ssp);
25+
ss_addr = MMU.ss_load<uint32_t>(ssp);
2626
else
27-
ss_addr = MMU.load<uint64_t>(ssp);
27+
ss_addr = MMU.ss_load<uint64_t>(ssp);
2828

2929
software_check(T0 == ss_addr, SHADOW_STACK_FAULT);
3030

riscv/insns/c_sspush_x1.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,9 @@ if (!xSSE) {
2121
const auto new_sp = ssp - xlen / 8;
2222

2323
if (xlen == 32)
24-
MMU.store<uint32_t>(new_sp, RA);
24+
MMU.ss_store<uint32_t>(new_sp, RA);
2525
else
26-
MMU.store<uint64_t>(new_sp, RA);
26+
MMU.ss_store<uint64_t>(new_sp, RA);
2727

2828
STATE.ssp->write(new_sp);
2929
}

riscv/insns/ssamoswap_d.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,4 +15,4 @@ else if (prv == PRV_S && STATE.v && !get_field(STATE.henvcfg->read(), HENVCFG_SS
1515
else if (prv == PRV_U && STATE.v && !get_field(STATE.senvcfg->read(), SENVCFG_SSE))
1616
throw trap_virtual_instruction(insn.bits());
1717
else
18-
WRITE_RD(MMU.amo<uint64_t>(RS1, [&](uint64_t UNUSED lhs) { return RS2; }));
18+
WRITE_RD(MMU.ss_amo<uint64_t>(RS1, [&](uint64_t UNUSED lhs) { return RS2; }));

riscv/insns/sspopchk_x1.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,9 @@ if (!xSSE) {
2424
uint64_t ss_addr;
2525

2626
if (xlen == 32)
27-
ss_addr = MMU.load<uint32_t>(ssp);
27+
ss_addr = MMU.ss_load<uint32_t>(ssp);
2828
else
29-
ss_addr = MMU.load<uint64_t>(ssp);
29+
ss_addr = MMU.ss_load<uint64_t>(ssp);
3030

3131
software_check(RA == ss_addr, SHADOW_STACK_FAULT);
3232

riscv/insns/sspopchk_x5.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,9 @@ if (!xSSE) {
2424
uint64_t ss_addr;
2525

2626
if (xlen == 32)
27-
ss_addr = MMU.load<uint32_t>(ssp);
27+
ss_addr = MMU.ss_load<uint32_t>(ssp);
2828
else
29-
ss_addr = MMU.load<uint64_t>(ssp);
29+
ss_addr = MMU.ss_load<uint64_t>(ssp);
3030

3131
software_check(T0 == ss_addr, SHADOW_STACK_FAULT);
3232

riscv/insns/sspush_x1.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,9 @@ if (!xSSE) {
2323
const auto new_sp = ssp - xlen / 8;
2424

2525
if (xlen == 32)
26-
MMU.store<uint32_t>(new_sp, RA);
26+
MMU.ss_store<uint32_t>(new_sp, RA);
2727
else
28-
MMU.store<uint64_t>(new_sp, RA);
28+
MMU.ss_store<uint64_t>(new_sp, RA);
2929

3030
STATE.ssp->write(new_sp);
3131
}

riscv/insns/sspush_x5.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,9 @@ if (!xSSE) {
2323
const auto new_sp = ssp - xlen / 8;
2424

2525
if (xlen == 32)
26-
MMU.store<uint32_t>(new_sp, T0);
26+
MMU.ss_store<uint32_t>(new_sp, T0);
2727
else
28-
MMU.store<uint64_t>(new_sp, T0);
28+
MMU.ss_store<uint64_t>(new_sp, T0);
2929

3030
STATE.ssp->write(new_sp);
3131
}

riscv/mmu.cc

Lines changed: 48 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -491,8 +491,15 @@ reg_t mmu_t::walk(mem_access_info_t access_info)
491491
reg_t page_mask = (reg_t(1) << PGSHIFT) - 1;
492492
reg_t satp = proc->get_state()->satp->readvirt(virt);
493493
vm_info vm = decode_vm_info(proc->get_const_xlen(), false, mode, satp);
494-
if (vm.levels == 0)
494+
495+
// use access flags(shstk) and zicfiss extension as conditions for checking shadow stack
496+
bool check_ss = proc->extension_enabled(EXT_ZICFISS) && access_info.flags.shstk;
497+
498+
if (vm.levels == 0) {
499+
if (check_ss)
500+
trap_store_access_fault(virt, addr, 0, 0);
495501
return s2xlate(addr, addr & ((reg_t(2) << (proc->xlen-1))-1), type, type, virt, hlvx, false) & ~page_mask; // zero-extend from xlen
502+
}
496503

497504
bool s_mode = mode == PRV_S;
498505
bool sum = proc->state.sstatus->readvirt(virt) & MSTATUS_SUM;
@@ -506,6 +513,9 @@ reg_t mmu_t::walk(mem_access_info_t access_info)
506513
vm.levels = 0;
507514

508515
reg_t base = vm.ptbase;
516+
reg_t vw = PTE_V | PTE_W;
517+
reg_t invalid_pte;
518+
509519
for (int i = vm.levels - 1; i >= 0; i--) {
510520
int ptshift = i * vm.idxbits;
511521
reg_t idx = (addr >> (PGSHIFT + ptshift)) & ((1 << vm.idxbits) - 1);
@@ -517,6 +527,8 @@ reg_t mmu_t::walk(mem_access_info_t access_info)
517527
bool pbmte = virt ? (proc->get_state()->henvcfg->read() & HENVCFG_PBMTE) : (proc->get_state()->menvcfg->read() & MENVCFG_PBMTE);
518528
bool hade = virt ? (proc->get_state()->henvcfg->read() & HENVCFG_ADUE) : (proc->get_state()->menvcfg->read() & MENVCFG_ADUE);
519529

530+
invalid_pte = pte;
531+
520532
if (pte & PTE_RSVD) {
521533
break;
522534
} else if (!proc->extension_enabled(EXT_SVNAPOT) && (pte & PTE_N)) {
@@ -531,11 +543,23 @@ reg_t mmu_t::walk(mem_access_info_t access_info)
531543
base = ppn << PGSHIFT;
532544
} else if ((pte & PTE_U) ? s_mode && (type == FETCH || !sum) : !s_mode) {
533545
break;
534-
} else if (!(pte & PTE_V) || (!(pte & PTE_R) && (pte & PTE_W))) {
546+
} else if (!(pte & PTE_V)) {
547+
break;
548+
} else if (!(pte & PTE_R) && (pte & PTE_W) && !check_ss) {
549+
// allow shadow stack page with R=0, W=1, X=0 permission
550+
break;
551+
} else if ((type == FETCH || hlvx) && !(pte & PTE_X)) {
535552
break;
536-
} else if (type == FETCH || hlvx ? !(pte & PTE_X) :
537-
type == LOAD ? !(pte & PTE_R) && !(mxr && (pte & PTE_X)) :
538-
!((pte & PTE_R) && (pte & PTE_W))) {
553+
} else if ((type == LOAD) && !(pte & PTE_R) && !(mxr && (pte & PTE_X)) &&
554+
!check_ss) {
555+
// allow ss load page with R=0, W=1, X=0 page
556+
break;
557+
} else if ((type == STORE) && !((pte & PTE_R) && (pte & PTE_W)) &&
558+
!check_ss) {
559+
// allow ss store page with R=0, W=1, X=0
560+
break;
561+
} else if (check_ss && ((pte & vw) != vw)) {
562+
// ss load/store page with R=0, W=1, X=0 and valid
539563
break;
540564
} else if ((ppn & ((reg_t(1) << ptshift) - 1)) != 0) {
541565
break;
@@ -570,10 +594,27 @@ reg_t mmu_t::walk(mem_access_info_t access_info)
570594
}
571595
}
572596

597+
if (check_ss) {
598+
if (!(invalid_pte & PTE_V))
599+
throw trap_store_page_fault(virt, addr, 0, 0);
600+
else if (invalid_pte & PTE_W || invalid_pte & PTE_X)
601+
throw trap_store_access_fault(virt, addr, 0, 0);
602+
else
603+
throw trap_store_page_fault(virt, addr, 0, 0);
604+
}
605+
573606
switch (type) {
574-
case FETCH: throw trap_instruction_page_fault(virt, addr, 0, 0);
607+
case FETCH: {
608+
if (proc->extension_enabled(EXT_ZICFISS) && ((invalid_pte & vw) == vw))
609+
throw trap_instruction_access_fault(virt, addr, 0, 0);
610+
throw trap_instruction_page_fault(virt, addr, 0, 0);
611+
}
575612
case LOAD: throw trap_load_page_fault(virt, addr, 0, 0);
576-
case STORE: throw trap_store_page_fault(virt, addr, 0, 0);
613+
case STORE: {
614+
if (proc->extension_enabled(EXT_ZICFISS) && ((invalid_pte & vw) == vw))
615+
throw trap_store_access_fault(virt, addr, 0, 0);
616+
throw trap_store_page_fault(virt, addr, 0, 0);
617+
}
577618
default: abort();
578619
}
579620
}

riscv/mmu.h

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,9 +42,10 @@ struct xlate_flags_t {
4242
const bool forced_virt : 1;
4343
const bool hlvx : 1;
4444
const bool lr : 1;
45+
const bool shstk : 1; //shadow stack page permission is R=0, W=1, X=0
4546

4647
bool is_special_access() const {
47-
return forced_virt || hlvx || lr;
48+
return forced_virt || hlvx || lr || shstk;
4849
}
4950
};
5051

@@ -136,6 +137,11 @@ class mmu_t
136137
return load<T>(addr, {forced_virt, hlvx, lr});
137138
}
138139

140+
template<typename T>
141+
T ss_load(reg_t addr) {
142+
return load<T>(addr, {false, false, false, /*shstk=*/ true});
143+
}
144+
139145
template<typename T>
140146
void ALWAYS_INLINE store(reg_t addr, T val, xlate_flags_t xlate_flags = {false, false, false}) {
141147
reg_t vpn = addr >> PGSHIFT;
@@ -161,6 +167,12 @@ class mmu_t
161167
store(addr, val, {forced_virt, hlvx, lr});
162168
}
163169

170+
// shadow stack store
171+
template<typename T>
172+
void ss_store(reg_t addr, T val) {
173+
store<T>(addr, val, {false, false, false, /*shstk=*/ true});
174+
}
175+
164176
// AMO/Zicbom faults should be reported as store faults
165177
#define convert_load_traps_to_store_traps(BODY) \
166178
try { \
@@ -187,6 +199,17 @@ class mmu_t
187199
})
188200
}
189201

202+
// for shadow stack amo swap
203+
template<typename T, typename op>
204+
T ss_amo(reg_t addr, op f) {
205+
convert_load_traps_to_store_traps({
206+
store_slow_path(addr, sizeof(T), nullptr, {false, false, false, /*shstk*/true}, false, true);
207+
auto lhs = ss_load<T>(addr);
208+
ss_store<T>(addr, f(lhs));
209+
return lhs;
210+
})
211+
}
212+
190213
template<typename T>
191214
T amo_compare_and_swap(reg_t addr, T comp, T swap) {
192215
convert_load_traps_to_store_traps({

0 commit comments

Comments
 (0)