12 #define MAX_STACKTRACES 16 13 #define MAX_FUNC_NAME 128 14 #define MAX_LOG_SIZE 512 17 #define LOG_LINE_MAX (1024 - PREFIX_MAX) 23 #define LIX_SIGNAL_STOP_MASK ( \ 24 BIT(SIGSTOP) | BIT(SIGTSTP) | \ 25 BIT(SIGTTIN) | BIT(SIGTTOU) ) 30 #define LIX_SIGNAL_IGNORE_MASK (\ 31 BIT(SIGCONT) | BIT(SIGCHLD) | \ 32 BIT(SIGWINCH) | BIT(SIGURG) ) 45 #define LIX_SIGNAL_FATAL(sig) \ 46 !((sig) > 0 && (sig) < SIGRTMIN && (BIT(sig) & (LIX_SIGNAL_IGNORE_MASK | LIX_SIGNAL_STOP_MASK))) 78 memzero(pCrashEvent,
sizeof(*pCrashEvent));
85 ERROR(
"[ERROR] IntNotifyIntroEvent failed: %08x\n", status);
116 QWORD ksymLogBufferLength = 0;
117 QWORD ksymLogFirstIdx = 0;
129 if (!ksymLogBufferLength)
135 if (!ksymLogFirstIdx)
140 *LogBufferGva = ksymLogBuffer;
141 *LogBufferLengthGva = ksymLogBufferLength;
142 *LogFirstIdxGva = ksymLogFirstIdx;
144 TRACE(
"[LIX CRASH] Found 'log_buf' at %llx, 'log_buf_len' at %llx and 'log_first_idx' at 0x%llx\n",
145 ksymLogBuffer, ksymLogBufferLength, ksymLogFirstIdx);
153 ERROR(
"[ERROR] IntKsymFindByName could not find log_buf_kexec_setup\n");
160 ksymLogBufferLength = 0;
162 while (ksymStart + ksymOffset < ksymEnd)
169 ERROR(
"[ERROR] IntDecDecodeInstructionFromBuffer failed with status: 0x%08x.\n", status);
174 ksymOffset += instrux.Length;
176 if (instrux.Instruction == ND_INS_MOV &&
177 instrux.Operands[0].Type == ND_OP_REG &&
178 instrux.Operands[0].Info.Register.Reg == NDR_RDX &&
179 instrux.Operands[1].Type == ND_OP_IMM &&
183 if (0 == ksymLogBuffer)
185 ksymLogBuffer = instrux.Operands[1].Info.Immediate.Imm;
187 else if (0 == ksymLogBufferLength)
189 ksymLogBufferLength = instrux.Operands[1].Info.Immediate.Imm;
191 else if (0 == ksymLogFirstIdx)
193 ksymLogFirstIdx = instrux.Operands[1].Info.Immediate.Imm;
196 if (ksymLogBuffer && ksymLogBufferLength && ksymLogFirstIdx)
198 *LogBufferGva = ksymLogBuffer;
199 *LogBufferLengthGva = ksymLogBufferLength;
200 *LogFirstIdxGva = ksymLogFirstIdx;
202 TRACE(
"[LIX CRASH] Found 'log_buf' at %llx, 'log_buf_len' at %llx and 'log_buf_idx' at %llx\n",
203 ksymLogBuffer, ksymLogBufferLength, ksymLogFirstIdx);
226 size_t totalHeapSize, freeHeapSize;
231 ERROR(
"[ERROR] IntQueryHeapSize failed: 0x%08x.\n", status);
235 return (freeHeapSize >= Size);
264 memzero(pEvent,
sizeof(*pEvent));
271 WARNING(
"[WARNING] IntLixTaskGetTrapFrame failed with status: 0x%08x\n", status);
276 pEvent->
Rip = trapFrame.
Rip;
283 TRACE(
"[UMEXCEPTION] Code: 0x%08x at RIP 0x%016llx inside process '%s' (Pid %d, Cr3 0x%016llx). Continuable: %d\n",
290 WARNING(
"[WARNING] IntNotifyIntroEvent failed: 0x%08x\n", status);
316 WARNING(
"[WARNING] IntLixTaskFindByGva failed for process 0x%016llx\n",
gVcpu->
Regs.
R8);
325 LOG(
"[SIGNAL] Override signal %d with SIGKILL for task %llx\n",
332 ERROR(
"[ERROR] IntDetSetReturnValue failed: %08x\n", status);
354 char *pLogBufferStart = NULL;
355 char *pLogBufferEnd = NULL;
356 QWORD logBufferPointerGva, logBufferLengthGva, logFirstIdxGva;
358 DWORD logBufferLength, logFirstIdx;
359 QWORD maxIterations = 0x10000;
364 ERROR(
"[ERROR] IntLixCrashFetchDmesgSymbol failed: 0x%08x\n", status);
371 ERROR(
"[ERROR] IntKernVirtMemFetchQword failed for %llx: 0x%08x\n", logBufferGva, status);
378 ERROR(
"[ERROR] IntKernVirtMemFetchDword failed for %llx: 0x%08x\n", logBufferLengthGva, status);
385 ERROR(
"[ERROR] IntKernVirtMemFetchDword failed for %llx: 0x%08x\n", logFirstIdxGva, status);
391 WARNING(
"[WARNING] Not enough heap is available (requested %d bytes)\n", logBufferLength);
398 ERROR(
"[ERROR] IntVirtMemMap failed with status 0x%08x for @%llx.", status, logBufferGva);
404 for (
DWORD index = 0; index < logBufferLength; index++)
407 while ((indexLine <
sizeof(dmesgLine) - 1) &&
408 (index < logBufferLength) &&
409 (pLogBufferStart[index] !=
'\n'))
413 dmesgLine[indexLine++] = pLogBufferStart[index];
417 dmesgLine[indexLine] = 0;
418 LOG(
"[DMESG]%s", dmesgLine);
424 pLogBufferEnd = pLogBufferStart + logBufferLength;
428 LOG(
"[INFO] start_idx is: %d", logFirstIdx);
430 while (--maxIterations)
433 const char *line = NULL;
435 if ((
char *)pHeader +
sizeof(*pHeader) >= pLogBufferEnd)
437 ERROR(
"[ERROR] In-guest DMESG buffer may be corrupted!\n");
441 if (0 == pHeader->
TextLength && logFirstIdx > 0)
443 LOG(
"[INFO] pHeader->TextLength is 0, will start from the beginning!");
450 LOG(
"[DMESG] End of DMESG\n");
456 if (toPrint >
sizeof(dmesgLine))
458 WARNING(
"[WARNING] TextLength %lu is bigger than our buffer size: %lu\n",
459 toPrint,
sizeof(dmesgLine));
461 toPrint =
sizeof(dmesgLine);
464 line = (
const char *)pHeader +
sizeof(*pHeader);
466 if (line + toPrint >= pLogBufferEnd)
468 ERROR(
"[ERROR] Last dmesg line is outside the mapped buffer. Will stop.");
472 memcpy(dmesgLine, line, toPrint);
475 dmesgLine[toPrint - 1] = 0;
484 WARNING(
"[WARNING] Reached max iterations count. DMESG log may be truncated!");
INTSTATUS IntVirtMemUnmap(void **HostPtr)
Unmaps a memory range previously mapped with IntVirtMemMap.
#define NSEC_TO_SEC(nsec)
IG_ARCH_REGS Regs
The current state of the guest registers.
EVENT_EXCEPTION_EVENT Exception
QWORD SystemCr3
The Cr3 used to map the kernel.
#define INT_STATUS_SUCCESS
DWORD MustKill
Will kill the process with the first occasion.
QWORD Gva
The guest virtual address of the task_struct.
INTSTATUS IntLixTaskSendExceptionEvent(DWORD Signal, LIX_TASK_OBJECT *Task)
Sends an event that contains the information about signal received by the provided task...
#define INT_SUCCESS(Status)
INTSTATUS IntDetSetReturnValue(DETOUR const *Detour, IG_ARCH_REGS *Registers, QWORD ReturnValue)
Sets the return value for a hooked guest function.
Informational event sent when the guest crashes. See EVENT_CRASH_EVENT.
#define INT_STATUS_NOT_NEEDED_HINT
Linux 'struct printk_log' buffer header.
int INTSTATUS
The status data type.
#define INT_STATUS_NOT_FOUND
BOOLEAN Continuable
True if the exception is considered to be continuable.
INTSTATUS IntQueryHeapSize(size_t *TotalHeapSize, size_t *FreeHeapSize)
Event structure for guest OS crashes.
#define INTRO_OPT_EVENT_PROCESS_CRASH
Enable application crash events (generates introEventExceptionEvent).
INTSTATUS IntLixCrashPanicHandler(void *Detour)
Called if the 'panic' or 'kcrash_exec' handler is hit.
INTSTATUS IntGuestUninitOnBugcheck(void const *Detour)
Prepares Introcore unload in case of a guest crash in order to clean up the code and data injected in...
struct _PRINTK_LOG_HEADER PRINTK_LOG_HEADER
Linux 'struct printk_log' buffer header.
GENERIC_ALERT gAlert
Global alert buffer.
static BOOLEAN IntLixCrashEnoughHeapAvailable(DWORD Size)
Checks if the size of the free heap is bigger than the provided size.
INTSTATUS IntLixCrashHandle(void *Detour)
Sends an event that contains the information about signal received by the current task...
INTSTATUS IntKernVirtMemFetchDword(QWORD GuestVirtualAddress, DWORD *Data)
Reads 4 bytes from the guest kernel memory.
#define IS_KERNEL_POINTER_LIX(p)
INTSTATUS IntKernVirtMemFetchQword(QWORD GuestVirtualAddress, QWORD *Data)
Reads 8 bytes from the guest kernel memory.
INTSTATUS IntNotifyIntroEvent(INTRO_EVENT_TYPE EventClass, void *Param, size_t EventSize)
Notifies the integrator about an introspection alert.
INTRO_PROCESS CurrentProcess
The currently active process.
QWORD Current
The currently used options.
#define LIX_SIGNAL_FATAL(sig)
Check if the provided signal is fatal.
#define UNREFERENCED_PARAMETER(P)
QWORD ExceptionCode
The code of the exception.
struct _PRINTK_LOG_HEADER * PPRINTK_LOG_HEADER
INTSTATUS IntLixTaskGetTrapFrame(const LIX_TASK_OBJECT *Task, LIX_TRAP_FRAME *TrapFrame)
Retrieves the trap frame for a Linux task.
INTRO_PROCESS CurrentProcess
The process in which the exception was triggered.
__must_check INTSTATUS IntVirtMemMap(QWORD Gva, DWORD Length, QWORD Cr3, DWORD Flags, void **HostPtr)
Maps a guest virtual memory range inside Introcore virtual address space.
Event structure for process exceptions.
MM Mm
Guest memory information, such as paging mode, system Cr3 value, etc.
GUEST_STATE gGuest
The current guest state.
static INTSTATUS IntLixCrashSendPanicEvent(void)
Send an event, if the operating system crashed, that contains information about the task that generat...
static INTSTATUS IntLixCrashFetchDmesgSymbol(QWORD *LogBufferGva, QWORD *LogBufferLengthGva, QWORD *LogFirstIdxGva)
Find the address of the symbols 'log_buf', 'log_buf_len' and 'log_first_idx'.
QWORD Rip
The RIP at which the exception was triggered.
CHAR ImageName[ALERT_IMAGE_NAME_LEN]
Image base name of the current process..
LIX_TASK_OBJECT * IntLixTaskFindByGva(QWORD TaskStruct)
Finds Linux process with the provided "task_struct" guest virtual address.
VCPU_STATE * gVcpu
The state of the current VCPU.
#define NSEC_TO_USEC(nsec)
void IntLixCrashDumpDmesg(void)
Dumps the 'dmesg' buffer from guest.
Informational event sent when a hardware exception is triggered by a guest process. See EVENT_EXCEPTION_EVENT.
void IntAlertFillLixCurrentProcess(INTRO_PROCESS *EventProcess)
Saves the current Linux process inside an event.
BOOLEAN DisableOnReturn
Set to True if after returning from this event handler, introcore must be unloaded.
BYTE Version
The version field of the version string.
QWORD IntKsymFindByName(const char *Name, QWORD *SymEnd)
Searches the given Name in kallsyms and returns the Start & End offset.
DWORD Pid
The PID of the process.
void IntAlertFillLixProcess(const LIX_TASK_OBJECT *Task, INTRO_PROCESS *EventProcess)
Saves information about a Linux process inside an event.
INTRO_PROT_OPTIONS CoreOptions
The activation and protection options for this guest.
INTSTATUS IntDecDecodeInstruction(IG_CS_TYPE CsType, QWORD Gva, void *Instrux)
Decode an instruction from the provided guest linear address.
LINUX_GUEST * gLixGuest
Global variable holding the state of a Linux guest.