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