|
| 1 | +# Challenge 3: Verifying Raw Pointer Arithmetic Operations |
| 2 | + |
| 3 | +- **Status:** Open |
| 4 | +- **Solution:** |
| 5 | +- **Tracking Issue:** <https://github.com/model-checking/verify-rust-std/issues/21> |
| 6 | +- **Start date:** 24/06/24 |
| 7 | +- **End date:** 24/12/10 |
| 8 | + |
| 9 | +------------------- |
| 10 | + |
| 11 | + |
| 12 | +## Goal |
| 13 | + |
| 14 | +The goal of this challenge is to verify safety of code that relies on raw pointer arithmetic, and eventual |
| 15 | +raw pointer access. |
| 16 | + |
| 17 | +## Motivation |
| 18 | + |
| 19 | +Raw pointer arithmetic is a common operation employed in the implementation of highly optimized code, |
| 20 | +as well as containers with dynamic size. |
| 21 | +Examples of the former are `str::repeat`, `[u8]::is_ascii`, |
| 22 | +while for the latter we have `Vec`, `VecDeque`, `HashMap`. |
| 23 | + |
| 24 | +These unsafe operations are usually abstracted from the end user with the usage of |
| 25 | +[safe abstractions](https://doc.rust-lang.org/beta/book/ch19-01-unsafe-rust.html#creating-a-safe-abstraction-over-unsafe-code). |
| 26 | +However, bugs in these abstractions may compromise entire applications, potentially becoming a security concern. |
| 27 | +See [CVE-2018-1000810](https://www.cvedetails.com/cve/CVE-2018-1000810/) for an example of an issue with an |
| 28 | +optimization of `str::repeat`. |
| 29 | + |
| 30 | +These safe abstractions are great candidates for software verification. |
| 31 | +They are critical for Rust applications safety, and they are modular by design. |
| 32 | + |
| 33 | +## Description |
| 34 | + |
| 35 | +Rust provides different options for pointer arithmetic, which have different semantics when it comes to safety. |
| 36 | +For example, methods such as [`ptr::offset`](https://doc.rust-lang.org/std/primitive.pointer.html#method.offset), |
| 37 | +[`ptr::add`](https://doc.rust-lang.org/std/primitive.pointer.html#method.add), |
| 38 | +and [`ptr::sub`](https://doc.rust-lang.org/std/primitive.pointer.html#method.sub) |
| 39 | +are unsafe, and one of their safety conditions is that: |
| 40 | +> - Both the starting and resulting pointer must be either in bounds or one byte past the end of the same allocated object. |
| 41 | +
|
| 42 | +I.e., violating this safety condition triggers immediate UB. |
| 43 | + |
| 44 | +On the other hand, wrapping operations such as |
| 45 | +[`ptr::wrapping_offset`](https://doc.rust-lang.org/std/primitive.pointer.html#method.wrapping_offset), |
| 46 | +[`ptr::wrapping_add`](https://doc.rust-lang.org/std/primitive.pointer.html#method.wrapping_add), |
| 47 | +[`ptr::wrapping_sub`](https://doc.rust-lang.org/std/primitive.pointer.html#method.wrapping_sub), |
| 48 | +are safe, however, the resulting pointer must not be used to read or write other allocated objects. |
| 49 | + |
| 50 | +Thus, we would like to be able to verify usage of these different methods within the standard library |
| 51 | +to ensure they are safely employed, |
| 52 | +as well as provide function contracts that can be used by other Rust crates to verify their own usage of these methods. |
| 53 | + |
| 54 | +### Assumptions |
| 55 | + |
| 56 | +For this challenge, we do not require a full proof that is independent of the pointee type `T`. |
| 57 | +Instead, we require that the verification is done for the following pointee types: |
| 58 | +1. All integer types. |
| 59 | +2. At least one `dyn Trait`. |
| 60 | +3. At least one slice. |
| 61 | +4. For unit type. |
| 62 | +5. At least one composite type with multiple non-ZST fields. |
| 63 | + |
| 64 | +### Success Criteria |
| 65 | + |
| 66 | +All the following unsafe functions must be annotated with safety contracts and the contracts have been verified: |
| 67 | + |
| 68 | +| Function | Location | |
| 69 | +|-----------------------------|----------| |
| 70 | +| *const T::add | core::ptr | |
| 71 | +| *const T::sub | core::ptr | |
| 72 | +| *const T::offset | core::ptr | |
| 73 | +| *const T::offset_from | core::ptr | |
| 74 | +| *const T::byte_add | core::ptr | |
| 75 | +| *const T::byte_sub | core::ptr | |
| 76 | +| *const T::byte_offset | core::ptr | |
| 77 | +| *const T::byte_offset_from | core::ptr | |
| 78 | +| *mut T::add | core::ptr | |
| 79 | +| *mut T::sub | core::ptr | |
| 80 | +| *mut T::offset | core::ptr | |
| 81 | +| *mut T::offset_from | core::ptr | |
| 82 | +| *mut T::byte_add | core::ptr | |
| 83 | +| *mut T::byte_sub | core::ptr | |
| 84 | +| *mut T::byte_offset | core::ptr | |
| 85 | +| *mut T::byte_offset_from | core::ptr | |
| 86 | + |
| 87 | +At least 3 of the following usages were proven safe: |
| 88 | + |
| 89 | +| Function | Location | |
| 90 | +|-------------------|---------------| |
| 91 | +| \[u8\]::is_asc_ii | core::slice | |
| 92 | +| String::remove | alloc::string | |
| 93 | + | Vec::swap_remove | alloc::vec | |
| 94 | + | Option::as_slice | core::option | |
| 95 | + | VecDeque::swap | collections::vec_deque | |
| 96 | + |
| 97 | +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): |
| 98 | + |
| 99 | +- Accessing (loading from or storing to) a place that is dangling or based on a misaligned pointer. |
| 100 | +- Performing a place projection that violates the requirements of in-bounds pointer arithmetic. |
| 101 | +A place projection is a field expression, a tuple index expression, or an array/slice index expression. |
| 102 | +- Invoking undefined behavior via compiler intrinsics. |
| 103 | +- Producing an invalid value, even in private fields and locals. |
| 104 | + |
| 105 | +Note: All solutions to verification challenges need to satisfy the criteria established in the [challenge book](../general-rules.md) |
| 106 | +in addition to the ones listed above. |
| 107 | + |
0 commit comments