summaryrefslogtreecommitdiffstats
path: root/connector/proc_mon_linux.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'connector/proc_mon_linux.cpp')
-rwxr-xr-xconnector/proc_mon_linux.cpp487
1 files changed, 487 insertions, 0 deletions
diff --git a/connector/proc_mon_linux.cpp b/connector/proc_mon_linux.cpp
new file mode 100755
index 0000000..16dd51c
--- /dev/null
+++ b/connector/proc_mon_linux.cpp
@@ -0,0 +1,487 @@
1#ifndef WIN32
2#include <unistd.h>
3#include <sys/socket.h>
4#include <algorithm>
5#include "shared.h"
6#include "proc_mon_linux.h"
7#include <malloc.h>
8#include "linux_proc_baseline.h"
9
10
11#define MAX_PIPE_WAIT_USECOND 100
12#define PROCESS_SCAN_ITERTIME 10
13const char *WM_PROC_LOCATION = "proc_collector";
14
15ProcMon* ProcMon::m_instance = NULL;
16
17ProcMon& ProcMon::instance()
18{
19 if ( m_instance == NULL )
20 {
21 m_instance = new ProcMon;
22 }
23
24 return *m_instance;
25}
26
27void ProcMon::destroy()
28{
29 delete m_instance;
30 m_instance = NULL;
31}
32
33int ProcMon::init( const wm_proc_t* config )
34{
35 pthread_mutex_init(&m_mutex, NULL);
36 setConfig( config );
37
38 int ret = setupNetlink();
39 if (ret != 0 )
40 {
41 fini();
42 return -1;
43 }
44
45 ret = setupMQ();
46 if (ret != 0 )
47 {
48 fini();
49 return -1;
50 }
51
52 return 0;
53}
54
55int ProcMon::working()
56{
57 int rc;
58 event_msg_t procMsg;
59 fd_set readfds;
60 int maxfd = m_procFd + 1;
61 struct timeval tv;
62 time_t last = time(0);
63
64 if ( m_config.flags.enabled == 0 )
65 {
66 return 0;
67 }
68
69 getInventoryProcesses();
70
71
72 while ( 1 )
73 {
74 FD_ZERO(&readfds);
75 FD_SET( m_procFd, &readfds );
76 tv.tv_sec = 1;
77 tv.tv_usec = 0;
78
79 if ( time(0) - last > PROCESS_SCAN_ITERTIME )
80 {
81 // scan processes
82 scanProcesses(last);
83 last = time(0);
84 }
85
86 rc = select( maxfd, &readfds, NULL, NULL, &tv );
87 if ( 0 == rc )
88 {
89 continue;
90 }
91
92 if ( -1 == rc )
93 {
94 if ( errno == EINTR )
95 {
96 continue;
97 }
98
99 mterror(WM_PROC_LOGTAG, "failed to listen to netlink socket, errno=(%d:%m)", errno);
100 return rc;
101 }
102
103 if ( FD_ISSET( m_procFd, &readfds ) )
104 {
105 rc = recv( m_procFd, &procMsg, sizeof(procMsg), 0 );
106 if( rc > 0 )
107 {
108 switch (procMsg.proc_ev.what)
109 {
110 case proc_event::PROC_EVENT_FORK:
111 handleForkMsg(procMsg);
112 break;
113 case proc_event::PROC_EVENT_EXEC:
114 handleExecMsg(procMsg);
115 break;
116 case proc_event::PROC_EVENT_COMM:
117 break;
118 case proc_event::PROC_EVENT_EXIT:
119 handleExitMsg(procMsg);
120 break;
121 default:
122 break;
123 }
124 }
125 else if (rc == -1)
126 {
127 if (errno == EINTR)
128 {
129 continue;
130 }
131 mterror(WM_PROC_LOGTAG, "failed to received from netlink socket, errno=(%d:%m)", errno);
132 }
133 }
134
135 malloc_trim(0);
136 }
137}
138
139ProcMon::ProcMon()
140{
141 m_mutex = PTHREAD_MUTEX_INITIALIZER;
142 m_processes.clear();
143 m_pidCache.clear();
144 m_procFd = -1;
145 m_queueFd = -1;
146}
147
148ProcMon::~ProcMon()
149{
150 fini();
151}
152
153void ProcMon::setConfig( const wm_proc_t* config )
154{
155 m_config.flags.enabled = config->flags.enabled;
156 m_config.flags.rootcheck = config->flags.rootcheck;
157 m_config.flags.limitcheck = config->flags.limitcheck;
158 m_config.flags.environcheck = config->flags.environcheck;
159 m_config.flags.statuscheck = config->flags.statuscheck;
160 m_config.flags.threadcheck = config->flags.threadcheck;
161 m_config.flags.cgroupcheck = config->flags.cgroupcheck;
162 m_config.flags.libcheck = config->flags.libcheck;
163 m_config.flags.malwarecheck = config->flags.malwarecheck;
164 m_config.interval = config->interval;
165}
166
167int ProcMon::setupNetlink()
168{
169 int rc;
170 int nl_sock;
171 struct sockaddr_nl sa_nl;
172 register_msg_t nlcn_msg;
173
174 nl_sock = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_CONNECTOR);
175 if (nl_sock == -1)
176 {
177 mterror(WM_PROC_LOGTAG, "Can't open netlink socket");
178 return -1;
179 }
180
181 sa_nl.nl_family = AF_NETLINK;
182 sa_nl.nl_groups = CN_IDX_PROC;
183 sa_nl.nl_pid = getpid();
184
185 rc = bind(nl_sock, (struct sockaddr *)&sa_nl, sizeof(sa_nl));
186 if (rc == -1)
187 {
188 mterror(WM_PROC_LOGTAG, "Can't bind netlink socket");
189 close(nl_sock);
190 return -1;
191 }
192
193 // create listener
194 memset(&nlcn_msg, 0, sizeof(nlcn_msg));
195 nlcn_msg.nl_hdr.nlmsg_len = sizeof(nlcn_msg);
196 nlcn_msg.nl_hdr.nlmsg_pid = getpid();
197 nlcn_msg.nl_hdr.nlmsg_type = NLMSG_DONE;
198
199 nlcn_msg.cn_msg.id.idx = CN_IDX_PROC;
200 nlcn_msg.cn_msg.id.val = CN_VAL_PROC;
201 nlcn_msg.cn_msg.len = sizeof(enum proc_cn_mcast_op);
202
203 nlcn_msg.cn_mcast = PROC_CN_MCAST_LISTEN;
204
205 rc = send(nl_sock, &nlcn_msg, sizeof(nlcn_msg), 0);
206 if (rc == -1)
207 {
208 mterror(WM_PROC_LOGTAG, "can't register to netlink");
209 close(nl_sock);
210 return -1;
211 }
212
213 m_procFd = nl_sock;
214 return 0;
215}
216
217int ProcMon::setupMQ()
218{
219 unsigned int indx;
220 // Connect to socket
221 for (indx = 0; indx < WM_MAX_ATTEMPTS; indx++)
222 {
223 m_queueFd = StartMQ(DEFAULTQPATH, WRITE);
224 if (m_queueFd > 0)
225 {
226 break;
227 }
228 wm_delay(1000 * WM_MAX_WAIT);
229 }
230
231 if (indx == WM_MAX_ATTEMPTS)
232 {
233 mterror(WM_PROC_LOGTAG, "Can't connect to queue.");
234 pthread_exit(NULL);
235 }
236
237 return 0;
238}
239
240
241void ProcMon::fini()
242{
243 m_processes.clear();
244 m_pidCache.clear();
245 if (m_procFd != -1 )
246 {
247 close( m_procFd);
248 m_procFd = -1;
249 }
250
251 if (m_queueFd != -1 )
252 {
253 close( m_queueFd);
254 m_queueFd = -1;
255 }
256}
257
258void ProcMon::getInventoryProcesses()
259{
260 DIR *procDir = opendir( "/proc" );
261 if ( NULL == procDir )
262 {
263 mterror(WM_PROC_LOGTAG, "failed to open /proc, errno=(%d:%m)", errno);
264 return;
265 }
266
267 struct dirent *entry = NULL;
268 while (NULL != (entry = readdir(procDir)))
269 {
270 if (!strcmp(entry->d_name, ".") || !strcmp(entry->d_name, ".."))
271 {
272 continue;
273 }
274 int pid = atoi(entry->d_name);
275 if (0 == pid)
276 {
277 continue;
278 }
279
280 Process *proc = new Process(pid);
281 if ( NULL == proc )
282 {
283 continue;
284 }
285 if(0 != proc->init())
286 {
287 delete proc;
288 proc = NULL;
289 continue;
290 }
291 std::pair<std::map<pid_t, Process*>::iterator,bool> ret = m_processes.insert(std::make_pair(pid, proc));
292 if(!ret.second)
293 {
294 delete proc;
295 proc = NULL;
296 continue;
297 }
298 std::vector<std::string> events = proc->getEvents();
299 if ( !events.empty() )
300 {
301 reportEvents(events);
302 }
303 usleep( 500 );
304 }
305
306 return;
307}
308
309void ProcMon::handleForkMsg( const event_msg_t& procMsg )
310{
311 pid_t pid = procMsg.proc_ev.event_data.fork.child_pid;
312 auto iter = m_pidCache.find( pid );
313 if ( iter != m_pidCache.end() )
314 {
315 m_pidCache.erase(iter);
316 return;
317 }
318
319 PidRelation relation;
320 relation.pid = pid;
321 relation.ppid = procMsg.proc_ev.event_data.fork.parent_pid;
322 relation.pidEvent = PidRelation::FORKEVENT;
323 relation.born = time(0);
324
325 m_pidCache.insert( std::make_pair(relation.pid, relation ));
326}
327
328void ProcMon::handleExecMsg( const event_msg_t& procMsg )
329{
330 pid_t pid = procMsg.proc_ev.event_data.exec.process_pid;
331 auto iter = m_pidCache.find( pid );
332 if ( iter == m_pidCache.end() )
333 {
334 return;
335 }
336
337 //mterror(WM_PROC_LOGTAG, "cache size:%lu", m_pidCache.size());
338 Process *proc = new Process( pid, iter->second.ppid, iter->second.born );
339 if ( NULL == proc )
340 {
341 return;
342 }
343 // check hidden process
344 if ( 0 != proc->init() )
345 {
346 return;
347 }
348 m_processes.insert( std::make_pair(pid, proc ));
349 std::vector<std::string> events = proc->getEvents();
350 if (!events.empty())
351 {
352 reportEvents(events);
353 }
354// m_pidCache.erase(iter);
355 //mterror(WM_PROC_LOGTAG, "exec process:%d exe:%s", pid, proc.exe().c_str());
356}
357
358void ProcMon::handleExitMsg( const event_msg_t& procMsg )
359{
360 pid_t pid = procMsg.proc_ev.event_data.exit.process_pid;
361 auto iter = m_pidCache.find( pid );
362 if ( iter != m_pidCache.end() )
363 {
364 m_pidCache.erase(iter);
365 }
366
367 auto procIter = m_processes.find(pid);
368 if ( procIter == m_processes.end() )
369 {
370 return;
371 }
372
373 std::vector<int> signals{ 3, 9, 10, 12, 15,16,17,30,31};
374
375 //if ( signals.end() == std::find( signals.begin(), signals.end(), procMsg.proc_ev.event_data.exit.exit_signal )
376 //|| (procMsg.proc_ev.event_data.exit.exit_code != 0))
377 {
378 // report abnormal events
379 cJSON *obj= cJSON_CreateObject();
380 cJSON_AddStringToObject(obj, "type", "exit");
381 cJSON_AddStringToObject(obj, "exe", procIter->second->exe().c_str());
382 cJSON_AddNumberToObject(obj, "pid", procIter->first);
383 cJSON_AddNumberToObject(obj, "event_time", time(0));
384 cJSON_AddNumberToObject(obj, "exit_signal", procMsg.proc_ev.event_data.exit.exit_signal);
385 cJSON_AddNumberToObject(obj, "exit_code", procMsg.proc_ev.event_data.exit.exit_code);
386 char *data = cJSON_PrintUnformatted( obj );
387 std::string msg(data);
388 free(data);
389 reportEvent( msg );
390 cJSON_Delete(obj);
391 //mterror(WM_PROC_LOGTAG, "%s", msg.c_str());
392 }
393
394 delete procIter->second;
395 m_processes.erase(procIter);
396 //mterror(WM_PROC_LOGTAG, "process collection:%d", m_processes.size());
397}
398
399void ProcMon::scanProcesses(time_t last)
400{
401 time_t now = time(0);
402// mterror(WM_PROC_LOGTAG, "pid cache size: %d , process collection size : %d", m_pidCache.size(), m_processes.size());
403 for (auto iter = m_pidCache.begin(); iter != m_pidCache.end(); )
404 {
405 if ( now - iter->second.born < 1 || m_processes.find(iter->second.pid) != m_processes.end())
406 {
407 iter++;
408 }
409 else
410 {
411 Process *proc = new Process( iter->second.pid, iter->second.ppid, iter->second.born);
412 if (NULL != proc )
413 {
414 if(0 != proc->init())
415 {
416 delete proc;
417 proc = NULL;
418 continue;
419 }
420 std::pair<std::map<pid_t, Process*>::iterator, bool> ret = m_processes.insert(std::make_pair(iter->first, proc));
421 if(!ret.second)
422 {
423 delete proc;
424 proc = NULL;
425 continue;
426 }
427 std::vector<std::string> events = proc->getEvents();
428 if (!events.empty())
429 {
430 reportEvents(events);
431 }
432
433 }
434 else
435 {
436 // hidden process found
437 cJSON *obj = cJSON_CreateObject();
438 cJSON_AddStringToObject(obj, "type", "rootkit");
439 cJSON_AddNumberToObject(obj, "pid", iter->first);
440 cJSON_AddNumberToObject(obj, "event_time", iter->second.born);
441 cJSON_AddNumberToObject(obj, "ppid", iter->second.ppid);
442 auto parent = m_processes.find(iter->second.ppid);
443 if (parent != m_processes.end())
444 {
445 cJSON_AddStringToObject(obj, "parent exe", parent->second->exe().c_str());
446 }
447 char *data = cJSON_PrintUnformatted(obj);
448 std::string msg(data);
449 free(data);
450 reportEvent(msg);
451 cJSON_Delete(obj);
452 }
453 iter = m_pidCache.erase(iter);
454 }
455 usleep( 500 );
456 }
457/*
458 if ( now - last < 60 )
459 {
460 return;
461 }
462*/
463 for (auto& procIter : m_processes )
464 {
465 procIter.second->scan();
466 std::vector<std::string> events = procIter.second->getEvents();
467 if (!events.empty())
468 {
469 reportEvents(events);
470 }
471 usleep( 5000 );
472 }
473}
474
475void ProcMon::reportEvent( const std::string& event )
476{
477 wm_sendmsg(MAX_PIPE_WAIT_USECOND, m_queueFd, event.c_str(), WM_PROC_LOCATION, PROC_COLLECTOR_MQ);
478}
479
480void ProcMon::reportEvents(const std::vector<std::string> &events)
481{
482 for (auto it : events)
483 {
484 wm_sendmsg(MAX_PIPE_WAIT_USECOND, m_queueFd, it.c_str(), WM_PROC_LOCATION, PROC_COLLECTOR_MQ);
485 }
486}
487#endif