split up constants.h some
[trinity.git] / fd-files.c
blobea0f0d84997fe4fb629f96451665908ded9978f0
1 #include <ftw.h>
2 #include <stdio.h>
3 #include <stdlib.h>
4 #include <string.h>
5 #include <unistd.h>
6 #include <fcntl.h>
7 #include <dirent.h>
8 #include <errno.h>
9 #include <sys/types.h>
10 #include <sys/stat.h>
12 #include "trinity.h" // __unused__
13 #include "arch.h" // page_size
14 #include "constants.h"
15 #include "files.h"
16 #include "list.h"
17 #include "log.h"
18 #include "maps.h"
19 #include "params.h"
20 #include "random.h"
21 #include "shm.h"
22 #include "sanitise.h"
23 #include "uid.h"
24 #include "utils.h"
26 static int files_added = 0;
27 const char **fileindex;
28 unsigned int files_in_index = 0;
29 unsigned int nr_file_fds = 0;
31 struct namelist {
32 struct list_head list;
33 const char *name;
36 static struct namelist *names = NULL;
38 static int ignore_files(const char *path)
40 unsigned int i, j;
41 unsigned int pathlen, offset = 0;
43 /* These are exact matches. */
44 const char *ignored_paths[] = {
45 ".", "..",
47 /* dangerous/noisy/annoying stuff in /proc */
48 "/proc/sysrq-trigger", "/proc/kmem", "/proc/kcore",
50 /* dangerous/noisy/annoying stuff in /dev */
51 "/dev/log", "/dev/mem", "/dev/kmsg",
52 NULL
55 /* Partial matches. */ //FIXME: This whole function should just use globs to pattern match.
56 const char *ignored_patterns[] = {
58 /* dangerous/noisy/annoying per-process stuff. */
59 "coredump_filter", "make-it-fail", "oom_adj", "oom_score_adj",
60 NULL
63 pathlen = strlen(path);
65 /* First do the exact matches */
66 for (i = 0; ignored_paths[i]; i++) {
67 if (strlen(ignored_paths[i]) != pathlen) {
68 continue;
71 if (!strcmp(path, ignored_paths[i])) {
72 debugf("Skipping %s\n", path);
73 return 1;
77 /* Now make sure none of the patterns match the end of the pathname */
78 for (j = 0; j < pathlen; j++) {
79 if (path[j] == '/')
80 offset = j;
82 offset++;
84 if (offset == 1)
85 return 0;
87 for (i = 0; ignored_patterns[i]; i++) {
88 if (!strcmp(path + offset, ignored_patterns[i])) {
89 debugf("Skipping pattern %s\n", path);
90 return 1;
94 /* special case to match tty* until I do globbing */
95 if (!strncmp(path + offset, "tty", 3)) {
96 debugf("Skipping %s\n", path);
97 return 1;
99 return 0;
102 static void add_to_namelist(const char *name)
104 struct namelist *newnode;
105 struct list_head *list = (struct list_head *) names;
107 newnode = zmalloc(sizeof(struct namelist));
108 newnode->name = strdup(name);
109 list_add_tail(&newnode->list, list);
112 static int check_stat_file(const struct stat *sb)
114 int openflag;
115 bool set_read = FALSE;
116 bool set_write = FALSE;
117 uid_t target_uid = orig_uid;
118 gid_t target_gid = orig_gid;
120 if (dropprivs == TRUE) {
121 target_uid = nobody_uid;
122 target_gid = nobody_gid;
125 if (S_ISLNK(sb->st_mode))
126 return -1;
128 if (sb->st_uid == target_uid) {
129 if (sb->st_mode & S_IRUSR)
130 set_read = TRUE;
131 if (sb->st_mode & S_IWUSR)
132 set_write = TRUE;
135 if (sb->st_gid == target_gid) {
136 if (sb->st_mode & S_IRGRP)
137 set_read = TRUE;
138 if (sb->st_mode & S_IWGRP)
139 set_write = TRUE;
142 if (sb->st_mode & S_IROTH)
143 set_read = TRUE;
144 if (sb->st_mode & S_IWOTH)
145 set_write = TRUE;
148 if ((set_read | set_write) == 0)
149 return -1;
151 if (set_read == TRUE)
152 openflag = O_RDONLY;
153 if (set_write == TRUE)
154 openflag = O_WRONLY;
155 if ((set_read == TRUE) && (set_write == TRUE))
156 openflag = O_RDWR;
158 if (S_ISDIR(sb->st_mode))
159 openflag = O_RDONLY;
161 return openflag;
164 static int file_tree_callback(const char *fpath, const struct stat *sb, __unused__ int typeflag, __unused__ struct FTW *ftwbuf)
167 if (ignore_files(fpath)) {
168 return FTW_SKIP_SUBTREE;
171 // Check we can read it.
172 if (check_stat_file(sb) == -1)
173 return FTW_CONTINUE;
175 if (shm->exit_reason != STILL_RUNNING)
176 return FTW_STOP;
178 add_to_namelist(fpath);
179 files_added++;
181 return FTW_CONTINUE;
185 static void open_fds(const char *dirpath)
187 int before = files_added;
188 int flags = FTW_DEPTH | FTW_ACTIONRETVAL | FTW_MOUNT;
189 int ret;
191 /* By default, don't follow symlinks so we only get each file once.
192 * But, if we do something like -V /lib, then follow it
194 * I'm not sure about this, might remove later.
196 if (victim_path == NULL)
197 flags |= FTW_PHYS;
199 ret = nftw(dirpath, file_tree_callback, 32, flags);
200 if (ret != 0) {
201 if (shm->exit_reason != EXIT_SIGINT)
202 output(0, "Something went wrong during nftw(%s). (%d:%s)\n",
203 dirpath, ret, strerror(errno));
204 return;
207 output(0, "Added %d filenames from %s\n", files_added - before, dirpath);
210 static void generate_filelist(void)
212 unsigned int i = 0;
213 struct list_head *node;
214 struct namelist *nl;
216 names = zmalloc(sizeof(struct namelist));
217 INIT_LIST_HEAD(&names->list);
219 output(1, "Generating file descriptors\n");
221 if (victim_path != NULL) {
222 open_fds(victim_path);
223 } else {
224 open_fds("/dev");
225 open_fds("/proc");
226 open_fds("/sys");
229 if (shm->exit_reason != STILL_RUNNING)
230 return;
232 if (files_added == 0) {
233 output(1, "Didn't add any files!!\n");
234 return;
237 /* Generate an index of pointers to the filenames */
239 fileindex = malloc(sizeof(char *) * files_added);
241 list_for_each(node, &names->list) {
242 nl = (struct namelist *) node;
243 fileindex[i++] = nl->name;
245 files_in_index = i;
248 static int open_file(void)
250 int fd;
251 int ret;
252 int tries = 0;
253 const char *filename;
254 int flags, randflags;
255 const char *modestr;
256 struct stat sb;
258 retry:
259 filename = get_filename();
260 ret = lstat(filename, &sb);
261 if (ret == -1)
262 goto retry;
264 flags = check_stat_file(&sb);
265 if (flags == -1)
266 goto retry;
268 /* OR in some random flags. */
269 retry_flags:
270 randflags = get_o_flags();
272 fd = open(filename, flags | randflags | O_NONBLOCK);
273 if (fd < 0) {
275 * if we failed to open the file, retry with different flags.
276 * we should eventually succeed, but set an arbitary upper limit of
277 * 50 tries before just giving up.
279 tries++;
280 if (tries == 50) {
281 output(2, "Couldn't open %s : %s\n", filename, strerror(errno));
282 return fd;
284 goto retry_flags;
287 switch (flags) {
288 case O_RDONLY: modestr = "read-only"; break;
289 case O_WRONLY: modestr = "write-only"; break;
290 case O_RDWR: modestr = "read-write"; break;
291 default: modestr = "unknown"; break;
293 output(2, "fd[%i] = %s (%s) flags:%x\n", fd, filename, modestr, randflags);
294 return fd;
297 int open_files(void)
299 unsigned int i, nr_to_open;
301 generate_filelist();
303 if (files_in_index == 0) /* Something bad happened. Crappy -V maybe? */
304 return FALSE; // FIXME: We should log something here probably.
306 if (files_in_index < NR_FILE_FDS)
307 nr_to_open = files_in_index;
308 else
309 nr_to_open = NR_FILE_FDS;
311 if (fileindex == NULL) /* this can happen if we ctrl-c'd */
312 return FALSE;
314 for (i = 0; i < nr_to_open; i++) {
315 int fd;
317 fd = open_file();
319 shm->file_fds[i] = fd;
320 nr_file_fds++;
322 return TRUE;
325 void close_files(void)
327 unsigned int i;
329 shm->current_fd = 0;
330 shm->fd_lifetime = 0;
332 // FIXME: Does this need locking? At the least, check for NULL fd's
333 for (i = 0; i < nr_file_fds; i++) {
334 int fd;
336 fd = shm->file_fds[i];
337 shm->file_fds[i] = 0;
338 if (fd != 0)
339 close(fd);
342 nr_file_fds = 0;
345 const char * get_filename(void)
347 if (files_in_index == 0) /* This can happen if we run with -n. Should we do something else ? */
348 return NULL;
350 return fileindex[rand() % files_in_index];
353 int rand_file_fd(void)
355 unsigned int fd_index;
357 fd_index = rand() % nr_file_fds;
358 return shm->file_fds[fd_index];