aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authoriximeow <me@iximeow.net>2024-06-24 14:06:22 -0700
committeriximeow <me@iximeow.net>2024-06-24 14:27:25 -0700
commitdd8bd5ce0772b08c271205508e48e98ef1c58ea8 (patch)
tree946630c89a554843dd33a9988a36bb43db48d539
parentddde47c4c8c2058379b448894bebb3e099ea0585 (diff)
justify the current max instruction length
this is also checked by a new fuzz target
-rw-r--r--fuzz/Cargo.toml6
-rw-r--r--fuzz/fuzz_targets/instruction_text_buffer_size_ok.rs51
-rw-r--r--src/lib.rs36
-rw-r--r--src/long_mode/display.rs4
-rw-r--r--src/protected_mode/display.rs4
-rw-r--r--src/real_mode/display.rs4
6 files changed, 96 insertions, 9 deletions
diff --git a/fuzz/Cargo.toml b/fuzz/Cargo.toml
index 2203dc3..a1f871e 100644
--- a/fuzz/Cargo.toml
+++ b/fuzz/Cargo.toml
@@ -36,6 +36,12 @@ test = false
doc = false
[[bin]]
+name = "instruction_text_buffer_size_ok"
+path = "fuzz_targets/instruction_text_buffer_size_ok.rs"
+test = false
+doc = false
+
+[[bin]]
name = "display_c_does_not_panic"
path = "fuzz_targets/display_c_does_not_panic.rs"
test = false
diff --git a/fuzz/fuzz_targets/instruction_text_buffer_size_ok.rs b/fuzz/fuzz_targets/instruction_text_buffer_size_ok.rs
new file mode 100644
index 0000000..2c88424
--- /dev/null
+++ b/fuzz/fuzz_targets/instruction_text_buffer_size_ok.rs
@@ -0,0 +1,51 @@
+#![no_main]
+#[macro_use] extern crate libfuzzer_sys;
+extern crate yaxpeax_x86;
+extern crate yaxpeax_arch;
+
+use std::fmt::Write;
+
+fuzz_target!(|data: &[u8]| {
+ let x86_64_decoder = yaxpeax_x86::long_mode::InstDecoder::default();
+ let x86_32_decoder = yaxpeax_x86::protected_mode::InstDecoder::default();
+ let x86_16_decoder = yaxpeax_x86::real_mode::InstDecoder::default();
+
+ if let Ok(inst) = x86_64_decoder.decode_slice(data) {
+ use yaxpeax_x86::long_mode::DisplayStyle;
+
+ let mut s = String::new();
+ write!(s, "{}", inst.display_with(DisplayStyle::Intel)).expect("can write");
+ // MAX_INSTRUCTION_LEN is not a public crate item yet...
+ assert!(s.len() < 512);
+ s.clear();
+ write!(s, "{}", inst.display_with(DisplayStyle::C)).expect("can write");
+ // MAX_INSTRUCTION_LEN is not a public crate item yet...
+ assert!(s.len() < 512);
+ };
+
+ if let Ok(inst) = x86_32_decoder.decode_slice(data) {
+ use yaxpeax_x86::protected_mode::DisplayStyle;
+
+ let mut s = String::new();
+ write!(s, "{}", inst.display_with(DisplayStyle::Intel)).expect("can write");
+ // MAX_INSTRUCTION_LEN is not a public crate item yet...
+ assert!(s.len() < 512);
+ s.clear();
+ write!(s, "{}", inst.display_with(DisplayStyle::C)).expect("can write");
+ // MAX_INSTRUCTION_LEN is not a public crate item yet...
+ assert!(s.len() < 512);
+ };
+
+ if let Ok(inst) = x86_16_decoder.decode_slice(data) {
+ use yaxpeax_x86::real_mode::DisplayStyle;
+
+ let mut s = String::new();
+ write!(s, "{}", inst.display_with(DisplayStyle::Intel)).expect("can write");
+ // MAX_INSTRUCTION_LEN is not a public crate item yet...
+ assert!(s.len() < 512);
+ s.clear();
+ write!(s, "{}", inst.display_with(DisplayStyle::C)).expect("can write");
+ // MAX_INSTRUCTION_LEN is not a public crate item yet...
+ assert!(s.len() < 512);
+ };
+});
diff --git a/src/lib.rs b/src/lib.rs
index 7ab6cb8..93274f9 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -138,6 +138,42 @@ pub use protected_mode::Arch as x86_32;
pub mod real_mode;
pub use real_mode::Arch as x86_16;
+// this exists to size `InstructionTextBuffer`'s buffer. it ideally would come from an `Arch`
+// impl, or something related to `Arch`, but i'm not yet sure how to wire that up into
+// yaxpeax-arch. so instead calculate an appropriate max size for all of 16-bit/32-bit/64-bit
+// instruction printing that `InstructionTextBuffer` can be used for.
+//
+// `InstructionTextBuffer` prints an `InstructionDisplayer`, which means either intel syntax or
+// pseudo-C. in the future, at&t probably, as well.
+//
+// the pseudo-C syntax's max length would be something like:
+// ```
+// xacquire xrelease lock { repnz qword if /* signed */ greater_or_equal(rflags) then jmp gs:[xmm31 +
+// xmm31 * 8 + 0x12345678]{k7}{z}{rne-sae} }
+// ```
+// (which is nonsensical) or for an unknown opcode,
+// ```
+// xacquire xrelease lock { op0 = op(op0, op1, op2, op3) }
+// ```
+// where `opN` is an operand. the longest operand, same as above, would be something like
+// ```
+// gs:[xmm31 + xmm31 * 8 + 0x12345678]{k7}{z}{rne-sae}
+// ```
+// for a length like 262 bytes of operand, 55 bytes of prefixes and syntax, and another up-to-20
+// bytes of opcode.
+//
+// the longest contextualize_c might write is around 337 bytes. round up to 512 because it's.. not
+// much extra.
+//
+// the same reasoning for intel syntax yields a smaller instruction:
+// ```
+// xacquire xrelease lock op op1, op2, op3, op4
+// ```
+// where the longest operands are the same as above. this comes out to closer to 307 bytes. 512
+// bytes is still the longest of the two options.
+#[allow(dead_code)] // can be an unused constant in some library configurations
+const MAX_INSTRUCTION_LEN: usize = 512;
+
const MEM_SIZE_STRINGS: [&'static str; 65] = [
"BUG",
"byte", "word", "BUG", "dword", "ptr", "far", "BUG", "qword",
diff --git a/src/long_mode/display.rs b/src/long_mode/display.rs
index 1193f35..89d952b 100644
--- a/src/long_mode/display.rs
+++ b/src/long_mode/display.rs
@@ -4410,9 +4410,7 @@ mod buffer_sink {
/// settings format instructions identically to their corresponding `fmt::Display`.
pub fn new() -> Self {
let mut buf = alloc::string::String::new();
- // TODO: move 512 out to a MAX_INSTRUCTION_LEN const and appropriate justification (and
- // fuzzing and ..)
- buf.reserve(512);
+ buf.reserve(crate::MAX_INSTRUCTION_LEN);
Self {
content: buf,
}
diff --git a/src/protected_mode/display.rs b/src/protected_mode/display.rs
index db12878..321b5b5 100644
--- a/src/protected_mode/display.rs
+++ b/src/protected_mode/display.rs
@@ -2955,9 +2955,7 @@ mod buffer_sink {
/// settings format instructions identically to their corresponding `fmt::Display`.
pub fn new() -> Self {
let mut buf = alloc::string::String::new();
- // TODO: move 512 out to a MAX_INSTRUCTION_LEN const and appropriate justification (and
- // fuzzing and ..)
- buf.reserve(512);
+ buf.reserve(crate::MAX_INSTRUCTION_LEN);
Self {
content: buf,
}
diff --git a/src/real_mode/display.rs b/src/real_mode/display.rs
index e8bd191..669b8d7 100644
--- a/src/real_mode/display.rs
+++ b/src/real_mode/display.rs
@@ -2957,9 +2957,7 @@ mod buffer_sink {
/// settings format instructions identically to their corresponding `fmt::Display`.
pub fn new() -> Self {
let mut buf = alloc::string::String::new();
- // TODO: move 512 out to a MAX_INSTRUCTION_LEN const and appropriate justification (and
- // fuzzing and ..)
- buf.reserve(512);
+ buf.reserve(crate::MAX_INSTRUCTION_LEN);
Self {
content: buf,
}