On 16 Mar 2017, at 4:52 PM, Watson Ladd <watso...@gmail.com> wrote:Dear all,I have several ideas for potentially useful instructions and extensions that can support additional mitigations. The first is COME FROM. All jump targets must be COME FROM on chips that support it when this extension is used. As a result the available gadgets for control flow manipulation is reduced. COME FROM has no other effects. The second is a shadow stack modification which adds three instructions: CALL, CALLR and RETURN and two privileged-mode registers STACKBASE and STACKLIM as well as modify the memory protection system to add a shadow access type. STACKBASE and STACKLIM are conceptually per user or kernel process.
CALL(R) has the same format as JA(R)L and the same semantics except it does not touch the destination register. Instead the address is pushed onto a stack, that may be dumped to memory between STACKBASE and STACKLIM. RETURN pops this stack. Memory accesses issued by these dumps are in shadow mode: a page with the shadow bit set may be written or read by them. If the stack size exceeds STACKLIM an error is reported to the OS. Multiple processes can use the same shadow page because of the STACKBASE and STACKLIM registers.
I look forward to discussing these proposals further/gathering other instructions that can assist in securing today's software.Sincerely,Watson
--
You received this message because you are subscribed to the Google Groups "RISC-V ISA Dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email to isa-dev+u...@groups.riscv.org.
To post to this group, send email to isa...@groups.riscv.org.
Visit this group at https://groups.google.com/a/groups.riscv.org/group/isa-dev/.
To view this discussion on the web visit https://groups.google.com/a/groups.riscv.org/d/msgid/isa-dev/77269e77-bda1-424b-8d7a-3b45d2225ad7%40groups.riscv.org.
CALL(R) has the same format as JA(R)L and the same semantics except it does not touch the destination register. Instead the address is pushed onto a stack, that may be dumped to memory between STACKBASE and STACKLIM. RETURN pops this stack. Memory accesses issued by these dumps are in shadow mode: a page with the shadow bit set may be written or read by them. If the stack size exceeds STACKLIM an error is reported to the OS. Multiple processes can use the same shadow page because of the STACKBASE and STACKLIM registers.RISC-V has no stack and uses a link register and there is only one indirect call instruction: JALR. RET is simply a macro that uses JALR with the return address link register as the target address (all returns are indirect). CALL is a macro for AUIPC+JALR which in some cases (mentioned above) can be regarded as a direct call.I guess the “stack hints” could be used to maintain a shadow stack which allows detection of return address substitution. i.e. JALR zero, ra where ra differs from the entry ra (maintained in the shadow stack). I wonder if any of these returns would actually be valid. I can look into this as I could map JALR onto a stack in binary translation.
It is also possible for the compiler to use the SafeStack technique (*1) whereby control flow information is spilt separately from the variable sized stack frame. None of the RISC-V jump instructions dictate the use of a particular stack as they do on other architectures, but the “stack hints” could potentially be used for security.RISC-V compilers can in fact save the return address in registers and may not always need to spill the return addresses onto the stack.
It is also possible for the compiler to use the SafeStack technique (*1) whereby control flow information is spilt separately from the variable sized stack frame. None of the RISC-V jump instructions dictate the use of a particular stack as they do on other architectures, but the “stack hints” could potentially be used for security.RISC-V compilers can in fact save the return address in registers and may not always need to spill the return addresses onto the stack.Yes. I was thinking along the lines of a small hardware return-address stack to achieve similar savings, although that might be too much implementation complexity.Regards,Michael.I look forward to discussing these proposals further/gathering other instructions that can assist in securing today's software.Sincerely,Watson--
You received this message because you are subscribed to the Google Groups "RISC-V ISA Dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email to isa-dev+u...@groups.riscv.org.
To post to this group, send email to isa...@groups.riscv.org.
Visit this group at https://groups.google.com/a/groups.riscv.org/group/isa-dev/.
To view this discussion on the web visit https://groups.google.com/a/groups.riscv.org/d/msgid/isa-dev/77269e77-bda1-424b-8d7a-3b45d2225ad7%40groups.riscv.org.
--
You received this message because you are subscribed to the Google Groups "RISC-V ISA Dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email to isa-dev+u...@groups.riscv.org.
To post to this group, send email to isa...@groups.riscv.org.
Visit this group at https://groups.google.com/a/groups.riscv.org/group/isa-dev/.
To view this discussion on the web visit https://groups.google.com/a/groups.riscv.org/d/msgid/isa-dev/ac3fe40c-95a2-4cb4-a284-e0ed1e7cc68d%40groups.riscv.org.
On Thursday, 16 March 2017 18:06:42 PDT Michael Clark wrote:
<snip>
> I think the most salient issue is extensions that depend on using a NOP i.e.
> strengthening extensions that aim to be backwards binary compatible. I
> think the foundation should consider adding some NOP encoding space in the
> base ISA that can be reserved for such extensions. i.e. so that standard
> implementations don’t have to handle costly illegal instruction faults on
> hardware without the jump target and jump return labels, when running
> strengthened code, but still remain binary compatible (just without the
> additive protection).
>
> Adding such custom NOPS (FENCE.NOP1, FENCE.NOP2, FENCE.NOP3, FENCE.NOP4)
> however would probably require a major ISA version number bump as code that
> used these NOPs would fault on current processors. i.e. reserve them in ISA
> version 3.0. I notice there are 4 bits of encoding space in funct7 and 2
> bits in funct3 near to FENCE (which also can also be a NOP on some
> implementations). It could alternatively come out of the CUSTOM opcode
> space, but processors would need to treat some encodings as NOPs to be able
> to run protected code without additional overhead.
>
> Overloading regular NOP embeddings doesn’t seem so clean and may have
> unintended consequences.
<snip>
I strongly disagree. In particular, there is a very large encoding space for NOPs in the existing encoding - ADDI x0, x0, imm12 alone supports 4,096 distinct NOPs, the same encoding space as is available for CSRs.
Throw in SLTI, SLTIU, XORI, ORI, and ANDI and the space grows even more.
Use LUI x0, imm20 and you have a _truly_ absurd encoding space.
If we can trust the RISC-V foundation to manage the CSR encoding space (which is considerably smaller), it seems entirely reasonable to trust them with managing the NOP encoding space similarly, rather than defining new and strange NOPs, which are themselves _not_ backwards-compatible as NOPs with the _released_ userspace ISA.
On 18 Mar 2017, at 7:17 PM, Albert Cahalan <acah...@gmail.com> wrote:On 3/16/17, Michael Clark <michae...@mac.com> wrote:Indirect call target labels for control flow integrity are becoming standard
features in several ISAs.
That said, I don't think RISC-V should implement a shadow stack as has been
done in other CFI implementations.
Consider that a separate issue. (very effective and very messy)A stack-less labelling approach for JALR would be distinct. In fact an
expanded target bit space in the label could provide more protection than
existing labelling approaches. The return label in a stack less model
following a JAL could for example encode some bits of the address of the
return instruction of the target procedure (with static linking) and provide
stronger protection than other CFI labelling techniques. i.e. if an attacker
gets control of the link register. This is in fact where more bits in the
label would be most useful. Returns.
Letting the instructions specify the extra bits on both sides of the jump/call
is better. Languages can use a hash of the function call signature or other
state. Besides generally reducing the available targets, identical hashes
are more likely to be uninteresting to the attacker.
JAL ra, proc# 1 instruction indirect return label (hash)ra: ADDI zero, ra, %pcrel_ret_hash(proc)#externproc:IJT # indirect jump target label…JALR zero, ra
JAL ra, proc# 2 instruction indirect return label (32-bit PC-relative to return)ra: ADDI zero, ra %pcrel_ret_lo(proc)AUIPC zero, %pcrel_ret_hi(proc)#externproc:IJT # indirect jump target label…JALR zero, ra
Calls and returns can somewhat use the same hash as long as there is at
least a way to tell which is which. Flipping all the bits would do. Some kinds
of optimization may die as a result; the returning function won't know the
correct arguments if it was reached via jumping from the tail of a function
that was called from where it is returning to.
Michael Clark wrote:
>> On 17/03/2017, at 3:48 PM, Alex Elsayed <etern...@gmail.com> wrote:
>>
>> I strongly disagree. In particular, there is a very large encoding space for NOPs in the existing encoding - ADDI x0, x0, imm12 alone supports 4,096 distinct NOPs, the same encoding space as is available for CSRs.
>>
>
> Fair point.
>
> Perhaps the use of these NOPs should somehow be coordinated.
>
> Indirect call target labels for control flow integrity are becoming standard features in several ISAs.
>
> That said, I don't think RISC-V should implement a shadow stack as has been done in other CFI implementations.
>
> A stack-less labelling approach for JALR would be distinct. In fact an expanded target bit space in the label could provide more protection than existing labelling approaches. The return label in a stack less model following a JAL could for example encode some bits of the address of the return instruction of the target procedure (with static linking) and provide stronger protection than other CFI labelling techniques. i.e. if an attacker gets control of the link register. This is in fact where more bits in the label would be most useful. Returns.
After thinking about this a bit, (and still unsure if we are being
trolled--"COME FROM" really bothers me)
-- Jacob
-- Jacob
--
You received this message because you are subscribed t8o the Google Groups "RISC-V ISA Dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email to isa-dev+u...@groups.riscv.org.
To post to this group, send email to isa...@groups.riscv.org.
Visit this group at https://groups.google.com/a/groups.riscv.org/group/isa-dev/.
To view this discussion on the web visit https://groups.google.com/a/groups.riscv.org/d/msgid/isa-dev/58CDEFD8.70308%40gmail.com.
On a side note, SafeStack is almost trivial on RISC-V because the stack is purely a software object. Using a second stack exclusively for user data and reserving the primary stack for control flow incurs only a slight cost of 1 or 2 callee-saved registers as stack and frame pointers for the data stack, but the data frame pointer could be stored on the control stack, reducing this to a single additional stack pointer.
-- Jacob
On 31 Mar 2017, at 6:36 PM, Stefan O'Rear <sor...@gmail.com> wrote:On Wed, Mar 15, 2017 at 8:52 PM, Watson Ladd <watso...@gmail.com> wrote:Dear all,
Hello and welcome to the RISC-V community!
(I am not even trying to represent the project in the following.)I have several ideas for potentially useful instructions and extensions that
can support additional mitigations. The first is COME FROM. All jump targets
1. I believe the person in charge of this area is David Chisnall at Cambridge.
2. You may have noticed that the base ISA is aggressively minimal and
leaves out things like integer rotates. Krste has commented a couple
times that "the hardest part is saying no". RISC-V's design purpose
was to be simple enough for research projects. Any proposal to add
anything faces an extremely uphill battle.
3. Proposals to add complicated features are even more uphill, due to
the RISC-V microarchitectural neutrality goal.
4. I for one am looking forward to the day - maybe 100 years from now
- when C is rare enough in security-critical codebases that we don't
have to jump through hoops to deal with stack-buffer overflows.must be COME FROM on chips that support it when this extension is used. As a
5. "When this extension is used" is extremely vague. Minimal
implementations and non-minimal implementations need to share a
software ecosystem, so adding new hard requirements for existing
software is problematic.
6. "Jump targets" is quite a bit of microarchitectural complexity. If
you're jumping to a swapped out page, do you trap before the jump, or
trap after (and lose the chance to check the jump target)?
7. RISC-V has a design goal of being "boring", in the sense that it
imposes very few novel challenges for implementors and compiler
writers. I am not aware of any mainstream ISA that does anything like
this proposal.
--
You received this message because you are subscribed to the Google Groups "RISC-V ISA Dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email to isa-dev+u...@groups.riscv.org.
To post to this group, send email to isa...@groups.riscv.org.
Visit this group at https://groups.google.com/a/groups.riscv.org/group/isa-dev/.
To view this discussion on the web visit https://groups.google.com/a/groups.riscv.org/d/msgid/isa-dev/CADJ6UvOiwC3A8N0RaP3uUPmejLeAX%3DBsf2VP374vqar6y7fQSw%40mail.gmail.com.
On 2 Apr 2017, at 12:12 PM, Jacob Bachmeyer <jcb6...@gmail.com> wrote:Michael Clark wrote:On 2 Apr 2017, at 11:29 AM, Jacob Bachmeyer <jcb6...@gmail.com <mailto:jcb6...@gmail.com>> wrote:
Michael Clark wrote:On 1 Apr 2017, at 2:24 PM, Jacob Bachmeyer <jcb6...@gmail.com <mailto:jcb6...@gmail.com>> wrote:
Michael Clark wrote:
The criticism of Intel’s CET is the number of bits used in indirect jump targets. In a stackless architecture, JALR could propose and expect a CFI cookie instruction at the target of the indirect jump, which may be the return point; the next instruction after JAL(R), or at indirect jump targets, to “tie” the indirect forward and return control flow. This was discussed at lengths in the thread. The number of bits represent the strength of the control flow “tie” and relate to the probability of finding an indirect target that can be used as a gadget. The return target after a JAL, if using the PC relative address of the called functions return can be “completely” tied (at the expense of tail calls). Note that tail calls are not possible in SysV i386 PIC ABI, so comparatively the loss of tail calls for the gain of CFI is not strictly a big loss.See the "sucfistatus" proposal I suggested earlier in this thread--the use of cookies and/or multiple stacks (which would be a pure ABI change, not affecting the hardware at all) does not preclude tail calls, although it does make them effectively visible to the calling function (which must ACCEPT the tail-called function's return cookie). A slightly further improved form of that proposal can even work with millicode--the function PROPOSEs a return cookie, then makes a direct jump to the common epilogue millicode, which returns with its (tail) caller's return cookie intact.
Yes. I liked the idea in principle however I still like the idea of a NOP embedding so that the ROP mitigations can be introduced without backwards incompatible ABI changes. I disagree with the false sense of security argument. It is more about not requiring a different set of binaries to run on systems without the CFI instructions. Backwards compatibility is not particularly novel, but a NOP embedding allows armoured binaries to run on cores without the instructions being present just like Linux or Windows can run on cores without SMAP, SMEP, NX or a variety of other security features being present. I think ABI backwards compatibility is really more of a simple necessity.
The fundamental problem is that there is not enough space in a NOP embedding. Note that the CFI.SALA instruction I suggested is 64 bits long. Also, a "CFI enable" flag allows CFI-capable implementations to run non-CFI binaries (if the discussion had continued, the next rewrite of CFI.SALA would have reduced cookies to 29 bits to accommodate a "CFI active" flag in sucfistatus and/or changed to cookies only), but a program has no good way to determine if its CFI protections are actually effective if the indirect landing is a baseline NOP. Using a new instruction solves this problem--a binary built for CFI will run *only* on systems that actually support CFI. (Or that at least recognize the instructions--a supervisor could take the illegal instruction trap and emulate CFI.SALA, at least for PROPOSE/ACCEPT--another reason to change to cookies only and drop the "how did we get here?" mechanism.)
In your proposal there needs to be some state held while jumping, populated during PROPOSE and checked during ACCEPT.
I can see that the instruction fetch unit is in a jumping state after executing the PROPOSE, changing program counter and then expecting to fetch an ACCEPT. If it is in this state could the jump state machine not reset or accumulate the state from multiple NOPs? in much the same way that you propose that there could be multiple ACCEPT instuctions to handle virtual functions. It is then just a matter of how the landing pad instruction(s) assemble the accept cookie.
This is not what I suggested. PROPOSE merely selects "cookie mode" and sets the cookie. If CFI is active, (baseline) JALR sets IJIP. If IJIP is set, execution of any instruction other than CFI.SALA faults. ACCEPT checks if the cookie matches its immediate and clears IJIP if so.
In "how did we get here?" mode, JALR simply copies its rs1 to a field in sucfistatus. Internal logic converts that value to a one-hot encoding for comparison with the mask in CFI.SALA. If ((mask & onehot) != 0), IJIP is cleared.
Special case: JALR with rs1==x0 does not set IJIP.It’s arguable whether handling another instruction width is more or less complex than populating the bits from what could be handled as “coprocessor instructions” for the “jump state machine”, that switch the fetch unit back into the normal state or cause a trap, depending on the observed cookie.
The state machine that I suggest is much simpler and is integrated into the main execution pipeline:
(1) (optional; selects "cookie mode") CFI.SALA as PROPOSE selects "cookie mode" and sets the cookie
(2) JALR sets IJIP and copies its rs1 to an internal register that is visible in sucfistatus in "how did we get here?" mode
(3a) CFI.SALA in "how did we get here?" mode checks if JALR's rs1 satisfies its mask and clears IJIP if so
(3b) CFI.SALA as ACCEPT checks if a cookie is set and clears both IJIP and "cookie mode" if its immediate matches the current cookie
(4) Executing any instruction other than CFI.SALA while IJIP is set raises CFI violation
I also expect that 64-bit instructions will eventually turn up in most non-microcontroller implementations anyway. (microcontroller == akin to PIC or AVR)
Clearly there has to be a mode where the CFI instructions are not enabled which is an essential part in your design. The argument is whether the cookies can be embedded in NOPs to allow the code to run on existing RISC-V systems.
The instructions are always enabled, but their use is not enforced unless "CFI enable" is set. ("CFI enable" was missing from the last draft.)
In fact, CFI.SALA as PROPOSE/ACCEPT provides another option: JALR can set IJIP even if CFI is not enforced iff a cookie is currently active. This allows a shared library, for example, to use CFI internally even if its host program was not built for CFI.
-- Jacob
--
You received this message because you are subscribed to the Google Groups "RISC-V ISA Dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email to isa-dev+u...@groups.riscv.org.
To post to this group, send email to isa...@groups.riscv.org.
Visit this group at https://groups.google.com/a/groups.riscv.org/group/isa-dev/.
To view this discussion on the web visit https://groups.google.com/a/groups.riscv.org/d/msgid/isa-dev/58E041F3.1020106%40gmail.com.
I’m just arguing that PROPOSE and ACCEPT are encoded within existing NOPs for example by adding a shift or match bit, where n-bits of a 20-bit immediate from a AUIPC NOP can be shifted into the cookie register over one or two instructions, primarily to support binary backwards compatibility.