Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Exit with a non-zero exitcode if the kernel panics. #7

Open
jschwe opened this issue Apr 27, 2020 · 7 comments
Open

Exit with a non-zero exitcode if the kernel panics. #7

jschwe opened this issue Apr 27, 2020 · 7 comments
Assignees

Comments

@jschwe
Copy link
Contributor

jschwe commented Apr 27, 2020

Uhyve should exit with a non-zero exitcode if the kernel panics. This is important for testing rusty-hermit with uhyve and CI, since I'm not a fan of parsing the output of stdout or stderr to determine if a program failed.

I'm not sure if Uhyve always returns a zero, but at least in the cases I've seen where uhyve shuts down due to a panic of the kernel, the exit code was zero.

@jounathaen
Copy link
Member

This is can easily be implemented, as the signal for the shutdown of the hypervisor is writing an value to a certain COM port. So you can return an arbitrary return code from the application and for example return another value in the panic handler than on regular shutdown.

I've already implemented this for uhyve's little sibling - ehyve. It can be easily backported for uhyve.

Would this be sufficient?

@jounathaen jounathaen self-assigned this Apr 28, 2020
@jschwe
Copy link
Contributor Author

jschwe commented Apr 28, 2020

Yes, That would be absolutely sufficient. Thanks for your help :)

@jounathaen
Copy link
Member

Took me embarrasingly long to realize, but this is actually the behaviour that uhyve has by default.

Panicing

#[cfg(target_os = "hermit")]
extern crate hermit_sys;

fn main()  {
        println!("Hello World!");
        panic!("asdf");
}
> cargo build -Z build-std=std,core,alloc,panic_abort --target x86_64-unknown-hermit
# [...]

> uhyve target/x86_64-unknown-hermit/debug/hermit-new
Hello World!
thread 'main' panicked at 'asdf', src/main.rs:6:9
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace

> echo $?
255

Return Error

#[cfg(target_os = "hermit")]
extern crate hermit_sys;

use std::io::{Error, ErrorKind};

fn main()  -> Result<(), std::io::Error> {
        println!("Hello World!");
        Err(Error::new(ErrorKind::Other, "oh no!"))
}
> uhyve target/x86_64-unknown-hermit/debug/hermit-new
Hello World!
Error: Custom { kind: Other, error: "oh no!" }

> echo $?
1

@jschwe
Copy link
Contributor Author

jschwe commented May 6, 2020

I'd like to reopen this issue. I checked and the two examples you posted work for me too. However this does not work for all cases.
To reproduce do the following:

  1. Clone rusty-hermit
  2. Checkout devel branch
  3. Switch to a new branch at commit 4b74fa4889f60c27eda89c40d3b22598ffc54ff5 (newer commits are not building for me)
  4. Initialize and update submodules
  5. Run cargo build -Z build-std=std,core,alloc,panic_abort --target x86_64-unknown-hermit
  6. Run uhyve -v target/x86_64-unknown-hermit/debug/rusty_demo
  7. Verify that this works and return code is 0 (no problem here)
  8. cd libhermit-rs/src/arch/x86_64
  9. Comment out lines 411 to 415 so that the we run into the "expect".
  10. cd back to rusty-hermit
  11. Run cargo clean
  12. Run cargo build -Z build-std=std,core,alloc,panic_abort --target x86_64-unknown-hermit
  13. Run uhyve -v target/x86_64-unknown-hermit/debug/rusty_demo
  14. Run echo $?. For me this gives 0, even though rusty-hermit crashed.

This also shows an issue that rusty-hermit may have when handling panics, but I should probably create a separate issue for that, since that isn't uhyve related.

Output of step 13

