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

Validate const value ranges in CLIF Validator #3059

Closed
afonso360 opened this issue Jul 3, 2021 · 8 comments · Fixed by #6850
Closed

Validate const value ranges in CLIF Validator #3059

afonso360 opened this issue Jul 3, 2021 · 8 comments · Fixed by #6850
Labels
cranelift:E-easy Issues suitable for newcomers to investigate, including Rust newcomers! cranelift Issues related to the Cranelift code generator good first issue Issues that are good for new contributors to tackle!

Comments

@afonso360
Copy link
Contributor

Feature

As discussed in #3056 (comment) we allow const instructions with values that are way too large for their type (i.e. 0xff00 for an i8). We should reject these modules in the CLIF validator.

Benefit

Rejecting these modules is a good way to prevent bugs in code generators using cranelift as a backend. As well as preventing issues where backends are not expecting constant values larger than the instruction type. Similar to #3056 (although this one is "legal") but with even more surprising values.

Implementation

The ideal place to implement this is in the CLIF validator, so that we can reject these CLIF modules.

Because CLIF values do not have signedness until time of use, we must allow both signed and unsigned ranges of values (-128..127 or 0..255 in the i8 case).

Alternatives

We can keep ignoring the issue (as we do now), or we can define some other behavior, such as masking the bottom bits depending on the type. But this has all the hallmarks of a bug in whatever code generator is producing this code, so we should probably not silently allow these modules.

@jameysharp
Copy link
Contributor

I think we do need this verifier pass. I'm finding it's difficult to reason about high bits in mid-end optimization passes, so we're getting them wrong frequently.

@bjorn3
Copy link
Contributor

bjorn3 commented Feb 3, 2023

Because CLIF values do not have signedness until time of use, we must allow both signed and unsigned ranges of values (-128..127 or 0..255 in the i8 case).

If we switch from Imm64 to a new Uimm64, it should be possible to limit it to just 0..255 and always zero-extend when creating the iconst from whichever frontend creates the clif ir. That would also remove a considerable amount of casts from cg_clif as rustc uses unsigned integers for immediates rather than signed integers.

@jameysharp jameysharp added good first issue Issues that are good for new contributors to tackle! cranelift:E-easy Issues suitable for newcomers to investigate, including Rust newcomers! labels Mar 1, 2023
@jameysharp
Copy link
Contributor

Fixing this issue doesn't need us to replace Imm64 with Uimm64. We can certainly discuss doing that too—it's probably a good idea—but for this purpose, we can mask off the high bits even though the type is technically signed.

We also don't need to allow e.g. -128..127. I think the conclusion we've recently come to in #5700 is that the upper bits should all be zero, which means an i8 can only be 0..255. If it's used in a signed way, those 8 bits will be sign-extended as needed to reinterpret them as -128..127.

So fixing this issue only requires that cranelift/codegen/src/verifier/mod.rs check that, for example, an iconst.i8 only has bits set within a mask of 0xFF. If somebody wants to pick this up I'm happy to go into more detail about how to do that.

@timjrd
Copy link
Contributor

timjrd commented Aug 15, 2023

Hi! 🙂 If these checks are still needed I'd like to contribute!

@jameysharp
Copy link
Contributor

Yes please, that would be great! Let us know if you have any questions.

@timjrd
Copy link
Contributor

timjrd commented Aug 15, 2023

@jameysharp in addition to Opcode::Iconst, should I also cover Opcode::Vconst? Also maybe Opcode::F32const and Opcode::F64const?

@jameysharp
Copy link
Contributor

Good question! I don't think any of those have range limits outside of their representation. For example, the operand to f32const is represented as an Ieee32, which is just a 32-bit value that preserves exactly the provided bits. There are no values for Ieee32 that are not valid for use with f32const, so we don't need to check anything about that instruction in the verifier. The trouble with iconst is that we always store the value in a 64-bit integer but, depending on the type attached to the instruction, not all of the bits are valid, so that's why we need special checks for that instruction in particular.

@timjrd
Copy link
Contributor

timjrd commented Aug 15, 2023

Got it! Thanks for the explanation. 🙂 SIMD consts and their variable length representations were a bit scary. 😅 I have a patch that adds checks for iconst, now I need to add some tests and that should be good. 👍

timjrd added a commit to timjrd/wasmtime that referenced this issue Aug 15, 2023
Implements the following checks:

  `iconst.i8`  immediate must be within 0 .. 0xFF
  `iconst.i16` immediate must be within 0 .. 0xFFFF
  `iconst.i32` immediate must be within 0 .. 0xFFFFFFFF

