summaryrefslogtreecommitdiffstats
path: root/connector/proc_collector_linux.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'connector/proc_collector_linux.cpp')
-rwxr-xr-xconnector/proc_collector_linux.cpp618
1 files changed, 618 insertions, 0 deletions
diff --git a/connector/proc_collector_linux.cpp b/connector/proc_collector_linux.cpp
new file mode 100755
index 0000000..478ac2b
--- /dev/null
+++ b/connector/proc_collector_linux.cpp
@@ -0,0 +1,618 @@
1#ifndef WIN32
2#include <sys/socket.h>
3#include <linux/netlink.h>
4#include <linux/connector.h>
5#include <linux/cn_proc.h>
6#include <errno.h>
7#include <sys/select.h>
8#include <sys/types.h>
9#include <sys/time.h>
10#include <unistd.h>
11
12#include "os_crypto/md5/md5_op.h"
13#include "external/procps/readproc.h"
14#include "proc_collector.h"
15
16static struct
17{
18 int queue_fd;
19 int proc_fd;
20} proc_monitor =
21{
22 .queue_fd = -1,
23 .proc_fd = -1
24};
25
26typedef struct __attribute__((aligned(NLMSG_ALIGNTO)))
27{
28 struct nlmsghdr nl_hdr;
29 struct __attribute__((__packed__))
30 {
31 struct cn_msg cn_msg;
32 enum proc_cn_mcast_op cn_mcast;
33 };
34} register_msg_t;
35
36typedef struct __attribute__((aligned(NLMSG_ALIGNTO)))
37{
38 struct nlmsghdr nl_hdr;
39 struct __attribute__((__packed__))
40 {
41 struct cn_msg cn_msg;
42 struct proc_event proc_ev;
43 };
44} event_msg_t;
45
46#define MAX_TEMP_PROCESS 5000
47#define TEMP_WAIT_TIME 1
48#define PROCESS_SLOT_EMPTY 0
49#define MAX_PATH_NAME 4096
50#define MAX_PIPE_WAIT_USECOND 100
51
52
53typedef struct
54{
55 pid_t pid;
56 pid_t ppid;
57 time_t fork_time;
58 int status;
59 char path[MAX_PATH_NAME];
60 os_md5 md5;
61 char parent_path[MAX_PATH_NAME];
62 os_md5 parent_md5;
63} process_parent_child_pair_t;
64static process_parent_child_pair_t temp_processes[ MAX_TEMP_PROCESS ];
65
66
67/*
68typedef struct
69{
70 pid_t pid; // process id
71 char *name; // process name
72 char *state; //program running state
73 pid_t ppid; // parent process id
74 char *pname; // parent process name
75 ulong utime; // process time in user mode
76 ulong stime; // process time in kernel mode
77 char **cmd_line; // command line
78 char *real_user; //
79 char *effective_user;
80 char *saved_user;
81 char *fs_user;
82 char *real_group;
83 char *effective_group;
84 char *saved_group;
85 char *fs_group;
86 int priority; // process priority
87 int nice; // nice value
88 long size; // the toal memory
89 long vm_size; // virtual memory
90 long resident; // occupied physical memory
91 long share; // shared memory
92 time_t start_time; // process startup time
93 int pgrp; /// process group
94 int session; // session id
95 long nlwp; // number of thread
96 int tgid; // task group id
97 int tty; // control terminal
98 int processor; // cpu number last executed on
99} proc_info_t;
100*/
101
102
103static void wm_proc_cleanup()
104{
105 if ( proc_monitor.proc_fd > 0 )
106 {
107 close( proc_monitor.proc_fd );
108 proc_monitor.proc_fd = -1;
109 }
110
111 if ( proc_monitor.queue_fd > 0 )
112 {
113 close( proc_monitor.queue_fd );
114 proc_monitor.queue_fd = -1;
115 }
116}
117
118
119static int wm_setup_netlink( )
120{
121 int rc;
122 int nl_sock;
123 struct sockaddr_nl sa_nl;
124 register_msg_t nlcn_msg;
125
126 nl_sock = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_CONNECTOR);
127 if (nl_sock == -1)
128 {
129 mterror( WM_PROC_LOGTAG, "Can't open netlink socket");
130 return -1;
131 }
132
133 sa_nl.nl_family = AF_NETLINK;
134 sa_nl.nl_groups = CN_IDX_PROC;
135 sa_nl.nl_pid = getpid(); // 向内核注册
136
137 rc = bind(nl_sock, (struct sockaddr *)&sa_nl, sizeof(sa_nl));
138 if (rc == -1)
139 {
140 mterror( WM_PROC_LOGTAG, "Can't bind netlink socket");
141 close(nl_sock);
142 return -1;
143 }
144
145 // create listener
146 memset(&nlcn_msg, 0, sizeof(nlcn_msg));
147 nlcn_msg.nl_hdr.nlmsg_len = sizeof(nlcn_msg);
148 nlcn_msg.nl_hdr.nlmsg_pid = getpid();
149 nlcn_msg.nl_hdr.nlmsg_type = NLMSG_DONE;
150
151 nlcn_msg.cn_msg.id.idx = CN_IDX_PROC;
152 nlcn_msg.cn_msg.id.val = CN_VAL_PROC;
153 nlcn_msg.cn_msg.len = sizeof(enum proc_cn_mcast_op);
154
155 nlcn_msg.cn_mcast = PROC_CN_MCAST_LISTEN ;
156
157 rc = send(nl_sock, &nlcn_msg, sizeof(nlcn_msg), 0);
158 if (rc == -1)
159 {
160 mterror(WM_PROC_LOGTAG, "can't register to netlink");
161 close( nl_sock );
162 return -1;
163 }
164
165 proc_monitor.proc_fd = nl_sock;
166 return 0;
167}
168
169static int wm_setup_mq( wm_proc_t *proc )
170{
171 unsigned int indx;
172 // Connect to socket
173 for (indx = 0; indx < WM_MAX_ATTEMPTS; indx++)
174 {
175 proc_monitor.queue_fd = StartMQ(DEFAULTQPATH, WRITE);
176 if ( proc_monitor.queue_fd > 0 )
177 {
178 break;
179 }
180 wm_delay(1000 * WM_MAX_WAIT);
181 }
182
183 if (indx == WM_MAX_ATTEMPTS)
184 {
185 mterror(WM_PROC_LOGTAG, "Can't connect to queue.");
186 pthread_exit(NULL);
187 }
188
189 // Cleanup exiting
190 atexit(wm_proc_cleanup);
191
192 return 0;
193}
194
195 int wm_proc_linux_setup( wm_proc_t *proc )
196 {
197 memset( temp_processes, 0, sizeof( temp_processes ) );
198 if ( wm_setup_netlink() < 0 )
199 {
200 return -1;
201 }
202 return wm_setup_mq(proc);
203 }
204
205static void get_path_and_md5( pid_t pid, char *path, char *md5 )
206{
207 char pid_path[MAX_PATH_NAME];
208 struct stat dir_stat;
209
210 memset( pid_path, 0, MAX_PATH_NAME);
211 snprintf( pid_path, MAX_PATH_NAME-1, "/proc/%d", pid );
212 if ( stat( pid_path, &dir_stat ) < 0 )
213 {
214 //mterror(WM_PROC_LOGTAG, "failed to open directory %s, errno=(%d:%m)", pid_path, errno );
215 return;
216 }
217
218 memset( pid_path, 0, MAX_PATH_NAME);
219 snprintf( pid_path, MAX_PATH_NAME-1, "/proc/%d/exe", pid );
220 memset( path, 0, MAX_PATH_NAME );
221 memset( md5, 0, sizeof(os_md5));
222 if ( readlink( pid_path, path, MAX_PATH_NAME ) < 0 )
223 {
224 memset(pid_path, 0, MAX_PATH_NAME);
225 snprintf(pid_path, MAX_PATH_NAME - 1, "/proc/%d/comm", pid);
226 memset(path, 0, MAX_PATH_NAME);
227 FILE* fp = fopen(pid_path, "rb");
228 if ( NULL == fp )
229 {
230 return;
231 }
232 fread( path, MAX_PATH_NAME, 1, fp );
233 if ( strlen( path ) > 0 )
234 {
235 path[strlen(path)-1] = '\0';
236 }
237 fclose( fp );
238 return;
239 }
240
241 OS_MD5_File(path, md5, OS_BINARY);
242
243 return;
244}
245
246
247
248static void get_process_baseinfo( const process_parent_child_pair_t *pair, const char *location )
249{
250 proc_t curr_proc;
251
252 memset( &curr_proc, 0, sizeof( proc_t ));
253
254 cJSON *process = cJSON_CreateObject();
255 if( NULL == process)
256 {
257 return;
258 }
259 cJSON_AddStringToObject(process, "type", "new process");
260 cJSON_AddNumberToObject(process, "pid", pair->pid);
261 cJSON_AddNumberToObject(process, "eventTime", pair->fork_time);
262 cJSON_AddNumberToObject(process, "ppid", pair->ppid);
263 if (strlen(pair->path) > 0)
264 {
265 cJSON_AddStringToObject(process, "exe", pair->path);
266 }
267 if (strlen(pair->md5) > 0)
268 {
269 cJSON_AddStringToObject(process, "md5", pair->md5);
270 }
271 if (strlen(pair->parent_path) > 0)
272 {
273 cJSON_AddStringToObject(process, "parent_exe", pair->parent_path);
274 }
275 if (strlen(pair->parent_md5) > 0)
276 {
277 cJSON_AddStringToObject(process, "parent_md5", pair->parent_md5);
278 }
279
280 // get process information
281 if (NULL != get_proc_stats(pair->pid, &curr_proc))
282 {
283 cJSON_AddStringToObject(process, "state", &curr_proc.state);
284 cJSON_AddNumberToObject(process, "utime", curr_proc.utime);
285 cJSON_AddNumberToObject(process, "stime", curr_proc.stime);
286 if (curr_proc.cmdline && curr_proc.cmdline[0])
287 {
288 cJSON *argvs = cJSON_CreateArray();
289 cJSON_AddStringToObject(process, "cmd", curr_proc.cmdline[0]);
290 for (int i = 1; curr_proc.cmdline[i]; i++)
291 {
292 if (!strlen(curr_proc.cmdline[i]) == 0)
293 {
294 cJSON_AddItemToArray(argvs, cJSON_CreateString(curr_proc.cmdline[i]));
295 }
296 }
297 if (cJSON_GetArraySize(argvs) > 0)
298 {
299 cJSON_AddItemToObject(process, "argvs", argvs);
300 }
301 else
302 {
303 cJSON_Delete(argvs);
304 }
305 }
306 cJSON_AddStringToObject(process, "euser", curr_proc.euser);
307 cJSON_AddStringToObject(process, "egroup", curr_proc.egroup);
308 cJSON_AddNumberToObject(process, "resident", curr_proc.resident);
309 cJSON_AddNumberToObject(process, "nlwp", curr_proc.nlwp);
310 cJSON_AddNumberToObject(process, "tty", curr_proc.tty);
311 cJSON_AddNumberToObject(process, "processor", curr_proc.processor);
312 /*
313 cJSON_AddStringToObject(process, "ruser", curr_proc.ruser);
314 cJSON_AddStringToObject(process, "suser", curr_proc.suser);
315 cJSON_AddStringToObject(process, "rgroup", curr_proc.rgroup);
316 cJSON_AddStringToObject(process, "sgroup", curr_proc.sgroup);
317 cJSON_AddStringToObject(process, "fgroup", curr_proc.fgroup);
318 cJSON_AddNumberToObject(process, "priority", curr_proc.priority);
319 cJSON_AddNumberToObject(process, "nice", curr_proc.nice);
320 cJSON_AddNumberToObject(process, "size", curr_proc.size);
321 cJSON_AddNumberToObject(process, "vm_size", curr_proc.vm_size);
322 cJSON_AddNumberToObject(process, "share", curr_proc.share);
323 cJSON_AddNumberToObject(process, "pgrp", curr_proc.pgrp);
324 cJSON_AddNumberToObject(process, "session", curr_proc.session);
325 cJSON_AddNumberToObject(process, "tgid", curr_proc.tgid);
326 */
327 }
328
329 char *msg = cJSON_PrintUnformatted(process);
330 wm_sendmsg( MAX_PIPE_WAIT_USECOND, proc_monitor.queue_fd, msg, location, PROC_COLLECTOR_MQ );
331 free(msg);
332 cJSON_Delete( process );
333
334 return;
335}
336
337 static void get_process_info( const process_parent_child_pair_t *pair, const char *location )
338 {
339 // get process base info
340 get_process_baseinfo( pair, location );
341
342 // get process library info
343
344 // find rootkit in user mode
345
346 // check process is a malware
347 }
348
349static void handle_temp_process( const char *location )
350{
351 int i = 0;
352 for ( i = 0; i < MAX_TEMP_PROCESS; i++ )
353 {
354 if ( ( temp_processes[i].status != PROCESS_SLOT_EMPTY ) && ( temp_processes[i].ppid != 0 ) )
355 {
356 mtdebug1(WM_PROC_LOGTAG, "handle process: %d, parent process:%d", temp_processes[i].pid, temp_processes[i].ppid );
357 get_process_info( &temp_processes[i], location );
358 temp_processes[i].status = PROCESS_SLOT_EMPTY;
359 }
360 }
361}
362
363static void handle_process_fork( const event_msg_t *proc_msg )
364{
365 int i = 0;
366 for ( i = 0; i < MAX_TEMP_PROCESS; i++ )
367 {
368 if ( temp_processes[i].status == PROCESS_SLOT_EMPTY )
369 {
370 get_path_and_md5( proc_msg->proc_ev.event_data.fork.child_pid, temp_processes[i].path, temp_processes[i].md5 );
371 get_path_and_md5( proc_msg->proc_ev.event_data.fork.parent_pid, temp_processes[i].parent_path, temp_processes[i].parent_md5);
372 temp_processes[i].pid = proc_msg->proc_ev.event_data.fork.child_pid;
373 temp_processes[i].ppid = proc_msg->proc_ev.event_data.fork.parent_pid;
374 temp_processes[i].fork_time = time(0);
375 temp_processes[i].status = !PROCESS_SLOT_EMPTY;
376 mtdebug1(WM_PROC_LOGTAG, "fork process: %d, parent process:%d", temp_processes[i].pid, temp_processes[i].ppid );
377 break;
378 }
379 }
380}
381
382static void handle_process_exec( const event_msg_t *proc_msg, const char *location )
383{
384 int i = 0;
385 for ( i = 0; i < MAX_TEMP_PROCESS; i++ )
386 {
387 if (temp_processes[i].pid == proc_msg->proc_ev.event_data.exec.process_pid
388 && temp_processes[i].status != PROCESS_SLOT_EMPTY)
389 {
390 get_path_and_md5( proc_msg->proc_ev.event_data.exec.process_pid, temp_processes[i].path, temp_processes[i].md5 );
391 mtdebug1(WM_PROC_LOGTAG, "exec process: %d, parent process:%d", temp_processes[i].pid, temp_processes[i].ppid );
392 get_process_info( &temp_processes[i], location );
393 temp_processes[i].status = PROCESS_SLOT_EMPTY;
394 break;
395 }
396 }
397}
398
399static void handle_process_exit( const event_msg_t *proc_msg, const char* location )
400{
401 int i = 0;
402 for ( i = 0; i < MAX_TEMP_PROCESS; i++ )
403 {
404 if ( ( temp_processes[i].status != PROCESS_SLOT_EMPTY )
405 && ( proc_msg->proc_ev.event_data.exit.process_pid == temp_processes[i].pid )
406 && ( temp_processes[i].ppid == 0 ) )
407 {
408 temp_processes[i].status = PROCESS_SLOT_EMPTY;
409 return;
410 }
411 }
412
413 cJSON *process = cJSON_CreateObject();
414 cJSON_AddStringToObject(process, "type", "exit");
415 cJSON_AddNumberToObject( process, "pid", proc_msg->proc_ev.event_data.exit.process_pid );
416 cJSON_AddNumberToObject( process, "eventTime", time(0) );
417 cJSON_AddNumberToObject(process, "exitCode", proc_msg->proc_ev.event_data.exit.exit_code);
418 cJSON_AddNumberToObject(process, "exitSignal", (int)proc_msg->proc_ev.event_data.exit.exit_signal);
419
420 char *exit_msg = cJSON_PrintUnformatted( process );
421 wm_sendmsg( MAX_PIPE_WAIT_USECOND, proc_monitor.queue_fd, exit_msg, location, PROC_COLLECTOR_MQ );
422 free( exit_msg );
423 cJSON_Delete( process );
424}
425
426static time_t get_process_start_time( pid_t pid )
427{
428 char path[MAX_PATH_NAME];
429 memset( path, 0, MAX_PATH_NAME);
430
431 snprintf( path, MAX_PATH_NAME-1, "/proc/%d", pid );
432
433 struct stat dir_stat;
434
435 if ( stat( path, &dir_stat) < 0 )
436 {
437 return 0;
438 }
439
440 return dir_stat.st_mtime;
441}
442
443static void get_inventory_processes(const char *location)
444{
445 DIR *proc_dir = opendir( "/proc" );
446 if ( NULL == proc_dir )
447 {
448 mterror( WM_PROC_LOGTAG, "failed to open /proc, errno=(%d:%m)", errno );
449 return;
450 }
451
452 struct dirent *entry = NULL;
453 while ( NULL != ( entry = readdir( proc_dir )))
454 {
455 if ( !strcmp( entry->d_name, "." ) || !strcmp( entry->d_name, ".." ) )
456 {
457 continue;
458 }
459 int pid = atoi( entry->d_name );
460 if ( 0 == pid )
461 {
462 continue;
463 }
464
465 char pid_path[MAX_PATH_NAME];
466 os_md5 md5;
467 memset( pid_path, 0, sizeof( MAX_PATH_NAME));
468 memset( md5, 0, sizeof( os_md5 ) );
469 get_path_and_md5( pid, pid_path, md5 );
470
471 cJSON *process = cJSON_CreateObject();
472 cJSON_AddStringToObject(process, "type", "new process");
473 cJSON_AddNumberToObject(process, "eventTime", time(0));
474 cJSON_AddNumberToObject(process, "pid", pid);
475 cJSON_AddNumberToObject(process, "startTime", get_process_start_time(pid));
476 if (strlen(pid_path) > 0)
477 {
478 cJSON_AddStringToObject(process, "exe", pid_path);
479 }
480 if (strlen(md5) > 0)
481 {
482 cJSON_AddStringToObject(process, "md5", md5);
483 }
484
485 proc_t curr_proc;
486 memset( &curr_proc, 0, sizeof( proc_t ));
487 if ( NULL != get_proc_stats(pid, &curr_proc ))
488 {
489 cJSON_AddStringToObject(process, "state", &curr_proc.state);
490 cJSON_AddNumberToObject(process, "utime", curr_proc.utime);
491 cJSON_AddNumberToObject(process, "stime", curr_proc.stime);
492 cJSON_AddStringToObject(process, "euser", curr_proc.euser);
493 cJSON_AddStringToObject(process, "egroup", curr_proc.egroup);
494 cJSON_AddNumberToObject(process, "resident", curr_proc.resident);
495 cJSON_AddNumberToObject(process, "nlwp", curr_proc.nlwp);
496 cJSON_AddNumberToObject(process, "tty", curr_proc.tty);
497 cJSON_AddNumberToObject(process, "processor", curr_proc.processor);
498 /*
499 cJSON_AddStringToObject(process, "ruser", curr_proc.ruser);
500 cJSON_AddStringToObject(process, "suser", curr_proc.suser);
501 cJSON_AddStringToObject(process, "rgroup", curr_proc.rgroup);
502 cJSON_AddStringToObject(process, "sgroup", curr_proc.sgroup);
503 cJSON_AddStringToObject(process, "fgroup", curr_proc.fgroup);
504
505 cJSON_AddNumberToObject(process, "priority", curr_proc.priority);
506 cJSON_AddNumberToObject(process, "nice", curr_proc.nice);
507 cJSON_AddNumberToObject(process, "size", curr_proc.size);
508 cJSON_AddNumberToObject(process, "vm_size", curr_proc.vm_size);
509 cJSON_AddNumberToObject(process, "share", curr_proc.share);
510 cJSON_AddNumberToObject(process, "pgrp", curr_proc.pgrp);
511 cJSON_AddNumberToObject(process, "session", curr_proc.session);
512 cJSON_AddNumberToObject(process, "tgid", curr_proc.tgid);
513 */
514
515 memset(pid_path, 0, sizeof(MAX_PATH_NAME));
516 memset(md5, 0, sizeof(os_md5));
517 get_path_and_md5(curr_proc.ppid, pid_path, md5);
518 if (strlen(pid_path) > 0)
519 {
520 cJSON_AddStringToObject(process, "parent_exe", pid_path);
521 }
522 if (strlen(md5) > 0)
523 {
524 cJSON_AddStringToObject(process, "parent_md5", md5);
525 }
526 }
527
528 char *msg = cJSON_PrintUnformatted(process);
529 wm_sendmsg(MAX_PIPE_WAIT_USECOND, proc_monitor.queue_fd, msg, location, PROC_COLLECTOR_MQ);
530 free(msg);
531 cJSON_Delete(process);
532 }
533
534 closedir( proc_dir);
535}
536
537int wm_proc_linux_process(wm_proc_t *proc, const char *location)
538{
539 int rc;
540 event_msg_t proc_msg;
541 fd_set readfds;
542 int max_fd = proc_monitor.proc_fd + 1;
543 struct timeval tv;
544
545 if (proc->flags.enabled == 0)
546 {
547 return 0;
548 merror("process collector disabled, let us rest.");
549 }
550
551
552 merror("process collector enabled, let us work.");
553
554 get_inventory_processes(location);
555
556 tv.tv_sec = 5;
557 tv.tv_usec = 0;
558
559 while (1)
560 {
561 FD_ZERO(&readfds);
562 FD_SET(proc_monitor.proc_fd, &readfds);
563
564 rc = select(max_fd, &readfds, NULL, NULL, &tv);
565 if (0 == rc)
566 {
567 handle_temp_process(location);
568 tv.tv_sec = 5;
569 tv.tv_usec = 0;
570 continue;
571 }
572 if (-1 == rc)
573 {
574 if (errno == EINTR)
575 {
576 continue;
577 }
578 mterror(WM_PROC_LOGTAG, "failed to listen to netlink socket, errno=(%d:%m)", errno);
579 return rc;
580 }
581 if (FD_ISSET(proc_monitor.proc_fd, &readfds))
582 {
583 rc = recv(proc_monitor.proc_fd, &proc_msg, sizeof(proc_msg), 0);
584 if (rc > 0)
585 {
586 switch (proc_msg.proc_ev.what)
587 {
588 case proc_event::PROC_EVENT_FORK:
589 handle_process_fork(&proc_msg);
590 tv.tv_sec = 1;
591 tv.tv_usec = 1000;
592 break;
593 case proc_event::PROC_EVENT_EXEC:
594 handle_process_exec(&proc_msg, location);
595 break;
596 case proc_event::PROC_EVENT_COMM:
597 break;
598 case proc_event::PROC_EVENT_EXIT:
599 handle_process_exit(&proc_msg, location);
600 break;
601 default:
602 break;
603 }
604 }
605 else if (rc == -1)
606 {
607 if (errno == EINTR)
608 {
609 continue;
610 }
611 mterror(WM_PROC_LOGTAG, "failed to received from netlink socket, errno=(%d:%m)", errno);
612 }
613 }
614 }
615
616 return 0;
617}
618#endif \ No newline at end of file