Imported Upstream version 2.4.3
[platform/upstream/audit.git] / src / autrace.c
1 /* autrace.c -- 
2  * Copyright 2005-09,2011,2015 Red Hat Inc., Durham, North Carolina.
3  * All Rights Reserved.
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18  *
19  * Authors:
20  *     Steve Grubb <sgrubb@redhat.com>
21  */
22
23 #include "config.h"
24 #include <stdio.h>
25 #include <string.h>
26 #include <sys/wait.h>
27 #include <unistd.h>
28 #include <fcntl.h>
29 #include <stdlib.h>
30 #include <errno.h>
31 #include <time.h>
32 #include <linux/net.h>
33 #include "libaudit.h"
34 #include "private.h"
35
36 /*
37  * This program will add the audit rules to trace a process similar
38  * to strace. It will then execute the process.
39  */
40 static int threat = 0;
41 static int count_rules(void);
42 static int count_em(int fd);
43 extern int delete_all_rules(int fd);
44
45 static void usage(void)
46 {
47         fprintf(stderr, "usage: autrace [-r] program\n");
48 }
49
50 static int insert_rule(int audit_fd, const char *field)
51 {
52         int rc;
53         int flags = AUDIT_FILTER_EXIT;
54         int action = AUDIT_ALWAYS;
55         struct audit_rule_data *rule = malloc(sizeof(struct audit_rule_data));
56         int machine = audit_detect_machine();
57         char *t_field = NULL;
58
59         if (rule == NULL)
60                 goto err;
61         memset(rule, 0, sizeof(struct audit_rule_data));
62         if (threat) {
63                 rc = 0;
64                 if (machine != MACH_AARCH64) {
65                         rc |= audit_rule_syscallbyname_data(rule, "open");
66                         rc |= audit_rule_syscallbyname_data(rule, "creat");
67                         rc |= audit_rule_syscallbyname_data(rule, "rename");
68                         rc |= audit_rule_syscallbyname_data(rule, "unlink");
69                         rc |= audit_rule_syscallbyname_data(rule, "mknod");
70                         rc |= audit_rule_syscallbyname_data(rule, "mkdir");
71                         rc |= audit_rule_syscallbyname_data(rule, "rmdir");
72                         rc |= audit_rule_syscallbyname_data(rule, "chown");
73                         rc |= audit_rule_syscallbyname_data(rule, "lchown");
74                         rc |= audit_rule_syscallbyname_data(rule, "chmod");
75                         rc |= audit_rule_syscallbyname_data(rule, "link");
76                         rc |= audit_rule_syscallbyname_data(rule, "symlink");
77                         rc |= audit_rule_syscallbyname_data(rule, "readlink");
78                 }
79                 rc |= audit_rule_syscallbyname_data(rule, "openat");
80                 rc |= audit_rule_syscallbyname_data(rule, "truncate");
81                 rc |= audit_rule_syscallbyname_data(rule, "renameat");
82                 rc |= audit_rule_syscallbyname_data(rule, "unlinkat");
83                 rc |= audit_rule_syscallbyname_data(rule, "mknodat");
84                 rc |= audit_rule_syscallbyname_data(rule, "mkdirat");
85                 rc |= audit_rule_syscallbyname_data(rule, "chdir");
86                 rc |= audit_rule_syscallbyname_data(rule, "fchownat");
87                 rc |= audit_rule_syscallbyname_data(rule, "fchmodat");
88                 rc |= audit_rule_syscallbyname_data(rule, "linkat");
89                 rc |= audit_rule_syscallbyname_data(rule, "symlinkat");
90                 rc |= audit_rule_syscallbyname_data(rule, "readlinkat");
91                 rc |= audit_rule_syscallbyname_data(rule, "execve");
92                 rc |= audit_rule_syscallbyname_data(rule, "name_to_handle_at");
93
94                 if (machine != MACH_X86 && machine != MACH_S390X && 
95                                                 machine != MACH_S390) {
96                         rc |= audit_rule_syscallbyname_data(rule, "connect");
97                         rc |= audit_rule_syscallbyname_data(rule, "bind");
98                         rc |= audit_rule_syscallbyname_data(rule, "accept");
99                         rc |= audit_rule_syscallbyname_data(rule, "sendto");
100                         rc |= audit_rule_syscallbyname_data(rule, "recvfrom");
101                         rc |= audit_rule_syscallbyname_data(rule, "accept4");
102                 }
103
104                 rc |= audit_rule_syscallbyname_data(rule, "sendfile");
105         } else
106                 rc = audit_rule_syscallbyname_data(rule, "all");
107         if (rc < 0)
108                 goto err;
109         t_field = strdup(field);
110         rc = audit_rule_fieldpair_data(&rule, t_field, flags);
111         free(t_field);
112         if (rc < 0)
113                 goto err;
114         rc = audit_add_rule_data(audit_fd, rule, flags, action);
115         if (rc < 0)
116                 goto err;
117
118         // Now if i386, lets add its network rules
119         if (machine == MACH_X86 || machine == MACH_S390X ||
120                                                 machine == MACH_S390) {
121                 int i, a0[6] = { SYS_CONNECT, SYS_BIND, SYS_ACCEPT, SYS_SENDTO,
122                                  SYS_RECVFROM, SYS_ACCEPT4 };
123                 for (i=0; i<6; i++) {
124                         char pair[32];
125
126                         memset(rule, 0, sizeof(struct audit_rule_data));
127                         rc |= audit_rule_syscallbyname_data(rule, "socketcall");
128                         snprintf(pair, sizeof(pair), "a0=%d", a0[i]);
129                         rc |= audit_rule_fieldpair_data(&rule, pair, flags);
130                         t_field = strdup(field);
131                         rc |= audit_rule_fieldpair_data(&rule, t_field, flags);
132                         free(t_field);
133                         rc |= audit_add_rule_data(audit_fd, rule, flags, action);
134                 }
135         }
136         free(rule);
137         return 0;
138 err:
139         fprintf(stderr, "Error inserting audit rule for %s\n", field);
140         free(rule);
141         return 1;
142 }
143
144 int key_match(struct audit_reply *rep)
145 {
146         return 1;
147 }
148
149 /*
150  * Algorithm:
151  * check that user is root
152  * check to see if program exists
153  * if so fork, child waits for parent
154  * parent clears audit rules, loads audit all syscalls with child's pid
155  * parent tells child to go & waits for sigchld
156  * child exec's program
157  * parent deletes rules after getting sigchld
158  */
159 int main(int argc, char *argv[])
160 {
161         int fd[2];
162         int pid,cmd=1;
163         char buf[2];
164
165         if (argc < 2) {
166                 usage();
167                 return 1;
168         }
169         if (strcmp(argv[cmd], "-h") == 0) {
170                 usage();
171                 return 1;
172         }
173         if (strcmp(argv[cmd], "-r") == 0) {
174                 threat = 1;
175                 cmd++;
176         }
177         if (getuid() != 0) {
178                 fprintf(stderr, "You must be root to run this program.\n");
179                 return 1;
180         }
181         if (access(argv[cmd], X_OK)) {
182                 if (errno == ENOENT)
183                         fprintf(stderr, "Error - can't find: %s\n", argv[cmd]); 
184                 else
185                         fprintf(stderr, "Error checking %s (%s)\n", 
186                                 argv[cmd], strerror(errno));
187                 return 1;
188         }
189         set_aumessage_mode(MSG_STDERR, DBG_NO);
190         switch (count_rules())
191         {
192                 case -1:
193                         if (errno == ECONNREFUSED)
194                                 fprintf(stderr,
195                                         "The audit system is disabled\n");
196                         else
197                                 fprintf(stderr,
198                                         "Error - can't get rule count.\n");
199                         return 1;
200                 case 0:
201                         break;
202                 default:
203                         fprintf(stderr, 
204                         "autrace cannot be run with rules loaded.\n"
205                         "Please delete all rules using 'auditctl -D' if you "
206                         "really wanted to\nrun this command.\n");
207                         return 1;
208         }
209         if (pipe(fd) != 0) {
210                 fprintf(stderr, "Error creating pipe.\n");
211                 return 1;
212         }
213         
214         switch ((pid=fork()))
215         {
216                 case -1:
217                         fprintf(stderr, "Error forking.\n");
218                         return 1;
219                 case 0: /* Child */
220                         close(fd[1]);
221                         printf("Waiting to execute: %s\n", argv[cmd]);
222                         while (read(fd[0], buf, 1) == -1 && errno == EINTR)
223                                 /* blank */ ;
224                         close(fd[0]);
225                         execvp(argv[cmd], &argv[cmd]);
226                         fprintf(stderr, "Failed to exec %s\n", argv[cmd]);
227                         return 1;
228                 default: /* Parent */
229                         close(fd[0]);
230                         fcntl(fd[1], F_SETFD, FD_CLOEXEC);
231                         {
232                                 char field[16];
233                                 int audit_fd;
234                                 audit_fd = audit_open();
235                                 if (audit_fd < 0)
236                                         exit(1);
237                                 snprintf(field, sizeof(field), "pid=%d", pid);
238                                 if (insert_rule(audit_fd, field)) {
239                                         kill(pid,SIGTERM);
240                                         (void)delete_all_rules(audit_fd);
241                                         exit(1);
242                                 }
243                                 snprintf(field, sizeof(field), "ppid=%d", pid);
244                                 if (insert_rule(audit_fd, field)) {
245                                         kill(pid,SIGTERM);
246                                         (void)delete_all_rules(audit_fd);
247                                         exit(1);
248                                 }
249                                 sleep(1);
250                                 if (write(fd[1],"1", 1) != 1) {
251                                         kill(pid,SIGTERM);
252                                         (void)delete_all_rules(audit_fd);
253                                         exit(1);
254                                 }
255                                 waitpid(pid, NULL, 0);
256                                 close(fd[1]);
257                                 puts("Cleaning up...");
258                                 (void)delete_all_rules(audit_fd);
259                                 close(audit_fd);
260                         }
261                         printf("Trace complete. "
262                                 "You can locate the records with "
263                                 "\'ausearch -i -p %d\'\n",
264                                 pid);
265                         break;
266         }
267
268         return 0;
269 }
270
271 static int count_rules(void)
272 {
273         int fd, total, rc;
274
275         fd = audit_open();
276         if (fd < 0) 
277                 return -1;
278
279         rc = audit_request_rules_list_data(fd);
280         if (rc > 0) 
281                 total = count_em(fd);
282         else 
283                 total = -1;
284
285         close(fd); 
286         return total;
287 }
288
289 static int count_em(int fd)
290 {
291         int i, retval, count = 0;
292         int timeout = 40; /* loop has delay of .1 - this is 4 seconds */
293         struct audit_reply rep;
294         fd_set read_mask;
295
296         FD_ZERO(&read_mask);
297         FD_SET(fd, &read_mask);
298
299         for (i = 0; i < timeout; i++) {
300                 retval = audit_get_reply(fd, &rep, GET_REPLY_NONBLOCKING, 0);
301                 if (retval > 0) {
302                         struct timeval t;
303
304                         if (rep.type == NLMSG_ERROR && 
305                                         rep.error->error == 0)
306                                 continue;
307                         t.tv_sec  = 0;
308                         t.tv_usec = 100000; /* .1 second */
309                         do {
310                                 retval=select(fd+1, &read_mask, NULL, NULL, &t);
311                         } while (retval < 0 && errno == EINTR);
312                         switch (rep.type)
313                         {
314                                 case NLMSG_DONE:
315                                         return count;
316                                 case AUDIT_LIST_RULES:
317                                         i = 0;
318                                         count++;
319                                         break;
320                                 case NLMSG_ERROR:
321                                         return -1;
322                                 default:
323                                         break;
324                         }
325                 }
326         }
327         return count;
328 }
329