Emulator sistem lawas atau CPU sederhana seperti TD4 (4-bit "CPU Buatan Tangan") rentan terhadap eksploitasi jika input biner diperlakukan sebagai trusted data. Mengimplementasikan interpreter TD4 tanpa validasi batas (bound checks) membuka celah out-of-bounds execution, buffer overflow pada host memory, hingga perilaku tidak terdefinisi (undefined behavior). Artikel ini menyajikan implementasi hardening emulator TD4 berbasis C modern.
Arsitektur TD4 dan Vektor Kerentanan
Arsitektur TD4 memiliki spesifikasi berikut:
- Ukuran Data dan Alamat: Data 4-bit, alamat memori (Program Counter / PC) 4-bit (16 alamat instruksi, 0x0 hingga 0xF).
- Register: Register A (4-bit), Register B (4-bit), Program Counter / PC (4-bit), dan Carry Flag C (1-bit).
- Memori Program (ROM): Maksimum 16 byte (16 baris instruksi @ 8-bit: 4-bit opcode + 4-bit immediate data).
- I/O: Port input IN (4-bit), Port output OUT (4-bit).
Vektor serangan utama terjadi pada runtime host ketika:
- File ROM yang dimuat melebihi 16 byte atau tidak diparsing dengan validasi ukuran.
- Instruksi manipulasi PC (
JMP Im,JNC Im) mengarahkan pembacaan di luar array ROM. - Bitwise arithmetic pada register 4-bit meluap ke tipe data host (misal
uint8_t) tanpa masking bit0x0F, merusak integritas state logika CPU. - Instruksi undefined atau invalid opcode mengeksekusi branch tak terduga.
Validasi ROM Image dan Parser Aman
Parser ROM harus memverifikasi ukuran payload secara ketat sebelum dieksekusi. Tidak boleh ada asumsi bahwa file selalu berukuran valid 16 byte.
#include <stdint.h>
#include <stdbool.h>
#include <stddef.h>
#define TD4_ROM_SIZE 16
#define TD4_REG_MASK 0x0F
typedef struct {
uint8_t a; // 4-bit
uint8_t b; // 4-bit
uint8_t pc; // 4-bit (0-15)
bool carry; // 1-bit
uint8_t out; // 4-bit
uint8_t rom[TD4_ROM_SIZE];
} TD4_CPU;
typedef enum {
TD4_OK = 0,
TD4_ERR_ROM_OVERFLOW,
TD4_ERR_INVALID_OPCODE,
TD4_ERR_INVALID_IO
} TD4_Status;
TD4_Status td4_load_rom(TD4_CPU *cpu, const uint8_t *buffer, size_t size) {
if (cpu == NULL || buffer == NULL) {
return TD4_ERR_INVALID_IO;
}
if (size > TD4_ROM_SIZE) {
return TD4_ERR_ROM_OVERFLOW;
}
for (size_t i = 0; i < TD4_ROM_SIZE; i++) {
cpu->rom[i] = (i < size) ? buffer[i] : 0x00; // Zero padding
}
return TD4_OK;
}Isolasi Register dan Masking Strict 4-bit
Host runtime menggunakan tipe data native (biasanya uint8_t). Tanpa proteksi, operasi cpu->a += data dapat bernilai 0x10 atau lebih, merusak logika hardware TD4. Lakukan clamp nilai secara konsisten menggunakan mask bit 0x0F dan catat state Carry Flag secara deterministik.
static inline void td4_add_reg_a(TD4_CPU *cpu, uint8_t imm) {
uint8_t raw = cpu->a + (imm & TD4_REG_MASK);
cpu->carry = (raw > TD4_REG_MASK); // Carry jika bit ke-4 aktif
cpu->a = raw & TD4_REG_MASK;
}Handling Invalid Opcode dan Memory Boundary Loop
Setiap pembacaan memori via Program Counter harus dipastikan berada di rentang 0x0 sampai 0xF. TD4 mendefinisikan opcode pada 4-bit atas instruksi (nibble tinggi), sedangkan immediate data berada pada 4-bit bawah (nibble rendah).
Jika opcode tidak dikenal ditemukan, sistem harus menghentikan eksekusi atau menangani fault secara eksplisit, bukan mengabaikannya atau memicu branch sembarang.
TD4_Status td4_step(TD4_CPU *cpu, uint8_t in_port) {
if (cpu == NULL) return TD4_ERR_INVALID_IO;
// Bound check Program Counter
if (cpu->pc >= TD4_ROM_SIZE) {
cpu->pc &= TD4_REG_MASK; // Hard clamp ke 4-bit
}
// Sanitasi input port (pastikan hanya 4-bit)
uint8_t sanitized_in = in_port & TD4_REG_MASK;
uint8_t instruction = cpu->rom[cpu->pc];
uint8_t opcode = (instruction >> 4) & 0x0F;
uint8_t imm = instruction & TD4_REG_MASK;
uint8_t next_pc = (cpu->pc + 1) & TD4_REG_MASK;
switch (opcode) {
case 0x0: // MOV A, Im
cpu->a = imm;
cpu->carry = false;
break;
case 0x5: // MOV A, B
cpu->a = cpu->b;
cpu->carry = false;
break;
case 0x3: // MOV B, Im
cpu->b = imm;
cpu->carry = false;
break;
case 0x4: // MOV B, A
cpu->b = cpu->a;
cpu->carry = false;
break;
case 0x1: // MOV A, IN
cpu->a = sanitized_in;
cpu->carry = false;
break;
case 0x2: // MOV IN, B -> IN port read into B
cpu->b = sanitized_in;
cpu->carry = false;
break;
case 0xB: // OUT B
cpu->out = cpu->b & TD4_REG_MASK;
cpu->carry = false;
break;
case 0x9: // OUT Im
cpu->out = imm;
cpu->carry = false;
break;
case 0x6: // ADD A, Im
td4_add_reg_a(cpu, imm);
break;
case 0x7: // ADD B, Im
{
uint8_t raw = cpu->b + imm;
cpu->carry = (raw > TD4_REG_MASK);
cpu->b = raw & TD4_REG_MASK;
}
break;
case 0xF: // JMP Im
next_pc = imm & TD4_REG_MASK;
cpu->carry = false;
break;
case 0xE: // JNC Im
if (!cpu->carry) {
next_pc = imm & TD4_REG_MASK;
}
cpu->carry = false;
break;
default:
// Opcode di luar spec TD4: trap error
return TD4_ERR_INVALID_OPCODE;
}
cpu->pc = next_pc;
return TD4_OK;
}Sanitasi I/O dan Pencegahan State Drift
Interfacing peripheral host dengan register 4-bit memerlukan validasi ganda:
- Input Port Sanitasi: Nilai dari sumber luar host dipotong via
in_port & 0x0Funtuk mencegah bit kotor masuk ke register A atau B. - Output Port Isolation: Register
outselalu diekspos sebagai nilai 4-bit murni ke modul display/LED atau bus komunikasi virtual host. - Flag Reset Deterministic: Instruksi non-arithmetic harus mereset flag carry sesuai standar perilaku IC 74HC161 / 74HC283 pada rangkaian fisik TD4.
Verifikasi Runtime
Lakukan self-check assert di awal runtime untuk memastikan arsitektur host dan emulator mempertahankan boundary contract:
#include <assert.h>
void td4_verify_hardening(void) {
TD4_CPU cpu = {0};
uint8_t payload[20] = {0x00};
// Test 1: Tolak ROM melebihi limit 16-byte
assert(td4_load_rom(&cpu, payload, 20) == TD4_ERR_ROM_OVERFLOW);
// Test 2: Validasi eksekusi normal dan masking
uint8_t valid_rom[2] = {0x6F, 0x00}; // ADD A, 0xF
assert(td4_load_rom(&cpu, valid_rom, 2) == TD4_OK);
cpu.a = 0x02;
assert(td4_step(&cpu, 0x00) == TD4_OK);
assert(cpu.a == 0x01); // (2 + 15) & 0xF = 1
assert(cpu.carry == true);
// Test 3: Deteksi opcode ilegal
cpu.rom[cpu.pc] = 0x80; // 0x8 bukan opcode legal TD4
assert(td4_step(&cpu, 0x00) == TD4_ERR_INVALID_OPCODE);
}Dengan validasi ketat ukuran ROM, masking bit arithmetic register, penegakan bound checking pada PC, dan penolakan opcode undefined, emulator terhindar dari crash memori host maupun anomali logika selama pemrosesan instruksi TD4.
Komentar
0 komentar
Masuk ke akun kamu untuk ikut berkomentar.
Belum ada komentar
Jadilah yang pertama ikut berdiskusi!