summaryrefslogtreecommitdiff
path: root/apf_interpreter.c
diff options
context:
space:
mode:
Diffstat (limited to 'apf_interpreter.c')
-rw-r--r--apf_interpreter.c30
1 files changed, 22 insertions, 8 deletions
diff --git a/apf_interpreter.c b/apf_interpreter.c
index e2f46cb..1585a34 100644
--- a/apf_interpreter.c
+++ b/apf_interpreter.c
@@ -1,5 +1,5 @@
/*
- * Copyright 2016, The Android Open Source Project
+ * Copyright 2018, The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -31,9 +31,8 @@
// superfluous ">= 0" with unsigned expressions generates compile warnings.
#define ENFORCE_UNSIGNED(c) ((c)==(uint32_t)(c))
-int accept_packet(const uint8_t* program, uint32_t program_len,
+int accept_packet(uint8_t* program, uint32_t program_len, uint32_t ram_len,
const uint8_t* packet, uint32_t packet_len,
- uint8_t* data, uint32_t data_len,
uint32_t filter_age) {
// Is offset within program bounds?
#define IN_PROGRAM_BOUNDS(p) (ENFORCE_UNSIGNED(p) && (p) < program_len)
@@ -42,7 +41,8 @@ int accept_packet(const uint8_t* program, uint32_t program_len,
// Is access to offset |p| length |size| within data bounds?
#define IN_DATA_BOUNDS(p, size) (ENFORCE_UNSIGNED(p) && \
ENFORCE_UNSIGNED(size) && \
- (p) + (size) <= data_len && \
+ (p) + (size) <= ram_len && \
+ (p) >= program_len && \
(p) + (size) >= (p)) // catch wraparounds
// Accept packet if not within program bounds
#define ASSERT_IN_PROGRAM_BOUNDS(p) ASSERT_RETURN(IN_PROGRAM_BOUNDS(p))
@@ -58,6 +58,8 @@ int accept_packet(const uint8_t* program, uint32_t program_len,
// Memory slot values.
uint32_t memory[MEMORY_ITEMS] = {};
// Fill in pre-filled memory slot values.
+ memory[MEMORY_OFFSET_PROGRAM_SIZE] = program_len;
+ memory[MEMORY_OFFSET_DATA_SIZE] = ram_len;
memory[MEMORY_OFFSET_PACKET_SIZE] = packet_len;
memory[MEMORY_OFFSET_FILTER_AGE] = filter_age;
ASSERT_IN_PACKET_BOUNDS(APF_FRAME_HEADER_SIZE);
@@ -265,22 +267,34 @@ int accept_packet(const uint8_t* program, uint32_t program_len,
}
break;
case LDDW_OPCODE: {
- uint32_t offs = imm + OTHER_REG;
+ uint32_t offs = OTHER_REG + signed_imm;
uint32_t size = 4;
uint32_t val = 0;
+ // Negative offsets wrap around the end of the address space.
+ // This allows us to efficiently access the end of the
+ // address space with one-byte immediates without using %=.
+ if (offs & 0x80000000) {
+ offs = ram_len + offs; // unsigned overflow intended
+ }
ASSERT_IN_DATA_BOUNDS(offs, size);
while (size--)
- val = (val << 8) | data[offs++];
+ val = (val << 8) | program[offs++];
REG = val;
break;
}
case STDW_OPCODE: {
- uint32_t offs = imm + OTHER_REG;
+ uint32_t offs = OTHER_REG + signed_imm;
uint32_t size = 4;
uint32_t val = REG;
+ // Negative offsets wrap around the end of the address space.
+ // This allows us to efficiently access the end of the
+ // address space with one-byte immediates without using %=.
+ if (offs & 0x80000000) {
+ offs = ram_len + offs; // unsigned overflow intended
+ }
ASSERT_IN_DATA_BOUNDS(offs, size);
while (size--) {
- data[offs++] = (val >> 24);
+ program[offs++] = (val >> 24);
val <<= 8;
}
break;