Skip to content

Commit 983ea29

Browse files
committed
fixing overflow issue in PHG parsing, adding a test for it
1 parent 43a4acf commit 983ea29

File tree

1 file changed

+41
-6
lines changed

1 file changed

+41
-6
lines changed

src/components/extensions.rs

Lines changed: 41 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ pub enum Extension {
4545
},
4646
PowerHeightGainDirectivity {
4747
power_watts: u16,
48-
antenna_height_feet: u16,
48+
antenna_height_feet: u32,
4949
antenna_gain_db: u8,
5050
antenna_directivity: Directivity,
5151
},
@@ -154,20 +154,37 @@ impl Extension {
154154
.ok_or_else(|| DecodeError::InvalidExtensionRange(b.to_vec()))?,
155155
}),
156156
b"PHG" => {
157+
// we do as u16 here because we want to allow up to P^2 values for POWER
158+
// so power_code is a byte in range [0, 255]
159+
// therefore power**2 can be [1, 65025]
160+
// but we need power_code to be a u16 lest we panic with a "attempt to multiply with overflow"
157161
let power_code = (bytes[3] as char)
158162
.to_digit(10)
159-
.ok_or_else(|| DecodeError::InvalidExtensionPhg(b.to_vec()))?;
163+
.ok_or_else(|| DecodeError::InvalidExtensionPhg(b.to_vec()))?
164+
as u16;
160165

161166
/*
162167
The height code may in fact be any ASCII character 0–9 and above. This is
163168
so that larger heights for balloons, aircraft or satellites may be specified.
164169
For example:
165170
: is the height code for 10240 feet (approximately 1.9 miles).
166171
; is the height code for 20480 feet (approximately 3.9 miles), and so on.
167-
*/
172+
173+
the max value for this is not presribed in APRS101, so we will bound it
174+
to something that fits in a u32, so the max of height_code can be 28 (after ASCII adjustment)
175+
which gives (2**28)*10 = 2684354560 feet (approx. 508k miles...)
176+
177+
178+
*/
168179
let height_code = bytes[4]
169180
.checked_sub(48)
170-
.ok_or_else(|| DecodeError::InvalidExtensionPhg(b.to_vec()))?;
181+
.ok_or_else(|| DecodeError::InvalidExtensionPhg(b.to_vec()))?
182+
as u32;
183+
184+
if !(0..28).contains(&height_code) {
185+
// too big!
186+
return Err(DecodeError::InvalidExtensionPhg(b.to_vec()));
187+
}
171188

172189
let gain_code = (bytes[5] as char)
173190
.to_digit(10)
@@ -180,8 +197,8 @@ impl Extension {
180197
.map_err(|_| DecodeError::InvalidExtensionPhg(b.to_vec()))?;
181198

182199
Ok(Self::PowerHeightGainDirectivity {
183-
power_watts: power_code.pow(2) as u16,
184-
antenna_height_feet: 2u16.pow(height_code as u32) * 10,
200+
power_watts: power_code.pow(2),
201+
antenna_height_feet: 2u32.pow(height_code) * 10,
185202
antenna_gain_db: gain_code as u8,
186203
antenna_directivity: directivtity,
187204
})
@@ -247,6 +264,8 @@ impl Extension {
247264

248265
#[cfg(test)]
249266
mod test {
267+
use crate::AprsPacket;
268+
250269
use super::*;
251270
#[test]
252271
fn test_parse_course_speed() {
@@ -340,4 +359,20 @@ mod test {
340359

341360
assert!(ext.encode(&mut buf).is_err())
342361
}
362+
363+
#[test]
364+
fn test_absurd_values1() {
365+
let raw_packet = [
366+
125, 13, 0, 0, 0, 5, 0, 0, 0, 0, 0, 1, 104, 1, 0, 0, 62, 0, 1, 1, 10, 4, 6, 0, 0, 0, 0,
367+
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 50, 58, 59, 18, 74, 146, 36, 73, 146, 36, 73, 2, 42, 50,
368+
50, 50, 50, 50, 50, 72, 51, 32, 32, 32, 46, 32, 32, 78, 58, 49, 55, 177, 52, 50, 46,
369+
51, 48, 87, 148, 80, 72, 71, 52, 203, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52,
370+
52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52,
371+
52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52,
372+
52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52,
373+
52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52,
374+
0, 0, 0, 0, 0, 0, 0, 6, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52,
375+
];
376+
let _packet = AprsPacket::decode_textual(&raw_packet).unwrap();
377+
}
343378
}

0 commit comments

Comments
 (0)