ujail: rework fs jail part
[project/procd.git] / jail / fs.c
1 /*
2 * Copyright (C) 2015 John Crispin <blogic@openwrt.org>
3 * Copyright (C) 2015 Etienne Champetier <champetier.etienne@gmail.com>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU Lesser General Public License version 2.1
7 * as published by the Free Software Foundation
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 */
14
15 #define _GNU_SOURCE
16
17 #include <assert.h>
18 #include <elf.h>
19 #include <errno.h>
20 #include <fcntl.h>
21 #include <linux/limits.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include <sys/stat.h>
25 #include <sys/mman.h>
26 #include <unistd.h>
27
28 #include <libubox/avl.h>
29 #include <libubox/avl-cmp.h>
30
31 #include "elf.h"
32 #include "fs.h"
33 #include "jail.h"
34 #include "log.h"
35
36 struct mount {
37 struct avl_node avl;
38 const char *path;
39 int readonly;
40 int error;
41 };
42
43 struct avl_tree mounts;
44
45 int add_mount(const char *path, int readonly, int error)
46 {
47 assert(path != NULL);
48
49 if (avl_find(&mounts, path))
50 return 1;
51
52 struct mount *m;
53 m = calloc(1, sizeof(struct mount));
54 assert(m != NULL);
55 m->avl.key = m->path = strdup(path);
56 m->readonly = readonly;
57 m->error = error;
58
59 avl_insert(&mounts, &m->avl);
60 DEBUG("adding mount %s ro(%d) err(%d)\n", m->path, m->readonly, m->error != 0);
61 return 0;
62 }
63
64 int mount_all(const char *jailroot) {
65 struct library *l;
66 struct mount *m;
67
68 avl_for_each_element(&libraries, l, avl)
69 add_mount(l->path, 1, -1);
70
71 avl_for_each_element(&mounts, m, avl)
72 if (mount_bind(jailroot, m->path, m->readonly, m->error))
73 return -1;
74
75 return 0;
76 }
77
78 void mount_list_init(void) {
79 avl_init(&mounts, avl_strcmp, false, NULL);
80 }
81
82 int add_path_and_deps(const char *path, int readonly, int error, int lib)
83 {
84 assert(path != NULL);
85
86 if (lib == 0 && path[0] != '/') {
87 ERROR("%s is not an absolute path\n", path);
88 return error;
89 }
90
91 char *map = NULL;
92 int fd, ret = -1;
93 if (path[0] == '/') {
94 if (avl_find(&mounts, path))
95 return 0;
96 fd = open(path, O_RDONLY);
97 if (fd == -1)
98 return error;
99 add_mount(path, readonly, error);
100 } else {
101 if (avl_find(&libraries, path))
102 return 0;
103 char *fullpath;
104 fd = lib_open(&fullpath, path);
105 if (fd == -1)
106 return error;
107 if (fullpath) {
108 alloc_library(fullpath, path);
109 free(fullpath);
110 }
111 }
112
113 struct stat s;
114 if (fstat(fd, &s) == -1) {
115 ERROR("fstat(%s) failed: %s\n", path, strerror(errno));
116 ret = error;
117 goto out;
118 }
119
120 if (!S_ISREG(s.st_mode)) {
121 ret = 0;
122 goto out;
123 }
124
125 /* too small to be an ELF or a script -> "normal" file */
126 if (s.st_size < 4) {
127 ret = 0;
128 goto out;
129 }
130
131 map = mmap(NULL, s.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
132 if (map == MAP_FAILED) {
133 ERROR("failed to mmap %s\n", path);
134 ret = -1;
135 goto out;
136 }
137
138 if (map[0] == ELFMAG0 && map[1] == ELFMAG1 && map[2] == ELFMAG2 && map[3] == ELFMAG3) {
139 ret = elf_load_deps(path, map);
140 goto out;
141 }
142
143 ret = 0;
144
145 out:
146 if (fd >= 0)
147 close(fd);
148 if (map)
149 munmap(map, s.st_size);
150
151 return ret;
152 }