Imported Upstream version 2.7
[ossec-hids.git] / src / rootcheck / check_rc_pids.c
1 /* @(#) $Id: ./src/rootcheck/check_rc_pids.c, 2011/09/08 dcid Exp $
2  */
3
4 /* Copyright (C) 2009 Trend Micro Inc.
5  * All right reserved.
6  *
7  * This program is a free software; you can redistribute it
8  * and/or modify it under the terms of the GNU General Public
9  * License (version 2) as published by the FSF - Free Software
10  * Foundation
11  */
12
13 #ifndef WIN32
14 #include "shared.h"
15 #include "rootcheck.h"
16
17
18 int noproc;
19
20
21 /** int proc_read(int pid)
22  * If /proc is mounted, check to see if the pid is present
23  */
24 int proc_read(int pid)
25 {
26     char dir[OS_SIZE_1024 +1];
27
28     if(noproc)
29         return(0);
30
31     snprintf(dir, OS_SIZE_1024, "%d", pid);
32     if(isfile_ondir(dir, "/proc"))
33     {
34         return(1);
35     }
36     return(0);
37 }
38
39
40 /** int proc_chdir(int pid)
41  * If /proc is mounted, check to see if the pid is present
42  */
43 int proc_chdir(int pid)
44 {
45     int ret = 0;
46     char curr_dir[OS_SIZE_1024 + 1];
47     char dir[OS_SIZE_1024 + 1];
48
49     if(noproc)
50         return(0);
51
52     if(!getcwd(curr_dir, OS_SIZE_1024))
53     {
54         return(0);
55     }
56
57     if(chdir("/proc") == -1)
58         return(0);
59
60     snprintf(dir, OS_SIZE_1024, "/proc/%d", pid);
61     if(chdir(dir) == 0)
62     {
63         ret = 1;
64     }
65
66     /* Returning to the previous directory */
67     chdir(curr_dir);
68
69     return(ret);
70 }
71
72
73 /** int proc_stat(int pid)
74  * If /proc is mounted, check to see if the pid is present there.
75  */
76 int proc_stat(int pid)
77 {
78     char proc_dir[OS_SIZE_1024 + 1];
79
80     if(noproc)
81         return(0);
82
83     snprintf(proc_dir, OS_SIZE_1024, "%s/%d", "/proc", pid);
84
85     if(is_file(proc_dir))
86     {
87         return(1);
88     }
89
90     return(0);
91 }
92
93
94 /** void loop_all_pids(char *ps, pid_t max_pid, int *_errors, int *_total)
95  * Check all the available PIDs for hidden stuff.
96  */
97 void loop_all_pids(char *ps, pid_t max_pid, int *_errors, int *_total)
98 {
99     int _kill0 = 0;
100     int _kill1 = 0;
101     int _gsid0 = 0;
102     int _gsid1 = 0;
103     int _gpid0 = 0;
104     int _gpid1 = 0;
105     int _ps0 = -1;
106     int _proc_stat  = 0;
107     int _proc_read  = 0;
108     int _proc_chdir = 0;
109
110     pid_t i = 1;
111     pid_t my_pid;
112
113     char command[OS_SIZE_1024 +1];
114
115     my_pid = getpid();
116
117     for(;;i++)
118     {
119         if((i <= 0)||(i > max_pid))
120             break;
121
122         (*_total)++;
123
124         _kill0 = 0;
125         _kill1 = 0;
126         _gsid0 = 0;
127         _gsid1 = 0;
128         _gpid0 = 0;
129         _gpid1 = 0;
130         _ps0 = -1;
131         _proc_stat  = 0;
132         _proc_read  = 0;
133         _proc_chdir = 0;
134
135
136         /* kill test */
137         if(!((kill(i, 0) == -1)&&(errno == ESRCH)))
138         {
139             _kill0 = 1;
140         }
141
142         /* getsid to test */
143         if(!((getsid(i) == -1)&&(errno == ESRCH)))
144         {
145             _gsid0 = 1;
146         }
147
148         /* getpgid test */
149         if(!((getpgid(i) == -1)&&(errno == ESRCH)))
150         {
151             _gpid0 = 1;
152         }
153
154
155         /* proc stat */
156         _proc_stat = proc_stat(i);
157
158         /* proc readdir */
159         _proc_read = proc_read(i);
160
161         /* proc chdir */
162         _proc_chdir = proc_chdir(i);
163
164
165         /* IF PID does not exist, keep going */
166         if(!_kill0 && !_gsid0 && !_gpid0 &&
167            !_proc_stat && !_proc_read && !_proc_chdir)
168         {
169             continue;
170         }
171
172         /* We do not need to look at our own pid */
173         else if(i == my_pid)
174         {
175             continue;
176         }
177
178         /* Checking the number of errors */
179         if((*_errors) > 15)
180         {
181             char op_msg[OS_SIZE_1024 +1];
182             snprintf(op_msg,OS_SIZE_1024,"Excessive number of hidden processes"
183                     ". It maybe a false-positive or "
184                     "something really bad is going on.");
185             notify_rk(ALERT_SYSTEM_CRIT, op_msg);
186             return;
187         }
188
189
190         /* checking if process appears on ps */
191         if(*ps)
192         {
193             snprintf(command, OS_SIZE_1024, "%s -p %d > /dev/null 2>&1",
194                                                         ps,
195                                                         (int)i);
196
197             /* Found PID on ps */
198             _ps0 = 0;
199             if(system(command) == 0)
200                 _ps0 = 1;
201         }
202
203         /* If we are being run by the ossec hids, sleep here (no rush) */
204         #ifdef OSSECHIDS
205         sleep(2);
206         #endif
207
208         /* Everyone returned ok */
209         if(_ps0 && _kill0 && _gsid0 && _gpid0 && _proc_stat && _proc_read)
210         {
211             continue;
212         }
213
214
215
216         /* If our kill or getsid system call, got the
217          * PID , but ps didn't, we need to find if it was a problem
218          * with a PID being deleted (not used anymore)
219          */
220         {
221             if(!((getsid(i) == -1)&&(errno == ESRCH)))
222             {
223                 _gsid1 = 1;
224             }
225
226             if(!((kill(i, 0) == -1)&&(errno == ESRCH)))
227             {
228                 _kill1 = 1;
229             }
230
231             if(!((getpgid(i) == -1)&&(errno == ESRCH)))
232             {
233                 _gpid1 = 1;
234             }
235
236
237             _proc_stat = proc_stat(i);
238
239             _proc_read = proc_read(i);
240
241             _proc_chdir = proc_chdir(i);
242
243             /* If it matches, process was terminated */
244             if(!_gsid1 &&!_kill1 &&!_gpid1 &&!_proc_stat &&
245                !_proc_read &&!_proc_chdir)
246             {
247                 continue;
248             }
249         }
250
251         #ifdef AIX
252         /* Ignoring AIX wait and sched programs. */
253         if((_gsid0 == _gsid1) &&
254            (_kill0 == _kill1) &&
255            (_gpid0 == _gpid1) &&
256            (_ps0 == 1) &&
257            (_gsid0 == 1) &&
258            (_kill0 == 0))
259         {
260             /* The wait and sched programs do not respond to kill 0.
261              * So, if everything else finds it, including ps, getpid, getsid,
262              * but not
263              * kill, we can safely ignore on AIX.
264              * A malicious program would specially try to hide from ps..
265              */
266             continue;
267         }
268         #endif
269
270
271         if((_gsid0 == _gsid1)&&
272            (_kill0 == _kill1)&&
273            (_gsid0 != _kill0))
274         {
275             /* If kill found, but getsid and getpgid didnt', it may
276              * be a defunct process -- ignore.
277              */
278             if(!((_kill0 == 1)&&(_gsid0 == 0)&&(_gpid0 == 0)&&(_gsid1 == 0)))
279             {
280                 char op_msg[OS_SIZE_1024 +1];
281
282                 snprintf(op_msg, OS_SIZE_1024, "Process '%d' hidden from "
283                         "kill (%d) or getsid (%d). Possible kernel-level"
284                         " rootkit.", (int)i, _kill0, _gsid0);
285
286                 notify_rk(ALERT_ROOTKIT_FOUND, op_msg);
287                 (*_errors)++;
288             }
289         }
290         else if((_kill1 != _gsid1)||
291                 (_gpid1 != _kill1)||
292                 (_gpid1 != _gsid1))
293         {
294             /* See defunct process comment above. */
295             if(!((_kill1 == 1)&&(_gsid1 == 0)&&(_gpid0 == 0)&&(_gsid1 == 0)))
296             {
297                 char op_msg[OS_SIZE_1024 +1];
298                 snprintf(op_msg, OS_SIZE_1024, "Process '%d' hidden from "
299                         "kill (%d), getsid (%d) or getpgid. Possible "
300                         "kernel-level rootkit.", (int)i, _kill1, _gsid1);
301
302                 notify_rk(ALERT_ROOTKIT_FOUND, op_msg);
303                 (*_errors)++;
304             }
305         }
306         else if((_proc_read != _proc_stat)||
307                 (_proc_read != _proc_chdir)||
308                 (_proc_stat != _kill1))
309         {
310             /* checking if the pid is a thread (not showing on proc */
311             if(!noproc && !check_rc_readproc((int)i))
312             {
313                 char op_msg[OS_SIZE_1024 +1];
314                 snprintf(op_msg, OS_SIZE_1024, "Process '%d' hidden from "
315                         "/proc. Possible kernel level rootkit.", (int)i);
316                 notify_rk(ALERT_ROOTKIT_FOUND, op_msg);
317                 (*_errors)++;
318             }
319         }
320         else if(_gsid1 && _kill1 && !_ps0)
321         {
322             /* checking if the pid is a thread (not showing on ps */
323             if(!check_rc_readproc((int)i))
324             {
325                 char op_msg[OS_SIZE_1024 +1];
326                 snprintf(op_msg, OS_SIZE_1024, "Process '%d' hidden from "
327                              "ps. Possible trojaned version installed.",
328                              (int)i);
329
330                 notify_rk(ALERT_ROOTKIT_FOUND, op_msg);
331                 (*_errors)++;
332             }
333         }
334     }
335 }
336
337
338 /*  check_rc_sys: v0.1
339  *  Scan the whole filesystem looking for possible issues
340  */
341 void check_rc_pids()
342 {
343     int _total = 0;
344     int _errors = 0;
345
346     char ps[OS_SIZE_1024 +1];
347
348     char proc_0[] = "/proc";
349     char proc_1[] = "/proc/1";
350
351     pid_t max_pid = MAX_PID;
352
353     noproc = 1;
354
355     /* Checking where ps is */
356     memset(ps, '\0', OS_SIZE_1024 +1);
357     strncpy(ps, "/bin/ps", OS_SIZE_1024);
358     if(!is_file(ps))
359     {
360         strncpy(ps, "/usr/bin/ps", OS_SIZE_1024);
361         if(!is_file(ps))
362             ps[0] = '\0';
363     }
364
365
366     /* Proc is mounted */
367     if(is_file(proc_0) && is_file(proc_1))
368     {
369         noproc = 0;
370     }
371
372     loop_all_pids(ps, max_pid, &_errors, &_total);
373
374     if(_errors == 0)
375     {
376         char op_msg[OS_SIZE_1024 +1];
377         snprintf(op_msg, OS_SIZE_1024, "No hidden process by Kernel-level "
378                                     "rootkits.\n      %s is not trojaned. "
379                                     "Analyzed %d processes.", ps, _total);
380         notify_rk(ALERT_OK, op_msg);
381     }
382
383     return;
384 }
385
386 /* EOF */
387 #else
388 void check_rc_pids()
389 {
390     return;
391 }
392 #endif