fix bytecodealliance#3059
timjrd added a commit to timjrd/wasmtime that referenced this issue Aug 29, 2023
Add the following checks:

  `iconst.i8`  immediate must be within 0 .. 2^8-1
  `iconst.i16` immediate must be within 0 .. 2^16-1
  `iconst.i32` immediate must be within 0 .. 2^32-1

Resolves bytecodealliance#3059
timjrd added a commit to timjrd/wasmtime that referenced this issue Aug 29, 2023
Add the following checks:

  `iconst.i8`  immediate must be within 0 .. 2^8-1
  `iconst.i16` immediate must be within 0 .. 2^16-1
  `iconst.i32` immediate must be within 0 .. 2^32-1

Resolves bytecodealliance#3059
timjrd added a commit to timjrd/wasmtime that referenced this issue Aug 31, 2023
Add the following checks:

`iconst.i8`  immediate must be within 0 .. 2^8-1
`iconst.i16` immediate must be within 0 .. 2^16-1
`iconst.i32` immediate must be within 0 .. 2^32-1

Resolves bytecodealliance#3059
github-merge-queue bot pushed a commit that referenced this issue Aug 31, 2023
* cranelift: Validate `iconst` ranges

Add the following checks:

`iconst.i8`  immediate must be within 0 .. 2^8-1
`iconst.i16` immediate must be within 0 .. 2^16-1
`iconst.i32` immediate must be within 0 .. 2^32-1

Resolves #3059

* cranelift: Parse `iconst` according to its type

Modifies the parser for textual CLIF so that V in `iconst.T V` is
parsed according to T.

Before this commit, something like `iconst.i32 0xffff_ffff_ffff` was
valid because all `iconst` were parsed the same as an
`iconst.i64`. Now the above example will throw an error.

Also, a negative immediate as in `iconst.iN -X` is now converted to
`2^N - X`.

This commit also fixes some broken tests.

* cranelift: Update tests to match new CLIF parser
pchickey pushed a commit that referenced this issue Sep 1, 2023
…6950)

