Date   

Re: comments on PMP enhancements

Andrew Waterman
 



On Tue, Feb 11, 2020 at 8:25 PM John Hauser <jh.riscv@...> wrote:
Hello all,

I've been studying the TEE Task Group's "PMP Enhancements" proposal
with great interest off-and-on for several weeks.  I definitely agree
with the intention of the proposal, but I see several issues.  For
presentation, I've numbered them 1 through 4 below.

1.
Currently, when a memory access is prevented by physical memory
attributes (PMAs) or by PMP, an access fault trap is taken.  The
proposal defines a new "security exception" and requires that some
blocked memory accesses take a security exception trap instead of the
usual access fault.  The document says

    A new exception will help distinguish the exceptions we get with
    the current PMP spec when the access type doesn’t match R/W/X flags
    on the matching rule, from the exception we get when violating the
    access controls of the new mechanisms in place.

I request that some explanation be provided for how this distinction
is expected be helpful; i.e., why "denied" accesses need a different
exception code than "enforced" accesses.  If the reason is supposed
to be obvious, it was not so to me.  Just saying it "will help
distinguish" isn't sufficient.  Why distinguish?  What good does it do?

For me, it seems obvious that these should all be access faults.

2.
As Jonathan Behrens has already noted, some systems depend on being
able to set mstatus.MXR = 1 temporarily to read S/U-executable
instructions, for emulation purposes.  The proposal should be modified
to say that any S/U-mode-only PMP region that grants execute permission
to S/U modes (bit X is set), implicitly grants read permission to
M mode when MXR = 1.

3.
I'm concerned that the use of the reserved combination W = 1, R = 0
for shared memory regions may be incompatible with a future use for
this encoding in page tables.  For example, one possible allocation of
the reserved W/R encoding in page tables could be:

    X W R

    0 1 0   uncached read-only page
    1 1 0   uncached read-write page

If so defined, the same _uncached_ property might also be sensible
for PMP entries, yet we would no longer be able to encode it the same
way, because we have allocated the reserved W/R combination for shared
memory regions instead.

To be clear, I know of no current plans to use the reserved W/R
encoding for an _uncached_ property this way, or for any other purpose.
I am merely giving an example of the sort of inconsistency that could
arise because of our choices today.

I understand that the reserved W/R encoding ended up in use because
there is opposition to touching the two reserved bits that still exist
in a PMP configuration byte, and there are few options for encoding
everything in just the four bits we already have:  L, X, W, R.  My own
choice would be to go ahead and consume a reserved bit to avoid the
risk of creating a mess of the encoding down the road.

4.
The biggest concern I have with the proposal is that the effort to
fully lock down the executable regions for M mode, while correct for
maximizing security in principle, doesn't leave enough flexibility
for some systems.  Tariq Kurd has given an example of a system that,
during booting, progressively expands the regions accessible to M mode,
which the current proposal prohibits.  I'd like to give a couple other
examples that are more specifically about execute permission, but
still revolve around the need to edit M-mode-only PMP entries even when
enhanced security is enabled.

Consider a complex operating system, running in M mode, that supports
loadable "kernel modules", which are components that can be brought
into memory or evicted in response to the varying needs of user-level
tasks.  With the current PMP proposal, when MML = 1, this M-mode OS
cannot dynamically adjust the regions of memory that are executable for
loadable modules.  Instead, the OS authors must make a choice:  either
pre-allocate the maximal amount of memory that could ever be needed for
loaded kernel modules, possibly wasting memory, or entirely forgo using
the security enhancement.  If they choose the latter because memory
really is scarce, how has security been improved?

Or consider the situation where there is more than one independent
stage of boot-time software that could benefit from enhanced PMP
security.  U-Boot, for example, is a complex piece of software in its
own right.  If a bootloader like U-Boot is used in an M/U-only system,
it's easy to imagine that enhanced security could help guard against
attacks.  But with the current proposal, U-Boot cannot set MML = 1,
because it would have to configure the executable regions not only
for itself but also for the operating system it subsequently loads,
something outside its knowledge or authority.  Because all current and
future executable regions must be known and configured before MML can
be enabled, a U-Boot-like loader must run with MML = 0.  Again, this
seems like a loss for security in this instance.

I have no argument with anyone who needs all the restrictions the
current proposal provides; we should be able to offer that.  But if we
require always that all executable regions be locked down in advance,
we're not providing sufficient flexibility for all systems at all
times, instead sometimes forcing an awkward "maximal security or none"
choice.

(To help his particular system, Mr. Kurd has proposed a DPL bit, Delay
PMP Lock.  However, this bit would conflict with one of the intended
purposes of PMP locking as I understand it, which is to permit earlier
initialization software to protect some regions from access by later,
less trusted, M-mode code.  By itself, the DPL solution is too simple
because, in general, we need to be able to set some PMP entries that
stay locked, while at the same time other entries remain unlocked for
editing but are nonetheless enforced.)

To bridge the gap between "maximal security" and "none", I've developed
a modified proposal with four security levels rather than just the
current two (MML = 0 or 1).  Unfortunately, I see no good way to
provide all the needed flexibility without also taking one of the two
reserved PMP configuration bits.  While having four security levels may
sound more complex, actually it's not, because the extra configuration
bit allows some encoding complexity to be reduced at the same time.
The only significant cost is the allocation of the reserved bit.  I'll
be sending my modified proposal in a follow-up message.

A while ago, I expressed opposition to consuming one of the remaining pmpcfg bits because it seemed, at the time, that the goals of this proposal could be accomplished without doing so.  If that is not in fact the case, I withdraw my objection.


Regards,

    - John Hauser




Re: comments on PMP enhancements

Sean Halle
 

Thank you John, Joe, Greg and Andrew for the interesting discussion.

One general question, at more of a management level.  Our architecture has 16 harts per core.  That means that the CSR logic is one of the largest modules in the core.  As a result, we are very sensitive to changes in the spec that would expand the CSR module further.  I have to admit that I didn't get a chance to dive deep enough to get a firm grasp on the implications of the proposed changes as far as changes to the amount of state that would be needed to support the upstream kernel on a distro like Fedora for high performance.  It appears at first blush that there would be no impact.. but there are many subtleties involved..  could you put our mind at rest about the consequences on logic to implement and especially impact on number of CSRs (assuming a high performance core and a distro like Fedora)?

Thank you,

Sean


On Wed, Feb 12, 2020 at 1:33 PM Andrew Waterman <andrew@...> wrote:


On Tue, Feb 11, 2020 at 8:25 PM John Hauser <jh.riscv@...> wrote:
Hello all,

I've been studying the TEE Task Group's "PMP Enhancements" proposal
with great interest off-and-on for several weeks.  I definitely agree
with the intention of the proposal, but I see several issues.  For
presentation, I've numbered them 1 through 4 below.

1.
Currently, when a memory access is prevented by physical memory
attributes (PMAs) or by PMP, an access fault trap is taken.  The
proposal defines a new "security exception" and requires that some
blocked memory accesses take a security exception trap instead of the
usual access fault.  The document says

    A new exception will help distinguish the exceptions we get with
    the current PMP spec when the access type doesn’t match R/W/X flags
    on the matching rule, from the exception we get when violating the
    access controls of the new mechanisms in place.

I request that some explanation be provided for how this distinction
is expected be helpful; i.e., why "denied" accesses need a different
exception code than "enforced" accesses.  If the reason is supposed
to be obvious, it was not so to me.  Just saying it "will help
distinguish" isn't sufficient.  Why distinguish?  What good does it do?

For me, it seems obvious that these should all be access faults.

2.
As Jonathan Behrens has already noted, some systems depend on being
able to set mstatus.MXR = 1 temporarily to read S/U-executable
instructions, for emulation purposes.  The proposal should be modified
to say that any S/U-mode-only PMP region that grants execute permission
to S/U modes (bit X is set), implicitly grants read permission to
M mode when MXR = 1.

3.
I'm concerned that the use of the reserved combination W = 1, R = 0
for shared memory regions may be incompatible with a future use for
this encoding in page tables.  For example, one possible allocation of
the reserved W/R encoding in page tables could be:

    X W R

    0 1 0   uncached read-only page
    1 1 0   uncached read-write page

If so defined, the same _uncached_ property might also be sensible
for PMP entries, yet we would no longer be able to encode it the same
way, because we have allocated the reserved W/R combination for shared
memory regions instead.

To be clear, I know of no current plans to use the reserved W/R
encoding for an _uncached_ property this way, or for any other purpose.
I am merely giving an example of the sort of inconsistency that could
arise because of our choices today.

I understand that the reserved W/R encoding ended up in use because
there is opposition to touching the two reserved bits that still exist
in a PMP configuration byte, and there are few options for encoding
everything in just the four bits we already have:  L, X, W, R.  My own
choice would be to go ahead and consume a reserved bit to avoid the
risk of creating a mess of the encoding down the road.

4.
The biggest concern I have with the proposal is that the effort to
fully lock down the executable regions for M mode, while correct for
maximizing security in principle, doesn't leave enough flexibility
for some systems.  Tariq Kurd has given an example of a system that,
during booting, progressively expands the regions accessible to M mode,
which the current proposal prohibits.  I'd like to give a couple other
examples that are more specifically about execute permission, but
still revolve around the need to edit M-mode-only PMP entries even when
enhanced security is enabled.

