seL4 / seL4

The seL4 microkernel

Home Page:https://sel4.systems

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

RISC-V write-only page mappings

Ivan-Velickovic opened this issue · comments

The creation of write-only page mappings on RISC-V does not seem correct to me.

I believe if I create a mapping with only write permissions, the value of vmRights becomes 0x1 based on putting debug logging in the kernel.

A vmRights of 0x1 means that is the VMKernelOnly entry of the vm_rights enum. This means that in makeUserPte, the value of RISCVGetWriteFromVMRights(vm_rights) is 0, when it should actually be one. Hence, a mapping with write access does not get created.

What's more confusing is that the kernel code also has this comment: /* Write-only frame cap rights not currently supported. */. However it does not seem to be preventing the user from creating write-only mappings, unlike on ARM.

I don't know if I'm reading the code right, so I decided to make an sel4test test to try confirm my suspicions. You can find the patch here: Ivan-Velickovic/sel4test@169f157.

I ran on the HiFive Unleashed and QEMU RISC-V virt and observed a memory fault on both. The following log is from the HiFive Unleashed run:

SEL4TEST: vaddr is 0x10fb3000
SEL4TEST: attempting to write
Pagefault from [VSPACE0015]: write fault at PC: 0x590e8 vaddr: 0x10fb3000, FSR 0x7
Register of root thread in test (may not be the thread that faulted)
Register dump:
pc:	0x590e8
ra:	0x590e2
sp:	0x10011a30
gp:	0xbd3a0
s0:	0x10011a90
s1:	0x10011af0
s2:	0x0
s3:	0x0
s4:	0x0
s5:	0x0
s6:	0x0
s7:	0x0
s8:	0x0
s9:	0x0
s10:	0x0
s11:	0x0
a0:	0x0
a1:	0x0
a2:	0x0
a3:	0x0
a4:	0x3
a5:	0x10fb3000
a6:	0x0
a7:	0xfffffffffffffff7
t0:	0x59a6a
t1:	0xa9f95
t2:	0x0
t3:	0xfffffffffffffff6
t4:	0x8
t5:	0x39
t6:	0xe
tp:	0xe7850
	Failure: result == SUCCESS at line 296 of file /home/ivanv/ts/sel4test/projects/sel4test/apps/sel4test-driver/src/testtypes.c
	Error: result == SUCCESS at line 217 of file /home/ivanv/ts/sel4test/projects/sel4test/apps/sel4test-driver/src/main.c
Starting test 3: Test all tests ran
Test suite failed. 2/3 tests passed.
*** FAILURES DETECTED ***

If we look at the objdump we find the following instructions:

    *((char *)vaddr) = 3;
   590e2:	fb843783          	ld	a5,-72(s0)
   590e6:	470d                	li	a4,3
   590e8:	00e78023          	sb	a4,0(a5)

The program counter that caused the fault is at 0x590e8, which is indeed doing a write.

Yes, I don't think write-only is supported on any of our architectures. You can provide the combination as input, but you can only actually create read, read-write, or kernel-only.

In that case I think we should make all the page mapping invocations consistent with ARM and report an error if the user tries to make a write-only mapping.

The RISC-V privileged spec explicitly says "Writable pages must also be marked readable; the contrary combinations are reserved for future use.". And in the table "Encoding of PTE R/W/X fields":

  • X=0, W=1, R=0: reserved for future use
  • X=1, W=1, R=0: reserved for future use

In that case I think we should make all the page mapping invocations consistent with ARM and report an error if the user tries to make a write-only mapping.

That does make perfect sense and would not be a big change to verify (should affect the relevant decode functions only).

Do we have a volunteer for implementing it?

It's already consistent with Arm. The behavior on arm if you request write only mapping is that it degrades to VMKernelOnly without returning an error. Systems may rely on silent downgrading of a request to read+write to read only if the underlying cap doesn't have write privileges. I guess what happens when requesting write only was unspecified as it's not a valid final request. But it's possible to have caps with write permissions and so should the kernel also return an error if someone requests a mapping with a cap that only has write rights?

When I made this issue I mistakenly thought that the kernel was returning an error on ARM for write-only mappings due to the kernel printing an error.

userError("Attempted to make unsupported write only mapping");

I guess I find the print confusing - is it trying to hint that user-space has potentially done something wrong or is it supposed to return an actual error?

When I made this issue I mistakenly thought that the kernel was returning an error on ARM for write-only mappings due to the kernel printing an error.

seL4/src/arch/arm/64/kernel/vspace.c

Line 155 in 76eee24

userError("Attempted to make unsupported write only mapping");
I guess I find the print confusing - is it trying to hint that user-space has potentially done something wrong or is it supposed to return an actual error?

This generates just a warning, but I agree that it is a bit weird and should be consistent across architectures if we want the warning.

Actually making it an error would require an RFC, because it's a breaking API change. That doesn't mean we can't do it, but the question is if this is really worth a breaking change.

Maybe the only thing that is needed is to document this properly in the manual.

I guess we can start with having consistent error messages making it clear in the manual.

Are there any other cases in the kernel where a cap needs to have certain permissions for an invocation to be successful?

I guess we can start with having consistent error messages making it clear in the manual.

Are there any other cases in the kernel where a cap needs to have certain permissions for an invocation to be successful?

Yes that is a normal kind of check. Whether it's wanted or not depends on each case.

I made #1261 and #1260 to try minimise future confusion.

I'm not the one who should decide whether the policy change is worth it, so I'm happy to close the issue or leave it up to someone else.

With the behaviour specified in the manual, I'd be happy to close this. So far there does not seem to be any need for a policy change.