Bitdefender Hypervisor Memory Introspection
lixnet.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2020 Bitdefender
3  * SPDX-License-Identifier: Apache-2.0
4  */
5 #include "lixnet.h"
6 #include "alerts.h"
7 #include "guests.h"
8 
9 #define LIX_FDTABLE_MAX_FDS_CAP 2048u
10 
11 typedef struct _SOCK_PROTO
15 {
17  CHAR Name[32];
18 } SOCK_PROTO;
19 
20 
21 static void
23  _In_ INTRONET_ENDPOINT *Connection
24  )
30 {
31  INTSTATUS status;
32  PEVENT_CONNECTION_EVENT pConnectionEvent;
33 
34  pConnectionEvent = &gAlert.Connection;
35 
36  IntAlertFillConnection(Connection, pConnectionEvent);
37 
38  status = IntNotifyIntroEvent(introEventConnectionEvent, pConnectionEvent, sizeof(*pConnectionEvent));
39  if (!INT_SUCCESS(status))
40  {
41  WARNING("[WARNING] IntNotifyIntroEvent failed: 0x%08x\n", status);
42  }
43 }
44 
45 
47 static INTSTATUS
49  _In_ QWORD SocketGva,
50  _Out_ INTRONET_ENDPOINT *Connection
51  )
67 {
68  INTSTATUS status;
69 
70  QWORD sock, proto;
71  CHAR protoName[32];
72  DWORD sockState = 0;
73 
74  DWORD iProto;
75 
76  static SOCK_PROTO protos[] =
77  {
78  {
79  .Name = "TCP"
80  },
81  {
82  .Name = "TCPv6"
83  },
84  };
85 
86  status = IntKernVirtMemFetchQword(SocketGva + LIX_FIELD(Socket, Sk), &sock);
87  if (!INT_SUCCESS(status))
88  {
89  ERROR("[ERROR] IntKernVirtMemFetchQword failed for GVA 0x%016llx: 0x%08x\n",
90  SocketGva + LIX_FIELD(Socket, Sk), status);
91  return status;
92  }
93 
94  status = IntKernVirtMemFetchQword(sock + LIX_FIELD(Sock, Proto), &proto);
95  if (!INT_SUCCESS(status))
96  {
97  ERROR("[ERROR] IntKernVirtMemFetchQword failed for GVA 0x%016llx: 0x%08x\n",
98  sock + LIX_FIELD(Sock, Proto), status);
99  return status;
100  }
101 
102  if (!IS_KERNEL_POINTER_LIX(proto))
103  {
104  WARNING("[WARNING] Sock 0x%016llx has NULL proto pointer.", sock);
106  }
107 
108  for (iProto = 0; iProto < ARRAYSIZE(protos); iProto++)
109  {
110  if (proto == protos[iProto].Gva)
111  {
112  break;
113  }
114  }
115 
116  if (iProto == ARRAYSIZE(protos))
117  {
118  status = IntKernVirtMemRead(proto + LIX_FIELD(Ungrouped, ProtoName), sizeof(protoName), protoName, NULL);
119  if (!INT_SUCCESS(status))
120  {
121  ERROR("[ERROR] IntKernVirtMemRead failed for GVA 0x%016llx: 0x%08x\n",
122  proto + LIX_FIELD(Ungrouped, ProtoName), status);
123  return INT_STATUS_SUCCESS;
124  }
125 
126  for (iProto = 0; iProto < ARRAYSIZE(protos); iProto++)
127  {
128  if (!strcmp(protos[iProto].Name, protoName))
129  {
130  protos[iProto].Gva = proto;
131  break;
132  }
133  }
134 
135  if (iProto == ARRAYSIZE(protos))
136  {
138  }
139  }
140 
141  status = IntKernVirtMemRead(sock + LIX_FIELD(Sock, State), 1, &sockState, NULL);
142  if (!INT_SUCCESS(status))
143  {
144  ERROR("[ERROR] IntKernVirtMemRead failed for GVA 0x%016llx: 0x%08x\n",
145  sock + LIX_FIELD(Sock, State), status);
146  return status;
147  }
148 
149  Connection->State = IntNetConvertState(sockState);
150  Connection->AddressFamily = (iProto == 0 ? introNetAfIpv4 : introNetAfIpv6);
151  Connection->Endpoint = sock;
152 
153  memset(&Connection->LocalAddress, 0, sizeof(Connection->LocalAddress));
154  memset(&Connection->RemoteAddress, 0, sizeof(Connection->RemoteAddress));
155 
156  if (introNetAfIpv6 == Connection->AddressFamily)
157  {
158  status = IntKernVirtMemRead(sock + LIX_FIELD(Sock, RcvSaddr), 16, &Connection->LocalAddress, NULL);
159  if (!INT_SUCCESS(status))
160  {
161  ERROR("[ERROR] IntKernVirtMemRead failed for GVA 0x%016llx: 0x%08x\n",
162  sock + LIX_FIELD(Sock, V6RcvSaddr), status);
163  return status;
164  }
165 
166  status = IntKernVirtMemRead(sock + LIX_FIELD(Sock, V6Daddr), 16, &Connection->RemoteAddress, NULL);
167  if (!INT_SUCCESS(status))
168  {
169  ERROR("[ERROR] IntKernVirtMemRead failed for GVA 0x%016llx: 0x%08x\n",
170  sock + LIX_FIELD(Sock, V6RcvSaddr), status);
171  return status;
172  }
173  }
174  else
175  {
176  status = IntKernVirtMemRead(sock + LIX_FIELD(Sock, RcvSaddr), 4, &Connection->LocalAddress, NULL);
177  if (!INT_SUCCESS(status))
178  {
179  ERROR("[ERROR] IntKernVirtMemRead failed for GVA 0x%016llx: 0x%08x\n",
180  sock + LIX_FIELD(Sock, RcvSaddr), status);
181  return status;
182  }
183 
184  status = IntKernVirtMemRead(sock + LIX_FIELD(Sock, Daddr), 4, &Connection->RemoteAddress, NULL);
185  if (!INT_SUCCESS(status))
186  {
187  ERROR("[ERROR] IntKernVirtMemRead failed for GVA 0x%016llx: 0x%08x\n",
188  sock + LIX_FIELD(Sock, RcvSaddr), status);
189  return status;
190  }
191  }
192 
193  status = IntKernVirtMemRead(sock + LIX_FIELD(Sock, Num), 2, &Connection->LocalPort, NULL);
194  if (!INT_SUCCESS(status))
195  {
196  ERROR("[ERROR] IntKernVirtMemRead failed for GVA 0x%016llx: 0x%08x\n",
197  sock + LIX_FIELD(Sock, Num), status);
198  return status;
199  }
200 
201  status = IntKernVirtMemRead(sock + LIX_FIELD(Sock, Dport), 2, &Connection->RemotePort, NULL);
202  if (!INT_SUCCESS(status))
203  {
204  ERROR("[ERROR] IntKernVirtMemRead failed for GVA 0x%016llx: 0x%08x\n",
205  sock + LIX_FIELD(Sock, Dport), status);
206  return status;
207  }
208 
209  return INT_STATUS_SUCCESS;
210 }
211 
212 
213 static BOOLEAN
215  _In_ QWORD StructFileGva,
216  _Out_ QWORD *SocketGva
217  )
228 {
229  INTSTATUS status;
230  QWORD dentry, inode;
231  UINT16 imode;
232 
233  *SocketGva = 0;
234 
235  status = IntKernVirtMemFetchQword(StructFileGva + LIX_FIELD(Ungrouped, FileDentry), &dentry);
236  if (!INT_SUCCESS(status))
237  {
238  ERROR("[ERROR] IntKernVirtMemFetchQword failed for GVA 0x%016llx: 0x%08x\n",
239  StructFileGva + LIX_FIELD(Ungrouped, FileDentry), status);
240  return FALSE;
241  }
242 
243  status = IntKernVirtMemFetchQword(dentry + LIX_FIELD(Dentry, Inode), &inode);
244  if (!INT_SUCCESS(status))
245  {
246  ERROR("[ERROR] IntKernVirtMemFetchQword failed for GVA 0x%016llx: 0x%08x\n",
247  dentry + LIX_FIELD(Dentry, Inode), status);
248  return FALSE;
249  }
250 
251  status = IntKernVirtMemRead(inode + LIX_FIELD(Inode, Imode), sizeof(imode), &imode, NULL);
252  if (!INT_SUCCESS(status))
253  {
254  ERROR("[ERROR] IntKernVirtMemRead failed for GVA 0x%016llx: 0x%08x\n",
255  dentry + LIX_FIELD(Dentry, Inode), status);
256  return FALSE;
257  }
258 
259  if (!S_ISSOCK(imode))
260  {
261  return FALSE;
262  }
263 
264  *SocketGva = inode - LIX_FIELD(Ungrouped, SocketAllocVfsInode);
265  return TRUE;
266 
267 }
268 
269 
270 INTSTATUS
272  _In_ LIX_TASK_OBJECT *Task
273  )
287 {
288  INTSTATUS status;
289 
290  INTRONET_ENDPOINT conn;
291  CHAR ipString[INTRONET_MIN_BUFFER_SIZE];
292 
293  QWORD files, fdt, fd;
294  DWORD maxFds;
295 
297  {
298  BUG_ON(TRUE);
299 
301  }
302 
304  {
306  }
307 
308  if (NULL == Task)
309  {
311  }
312 
313  status = IntKernVirtMemFetchQword(Task->Gva + LIX_FIELD(TaskStruct, Files), &files);
314  if (!INT_SUCCESS(status))
315  {
316  ERROR("[ERROR] IntKernVirtMemFetchQword failed for %llx: 0x%08x\n",
317  Task->Gva + LIX_FIELD(TaskStruct, Files), status);
318  return status;
319  }
320 
321  status = IntKernVirtMemFetchQword(files + LIX_FIELD(Files, Fdt), &fdt);
322  if (!INT_SUCCESS(status))
323  {
324  ERROR("[ERROR] IntKernVirtMemFetchQword failed for %llx: 0x%08x\n", files + LIX_FIELD(Files, Fdt), status);
325  return status;
326  }
327 
328  status = IntKernVirtMemFetchDword(fdt + LIX_FIELD(FdTable, MaxFds), &maxFds);
329  if (!INT_SUCCESS(status))
330  {
331  ERROR("[ERROR] IntKernVirtMemFetchQword failed for %llx: 0x%08x\n", fdt + LIX_FIELD(FdTable, MaxFds), status);
332  return status;
333  }
334 
335  status = IntKernVirtMemFetchQword(fdt + LIX_FIELD(FdTable, Fd), &fd);
336  if (!INT_SUCCESS(status))
337  {
338  ERROR("[ERROR] IntKernVirtMemFetchQword failed for %llx: 0x%08x\n", files + LIX_FIELD(FdTable, Fd), status);
339  return status;
340  }
341 
342  conn.OwnerTask = Task;
343 
344  maxFds = MIN(maxFds, LIX_FDTABLE_MAX_FDS_CAP);
345  for (DWORD iFd = 0; iFd < maxFds; iFd++)
346  {
347  QWORD file;
348  QWORD socketGva;
349 
350  status = IntKernVirtMemFetchQword(fd + iFd * sizeof(QWORD), &file);
351  if (!INT_SUCCESS(status))
352  {
353  ERROR("[ERROR] IntKernVirtMemFetchQword failed for %llx: 0x%08x\n", fd + iFd * 8ull, status);
354  return status;
355  }
356 
357  if ((!IS_KERNEL_POINTER_LIX(file)) || (!IntLixNetFileIsSocket(file, &socketGva)))
358  {
359  continue;
360  }
361 
362  status = IntLixNetGetConnectionFromSocket(socketGva, &conn);
363  if (!INT_SUCCESS(status))
364  {
365  ERROR("[ERROR] IntLixSocketGetConnection failed for socket %llx : 0x%08x\n", socketGva, status);
366  continue;
367  }
368 
369  if (INT_STATUS_NOT_NEEDED_HINT == status)
370  {
371  continue;
372  }
373 
375 
376  IntNetAddrToStr(conn.AddressFamily, &conn.RemoteAddress, ipString);
377  TRACE("[CONNECTION] Owner %s | Family: %u | State %s | LocalPort: %hu | RemoteAddress: %s | Endpoint %016llx\n",
379  conn.LocalPort, ipString, conn.Endpoint);
380 
381  }
382 
383  return INT_STATUS_SUCCESS;
384 }
385 
386 
387 INTSTATUS
389  void
390  )
399 {
400  INTSTATUS status;
401 
403  {
404  BUG_ON(TRUE);
405 
407  }
408 
410  {
412  }
413 
415  if (!INT_SUCCESS(status))
416  {
417  ERROR("[ERROR] IntLixTaskIterateTasks failed: 0x%08x\n", status);
418  }
419 
420  return status;
421 }
_Bool BOOLEAN
Definition: intro_types.h:58
#define _Out_
Definition: intro_sal.h:22
EVENT_CONNECTION_EVENT Connection
Definition: alerts.h:30
#define _In_
Definition: intro_sal.h:21
#define INT_STATUS_SUCCESS
Definition: introstatus.h:54
INTRONET_PORT LocalPort
Local port.
Definition: intronet.h:37
An internal structure used to cache the "struct proto" addresses of required connection types...
Definition: lixnet.c:14
CHAR Name[32]
The protocol name as defined in Linux kernel.
Definition: lixnet.c:17
#define _Success_(expr)
Definition: intro_sal.h:47
#define INT_SUCCESS(Status)
Definition: introstatus.h:42
#define BUG_ON(cond)
Definition: introdefs.h:236
#define ARRAYSIZE(A)
Definition: introdefs.h:101
struct _SOCK_PROTO SOCK_PROTO
An internal structure used to cache the "struct proto" addresses of required connection types...
#define INT_STATUS_NOT_NEEDED_HINT
Definition: introstatus.h:317
#define ERROR(fmt,...)
Definition: glue.h:62
INTRO_NET_AF AddressFamily
Address family.
Definition: intronet.h:29
int INTSTATUS
The status data type.
Definition: introstatus.h:24
LIX_TASK_OBJECT * OwnerTask
Pointer to the task that owns the connection.
Definition: intronet.h:53
const char * IntNetStateToString(INTRO_NET_STATE State)
Converts a connection state to a string.
Definition: intronet.h:69
INTRO_GUEST_TYPE OSType
The type of the guest.
Definition: guests.h:274
#define INTRO_OPT_EVENT_CONNECTIONS
Enable connection events.
Definition: intro_types.h:466
static INTSTATUS IntLixNetGetConnectionFromSocket(QWORD SocketGva, INTRONET_ENDPOINT *Connection)
Fills an INTRONET_ENDPOINT structure from a TCP/IP socket GVA.
Definition: lixnet.c:48
#define MIN(a, b)
Definition: introdefs.h:146
static BOOLEAN IntLixNetFileIsSocket(QWORD StructFileGva, QWORD *SocketGva)
Check if a give file object is a socked and return the socket GVA.
Definition: lixnet.c:214
#define INTRONET_MIN_BUFFER_SIZE
The minimum buffer size needed for the textual representation of an IP address.
Definition: intronet.h:12
GENERIC_ALERT gAlert
Global alert buffer.
Definition: alerts.c:27
INTSTATUS IntKernVirtMemFetchDword(QWORD GuestVirtualAddress, DWORD *Data)
Reads 4 bytes from the guest kernel memory.
Definition: introcore.c:829
#define IS_KERNEL_POINTER_LIX(p)
Definition: lixguest.h:11
INTSTATUS IntKernVirtMemFetchQword(QWORD GuestVirtualAddress, QWORD *Data)
Reads 8 bytes from the guest kernel memory.
Definition: introcore.c:811
INTSTATUS IntNotifyIntroEvent(INTRO_EVENT_TYPE EventClass, void *Param, size_t EventSize)
Notifies the integrator about an introspection alert.
Definition: glue.c:1042
unsigned long long QWORD
Definition: intro_types.h:53
DWORD IntNetAddrToStr(const INTRO_NET_AF Family, const INTRONET_ADDRESS *Address, CHAR *String)
Converts an IP address to a string.
Definition: intronet.c:11
QWORD Current
The currently used options.
Definition: guests.h:232
An endpoint.
Definition: intronet.h:26
#define TRUE
Definition: intro_types.h:30
#define LIX_FDTABLE_MAX_FDS_CAP
The maximum number of file descriptors to be iterated.
Definition: lixnet.c:9
#define LIX_FIELD(Structure, Field)
Macro used to access fields inside the LIX_OPAQUE_FIELDS structure.
Definition: lixguest.h:426
#define TRACE(fmt,...)
Definition: glue.h:58
INTRO_NET_STATE State
Connection state.
Definition: intronet.h:32
Informational event containing the connections opened by a process. See EVENT_CONNECTION_EVENT.
Definition: intro_types.h:113
#define WARNING(fmt,...)
Definition: glue.h:60
uint32_t DWORD
Definition: intro_types.h:49
static void IntLixNetSendConnectionEvent(INTRONET_ENDPOINT *Connection)
Sends a connection event to the integrator.
Definition: lixnet.c:22
char Comm[LIX_COMM_SIZE]
The short name of the executable.
Definition: lixprocess.h:44
GUEST_STATE gGuest
The current guest state.
Definition: guests.c:48
INTSTATUS IntLixNetSendGuestConnections(void)
Sends all active in-guest TCP/IP connections as events to the integrator.
Definition: lixnet.c:388
INTRONET_ADDRESS RemoteAddress
Remote address.
Definition: intronet.h:42
#define S_ISSOCK(m)
Definition: lixddefs.h:253
INTSTATUS IntKernVirtMemRead(QWORD KernelGva, DWORD Length, void *Buffer, DWORD *RetLength)
Reads data from a guest kernel virtual memory range.
Definition: introcore.c:674
uint16_t UINT16
Definition: intro_types.h:38
#define INT_STATUS_INVALID_PARAMETER_1
Definition: introstatus.h:62
#define INT_STATUS_NOT_SUPPORTED
Definition: introstatus.h:287
INTSTATUS IntLixTaskIterateTasks(PFUNC_LixTaskIterateTasks Callback)
Call the Callback parameter for each task saved internally.
Definition: lixprocess.c:4850
Event structure for connections.
Definition: intro_types.h:1843
INTSTATUS IntLixNetSendTaskConnections(LIX_TASK_OBJECT *Task)
Sends all active TCP/IP connections from a task to the integrator.
Definition: lixnet.c:271
void IntAlertFillConnection(const INTRONET_ENDPOINT *Connection, EVENT_CONNECTION_EVENT *Event)
Saves information about a guest connection in an event.
Definition: alerts.c:1328
QWORD Gva
The GVA of the "struct proto" object.
Definition: lixnet.c:16
char CHAR
Definition: intro_types.h:56
QWORD Endpoint
Guest virtual address of the endpoint/socket object.
Definition: intronet.h:61
INTRO_PROT_OPTIONS CoreOptions
The activation and protection options for this guest.
Definition: guests.h:267
INTRO_NET_STATE IntNetConvertState(const DWORD State)
Converts a guest connection state to an Introcore connection state.
Definition: intronet.c:168
#define FALSE
Definition: intro_types.h:34