Consider a complex operating system, running in M mode, that supports
loadable "kernel modules", which are components that can be brought
into memory or evicted in response to the varying needs of user-level
tasks.  With the current PMP proposal, when MML = 1, this M-mode OS
cannot dynamically adjust the regions of memory that are executable for
loadable modules.  Instead, the OS authors must make a choice:  either
pre-allocate the maximal amount of memory that could ever be needed for
loaded kernel modules, possibly wasting memory, or entirely forgo using
the security enhancement.  If they choose the latter because memory
really is scarce, how has security been improved?

Or consider the situation where there is more than one independent
stage of boot-time software that could benefit from enhanced PMP
security.  U-Boot, for example, is a complex piece of software in its
own right.  If a bootloader like U-Boot is used in an M/U-only system,
it's easy to imagine that enhanced security could help guard against
attacks.  But with the current proposal, U-Boot cannot set MML = 1,
because it would have to configure the executable regions not only
for itself but also for the operating system it subsequently loads,
something outside its knowledge or authority.  Because all current and
future executable regions must be known and configured before MML can
be enabled, a U-Boot-like loader must run with MML = 0.  Again, this
seems like a loss for security in this instance.

I have no argument with anyone who needs all the restrictions the
current proposal provides; we should be able to offer that.  But if we
require always that all executable regions be locked down in advance,
we're not providing sufficient flexibility for all systems at all
times, instead sometimes forcing an awkward "maximal security or none"
choice.

(To help his particular system, Mr. Kurd has proposed a DPL bit, Delay
PMP Lock.  However, this bit would conflict with one of the intended
purposes of PMP locking as I understand it, which is to permit earlier
initialization software to protect some regions from access by later,
less trusted, M-mode code.  By itself, the DPL solution is too simple
because, in general, we need to be able to set some PMP entries that
stay locked, while at the same time other entries remain unlocked for
editing but are nonetheless enforced.)

To bridge the gap between "maximal security" and "none", I've developed
a modified proposal with four security levels rather than just the
current two (MML = 0 or 1).  Unfortunately, I see no good way to
provide all the needed flexibility without also taking one of the two
reserved PMP configuration bits.  While having four security levels may
sound more complex, actually it's not, because the extra configuration
bit allows some encoding complexity to be reduced at the same time.
The only significant cost is the allocation of the reserved bit.  I'll
be sending my modified proposal in a follow-up message.

A while ago, I expressed opposition to consuming one of the remaining pmpcfg bits because it seemed, at the time, that the goals of this proposal could be accomplished without doing so.  If that is not in fact the case, I withdraw my objection.


Regards,

    - John Hauser




Re: misa.T bit = Ztso?

Andrew Waterman
 


On Mon, Dec 30, 2019 at 1:05 PM Andrew Waterman <andrew@...> wrote:
A while back, it was proposed that the Ztso extension (which strengthens the memory model to RVTSO instead of RVWMO) be discoverable via the misa.T bit.  The T bit had been tentatively reserved for a transactional memory extension, but there has been no progress on that front, and there probably won't be for a while.

If we were to repurpose misa.T for Ztso, then we would (for now) require that misa.T not be writable, and that all harts hardwire misa.T to the same value.  This allows us to avoid specifying what it means to have RVTSO and RVWMO harts interacting with each other.  In the future, we could consider revising the spec to allow the bit to be writable.

The alternative is to make Ztso discoverable through some other mechanism (i.e. config string).

I have a slight preference for using misa.T for this purpose, because it'll make it easier to support dynamically switching the memory model, should we ever choose to allow that.  What do y'all think?

Andrew


Re: comments on PMP enhancements

John Hauser
 

Sean Halle wrote:
I have to admit that
I didn't get a chance to dive deep enough to get a firm grasp on the
implications of the proposed changes as far as changes to the amount of
state that would be needed to support the upstream kernel on a distro like
Fedora for high performance. It appears at first blush that there would be
no impact.. but there are many subtleties involved.. could you put our
mind at rest about the consequences on logic to implement and especially
impact on number of CSRs (assuming a high performance core and a distro
like Fedora)?
Hi Sean,

I'm afraid I wasn't completely clear on what question you're asking.
Is your baseline case a Fedora OS that doesn't configure PMP? I don't
know the current behavior of Fedora, but it's certainly possible it
doesn't use PMP to date. If that's the case, the number of PMP entries
your system would need per hart is obviously minimized, possibly zero.
That said, your existing hardware may implement some number of PMP
entries anyway, and I would not know what that number is, for purposes
of comparison. So I think there are yet too many unknowns in this
question for me to try to answer.

In terms of the cost of my proposal for four security levels versus
the task group's working proposal, it's impossible to give any exact
numbers without an actual implementation, but I can suggest some
ballpark estimates. First, there is a cost per PMP entry of one
flip-flop (definitely) and perhaps a dozen additional gates. Add to
that another maybe two dozen gates shared by all PMP entries; how many
gates, I'm not sure. Altogether that should be relatively small
on a per-PMP-entry basis. By far, the most expensive parts of a PMP
implementation have got to be the address CSRs and the checking for
address matches, both of which are unchanged by any of these security
enhancement proposals, either the working proposal or mine.

With my proposal, some systems might need fewer PMP entries than with
the working proposal, which could be a net hardware savings if fewer
entries are actually implemented. Such (potential) savings would be
very much software-dependent.

Regards,

- John Hauser


Re: comments on PMP enhancements

Bill Huffman
 

Hello John,

I'm thinking positively about your proposal for a 2-bit MSL field and a
2-bit PL field per PMP entry. But I'm still a little concerned by what
you say below...

Chipmakers sometimes wish to include code in a memory region which is
set by boot code to be execute-only forever (until reset). They want to
do this so that even their customers, who do additional programming on
the chip - including in M mode - cannot read the chipmaker's code.

With the statements about MXR, MPRV, and MPP below, I think this can
only be accomplished for code executable in M mode only. I wonder if
there is a way it can be done for code executable in S/U mode.

Bill

On 2/11/20 8:48 PM, John Hauser wrote:

I wrote:
2.
As Jonathan Behrens has already noted, some systems depend on being
able to set mstatus.MXR = 1 temporarily to read S/U-executable
instructions, for emulation purposes. The proposal should be modified
to say that any S/U-mode-only PMP region that grants execute permission
to S/U modes (bit X is set), implicitly grants read permission to
M mode when MXR = 1.
Correction: I believe that should say "... implicitly grants read
permission to S/U modes when in M mode and MXR = 1". This is relevant
only when MPRV = 1 and MPP = 0 or 1, so it's a rather narrow case.
Hopefully I've got it right this time.

- John Hauser



Re: comments on PMP enhancements

John Hauser
 

Bill Huffman wrote:
Chipmakers sometimes wish to include code in a memory region which is
set by boot code to be execute-only forever (until reset). They want to
do this so that even their customers, who do additional programming on
the chip - including in M mode - cannot read the chipmaker's code.

With the statements about MXR, MPRV, and MPP below, I think this can
only be accomplished for code executable in M mode only.
Concerning PMP, that's what I was suggesting, yes.

I wonder if there is a way it can be done for code executable in S/U
mode.
I believe the answer can be physical memory attributes (PMAs), which
apply in addition to the software-programmable PMP mechanism. If this
is a ROM at known addresses, then just say the region is execute-only
according to the machine's PMAs. PMP can't override that.

If the address range is unknown at chip fabrication time or starts as
writable, you can still invent a custom mechanism to manipulate the
chip's PMAs underneath the standard PMP facility, without violating
any RISC-V rules as I understand them. Obviously, a custom mechanism
wouldn't be portable beyond your own line of chips, but it doesn't need
to be for this purpose, does it?

- John Hauser


Re: comments on PMP enhancements

Bill Huffman
 

On 2/12/20 10:38 PM, John Hauser wrote:

Bill Huffman wrote:
Chipmakers sometimes wish to include code in a memory region which is
set by boot code to be execute-only forever (until reset). They want to
do this so that even their customers, who do additional programming on
the chip - including in M mode - cannot read the chipmaker's code.

With the statements about MXR, MPRV, and MPP below, I think this can
only be accomplished for code executable in M mode only.
Concerning PMP, that's what I was suggesting, yes.

I wonder if there is a way it can be done for code executable in S/U
mode.
I believe the answer can be physical memory attributes (PMAs), which
apply in addition to the software-programmable PMP mechanism. If this
is a ROM at known addresses, then just say the region is execute-only
according to the machine's PMAs. PMP can't override that.

If the address range is unknown at chip fabrication time or starts as
writable, you can still invent a custom mechanism to manipulate the
chip's PMAs underneath the standard PMP facility, without violating
any RISC-V rules as I understand them. Obviously, a custom mechanism
wouldn't be portable beyond your own line of chips, but it doesn't need
to be for this purpose, does it?

- John Hauser
Sure, something custom would work. And what you suggested is a good
possibility. But I brought it up because I thought the use case might
be more broadly applicable and maybe some combination in the privilege
spec would allow for that. I'll think some more about it.

Bill


Re: comments on PMP enhancements

Nick Kossifidis
 

Hello John and thanks for your feedback,


On 2/12/20 6:19 AM, John Hauser wrote:
1.
Currently, when a memory access is prevented by physical memory
attributes (PMAs) or by PMP, an access fault trap is taken. The
proposal defines a new "security exception" and requires that some
blocked memory accesses take a security exception trap instead of the
usual access fault. The document says

A new exception will help distinguish the exceptions we get with
the current PMP spec when the access type doesn’t match R/W/X flags
on the matching rule, from the exception we get when violating the
access controls of the new mechanisms in place.

I request that some explanation be provided for how this distinction
is expected be helpful; i.e., why "denied" accesses need a different
exception code than "enforced" accesses. If the reason is supposed
to be obvious, it was not so to me. Just saying it "will help
distinguish" isn't sufficient. Why distinguish? What good does it do?

For me, it seems obvious that these should all be access faults.
The new mechanism (when MML is set) introduces a barrier between S/U
mode and M mode, We want to be able to distinguish between an access
fault due to crossing that barrier, from other access faults. In other
words if M mode gets an access fault on its own memory we'll get an
access fault as in the current spec, if it gets an access fault on
memory that's marked for S/U use (see truth table) we'll get a security
exception. The reason is that we may want to handle this differently in
sw and it also helps in debugging.

2.
As Jonathan Behrens has already noted, some systems depend on being
able to set mstatus.MXR = 1 temporarily to read S/U-executable
instructions, for emulation purposes. The proposal should be modified
to say that any S/U-mode-only PMP region that grants execute permission
to S/U modes (bit X is set), implicitly grants read permission to
M mode when MXR = 1.
mstatus.MXR is not related to PMP, it's related to virtual memory
permissions and is outside PMP's scope, the scenario you mention
involves using mstatus.MPRV to access the region with S/U privileges
(and virtual memory in place). That's still possible because the
access in this case happens as S/U mode (not as M mode) and so the
S/U mode PMP rules apply.

3.
I'm concerned that the use of the reserved combination W = 1, R = 0
for shared memory regions may be incompatible with a future use for
this encoding in page tables. For example, one possible allocation of
the reserved W/R encoding in page tables could be:

X W R

0 1 0 uncached read-only page
1 1 0 uncached read-write page

If so defined, the same _uncached_ property might also be sensible
for PMP entries, yet we would no longer be able to encode it the same
way, because we have allocated the reserved W/R combination for shared
memory regions instead.

To be clear, I know of no current plans to use the reserved W/R
encoding for an _uncached_ property this way, or for any other purpose.
I am merely giving an example of the sort of inconsistency that could
arise because of our choices today.

I understand that the reserved W/R encoding ended up in use because
there is opposition to touching the two reserved bits that still exist
in a PMP configuration byte, and there are few options for encoding
everything in just the four bits we already have: L, X, W, R. My own
choice would be to go ahead and consume a reserved bit to avoid the
risk of creating a mess of the encoding down the road.
I see your point (that was also our initial approach as you mentioned)
but I don't see why we should be compatible with PTEs. The write-only
combination may be used for all sorts of different reasons on PTEs, it
doesn't have to be compatible with PMP rules. Also we are dealing with a
different resource (physical memory vs virtual), with different address
mapping schemes (we don't have pages here) and different needs (a shared
page for example is a different thing than a shared PMP region, it can
be executable e.g. across processes on U mode).

4.
The biggest concern I have with the proposal is that the effort to
fully lock down the executable regions for M mode, while correct for
maximizing security in principle, doesn't leave enough flexibility
for some systems. Tariq Kurd has given an example of a system that,
during booting, progressively expands the regions accessible to M mode,
which the current proposal prohibits. I'd like to give a couple other
examples that are more specifically about execute permission, but
still revolve around the need to edit M-mode-only PMP entries even when
enhanced security is enabled.

Consider a complex operating system, running in M mode, that supports
loadable "kernel modules", which are components that can be brought
into memory or evicted in response to the varying needs of user-level
tasks. With the current PMP proposal, when MML = 1, this M-mode OS
cannot dynamically adjust the regions of memory that are executable for
loadable modules. Instead, the OS authors must make a choice: either
pre-allocate the maximal amount of memory that could ever be needed for
loaded kernel modules, possibly wasting memory, or entirely forgo using
the security enhancement. If they choose the latter because memory
really is scarce, how has security been improved?

Or consider the situation where there is more than one independent
stage of boot-time software that could benefit from enhanced PMP
security. U-Boot, for example, is a complex piece of software in its
own right. If a bootloader like U-Boot is used in an M/U-only system,
it's easy to imagine that enhanced security could help guard against
attacks. But with the current proposal, U-Boot cannot set MML = 1,
because it would have to configure the executable regions not only
for itself but also for the operating system it subsequently loads,
something outside its knowledge or authority. Because all current and
future executable regions must be known and configured before MML can
be enabled, a U-Boot-like loader must run with MML = 0. Again, this
seems like a loss for security in this instance.

I have no argument with anyone who needs all the restrictions the
current proposal provides; we should be able to offer that. But if we
require always that all executable regions be locked down in advance,
we're not providing sufficient flexibility for all systems at all
times, instead sometimes forcing an awkward "maximal security or none"
choice.

(To help his particular system, Mr. Kurd has proposed a DPL bit, Delay
PMP Lock. However, this bit would conflict with one of the intended
purposes of PMP locking as I understand it, which is to permit earlier
initialization software to protect some regions from access by later,
less trusted, M-mode code. By itself, the DPL solution is too simple
because, in general, we need to be able to set some PMP entries that
stay locked, while at the same time other entries remain unlocked for
editing but are nonetheless enforced.)
The issue you mention is there regardless of the MML bit, in the current
spec the only way to restrict M mode is also by using locked rules. I
don't see how we can enforce memory isolation across M-mode processes /
boot stages by allowing the rules that enforce that isolation to be
removed by M-mode.

It's not the same thing as with S mode or U mode where one needs to
tamper with page tables to be able to bypass memory isolation, to do so
one has to completely compromise the core of the OS, in which case there
are bigger security issues to worry about. In this case removing a PMP
rule is one instruction away, the attacker doesn't need to tamper with
any data structures nor take control over the OS. I don't see what kind
of security benefits we get e.g. across different boot stages on M-mode
where the next stage can just flush the PMP ruleset in 16 instructions
or less. I can only see this as a debug feature to be able to catch
invalid accesses, or as in Tariq's threat model, detect a glitch attack.
Also note that in Tariq's case they lock down all memory by default and
gradualy allow regions as the boot process moves on, something also not
compatible with current PMP spec.

Such a discussion however is more relevant to secure boot /
anti-tampering than a proposal for preventing memory access / execution
from M mode like this one. Locking down mtvec for example is a far more
important feature when it comes to secure boot.

As for the examples you brought up, MML is meant to be set after
system's initialization. Initialization may as well include loading
kernel modules or unpacking the kernel etc (especially when that happens
on M mode). It's up to the developers / administrators to decide when to
switch it on. As mentioned on the proposal:

"The idea with this restriction is that after the Firmware or the OS
running on M-mode is initialized, no new code regions are expected to be
added since nothing else is expected to run on M-mode (everything else
will run on S/U mode). Since we want to limit the attack surface of the
system as much as possible, it makes sense to disallow any new code
regions which may include malicious code to be executed on M-mode."

Unless for some reasons people need to load/unload kernel modules all
the time, I don't see how MML prevents them to use them during boot and
set MML afterwards, modules are usually loaded early on init, before
loading daemons and allowing user sessions.

To bridge the gap between "maximal security" and "none", I've developed
a modified proposal with four security levels rather than just the
current two (MML = 0 or 1). Unfortunately, I see no good way to
provide all the needed flexibility without also taking one of the two
reserved PMP configuration bits. While having four security levels may
sound more complex, actually it's not, because the extra configuration
bit allows some encoding complexity to be reduced at the same time.
The only significant cost is the allocation of the reserved bit. I'll
be sending my modified proposal in a follow-up message.
I'll check it out and reply there. Have in mind that this proposal is
meant to solve a specific problem related to a specific threat model,
it's not about changing PMP in general to do all sorts of stuff. Before
we have something else I'd appreciate a threat model and a problem
description.

P.S. U-boot usually knows the executable regions of the kernel, first
because it needs to jump there, second because it's the one that put the
kernel there (and/or unpacked it). Unless we are talking about a kernel
that self-extracts or relocates itself, u-boot can set MML before
jumping to the kernel if needed (and there are no modules to load).

Also loadable modules are not considered a secure approach (unless you
force them to be valid signed etc), nor they save resources (to the
contrary you need more resources to support loading them, even more for
verifying their integrity / authenticity). On embedded systems such as
those without S mode, where Linux will run on M mode, the vendor most
probably knows the hardware in there and will use a static kernel image
instead of supporting loading modules, to save up resources. The only
reason I see for using loadable modules there would be some licensing
stuff that prevents them from being built-in the kernel image.


Regards,
Nick


Re: [RISC-V] [tech-tee] [RISC-V] [tech-privileged] comments on PMP enhancements

Mr Tariq Kurd <tariq.kurd@...>
 

>A while ago, I expressed opposition to consuming one of the remaining pmpcfg bits because it seemed,

>at the time, that the goals of this proposal could be accomplished without doing so.  If that is not in

>fact the case, I withdraw my objection.

 

If we can use one of the reserved bits then the whole problem becomes much simpler because we no longer need to overload the behaviour of the L bit. Simply separating the locking from the permission programming in the PMP proposal is a much more elegant solution, and gives much more flexibility than the DPL bit. I think the cost of 1-bit per PMP entry is very low (only 16-flip-flops in total).

 