[0][INFO] Welcome to HermitCore-rs 0.3.26
[0][INFO] Kernel starts at 0x200000
[0][INFO] BSS starts at 0x445600
[0][INFO] TLS starts at 0x443828 (size 264 Bytes)
[0][INFO] Total memory size: 64 MB
[0][INFO] A pure Rust application is running on top of HermitCore!
[0][INFO] Heap: size 50 MB, start address 0x600000
[0][INFO] Heap is located at 0x600000 -- 0x3800000 (0 Bytes unmapped)
[0][INFO] 
[0][INFO] ===================== PHYSICAL MEMORY FREE LIST ======================
[0][INFO] 0x00000003800000 - 0x00000004000000
[0][INFO] ======================================================================
[0][INFO] 
[0][INFO] 
[0][INFO] ================== KERNEL VIRTUAL MEMORY FREE LIST ===================
[0][INFO] 0x00000003800000 - 0x00800000000000
[0][INFO] ======================================================================
[0][INFO] 
[0][TRACE] __sys_malloc: allocate memory at 0x6000e8 (size 0x408, align 0x8)
[0][ERROR] Page Fault (#PF) Exception: ExceptionStackFrame {
    instruction_pointer: 0x38c66b,
    code_segment: 0x8,
    cpu_flags: 0x10287,
    stack_pointer: 0x1ffb90,
    stack_segment: 0x10,
}
[0][ERROR] virtual_address = 0x3830000, page fault error = The fault was caused by a non-present page.
The access causing the fault was a read.
The access causing the fault originated when the processor was executing in supervisor mode.
The fault was not caused by reserved bit violation.
The fault was not caused by an instruction fetch.
[0][ERROR] fs = 0x0, gs = 0x447728
[0][ERROR] General Protection (#GP) Exception: ExceptionStackFrame {
[Redacted everything inbetween here since I hit the Character limit]

[0][ERROR] General Protection (#GP) Exception: ExceptionStackFrame {
    
Dump state of CPU 0

Registers:
----------
kvm_regs { rax: 3026652, rbx: 3026652, rcx: 19, rdx: 3026652, rsi: 19, rdi: 3026652, rsp: 73728, rbp: 0, r8: 19, r9: 1, r10: 0, r11: 0, r12: 19, r13: 73824, r14: 19, r15: 0, rip: 3799712, rflags: 65554 }kvm_sregs { cs: kvm_segment { base: 0, limit: 0, selector: 8, type_: 11, present: 1, dpl: 0, db: 0, s: 1, l: 1, g: 0, avl: 0, unusable: 0, padding: 0 }, ds: kvm_segment { base: 0, limit: 0, selector: 16, type_: 3, present: 1, dpl: 0, db: 0, s: 1, l: 0, g: 0, avl: 0, unusable: 0, padding: 0 }, es: kvm_segment { base: 0, limit: 0, selector: 16, type_: 3, present: 1, dpl: 0, db: 0, s: 1, l: 0, g: 0, avl: 0, unusable: 0, padding: 0 }, fs: kvm_segment { base: 0, limit: 65535, selector: 0, type_: 3, present: 1, dpl: 0, db: 0, s: 1, l: 0, g: 0, avl: 0, unusable: 0, padding: 0 }, gs: kvm_segment { base: 4486952, limit: 65535, selector: 0, type_: 3, present: 1, dpl: 0, db: 0, s: 1, l: 0, g: 0, avl: 0, unusable: 0, padding: 0 }, ss: kvm_segment { base: 0, limit: 0, selector: 16, type_: 3, present: 1, dpl: 0, db: 0, s: 1, l: 0, g: 0, avl: 0, unusable: 0, padding: 0 }, tr: kvm_segment { base: 6291456, limit: 103, selector: 24, type_: 11, present: 1, dpl: 0, db: 0, s: 0, l: 0, g: 0, avl: 0, unusable: 0, padding: 0 }, ldt: kvm_segment { base: 0, limit: 65535, selector: 0, type_: 2, present: 1, dpl: 0, db: 0, s: 0, l: 0, g: 0, avl: 0, unusable: 0, padding: 0 }, gdt: kvm_dtable { base: 58720256, limit: 65535, padding: [0, 0, 0] }, idt: kvm_dtable { base: 4482844, limit: 4095, padding: [0, 0, 0] }, cr0: 2147549235, cr2: 6291500, cr3: 65536, cr4: 329312, cr8: 0, efer: 3329, apic_base: 4276095232, interrupt_bitmap: [0, 0, 0, 0] }
Segment registers:
------------------
register  selector  base              limit     type  p dpl db s l g avl
cs        kvm_segment { base: 0, limit: 0, selector: 8, type_: 11, present: 1, dpl: 0, db: 0, s: 1, l: 1, g: 0, avl: 0, unusable: 0, padding: 0 }
ss        kvm_segment { base: 0, limit: 0, selector: 16, type_: 3, present: 1, dpl: 0, db: 0, s: 1, l: 0, g: 0, avl: 0, unusable: 0, padding: 0 }
ds        kvm_segment { base: 0, limit: 0, selector: 16, type_: 3, present: 1, dpl: 0, db: 0, s: 1, l: 0, g: 0, avl: 0, unusable: 0, padding: 0 }
es        kvm_segment { base: 0, limit: 0, selector: 16, type_: 3, present: 1, dpl: 0, db: 0, s: 1, l: 0, g: 0, avl: 0, unusable: 0, padding: 0 }
fs        kvm_segment { base: 0, limit: 65535, selector: 0, type_: 3, present: 1, dpl: 0, db: 0, s: 1, l: 0, g: 0, avl: 0, unusable: 0, padding: 0 }
gs        kvm_segment { base: 4486952, limit: 65535, selector: 0, type_: 3, present: 1, dpl: 0, db: 0, s: 1, l: 0, g: 0, avl: 0, unusable: 0, padding: 0 }
tr        kvm_segment { base: 6291456, limit: 103, selector: 24, type_: 11, present: 1, dpl: 0, db: 0, s: 0, l: 0, g: 0, avl: 0, unusable: 0, padding: 0 }
ldt       kvm_segment { base: 0, limit: 65535, selector: 0, type_: 2, present: 1, dpl: 0, db: 0, s: 0, l: 0, g: 0, avl: 0, unusable: 0, padding: 0 }
gdt                 kvm_dtable { base: 58720256, limit: 65535, padding: [0, 0, 0] }
idt                 kvm_dtable { base: 4482844, limit: 4095, padding: [0, 0, 0] }

APIC:
-----
efer: 0000000000000d01  apic base: 00000000fee00900

@jounathaen
Copy link
Member

Ok, seems that a userspace panic produces a correct return value, but a panic in the kernel code does not.

@jschwe
Copy link
Contributor Author

jschwe commented May 15, 2020

I'd like to link to the Travis CI build for commit 4a2381c. In release mode it seems a race condition occured that caused a Panic due to a BorrowError: [0][!!!PANIC!!!] /home/travis/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/src/libcore/cell.rs:798: already mutably borrowed: BorrowError
Given the output I assume that the BorrowError occured in the kernel or demo and not in uhyve.
The thing that makes this related to this isssue is that uhyve doesn't exit after the panic.

I've saved the log output here so it doesn't get lost if someone reruns the build.
log.txt

@jschwe
Copy link
Contributor Author

jschwe commented Jan 21, 2021

I'm updating this Issue, since apparently it is still relevant.
https://git.rwth-aachen.de/acs/public/hermitcore/libhermit-rs/-/jobs/1378271 shows a CI run where the kernel crashed, but uhyve exited with 0 and the test was marked as passed.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants