|
| 1 | +# Challenge 13: Safety of `CStr` |
| 2 | + |
| 3 | +- **Status:** Open |
| 4 | +- **Solution:** |
| 5 | +- **Tracking Issue:** [#150](https://github.com/model-checking/verify-rust-std/issues/150) |
| 6 | +- **Start date:** 2024/11/04 |
| 7 | +- **End date:** 2025/01/31 |
| 8 | + |
| 9 | +------------------- |
| 10 | +## Goal |
| 11 | + |
| 12 | +Verify that `CStr` safely represents a borrowed reference to a null-terminated array of bytes sequences similar to |
| 13 | +the C string representation. |
| 14 | + |
| 15 | +## Motivation |
| 16 | + |
| 17 | +The `CStr` structure is meant to be used to build safe wrappers of FFI functions that may leverage `CStr::as_ptr` |
| 18 | +and the unsafe `CStr::from_ptr` constructor to provide a safe interface to other consumers. |
| 19 | +It provides safe methods to convert `CStr` to a Rust `&str` by performing UTF-8 validation, or into an owned `CString`. |
| 20 | + |
| 21 | +Any issue with this structure or misusage of its unsafe methods could trigger an invalid memory access, which poses |
| 22 | +a security risk for their users. |
| 23 | + |
| 24 | +## Description |
| 25 | + |
| 26 | +The goal of this challenge is to ensure the safety of the `CStr` struct implementation. |
| 27 | +First, we need to specify a safety invariant that captures the essential safety properties that must be maintained. |
| 28 | + |
| 29 | +Next, we should verify that all the safe, public methods respect this invariant. |
| 30 | +For example, we can check that creating a `CStr` from a byte slice with method `from_bytes_with_nul` will only yield |
| 31 | +safe values of `CStr`. |
| 32 | + |
| 33 | +Finally, for unsafe methods like `from_ptr()` and `from_bytes_with_nul_unchecked`, we need to specify appropriate safety contracts. |
| 34 | +These contracts should ensure no undefined behavior occurs within the unsafe methods themselves, |
| 35 | +and that they maintain the overall safety invariant of `CStr` when called correctly. |
| 36 | + |
| 37 | +### Assumptions |
| 38 | + |
| 39 | +- Harnesses may be bounded. |
| 40 | + |
| 41 | +### Success Criteria |
| 42 | + |
| 43 | +1. Implement the `Invariant` trait for `CStr`. |
| 44 | + |
| 45 | +2. Verify that the `CStr` safety invariant holds after calling any of the following public safe methods. |
| 46 | + |
| 47 | +| Function | Location | |
| 48 | +|------------------------|--------------------| |
| 49 | +| `from_bytes_until_nul` | `core::ffi::c_str` | |
| 50 | +| `from_bytes_with_nul` | `core::ffi::c_str` | |
| 51 | +| `count_bytes` | `core::ffi::c_str` | |
| 52 | +| `is_empty` | `core::ffi::c_str` | |
| 53 | +| `to_bytes` | `core::ffi::c_str` | |
| 54 | +| `to_bytes_with_nul` | `core::ffi::c_str` | |
| 55 | +| `bytes` | `core::ffi::c_str` | |
| 56 | +| `to_str` | `core::ffi::c_str` | |
| 57 | +| `as_ptr` | `core::ffi::c_str` | |
| 58 | + |
| 59 | +3. Annotate and verify the safety contracts for the following unsafe functions: |
| 60 | + |
| 61 | +| Function | Location | |
| 62 | +|--------------------------------|---------------------| |
| 63 | +| `from_ptr` | `core::ffi::c_str` | |
| 64 | +| `from_bytes_with_nul_uncheked` | `core::ffi::c_str` | |
| 65 | +| `strlen` | `core::ffi::c_str` | |
| 66 | + |
| 67 | +4. Verify that the following trait implementations for the `CStr` type are safe: |
| 68 | + |
| 69 | + |
| 70 | +| Trait | Implementation Location | |
| 71 | +|-------------------------------------|-------------------------| |
| 72 | +| `CloneToUninit` [^unsafe-fn] | `core::clone` | |
| 73 | +| `ops::Index<ops::RangeFrom<usize>>` | `core::ffi::c_str` | |
| 74 | + |
| 75 | +[^unsafe-fn]: Unsafe functions will require safety contracts. |
| 76 | + |
| 77 | +All proofs must automatically ensure the absence of the following undefined behaviors [ref](https://github.com/rust-lang/reference/blob/142b2ed77d33f37a9973772bd95e6144ed9dce43/src/behavior-considered-undefined.md): |
| 78 | + |
| 79 | +- Accessing (loading from or storing to) a place that is dangling or based on a misaligned pointer. |
| 80 | +- Performing a place projection that violates the requirements of in-bounds pointer arithmetic. |
| 81 | +- Mutating immutable bytes. |
| 82 | +- Accessing uninitialized memory. |
| 83 | + |
| 84 | +Note: All solutions to verification challenges need to satisfy the criteria established in the |
| 85 | +[challenge book](../general-rules.md) in addition to the ones listed above. |
0 commit comments