I think that we will sleep much more easily if we separate the functionality, because the current proposal excludes use cases that we already know of (as listed in this email thread) and will exclude others that we have yet to discover.

 

Can we proceed in this direction?

 

Tariq

 

From: tech-tee@... [mailto:tech-tee@...] On Behalf Of Andrew Waterman
Sent: 12 February 2020 21:33
To: John Hauser <jh.riscv@...>
Cc: tech-privileged@...; tech-tee@...; Nick Kossifidis <mick@...>
Subject: Re: [RISC-V] [tech-tee] [RISC-V] [tech-privileged] comments on PMP enhancements

 

 

 

On Tue, Feb 11, 2020 at 8:25 PM John Hauser <jh.riscv@...> wrote:

Hello all,

I've been studying the TEE Task Group's "PMP Enhancements" proposal
with great interest off-and-on for several weeks.  I definitely agree
with the intention of the proposal, but I see several issues.  For
presentation, I've numbered them 1 through 4 below.

1.
Currently, when a memory access is prevented by physical memory
attributes (PMAs) or by PMP, an access fault trap is taken.  The
proposal defines a new "security exception" and requires that some
blocked memory accesses take a security exception trap instead of the
usual access fault.  The document says

    A new exception will help distinguish the exceptions we get with
    the current PMP spec when the access type doesn’t match R/W/X flags
    on the matching rule, from the exception we get when violating the
    access controls of the new mechanisms in place.

I request that some explanation be provided for how this distinction
is expected be helpful; i.e., why "denied" accesses need a different
exception code than "enforced" accesses.  If the reason is supposed
to be obvious, it was not so to me.  Just saying it "will help
distinguish" isn't sufficient.  Why distinguish?  What good does it do?

For me, it seems obvious that these should all be access faults.

2.
As Jonathan Behrens has already noted, some systems depend on being
able to set mstatus.MXR = 1 temporarily to read S/U-executable
instructions, for emulation purposes.  The proposal should be modified
to say that any S/U-mode-only PMP region that grants execute permission
to S/U modes (bit X is set), implicitly grants read permission to
M mode when MXR = 1.

3.
I'm concerned that the use of the reserved combination W = 1, R = 0
for shared memory regions may be incompatible with a future use for
this encoding in page tables.  For example, one possible allocation of
the reserved W/R encoding in page tables could be:

    X W R

    0 1 0   uncached read-only page
    1 1 0   uncached read-write page

If so defined, the same _uncached_ property might also be sensible
for PMP entries, yet we would no longer be able to encode it the same
way, because we have allocated the reserved W/R combination for shared
memory regions instead.

To be clear, I know of no current plans to use the reserved W/R
encoding for an _uncached_ property this way, or for any other purpose.
I am merely giving an example of the sort of inconsistency that could
arise because of our choices today.

I understand that the reserved W/R encoding ended up in use because
there is opposition to touching the two reserved bits that still exist
in a PMP configuration byte, and there are few options for encoding
everything in just the four bits we already have:  L, X, W, R.  My own
choice would be to go ahead and consume a reserved bit to avoid the
risk of creating a mess of the encoding down the road.

4.
The biggest concern I have with the proposal is that the effort to
fully lock down the executable regions for M mode, while correct for
maximizing security in principle, doesn't leave enough flexibility
for some systems.  Tariq Kurd has given an example of a system that,
during booting, progressively expands the regions accessible to M mode,
which the current proposal prohibits.  I'd like to give a couple other
examples that are more specifically about execute permission, but
still revolve around the need to edit M-mode-only PMP entries even when
enhanced security is enabled.

Consider a complex operating system, running in M mode, that supports
loadable "kernel modules", which are components that can be brought
into memory or evicted in response to the varying needs of user-level
tasks.  With the current PMP proposal, when MML = 1, this M-mode OS
cannot dynamically adjust the regions of memory that are executable for
loadable modules.  Instead, the OS authors must make a choice:  either
pre-allocate the maximal amount of memory that could ever be needed for
loaded kernel modules, possibly wasting memory, or entirely forgo using
the security enhancement.  If they choose the latter because memory
really is scarce, how has security been improved?

Or consider the situation where there is more than one independent
stage of boot-time software that could benefit from enhanced PMP
security.  U-Boot, for example, is a complex piece of software in its
own right.  If a bootloader like U-Boot is used in an M/U-only system,
it's easy to imagine that enhanced security could help guard against
attacks.  But with the current proposal, U-Boot cannot set MML = 1,
because it would have to configure the executable regions not only
for itself but also for the operating system it subsequently loads,
something outside its knowledge or authority.  Because all current and
future executable regions must be known and configured before MML can
be enabled, a U-Boot-like loader must run with MML = 0.  Again, this
seems like a loss for security in this instance.

I have no argument with anyone who needs all the restrictions the
current proposal provides; we should be able to offer that.  But if we
require always that all executable regions be locked down in advance,
we're not providing sufficient flexibility for all systems at all
times, instead sometimes forcing an awkward "maximal security or none"
choice.

(To help his particular system, Mr. Kurd has proposed a DPL bit, Delay
PMP Lock.  However, this bit would conflict with one of the intended
purposes of PMP locking as I understand it, which is to permit earlier
initialization software to protect some regions from access by later,
less trusted, M-mode code.  By itself, the DPL solution is too simple
because, in general, we need to be able to set some PMP entries that
stay locked, while at the same time other entries remain unlocked for
editing but are nonetheless enforced.)

To bridge the gap between "maximal security" and "none", I've developed
a modified proposal with four security levels rather than just the
current two (MML = 0 or 1).  Unfortunately, I see no good way to
provide all the needed flexibility without also taking one of the two
reserved PMP configuration bits.  While having four security levels may
sound more complex, actually it's not, because the extra configuration
bit allows some encoding complexity to be reduced at the same time.
The only significant cost is the allocation of the reserved bit.  I'll
be sending my modified proposal in a follow-up message.

 

A while ago, I expressed opposition to consuming one of the remaining pmpcfg bits because it seemed, at the time, that the goals of this proposal could be accomplished without doing so.  If that is not in fact the case, I withdraw my objection.

 


Regards,

    - John Hauser



Re: comments on PMP enhancements

John Hauser
 

Nick Kossifidis wrote:
The new mechanism (when MML is set) introduces a barrier between S/U
mode and M mode, We want to be able to distinguish between an access
fault due to crossing that barrier, from other access faults. In other
words if M mode gets an access fault on its own memory we'll get an
access fault as in the current spec, if it gets an access fault on
memory that's marked for S/U use (see truth table) we'll get a security
exception. The reason is that we may want to handle this differently in
sw and it also helps in debugging.
I'm sorry to say, providing information to a debugger is not usually
considered a valid reason for additional RISC-V exception codes when
the same information can be extracted from elsewhere. If it were,
RISC-V would have dozens more exception codes than it does. A debugger
is assumed to be able to examine the PMP table itself, if necessary, to
learn more about the cause of a fault.

Your reason that "we may want to handle this differently in software"
is no more specific than before. I see your desire to be as helpful
as possible to software (and debugging), but please understand, this
sort of "might be useful" argument for additional exception codes
has already been rejected many times before. To make a better case,
you need at a minimum a compelling example that requires different
handling, and probably one where speed matters (so the software can't
just examine the PMP table to separate the cases itself).