* Enhance `async` configuration of `bindgen!` macro (#6942)

This commit takes a leaf out of `wiggle`'s book to enable bindings
generation for async host functions where only some host functions are
async instead of all of them. This enhances the `async` key with a few
more options:

    async: {
        except_imports: ["foo"],
        only_imports: ["bar"],
    }

This is beyond what `wiggle` supports where either an allow-list or
deny-list can be specified (although only one can be specified). This
can be useful if either the list of sync imports or the list of async
imports is small.

* cranelift-interpreter: Fix SIMD shifts and rotates (#6939)

* cranelift-interpreter: Fix SIMD `ishl`/`{s,u}`shr

* fuzzgen: Enable a few more ops

* cranelift: Fix tests for {u,s}shr

* fuzzgen: Change pattern matching arms for shifts

Co-Authored-By: Jamey Sharp <[email protected]>

---------

Co-authored-by: Jamey Sharp <[email protected]>

* Partially revert CLI argument changes from #6737 (#6944)

* Partially revert CLI argument changes from #6737

This commit is a partial revert of #6737. That change was reverted
in #6830 for the 12.0.0 release of Wasmtime and otherwise it's currently
slated to get released with the 13.0.0 release of Wasmtime. Discussion
at today's Wasmtime meeting concluded that it's best to couple this
change with #6925 as a single release rather than spread out across
multiple releases. This commit is thus the revert of #6737, although
it's a partial revert in that I've kept many of the new tests added to
showcase the differences before/after when the change lands.

This means that Wasmtime 13.0.0 will exhibit the same CLI behavior as
12.0.0 and all prior releases. The 14.0.0 release will have both a new
CLI and new argument passing semantics. I'll revert this revert (aka
re-land #6737) once the 13.0.0 release branch is created and `main`
becomes 14.0.0.

* Update release notes

* riscv64: Use `PCRelLo12I` relocation on Loads (#6938)

* riscv64: Use `PCRelLo12I` relocation on Loads

* riscv64: Strenghten pattern matching when emitting Load's

* riscv64: Clarify some of the load address logic

* riscv64: Even stronger matching

* Update Rust in CI to 1.72.0, clarify Wasmtime's MSRV (#6900)

* Update Rust in CI to 1.72.0

* Update CI, tooling, and docs for MSRV

This commit codifies an MSRV policy for Wasmtime at "stable minus two"
meaning that the latest three releases of Rust will be supported. This
is enforced on CI with a full test suite job running on Linux x86_64
with the minimum supported Rust version. The full test suite will use
the latest stable version. A downside of this approach is that new
changes may break MSRV support on non-Linux or non-x86_64 platforms and
we won't know about it, but that's deemed a minor enough risk at this
time.

A minor fix is applied to Wasmtime's `Cargo.toml` to support Rust 1.70.0
instead of requiring Rust 1.71.0

* Fix installation of rust

* Scrape MSRV from Cargo.toml

* Cranelift is the same as Wasmtime's MSRV now, more words too

* Fix a typo

* aarch64: Use `RegScaled*` addressing modes (#6945)

This commit adds a few cases to `amode` construction on AArch64 for
using the `RegScaled*` variants of `AMode`. This won't affect wasm due
to this only matching the sign-extension happening before the shift, but
it should otherwise help non-wasm Cranelift use cases.

Closes #6742

* cranelift: Validate `iconst` ranges (#6850)

* cranelift: Validate `iconst` ranges

Add the following checks:

`iconst.i8`  immediate must be within 0 .. 2^8-1
`iconst.i16` immediate must be within 0 .. 2^16-1
`iconst.i32` immediate must be within 0 .. 2^32-1

Resolves #3059

* cranelift: Parse `iconst` according to its type

Modifies the parser for textual CLIF so that V in `iconst.T V` is
parsed according to T.

Before this commit, something like `iconst.i32 0xffff_ffff_ffff` was
valid because all `iconst` were parsed the same as an
`iconst.i64`. Now the above example will throw an error.

Also, a negative immediate as in `iconst.iN -X` is now converted to
`2^N - X`.

This commit also fixes some broken tests.

* cranelift: Update tests to match new CLIF parser

* Some minor fixes and features for WASI and sockets (#6948)

* Use `command::add_to_linker` in tests to reduce the number of times
  all the `add_to_linker` are listed.
* Add all `wasi:sockets` interfaces currently implemented to both the
  sync and async `command` functions (this enables all the interfaces in
  the CLI for example).
* Use `tokio::net::TcpStream::try_io` whenever I/O is performed on a
  socket, ensuring that readable/writable flags are set/cleared
  appropriately (otherwise once readable a socket is infinitely readable).
* Add a `with_ambient_tokio_runtime` helper function to use when
  creating a `tokio::net::TcpStream` since otherwise it panics due to a
  lack of active runtime in a synchronous context.
* Add `WouldBlock` handling to return a 0-length read.
* Add an `--inherit-network` CLI flag to enable basic usage of sockets
  in the CLI.

This will conflict a small amount with #6877 but should be easy to
resolve, and otherwise this targets different usability points/issues
than that PR.

---------

Co-authored-by: Afonso Bordado <[email protected]>
Co-authored-by: Jamey Sharp <[email protected]>
Co-authored-by: Timothée Jourde <[email protected]>
timjrd added a commit to timjrd/wasmtime that referenced this issue Sep 5, 2023
github-merge-queue bot pushed a commit that referenced this issue Sep 5, 2023
Resolves #6965
Linked to #3059 #6850 #6958

Co-authored-by: Afonso Bordado <[email protected]>
eduardomourar pushed a commit to eduardomourar/wasmtime that referenced this issue Sep 6, 2023
* cranelift: Validate `iconst` ranges

Add the following checks:

`iconst.i8`  immediate must be within 0 .. 2^8-1
`iconst.i16` immediate must be within 0 .. 2^16-1
`iconst.i32` immediate must be within 0 .. 2^32-1

Resolves bytecodealliance#3059

* cranelift: Parse `iconst` according to its type

Modifies the parser for textual CLIF so that V in `iconst.T V` is
parsed according to T.

Before this commit, something like `iconst.i32 0xffff_ffff_ffff` was
valid because all `iconst` were parsed the same as an
`iconst.i64`. Now the above example will throw an error.

Also, a negative immediate as in `iconst.iN -X` is now converted to
`2^N - X`.

This commit also fixes some broken tests.

* cranelift: Update tests to match new CLIF parser
eduardomourar pushed a commit to eduardomourar/wasmtime that referenced this issue Sep 6, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
cranelift:E-easy Issues suitable for newcomers to investigate, including Rust newcomers! cranelift Issues related to the Cranelift code generator good first issue Issues that are good for new contributors to tackle!
Projects
None yet
Development

Successfully merging a pull request may close this issue.

5 participants