1 /* Copyright (C) 2009 Trend Micro Inc.
4 * This program is a free software; you can redistribute it
5 * and/or modify it under the terms of the GNU General Public
6 * License (version 2) as published by the FSF - Free Software
12 #include "rootcheck.h"
15 static int proc_read(int pid);
16 static int proc_chdir(int pid);
17 static int proc_stat(int pid);
18 static void loop_all_pids(const char *ps, pid_t max_pid, int *_errors, int *_total);
20 /* Global variables */
24 /* If /proc is mounted, check to see if the pid is present */
25 static int proc_read(int pid)
27 char dir[OS_SIZE_1024 + 1];
33 snprintf(dir, OS_SIZE_1024, "%d", pid);
34 if (isfile_ondir(dir, "/proc")) {
40 /* If /proc is mounted, check to see if the pid is present */
41 static int proc_chdir(int pid)
44 char curr_dir[OS_SIZE_1024 + 1];
45 char dir[OS_SIZE_1024 + 1];
50 if (getcwd(curr_dir, OS_SIZE_1024) == NULL) {
53 if (chdir("/proc") == -1) {
57 snprintf(dir, OS_SIZE_1024, "/proc/%d", pid);
58 if (chdir(dir) == 0) {
62 /* Returning to the previous directory */
63 if (chdir(curr_dir) == -1) {
70 /* If /proc is mounted, check to see if the pid is present there */
71 static int proc_stat(int pid)
73 char proc_dir[OS_SIZE_1024 + 1];
79 snprintf(proc_dir, OS_SIZE_1024, "%s/%d", "/proc", pid);
81 if (is_file(proc_dir)) {
88 /* Check all the available PIDs for hidden stuff */
89 static void loop_all_pids(const char *ps, pid_t max_pid, int *_errors, int *_total)
105 char command[OS_SIZE_1024 + 1];
110 if ((i <= 0) || (i > max_pid)) {
125 if (!((kill(i, 0) == -1) && (errno == ESRCH))) {
130 if (!((getsid(i) == -1) && (errno == ESRCH))) {
135 if (!((getpgid(i) == -1) && (errno == ESRCH))) {
140 _proc_stat = proc_stat(i);
141 _proc_read = proc_read(i);
142 _proc_chdir = proc_chdir(i);
144 /* If PID does not exist, move on */
145 if (!_kill0 && !_gsid0 && !_gpid0 &&
146 !_proc_stat && !_proc_read && !_proc_chdir) {
150 /* Ignore our own pid */
155 /* Check the number of errors */
156 if ((*_errors) > 15) {
157 char op_msg[OS_SIZE_1024 + 1];
158 snprintf(op_msg, OS_SIZE_1024, "Excessive number of hidden processes"
159 ". It maybe a false-positive or "
160 "something really bad is going on.");
161 notify_rk(ALERT_SYSTEM_CRIT, op_msg);
165 /* Check if the process appears in ps(1) output */
167 snprintf(command, OS_SIZE_1024, "%s -p %d > /dev/null 2>&1", ps, (int)i);
169 if (system(command) == 0) {
174 /* If we are run in the context of OSSEC-HIDS, sleep here (no rush) */
176 debug1("%s: DEBUG: pause for %u", ARGV0, rootcheck.tsleep);
177 sleep(rootcheck.tsleep);
180 /* Everything fine, move on */
181 if (_ps0 && _kill0 && _gsid0 && _gpid0 && _proc_stat && _proc_read) {
186 * If our kill or getsid system call got the PID but ps(1) did not,
187 * find out if the PID is deleted (not used anymore)
189 if (!((getsid(i) == -1) && (errno == ESRCH))) {
192 if (!((kill(i, 0) == -1) && (errno == ESRCH))) {
195 if (!((getpgid(i) == -1) && (errno == ESRCH))) {
199 _proc_stat = proc_stat(i);
200 _proc_read = proc_read(i);
201 _proc_chdir = proc_chdir(i);
203 /* If it matches, process was terminated in the meantime, so move on */
204 if (!_gsid1 && !_kill1 && !_gpid1 && !_proc_stat &&
205 !_proc_read && !_proc_chdir) {
210 /* Ignore AIX wait and sched programs */
211 if (_gsid0 == _gsid1 &&
217 /* The wait and sched programs do not respond to kill 0.
218 * So if everything else finds it, including ps, getpid, getsid,
219 * but not kill, we can safely ignore on AIX.
220 * A malicious program would specially try to hide from ps.
226 if (_gsid0 == _gsid1 &&
229 /* If kill worked, but getsid and getpgid did not, it may
230 * be a defunct process -- ignore.
232 if (! (_kill0 == 1 && _gsid0 == 0 && _gpid0 == 0) ) {
233 char op_msg[OS_SIZE_1024 + 1];
235 snprintf(op_msg, OS_SIZE_1024, "Process '%d' hidden from "
236 "kill (%d) or getsid (%d). Possible kernel-level"
237 " rootkit.", (int)i, _kill0, _gsid0);
238 notify_rk(ALERT_ROOTKIT_FOUND, op_msg);
241 } else if (_kill1 != _gsid1 ||
244 /* See defunct process comment above */
245 if (! (_kill1 == 1 && _gsid0 == 0 && _gpid0 == 0 && _gsid1 == 0) ) {
246 char op_msg[OS_SIZE_1024 + 1];
248 snprintf(op_msg, OS_SIZE_1024, "Process '%d' hidden from "
249 "kill (%d), getsid (%d) or getpgid. Possible "
250 "kernel-level rootkit.", (int)i, _kill1, _gsid1);
251 notify_rk(ALERT_ROOTKIT_FOUND, op_msg);
254 } else if (_proc_read != _proc_stat ||
255 _proc_read != _proc_chdir ||
256 _proc_stat != _kill1) {
257 /* Check if the pid is a thread (not showing in /proc */
258 if (!noproc && !check_rc_readproc((int)i)) {
259 char op_msg[OS_SIZE_1024 + 1];
261 snprintf(op_msg, OS_SIZE_1024, "Process '%d' hidden from "
262 "/proc. Possible kernel level rootkit.", (int)i);
263 notify_rk(ALERT_ROOTKIT_FOUND, op_msg);
266 } else if (_gsid1 && _kill1 && !_ps0) {
267 /* checking if the pid is a thread (not showing on ps */
268 if (!check_rc_readproc((int)i)) {
269 char op_msg[OS_SIZE_1024 + 1];
271 snprintf(op_msg, OS_SIZE_1024, "Process '%d' hidden from "
272 "ps. Possible trojaned version installed.",
274 notify_rk(ALERT_ROOTKIT_FOUND, op_msg);
281 /* Scan the whole filesystem looking for possible issues */
287 char ps[OS_SIZE_1024 + 1];
289 char proc_0[] = "/proc";
290 char proc_1[] = "/proc/1";
292 pid_t max_pid = MAX_PID;
295 /* Checking where ps is */
296 memset(ps, '\0', OS_SIZE_1024 + 1);
297 strncpy(ps, "/bin/ps", OS_SIZE_1024);
299 strncpy(ps, "/usr/bin/ps", OS_SIZE_1024);
305 /* Proc is mounted */
306 if (is_file(proc_0) && is_file(proc_1)) {
310 loop_all_pids(ps, max_pid, &_errors, &_total);
313 char op_msg[OS_SIZE_1024 + 1];
314 snprintf(op_msg, OS_SIZE_1024, "No hidden process by Kernel-level "
315 "rootkits.\n %s is not trojaned. "
316 "Analyzed %d processes.", ps, _total);
317 notify_rk(ALERT_OK, op_msg);