mstatus.MXR is not related to PMP, it's related to virtual memory
permissions and is outside PMP's scope, the scenario you mention
involves using mstatus.MPRV to access the region with S/U privileges
(and virtual memory in place). That's still possible because the
access in this case happens as S/U mode (not as M mode) and so the
S/U mode PMP rules apply.
The case that needs to be dealt with is an S/U-mode-only region that
is execute-only, without read permission. (Please see my correction
in another message.) In such a case, M mode has the authority to
temporarily reprogram the PMP entry to grant read permission to S/U
mode, then perform a read with MPRV = 1, and lastly restore the PMP
entry to execute-only. If address translation is active, this actually
requires M mode first walk the page tables to translate the virtual
address into a physical address before searching the PMP table to find
the relevant PMP entry. But there's no reason for us to make software
go through all this trouble; we should just have MXR = 1 grant read
permission to S/U level while executing in M mode. (Yes, that sounds
contradictory, but remember it's for when MPRV = 1.)

Have in mind that this proposal is
meant to solve a specific problem related to a specific threat model,
it's not about changing PMP in general to do all sorts of stuff. Before
we have something else I'd appreciate a threat model and a problem
description.
I believe we need to widen the scope of this proposal to cover other
cases. Sticking to the narrower scope you prefer would be fine except
for one thing: We know that handling these other cases is going to
also involve PMP, so there's an overlap there. If we don't try to
address all the demands on PMP together, we will end up with a layering
of modifications that, as Greg Favor has said, are not likely to fit
together as well.

Locking down mtvec may also be important, but since it doesn't involve
PMP, such other security features can be defined independently, as you
propose.

P.S. U-boot usually knows the executable regions of the kernel, first
because it needs to jump there, second because it's the one that put the
kernel there (and/or unpacked it). Unless we are talking about a kernel
that self-extracts or relocates itself, u-boot can set MML before
jumping to the kernel if needed (and there are no modules to load).
As you put it yourself, "U-Boot usually knows the executable regions of
the kernel", except when it doesn't, because the kernel self-extracts,
or relocates itself, or has loadable modules. And yes, if desired, an
OS's loadable modules might be signed; I don't see why not. I think we
should want to cover as many use cases as we reasonably can, as best as
we can.

Regards,

- John Hauser


Re: comments on PMP enhancements

Andrew Waterman
 



On Thu, Feb 13, 2020 at 12:31 PM John Hauser <jh.riscv@...> wrote:
Nick Kossifidis wrote:
> The new mechanism (when MML is set) introduces a barrier between S/U
> mode and M mode, We want to be able to distinguish between an access
> fault due to crossing that barrier, from other access faults. In other
> words if M mode gets an access fault on its own memory we'll get an
> access fault as in the current spec, if it gets an access fault on
> memory that's marked for S/U use (see truth table) we'll get a security
> exception. The reason is that we may want to handle this differently in
> sw and it also helps in debugging.

I'm sorry to say, providing information to a debugger is not usually
considered a valid reason for additional RISC-V exception codes when
the same information can be extracted from elsewhere.  If it were,
RISC-V would have dozens more exception codes than it does.  A debugger
is assumed to be able to examine the PMP table itself, if necessary, to
learn more about the cause of a fault.

Your reason that "we may want to handle this differently in software"
is no more specific than before.  I see your desire to be as helpful
as possible to software (and debugging), but please understand, this
sort of "might be useful" argument for additional exception codes
has already been rejected many times before.  To make a better case,
you need at a minimum a compelling example that requires different
handling, and probably one where speed matters (so the software can't
just examine the PMP table to separate the cases itself).

I concur with JohnH's reasoning.  Omitting the new cause code does not remove any essential functionality, since M-mode software or debugger software can examine the protection and translation structures to determine why the exception occurred.  So the new cause codes would need to be motivated by improving the performance of a critical code path.


> mstatus.MXR is not related to PMP, it's related to virtual memory
> permissions and is outside PMP's scope, the scenario you mention
> involves using mstatus.MPRV to access the region with S/U privileges
> (and virtual memory in place). That's still possible because the
> access in this case happens as S/U mode (not as M mode) and so the
> S/U mode PMP rules apply.

The case that needs to be dealt with is an S/U-mode-only region that
is execute-only, without read permission.  (Please see my correction
in another message.)  In such a case, M mode has the authority to
temporarily reprogram the PMP entry to grant read permission to S/U
mode, then perform a read with MPRV = 1, and lastly restore the PMP
entry to execute-only.  If address translation is active, this actually
requires M mode first walk the page tables to translate the virtual
address into a physical address before searching the PMP table to find
the relevant PMP entry.  But there's no reason for us to make software
go through all this trouble; we should just have MXR = 1 grant read
permission to S/U level while executing in M mode.  (Yes, that sounds
contradictory, but remember it's for when MPRV = 1.)

> Have in mind that this proposal is
> meant to solve a specific problem related to a specific threat model,
> it's not about changing PMP in general to do all sorts of stuff. Before
> we have something else I'd appreciate a threat model and a problem
> description.

I believe we need to widen the scope of this proposal to cover other
cases.  Sticking to the narrower scope you prefer would be fine except
for one thing:  We know that handling these other cases is going to
also involve PMP, so there's an overlap there.  If we don't try to
address all the demands on PMP together, we will end up with a layering
of modifications that, as Greg Favor has said, are not likely to fit
together as well.

Locking down mtvec may also be important, but since it doesn't involve
PMP, such other security features can be defined independently, as you
propose.

> P.S. U-boot usually knows the executable regions of the kernel, first
> because it needs to jump there, second because it's the one that put the
> kernel there (and/or unpacked it). Unless we are talking about a kernel
> that self-extracts or relocates itself, u-boot can set MML before
> jumping to the kernel if needed (and there are no modules to load).

As you put it yourself, "U-Boot usually knows the executable regions of
the kernel", except when it doesn't, because the kernel self-extracts,
or relocates itself, or has loadable modules.  And yes, if desired, an
OS's loadable modules might be signed; I don't see why not.  I think we
should want to cover as many use cases as we reasonably can, as best as
we can.

Regards,

    - John Hauser




Re: comments on PMP enhancements

Bill Huffman
 

On 2/13/20 12:30 PM, John Hauser wrote:
EXTERNAL MAIL


Nick Kossifidis wrote:
The new mechanism (when MML is set) introduces a barrier between S/U
mode and M mode, We want to be able to distinguish between an access
fault due to crossing that barrier, from other access faults. In other
words if M mode gets an access fault on its own memory we'll get an
access fault as in the current spec, if it gets an access fault on
memory that's marked for S/U use (see truth table) we'll get a security
exception. The reason is that we may want to handle this differently in
sw and it also helps in debugging.
I'm sorry to say, providing information to a debugger is not usually
considered a valid reason for additional RISC-V exception codes when
the same information can be extracted from elsewhere. If it were,
RISC-V would have dozens more exception codes than it does. A debugger
is assumed to be able to examine the PMP table itself, if necessary, to
learn more about the cause of a fault.

Your reason that "we may want to handle this differently in software"
is no more specific than before. I see your desire to be as helpful
as possible to software (and debugging), but please understand, this
sort of "might be useful" argument for additional exception codes
has already been rejected many times before. To make a better case,
you need at a minimum a compelling example that requires different
handling, and probably one where speed matters (so the software can't
just examine the PMP table to separate the cases itself).
I'm afraid I agree with John. I asked the same question myself some
months ago - but less forcefully. :-)


mstatus.MXR is not related to PMP, it's related to virtual memory
permissions and is outside PMP's scope, the scenario you mention
involves using mstatus.MPRV to access the region with S/U privileges
(and virtual memory in place). That's still possible because the
access in this case happens as S/U mode (not as M mode) and so the
S/U mode PMP rules apply.
The case that needs to be dealt with is an S/U-mode-only region that
is execute-only, without read permission. (Please see my correction
in another message.) In such a case, M mode has the authority to
temporarily reprogram the PMP entry to grant read permission to S/U
mode, then perform a read with MPRV = 1, and lastly restore the PMP
entry to execute-only. If address translation is active, this actually
requires M mode first walk the page tables to translate the virtual
address into a physical address before searching the PMP table to find
the relevant PMP entry. But there's no reason for us to make software
go through all this trouble; we should just have MXR = 1 grant read
permission to S/U level while executing in M mode. (Yes, that sounds
contradictory, but remember it's for when MPRV = 1.)
On one level, I agree with John here. But MXR and MPRV were set up when
M mode never had less permission than S/U. I'm not sure I understand
current behavior when the PMP entry is locked with execute-only
permission (which applies to M as well as S/U) and MXR is set. Does
that make M mode able to read instructions even though M mode itself
couldn't otherwise read them? That seems to me to reduce the meaning of
execute-only to something less than execute-only.


Have in mind that this proposal is
meant to solve a specific problem related to a specific threat model,
it's not about changing PMP in general to do all sorts of stuff. Before
we have something else I'd appreciate a threat model and a problem
description.
I believe we need to widen the scope of this proposal to cover other
cases. Sticking to the narrower scope you prefer would be fine except
for one thing: We know that handling these other cases is going to
also involve PMP, so there's an overlap there. If we don't try to
address all the demands on PMP together, we will end up with a layering
of modifications that, as Greg Favor has said, are not likely to fit
together as well.

Locking down mtvec may also be important, but since it doesn't involve
PMP, such other security features can be defined independently, as you
propose.
I tend to think the broader view is good. Otherwise we'll get contorted
bits here (sooner than we otherwise would :-) ). Locking mtvec seems
like it might be related. To me, even though it's, in some ways a
separate proposal, understanding the level of security provided should
include as many aspects as possible. Otherwise we may find when we get
to mtvec we didn't consider something.

Bill


P.S. U-boot usually knows the executable regions of the kernel, first
because it needs to jump there, second because it's the one that put the
kernel there (and/or unpacked it). Unless we are talking about a kernel
that self-extracts or relocates itself, u-boot can set MML before
jumping to the kernel if needed (and there are no modules to load).
As you put it yourself, "U-Boot usually knows the executable regions of
the kernel", except when it doesn't, because the kernel self-extracts,
or relocates itself, or has loadable modules. And yes, if desired, an
OS's loadable modules might be signed; I don't see why not. I think we
should want to cover as many use cases as we reasonably can, as best as
we can.

Regards,

- John Hauser



Re: comments on PMP enhancements

Nick Kossifidis
 

Στις 2020-02-13 22:30, John Hauser έγραψε:
Nick Kossifidis wrote:
The new mechanism (when MML is set) introduces a barrier between S/U
mode and M mode, We want to be able to distinguish between an access
fault due to crossing that barrier, from other access faults. In other
words if M mode gets an access fault on its own memory we'll get an
access fault as in the current spec, if it gets an access fault on
memory that's marked for S/U use (see truth table) we'll get a security
exception. The reason is that we may want to handle this differently in
sw and it also helps in debugging.
I'm sorry to say, providing information to a debugger is not usually
considered a valid reason for additional RISC-V exception codes when
the same information can be extracted from elsewhere. If it were,
RISC-V would have dozens more exception codes than it does. A debugger
is assumed to be able to examine the PMP table itself, if necessary, to
learn more about the cause of a fault.
Your reason that "we may want to handle this differently in software"
is no more specific than before. I see your desire to be as helpful
as possible to software (and debugging), but please understand, this
sort of "might be useful" argument for additional exception codes
has already been rejected many times before. To make a better case,
you need at a minimum a compelling example that requires different
handling, and probably one where speed matters (so the software can't
just examine the PMP table to separate the cases itself).
S/U mode doesn't have access to PMP registers so it's not possible to distinguish between an access fault e.g. due to a bug on an application / driver, from an access fault due to M mode trying to access one of the S/U-mode-only regions, or from an application / driver trying to access an M-mode-only region. It may be possible to recover from such a bug e.g. by restarting the application but handling / recovering from such a security violation is a different thing and usually involves different reporting and possibly running the system in a kind of "safe mode" with certain features disabled.

mstatus.MXR is not related to PMP, it's related to virtual memory
permissions and is outside PMP's scope, the scenario you mention
involves using mstatus.MPRV to access the region with S/U privileges
(and virtual memory in place). That's still possible because the
access in this case happens as S/U mode (not as M mode) and so the
S/U mode PMP rules apply.
The case that needs to be dealt with is an S/U-mode-only region that
is execute-only, without read permission. (Please see my correction
in another message.) In such a case, M mode has the authority to
temporarily reprogram the PMP entry to grant read permission to S/U
mode, then perform a read with MPRV = 1, and lastly restore the PMP
entry to execute-only. If address translation is active, this actually
requires M mode first walk the page tables to translate the virtual
address into a physical address before searching the PMP table to find
the relevant PMP entry. But there's no reason for us to make software
go through all this trouble; we should just have MXR = 1 grant read
permission to S/U level while executing in M mode. (Yes, that sounds
contradictory, but remember it's for when MPRV = 1.)
So the idea is to have MXR also work for S/U-mode-only PMP regions ? I see how that would help on a system without an MMU, it'll also be more consistent this way, but on a system with MMU I don't see why it makes sense to use PMP to mark a region as execute-only. It makes more sense to mark the region as R/W/X for S/U mode and leave it to the OS running on S mode to add further restrictions through the MMU, in which case MXR will work as-is.

I agree with this approach as long as we make sure that MXR can only be set to 1 when running on M-mode, on the current spec it's allowed to be set regardless of privilege mode as with MPRV. I remember there was a discussion regarding MPRV to mandate it can only be set when on M-mode but I just checked the latest draft and it hasn't changed. Leaving MPRV set will most probably result the sw to crash, but if MXR is left set outside M-mode we basically remove the protection on any execute-only memory region, especially if this also works for PMP regions.

Have in mind that this proposal is
meant to solve a specific problem related to a specific threat model,
it's not about changing PMP in general to do all sorts of stuff. Before
we have something else I'd appreciate a threat model and a problem
description.
I believe we need to widen the scope of this proposal to cover other
cases. Sticking to the narrower scope you prefer would be fine except
for one thing: We know that handling these other cases is going to
also involve PMP, so there's an overlap there. If we don't try to
address all the demands on PMP together, we will end up with a layering
of modifications that, as Greg Favor has said, are not likely to fit
together as well.
I just want to be sure that we are after specific issues and -in case of security controls- have specific threat models in mind. Coming up with solutions without having discussed the problem first and proposing security controls without a threat model won't work.

Locking down mtvec may also be important, but since it doesn't involve
PMP, such other security features can be defined independently, as you
propose.

P.S. U-boot usually knows the executable regions of the kernel, first
because it needs to jump there, second because it's the one that put the
kernel there (and/or unpacked it). Unless we are talking about a kernel
that self-extracts or relocates itself, u-boot can set MML before
jumping to the kernel if needed (and there are no modules to load).
As you put it yourself, "U-Boot usually knows the executable regions of
the kernel", except when it doesn't, because the kernel self-extracts,
or relocates itself, or has loadable modules. And yes, if desired, an
OS's loadable modules might be signed; I don't see why not. I think we
should want to cover as many use cases as we reasonably can, as best as
we can.
Still MML can always be set after decompression/relocation/loading modules, I don't see why it's an issue and I don't see what's the added security gain by allowing temporary M-mode-only regions (removable) during boot or in general, where anything running there can remove them in a few instructions. The threat model Tariq brought up was about detecting a glitch attack but the glitch can also happen when setting a rule in the first place, I don't see how this is the proper approach, PMP is not there as an anti-tampering mechanism. If we want this as a debug feature I'm ok with it but it must be treated as such and not as a security improvement. Same goes for the ability to let M-mode still execute any region not covered by PMP, or being able to register new executable regions for "greater flexibility". We first need to decide if there are valid use cases / threat models that need to be addressed and then talk about possible modifications to the proposal.

Regards,
Nick


Re: comments on PMP enhancements

John Hauser
 

I wrote:
The case that needs to be dealt with is an S/U-mode-only region that
is execute-only, without read permission. [...]
Bill Huffman:
On one level, I agree with John here. But MXR and MPRV were set up when
M mode never had less permission than S/U. I'm not sure I understand
current behavior when the PMP entry is locked with execute-only
permission (which applies to M as well as S/U) and MXR is set. Does
that make M mode able to read instructions even though M mode itself
couldn't otherwise read them? That seems to me to reduce the meaning of
execute-only to something less than execute-only.
To answer your question, for current standard PMP, when a PMP entry
makes a region execute-only for all modes, MXR does not make reading
possible from any mode, because MXR is currently defined only to modify
page table permissions, not PMP. I wasn't proposing to allow M mode to
read from its own execute-only regions, nor S/U mode to read from its
own execute-only regions. No existing or proposed rule for MXR allows
that.

However... Now that you've pushed me to look at this once again, I've
realized a flaw in my MXR proposal that I missed before. The upshot is
that I withdraw my demand for a special case for handling MXR. Anyone
interested in the reason why can read on.

The current standard allows a PMP entry to define a region that is
execute-only for S/U mode but with full access for M mode. What I
overlooked earlier is that MXR doesn't let M mode read that memory when
MPRV = 1 and MPP = 0 or 1. So the problem I wanted to solve exists
already; execute-only regions for S/U mode can already be trouble if
any instructions need to be emulated in M mode.

I guess the correct answer is that M mode shouldn't configure
execute-only regions for S/U mode unless it's prepared to deal with
this, which in practice probably means it needs to know ahead of time
that no instructions in the region require emulation. If that's
considered an adequate resolution, it can apply also to any S/U-mode-
only regions that are execute-only, which is the case I was pursuing.
On the other hand, on the chance it's not considered adequate, then any
changes made to how MXR, MPRV, and PMP interact ought to be addressed
separately from the PMP enhancement proposal. The two issues should be
considered orthogonal.

Sorry about the distraction.

I tend to think the broader view is good. Otherwise we'll get contorted
bits here (sooner than we otherwise would :-) ). Locking mtvec seems
like it might be related. To me, even though it's, in some ways a
separate proposal, understanding the level of security provided should
include as many aspects as possible. Otherwise we may find when we get
to mtvec we didn't consider something.
I don't object to everything being looked at before committing to any
security extensions. But I got the impression there may be some who
hope to elevate the task group's current proposal ASAP.

- John Hauser


Re: [RISC-V] [tech-tee] [RISC-V] [tech-privileged] comments on PMP enhancements

Mr Tariq Kurd <tariq.kurd@...>
 

The threat model Tariq brought up was about detecting a glitch attack but the glitch can also happen when setting
a rule in the first place, I don't see how this is the proper approach, PMP is not there as an anti-tampering
mechanism. If we want this as a debug feature I'm ok with it but it must be treated as such and not as a security
improvement.

It's not just for glitch protection, but also for security to control access permissions.
The software is loaded from the boot ROM and the boot ROM does not contain software to unlock the PMP entries so we are not (obviously) susceptible to a code-reuse ROP attack to reprogram the PMP, because the software to do so doesn't exist in the existing code.
If we need to lock regions to prevent such things from other software later then we need the flexibility to be able to lock the regions individually on a case by case basis.

Put simply we need orthogonal controls for locking and M-mode only access.

There are multiple use cases for the PMP, some we know about but many we don't and others won't have been thought of yet - so the proposal need to be flexible. Nick has a use case in mind which is perfectly valid with MML but unfortunately it doesn't cover our use case, and it also causes problems for Nvidia as Joe told us during the meeting on Tuesday.

Given that Andrew Waterman has dropped his objection to using an extra bit from the PMPCFG field we should allocate one.

So how about PMPCFG[5] = M, which can be read-only-zero to exactly match the current PMP spec.

If MML=0, M=0 for any PMP entry, then the entry operates exactly as the current PMP spec.
If MML=0, M=1 for any PMP entry, then the RWX permissions are applied to all modes equally (see the attachment)
If MML=1, M=? for any PMP entry, then the RWX bits operate as they do for the MML proposal, except that the truth table has M,R,W,X as inputs instead of L,R,W,X (see the attachment)

For example, in the MML proposal:
- LRWX=1001 means "M-mode locked execute only region" - and it's locked
In my modified proposal:
- MRWX=1001 means "M-mode execute only region", and the L bit states whether it is locked.

I've attached the truth table in a word document - it's not a full proposal, just showing how to program the permissions.

I think this is a good simplification also for when MML=0 as it gives more flexibility than the current proposal.

So in summary this updated proposal gives us
1. M mode has all permissions and S/U modes have restricted permissions (unlocked) - M=0, MML=0, L=0
2. M mode and S/U modes all have the same permissions (locked) - M=0, MML=0, L=1
3. M mode and S/U modes all have the same permissions (unlocked) - M=1, MML=0, L=0
4. S/U mode permissions with no M-mode access (unlocked) - M=0, MML=1, L=0
5. S/U mode permissions with no M-mode access (locked) - M=0, MML=1, L=1
6. Shared regions (unlocked) - M=0, MML=1, L=0
7. Shared regions (locked) - M=0, MML=1, L=1

The existing standard gives us 1 and 2, the other modes are all new

Tariq

-----Original Message-----
From: tech-tee@... [mailto:tech-tee@...] On Behalf Of Nick Kossifidis
Sent: 14 February 2020 02:40
To: John Hauser <jh.riscv@...>
Cc: Nick Kossifidis <mick@...>; tech-tee@...; tech-privileged@...
Subject: Re: [RISC-V] [tech-tee] [RISC-V] [tech-privileged] comments on PMP enhancements

Στις 2020-02-13 22:30, John Hauser έγραψε:
Nick Kossifidis wrote:
The new mechanism (when MML is set) introduces a barrier between S/U
mode and M mode, We want to be able to distinguish between an access
fault due to crossing that barrier, from other access faults. In
other words if M mode gets an access fault on its own memory we'll
get an access fault as in the current spec, if it gets an access
fault on memory that's marked for S/U use (see truth table) we'll get
a security exception. The reason is that we may want to handle this
differently in sw and it also helps in debugging.
I'm sorry to say, providing information to a debugger is not usually
considered a valid reason for additional RISC-V exception codes when
the same information can be extracted from elsewhere. If it were,
RISC-V would have dozens more exception codes than it does. A
debugger is assumed to be able to examine the PMP table itself, if
necessary, to learn more about the cause of a fault.

Your reason that "we may want to handle this differently in software"
is no more specific than before. I see your desire to be as helpful
as possible to software (and debugging), but please understand, this
sort of "might be useful" argument for additional exception codes has
already been rejected many times before. To make a better case, you
need at a minimum a compelling example that requires different
handling, and probably one where speed matters (so the software can't
just examine the PMP table to separate the cases itself).
S/U mode doesn't have access to PMP registers so it's not possible to distinguish between an access fault e.g. due to a bug on an application / driver, from an access fault due to M mode trying to access one of the S/U-mode-only regions, or from an application / driver trying to access an M-mode-only region. It may be possible to recover from such a bug e.g. by restarting the application but handling / recovering from such a security violation is a different thing and usually involves different reporting and possibly running the system in a kind of "safe mode" with certain features disabled.

mstatus.MXR is not related to PMP, it's related to virtual memory
permissions and is outside PMP's scope, the scenario you mention
involves using mstatus.MPRV to access the region with S/U privileges
(and virtual memory in place). That's still possible because the
access in this case happens as S/U mode (not as M mode) and so the
S/U mode PMP rules apply.
The case that needs to be dealt with is an S/U-mode-only region that
is execute-only, without read permission. (Please see my correction
in another message.) In such a case, M mode has the authority to
temporarily reprogram the PMP entry to grant read permission to S/U
mode, then perform a read with MPRV = 1, and lastly restore the PMP
entry to execute-only. If address translation is active, this
actually requires M mode first walk the page tables to translate the
virtual address into a physical address before searching the PMP table
to find the relevant PMP entry. But there's no reason for us to make
software go through all this trouble; we should just have MXR = 1
grant read permission to S/U level while executing in M mode. (Yes,
that sounds contradictory, but remember it's for when MPRV = 1.)
So the idea is to have MXR also work for S/U-mode-only PMP regions ? I see how that would help on a system without an MMU, it'll also be more consistent this way, but on a system with MMU I don't see why it makes sense to use PMP to mark a region as execute-only. It makes more sense to mark the region as R/W/X for S/U mode and leave it to the OS running on S mode to add further restrictions through the MMU, in which case MXR will work as-is.

I agree with this approach as long as we make sure that MXR can only be set to 1 when running on M-mode, on the current spec it's allowed to be set regardless of privilege mode as with MPRV. I remember there was a discussion regarding MPRV to mandate it can only be set when on M-mode but I just checked the latest draft and it hasn't changed. Leaving MPRV set will most probably result the sw to crash, but if MXR is left set outside M-mode we basically remove the protection on any execute-only memory region, especially if this also works for PMP regions.

Have in mind that this proposal is
meant to solve a specific problem related to a specific threat model,
it's not about changing PMP in general to do all sorts of stuff.
Before
we have something else I'd appreciate a threat model and a problem
description.
I believe we need to widen the scope of this proposal to cover other
cases. Sticking to the narrower scope you prefer would be fine except
for one thing: We know that handling these other cases is going to
also involve PMP, so there's an overlap there. If we don't try to
address all the demands on PMP together, we will end up with a
layering of modifications that, as Greg Favor has said, are not likely
to fit together as well.
I just want to be sure that we are after specific issues and -in case of security controls- have specific threat models in mind. Coming up with solutions without having discussed the problem first and proposing security controls without a threat model won't work.

Locking down mtvec may also be important, but since it doesn't involve
PMP, such other security features can be defined independently, as you
propose.

P.S. U-boot usually knows the executable regions of the kernel, first
because it needs to jump there, second because it's the one that put
the kernel there (and/or unpacked it). Unless we are talking about a
kernel that self-extracts or relocates itself, u-boot can set MML
before jumping to the kernel if needed (and there are no modules to
load).
As you put it yourself, "U-Boot usually knows the executable regions
of the kernel", except when it doesn't, because the kernel
self-extracts, or relocates itself, or has loadable modules. And yes,
if desired, an OS's loadable modules might be signed; I don't see why
not. I think we should want to cover as many use cases as we
reasonably can, as best as we can.
Still MML can always be set after decompression/relocation/loading modules, I don't see why it's an issue and I don't see what's the added security gain by allowing temporary M-mode-only regions (removable) during boot or in general, where anything running there can remove them in a few instructions. The threat model Tariq brought up was about detecting a glitch attack but the glitch can also happen when setting a rule in the first place, I don't see how this is the proper approach, PMP is not there as an anti-tampering mechanism. If we want this as a debug feature I'm ok with it but it must be treated as such and not as a security improvement. Same goes for the ability to let M-mode still execute any region not covered by PMP, or being able to register new executable regions for "greater flexibility". We first need to decide if there are valid use cases / threat models that need to be addressed and then talk about possible modifications to the proposal.

Regards,
Nick


Re: [RISC-V] [tech-tee] [RISC-V] [tech-privileged] comments on PMP enhancements

Nick Kossifidis
 

Hello Tariq,

On 2/14/20 1:39 PM, Tariq Kurd wrote:
The threat model Tariq brought up was about detecting a glitch attack but the glitch can also happen when setting
a rule in the first place, I don't see how this is the proper approach, PMP is not there as an anti-tampering
mechanism. If we want this as a debug feature I'm ok with it but it must be treated as such and not as a security
improvement.

It's not just for glitch protection, but also for security to control access permissions.
The software is loaded from the boot ROM and the boot ROM does not contain software to unlock the PMP entries so we are not (obviously) susceptible to a code-reuse ROP attack to reprogram the PMP, because the software to do so doesn't exist in the existing code.
If we need to lock regions to prevent such things from other software later then we need the flexibility to be able to lock the regions individually on a case by case basis.

Put simply we need orthogonal controls for locking and M-mode only access.
You don't need to do a ROP attack on BootROM to remove the rules, any
code that runs on M-mode can remove them in a few instructions. I don't
see how we can have a security control on M mode without also locking
the rules for preventing further modifications from the next boot
stages. If the next boot stage runs on S/U mode then that's not a
problem since S/U-mode-only rules are removable.

When defining security controls there are guarantees we put in place.
Let's say that we did everything correctly, both in hw and sw, up to the
point where we place the PMP rule there to prevent "other software"
running on M-mode from accessing some memory region. Can we guarantee
that this restriction will be enforced and that "other software" can't
simply bypass it ? I don't believe we can provide such a guarantee,
hence we can't claim this approach to be a security control. If the code
we are trying to restrict has direct control over the security control,
then it's not a security control, it's an ilusion of a security control.
To the contrary it may pose a security threat.

In contrast a locked PMP rule guarantees that "other software" on M mode
can't remove it, same goes for rules placed by M mode for restricting
S/U mode, since S/U mode can't modify PMP entries, or with MMU
restrictions implemented on S mode, since U mode can't modify the page
tables.

Your DMC proposal for exapmle for restricting M mode from accessing any
region not covered by a PMP rule is a security control, it's a more
strict version of MML where M mode is only restricted from executing
such a region. I'm more positive towards adding that, than allowing for
unlocked M-mode-only PMP rules, although the same can be achieved with a
locked M-mode-only rule, or with a locked PMA rule (that's even better
since it's valid for all harts).

There are multiple use cases for the PMP, some we know about but many we don't and others won't have been thought of yet - so the proposal need to be flexible. Nick has a use case in mind which is perfectly valid with MML but unfortunately it doesn't cover our use case, and it also causes problems for Nvidia as Joe told us during the meeting on Tuesday.
We had the same discussion with Joe some time ago, they wanted to
restrict their BootROM if I remember corectly so that it becomes
inaccessible after it jumps to the next boot stage. We concluded that
since this is not a per-hart protection, it's better to handle it in PMA
checker instead of PMP (and I think there was a proposal for a task
group on programmable PMAs where such solutions can be discussed). In
any case their scenario is covered by the current proposal, unless there
is a different scenario I'm not aware of.

If we can come up with specific use cases not covered by the current
proposal, and valid threat models for them, I'm all in for proposing new
security controls, what I try to prevent is to allow for weak security
controls in the name of flexibility.

As we discussed on our previous call, I'm not against such a feature, as
Andy pointed out, it is a useful debug feature and I can understand why
you may want to use it. My ojections are:

a) It should be disabled by default.
b) It should be noted that this is not a security control but a debug
feature.
c) It should be noted that this needs to be disabled after sw is done
using it (e.g. during the boot sequence), and remains disabled until
hard-reset (sticky bit).

Regards,
Nick


Re: comments on PMP enhancements

John Hauser
 

Nick Kossifidis wrote:
You don't need to do a ROP attack on BootROM to remove the rules, any
code that runs on M-mode can remove them in a few instructions. I don't
see how we can have a security control on M mode without also locking
the rules for preventing further modifications from the next boot
stages. [...]
I'd like to point out that my own proposal does always allow for the
locking of regions for the next boot stages, when that's appropriate.

When defining security controls there are guarantees we put in place.
Let's say that we did everything correctly, both in hw and sw, up to the
point where we place the PMP rule there to prevent "other software"
running on M-mode from accessing some memory region. Can we guarantee
that this restriction will be enforced and that "other software" can't
simply bypass it ? I don't believe we can provide such a guarantee,
hence we can't claim this approach to be a security control. If the code
we are trying to restrict has direct control over the security control,
then it's not a security control, it's an ilusion of a security control.
To the contrary it may pose a security threat.
If unlocked M-mode PMP entries can't be called security controls, then
fine, let's call them something else. As I see it, the point is that
there is a demand/need for such an ability, it obviously involves PMP,
and furthermore it's been shown that the physical mechanisms are very
close to one another. If you ignore this other need and adopt the
current proposal, there's a very good chance we'll end up having to
retrofit the PMP table to support this other need later, creating a
bigger mess than if we learn to accomodate it now.

I understand you're afraid that offering any compromises in the PMP
mechanism will allow developers to choose the not-totally-secure
options and delude themselves that it gives them true security.
But that's not a hardware-mechanisms problem; that's a problem for
software policies and their enforcement. That concern needs to be
dealt with in a different way than by hobbling the hardware.

For my part, I will try to be much more careful about my use of the
words "secure" and "security" going forward.

Regards,

- John Hauser


Re: [RISC-V] [tech-tee] comments on PMP enhancements

Mr Tariq Kurd <tariq.kurd@...>
 

As we discussed on our previous call, I'm not against such a feature, as Andy pointed out, it is a useful debug
feature and I can understand why you may want to use it. My objections are:
a) It should be disabled by default.
b) It should be noted that this is not a security control but a debug feature.
c) It should be noted that this needs to be disabled after sw is done using it (e.g. during the boot sequence), and
remains disabled until hard-reset (sticky bit).

Hi Nick,

Thanks for the feedback, and I understand your arguments.

When you say "It" above are you talking about:
1. my original proposal (DMC and DPL)
2. my updated proposal (M-bit in each PMP entry)

The best solution for us would be the M-bit in each PMP entry and also DMC, as this gives us the smallest PMP hardware for our embedded cores.

I can write a two proposals, one for the M-bit and one for DMC and email them if you like

Tariq

-----Original Message-----
From: tech-tee@... [mailto:tech-tee@...] On Behalf Of John Hauser
Sent: 14 February 2020 20:57
To: tech-tee@...; tech-privileged@...
Subject: Re: [RISC-V] [tech-tee] comments on PMP enhancements

Nick Kossifidis wrote:
You don't need to do a ROP attack on BootROM to remove the rules, any
code that runs on M-mode can remove them in a few instructions. I
don't see how we can have a security control on M mode without also
locking the rules for preventing further modifications from the next
boot stages. [...]
I'd like to point out that my own proposal does always allow for the locking of regions for the next boot stages, when that's appropriate.

When defining security controls there are guarantees we put in place.
Let's say that we did everything correctly, both in hw and sw, up to
the point where we place the PMP rule there to prevent "other software"
running on M-mode from accessing some memory region. Can we guarantee
that this restriction will be enforced and that "other software" can't
simply bypass it ? I don't believe we can provide such a guarantee,
hence we can't claim this approach to be a security control. If the
code we are trying to restrict has direct control over the security
control, then it's not a security control, it's an ilusion of a security control.
To the contrary it may pose a security threat.
If unlocked M-mode PMP entries can't be called security controls, then fine, let's call them something else. As I see it, the point is that there is a demand/need for such an ability, it obviously involves PMP, and furthermore it's been shown that the physical mechanisms are very close to one another. If you ignore this other need and adopt the current proposal, there's a very good chance we'll end up having to retrofit the PMP table to support this other need later, creating a bigger mess than if we learn to accomodate it now.

I understand you're afraid that offering any compromises in the PMP mechanism will allow developers to choose the not-totally-secure options and delude themselves that it gives them true security.
But that's not a hardware-mechanisms problem; that's a problem for software policies and their enforcement. That concern needs to be dealt with in a different way than by hobbling the hardware.

For my part, I will try to be much more careful about my use of the words "secure" and "security" going forward.

Regards,

- John Hauser


Re: comments on PMP enhancements

Allen Baum
 

Two  quick comments:
- I am assuming that this is a proposal to replace the existing "enhanced" PMP proposal, rather than an "enhanced-enhanced" PMP proposal.

 - do we ever need to allow Write_Only and Write&Execute regions? OR can we continue to disallow them, except for the specific shared RW/RO regions defined by the enhanced proposal
( which in this case is when MML=1,  M=0 as opposed to the enhanced proposal of MML=1, L=0)

Separately, there is a proposal to have an S-PMP, which further filters addresses but allows Smode to configure them.
It would be useeful to consider whether they would be completely separate CSRs or they could overlay the existing ones ones somehow. 
Even if they are totally separate, it would be useful to ensure the encodings were similar enough that the same HW (with simple external wiring changes) would work for both.


On Fri, Feb 14, 2020 at 12:57 PM John Hauser <jh.riscv@...> wrote:
Nick Kossifidis wrote:
> You don't need to do a ROP attack on BootROM to remove the rules, any
> code that runs on M-mode can remove them in a few instructions. I don't
> see how we can have a security control on M mode without also locking
> the rules for preventing further modifications from the next boot
> stages.  [...]

I'd like to point out that my own proposal does always allow for the
locking of regions for the next boot stages, when that's appropriate.

> When defining security controls there are guarantees we put in place.
> Let's say that we did everything correctly, both in hw and sw, up to the
> point where we place the PMP rule there to prevent "other software"
> running on M-mode from accessing some memory region. Can we guarantee
> that this restriction will be enforced and that "other software" can't
> simply bypass it ? I don't believe we can provide such a guarantee,
> hence we can't claim this approach to be a security control. If the code
> we are trying to restrict has direct control over the security control,
> then it's not a security control, it's an ilusion of a security control.
> To the contrary it may pose a security threat.

If unlocked M-mode PMP entries can't be called security controls, then
fine, let's call them something else.  As I see it, the point is that
there is a demand/need for such an ability, it obviously involves PMP,
and furthermore it's been shown that the physical mechanisms are very
close to one another.  If you ignore this other need and adopt the
current proposal, there's a very good chance we'll end up having to
retrofit the PMP table to support this other need later, creating a
bigger mess than if we learn to accomodate it now.

I understand you're afraid that offering any compromises in the PMP
mechanism will allow developers to choose the not-totally-secure
options and delude themselves that it gives them true security.
But that's not a hardware-mechanisms problem; that's a problem for
software policies and their enforcement.  That concern needs to be
dealt with in a different way than by hobbling the hardware.

For my part, I will try to be much more careful about my use of the
words "secure" and "security" going forward.

Regards,

    - John Hauser




Re: [RISC-V] [tech-tee] comments on PMP enhancements

Nick Kossifidis
 

Hello Tariq,

Στις 2020-02-17 11:02, Mr Tariq Kurd έγραψε:
Hi Nick,
Thanks for the feedback, and I understand your arguments.
When you say "It" above are you talking about:
1. my original proposal (DMC and DPL)
2. my updated proposal (M-bit in each PMP entry)
The best solution for us would be the M-bit in each PMP entry and also
DMC, as this gives us the smallest PMP hardware for our embedded
cores.
I can write a two proposals, one for the M-bit and one for DMC and
email them if you like
Tariq
I'm referring to your original proposal of a bit that when set allows for locked rules to be removed / edited (DPL) temporarily. I also see some value as I mentioned for the DMC bit you also proposed and it seems others believe it would be useful, although it can be implemented differently. I understand that you want to be flexible to allow both locked and unlocked rules for M-mode with the per-entry M bit but to me this introduces a security risk and doesn't provide any security benefits.

As we discussed on our conf call we can simply add the two bits you propose on mseccfg introduced on the group's proposal, if you agree with having them disabled by default (to also be backwards compatible), not define DPL as a security control (DMC on the other hand is a security control and we can define it as such), and allow DPL to be locked (possibly with another bit) so that it can't be re-enabled after sw is done using it.

Regards,
Nick