Commit | Line | Data |
---|---|---|
1cac41cb MB |
1 | /* |
2 | * fs/sdcardfs/packagelist.c | |
3 | * | |
4 | * Copyright (c) 2013 Samsung Electronics Co. Ltd | |
5 | * Authors: Daeho Jeong, Woojoong Lee, Seunghwan Hyun, | |
6 | * Sunghwan Yun, Sungjong Seo | |
7 | * | |
8 | * This program has been developed as a stackable file system based on | |
9 | * the WrapFS which written by | |
10 | * | |
11 | * Copyright (c) 1998-2011 Erez Zadok | |
12 | * Copyright (c) 2009 Shrikar Archak | |
13 | * Copyright (c) 2003-2011 Stony Brook University | |
14 | * Copyright (c) 2003-2011 The Research Foundation of SUNY | |
15 | * | |
16 | * This file is dual licensed. It may be redistributed and/or modified | |
17 | * under the terms of the Apache 2.0 License OR version 2 of the GNU | |
18 | * General Public License. | |
19 | */ | |
20 | ||
21 | #include "sdcardfs.h" | |
22 | #include <linux/syscalls.h> | |
23 | #include <linux/kthread.h> | |
24 | #include <linux/inotify.h> | |
25 | #include <linux/delay.h> | |
26 | ||
27 | struct hashtable_entry { | |
28 | struct hlist_node hlist; | |
29 | void *key; | |
30 | unsigned int value; | |
31 | }; | |
32 | ||
33 | static struct kmem_cache *hashtable_entry_cachep; | |
34 | ||
35 | /* Path to system-provided mapping of package name to appIds */ | |
36 | static const char *const kpackageslist_file = "/data/system/packages.list"; | |
37 | /* Supplementary groups to execute with */ | |
38 | static const gid_t kgroups[1] = { AID_PACKAGE_INFO }; | |
39 | ||
40 | static unsigned int str_hash(void *key) | |
41 | { | |
42 | int i; | |
43 | unsigned int h = strlen(key); | |
44 | char *data = (char *)key; | |
45 | ||
46 | for (i = 0; i < strlen(key); i++) { | |
47 | h = h * 31 + *data; | |
48 | data++; | |
49 | } | |
50 | return h; | |
51 | } | |
52 | ||
53 | appid_t get_appid(void *pkgl_id, const char *app_name) | |
54 | { | |
55 | struct packagelist_data *pkgl_dat = (struct packagelist_data *)pkgl_id; | |
56 | struct hashtable_entry *hash_cur; | |
57 | unsigned int hash = str_hash((void *)app_name); | |
58 | appid_t ret_id; | |
59 | ||
60 | //printk(KERN_INFO "sdcardfs: %s: %s, %u\n", __func__, (char *)app_name, hash); | |
61 | mutex_lock(&pkgl_dat->hashtable_lock); | |
62 | hash_for_each_possible(pkgl_dat->package_to_appid, hash_cur, hlist, hash) { | |
63 | //printk(KERN_INFO "sdcardfs: %s: %s\n", __func__, (char *)hash_cur->key); | |
64 | if (!strcasecmp(app_name, hash_cur->key)) { | |
65 | ret_id = (appid_t)hash_cur->value; | |
66 | mutex_unlock(&pkgl_dat->hashtable_lock); | |
67 | //printk(KERN_INFO "=> app_id: %d\n", (int)ret_id); | |
68 | return ret_id; | |
69 | } | |
70 | } | |
71 | mutex_unlock(&pkgl_dat->hashtable_lock); | |
72 | //printk(KERN_INFO "=> app_id: %d\n", 0); | |
73 | return 0; | |
74 | } | |
75 | ||
76 | /* Kernel has already enforced everything we returned through | |
77 | * derive_permissions_locked(), so this is used to lock down access | |
78 | * even further, such as enforcing that apps hold sdcard_rw. */ | |
79 | int check_caller_access_to_name(struct inode *parent_node, const char *name) | |
80 | { | |
81 | /* Always block security-sensitive files at root */ | |
82 | if (parent_node && SDCARDFS_I(parent_node)->perm == PERM_ROOT) { | |
83 | if (!strcasecmp(name, "autorun.inf") | |
84 | || !strcasecmp(name, ".android_secure") | |
85 | || !strcasecmp(name, "android_secure")) { | |
86 | return 0; | |
87 | } | |
88 | } | |
89 | ||
90 | /* Root always has access; access for any other UIDs should always | |
91 | * be controlled through packages.list. */ | |
92 | if (uid_eq(current_fsuid(), make_kuid(current_user_ns(), 0))) { | |
93 | return 1; | |
94 | } | |
95 | ||
96 | /* No extra permissions to enforce */ | |
97 | return 1; | |
98 | } | |
99 | ||
100 | /* This function is used when file opening. The open flags must be | |
101 | * checked before calling check_caller_access_to_name() */ | |
102 | int open_flags_to_access_mode(int open_flags) | |
103 | { | |
104 | if ((open_flags & O_ACCMODE) == O_RDONLY) { | |
105 | return 0; /* R_OK */ | |
106 | } else if ((open_flags & O_ACCMODE) == O_WRONLY) { | |
107 | return 1; /* W_OK */ | |
108 | } else { | |
109 | /* Probably O_RDRW, but treat as default to be safe */ | |
110 | return 1; /* R_OK | W_OK */ | |
111 | } | |
112 | } | |
113 | ||
114 | static int insert_str_to_int(struct packagelist_data *pkgl_dat, void *key, int value) | |
115 | { | |
116 | struct hashtable_entry *hash_cur; | |
117 | struct hashtable_entry *new_entry; | |
118 | unsigned int hash = str_hash(key); | |
119 | ||
120 | //printk(KERN_INFO "sdcardfs: %s: %s: %d, %u\n", __func__, (char *)key, value, hash); | |
121 | hash_for_each_possible(pkgl_dat->package_to_appid, hash_cur, hlist, hash) { | |
122 | if (!strcasecmp(key, hash_cur->key)) { | |
123 | hash_cur->value = value; | |
124 | return 0; | |
125 | } | |
126 | } | |
127 | new_entry = kmem_cache_alloc(hashtable_entry_cachep, GFP_KERNEL); | |
128 | if (!new_entry) | |
129 | return -ENOMEM; | |
130 | new_entry->key = kstrdup(key, GFP_KERNEL); | |
131 | new_entry->value = value; | |
132 | hash_add(pkgl_dat->package_to_appid, &new_entry->hlist, hash); | |
133 | return 0; | |
134 | } | |
135 | ||
136 | static void remove_str_to_int(struct hashtable_entry *h_entry) | |
137 | { | |
138 | //printk(KERN_INFO "sdcardfs: %s: %s: %d\n", __func__, (char *)h_entry->key, h_entry->value); | |
139 | kfree(h_entry->key); | |
140 | kmem_cache_free(hashtable_entry_cachep, h_entry); | |
141 | } | |
142 | ||
143 | /*static void remove_int_to_null(struct hashtable_entry *h_entry) { | |
144 | //printk(KERN_INFO "sdcardfs: %s: %d: %d\n", __func__, (int)h_entry->key, h_entry->value); | |
145 | kmem_cache_free(hashtable_entry_cachep, h_entry); | |
146 | }*/ | |
147 | ||
148 | static void remove_all_hashentrys(struct packagelist_data *pkgl_dat) | |
149 | { | |
150 | struct hashtable_entry *hash_cur; | |
151 | struct hlist_node *h_t; | |
152 | int i; | |
153 | ||
154 | hash_for_each_safe(pkgl_dat->package_to_appid, i, h_t, hash_cur, hlist) | |
155 | remove_str_to_int(hash_cur); | |
156 | ||
157 | hash_init(pkgl_dat->package_to_appid); | |
158 | } | |
159 | ||
160 | static int read_package_list(struct packagelist_data *pkgl_dat) | |
161 | { | |
162 | int ret; | |
163 | int fd; | |
164 | int read_amount; | |
165 | ||
166 | printk(KERN_INFO "sdcardfs: read_package_list\n"); | |
167 | ||
168 | mutex_lock(&pkgl_dat->hashtable_lock); | |
169 | ||
170 | remove_all_hashentrys(pkgl_dat); | |
171 | ||
172 | fd = sys_open(kpackageslist_file, O_RDONLY, 0); | |
173 | if (fd < 0) { | |
174 | printk(KERN_ERR "sdcardfs: failed to open package list\n"); | |
175 | mutex_unlock(&pkgl_dat->hashtable_lock); | |
176 | return fd; | |
177 | } | |
178 | ||
179 | while ((read_amount = sys_read(fd, pkgl_dat->read_buf, | |
180 | sizeof(pkgl_dat->read_buf))) > 0) { | |
181 | int appid; | |
182 | int one_line_len = 0; | |
183 | int additional_read; | |
184 | ||
185 | while (one_line_len < read_amount) { | |
186 | if (pkgl_dat->read_buf[one_line_len] == '\n') { | |
187 | one_line_len++; | |
188 | break; | |
189 | } | |
190 | one_line_len++; | |
191 | } | |
192 | additional_read = read_amount - one_line_len; | |
193 | if (additional_read > 0) | |
194 | sys_lseek(fd, -additional_read, SEEK_CUR); | |
195 | ||
196 | if (sscanf(pkgl_dat->read_buf, "%s %d %*d %*s %*s %s", | |
197 | pkgl_dat->app_name_buf, &appid, | |
198 | pkgl_dat->gids_buf) == 3) { | |
199 | ret = insert_str_to_int(pkgl_dat, pkgl_dat->app_name_buf, appid); | |
200 | if (ret) { | |
201 | sys_close(fd); | |
202 | mutex_unlock(&pkgl_dat->hashtable_lock); | |
203 | return ret; | |
204 | } | |
205 | } | |
206 | } | |
207 | ||
208 | sys_close(fd); | |
209 | mutex_unlock(&pkgl_dat->hashtable_lock); | |
210 | return 0; | |
211 | } | |
212 | ||
213 | static int packagelist_reader(void *thread_data) | |
214 | { | |
215 | struct packagelist_data *pkgl_dat = (struct packagelist_data *)thread_data; | |
216 | struct inotify_event *event; | |
217 | bool active = false; | |
218 | int event_pos; | |
219 | int event_size; | |
220 | int res = 0; | |
221 | int nfd; | |
222 | ||
223 | allow_signal(SIGINT); | |
224 | ||
225 | nfd = sys_inotify_init(); | |
226 | if (nfd < 0) { | |
227 | printk(KERN_ERR "sdcardfs: inotify_init failed: %d\n", nfd); | |
228 | return nfd; | |
229 | } | |
230 | ||
231 | while (!kthread_should_stop()) { | |
232 | if (signal_pending(current)) { | |
233 | msleep(100); | |
234 | continue; | |
235 | } | |
236 | ||
237 | if (!active) { | |
238 | res = sys_inotify_add_watch(nfd, kpackageslist_file, IN_DELETE_SELF); | |
239 | if (res < 0) { | |
240 | if (res == -ENOENT || res == -EACCES) { | |
241 | /* Framework may not have created yet, sleep and retry */ | |
242 | printk(KERN_ERR "sdcardfs: missing packages.list; retrying\n"); | |
243 | ssleep(2); | |
244 | printk(KERN_ERR "sdcardfs: missing packages.list_end; retrying\n"); | |
245 | continue; | |
246 | } else { | |
247 | printk(KERN_ERR "sdcardfs: inotify_add_watch failed: %d\n", res); | |
248 | goto interruptable_sleep; | |
249 | } | |
250 | } | |
251 | /* Watch above will tell us about any future changes, so | |
252 | * read the current state. */ | |
253 | res = read_package_list(pkgl_dat); | |
254 | if (res) { | |
255 | printk(KERN_ERR "sdcardfs: read_package_list failed: %d\n", res); | |
256 | goto interruptable_sleep; | |
257 | } | |
258 | active = true; | |
259 | atomic_set(&pkgl_dat->newly_created, 1); | |
260 | } | |
261 | ||
262 | event_pos = 0; | |
263 | res = sys_read(nfd, pkgl_dat->event_buf, sizeof(pkgl_dat->event_buf)); | |
264 | if (res < (int) sizeof(*event)) { | |
265 | if (res == -EINTR) | |
266 | continue; | |
267 | printk(KERN_ERR "sdcardfs: failed to read inotify event: %d\n", res); | |
268 | goto interruptable_sleep; | |
269 | } | |
270 | ||
271 | while (res >= (int) sizeof(*event)) { | |
272 | event = (struct inotify_event *) (pkgl_dat->event_buf + event_pos); | |
273 | ||
274 | printk(KERN_INFO "sdcardfs: inotify event: %08x\n", event->mask); | |
275 | if ((event->mask & IN_IGNORED) == IN_IGNORED) { | |
276 | /* Previously watched file was deleted, probably due to move | |
277 | * that swapped in new data; re-arm the watch and read. */ | |
278 | active = false; | |
279 | } | |
280 | ||
281 | event_size = sizeof(*event) + event->len; | |
282 | res -= event_size; | |
283 | event_pos += event_size; | |
284 | } | |
285 | continue; | |
286 | ||
287 | interruptable_sleep: | |
288 | set_current_state(TASK_INTERRUPTIBLE); | |
289 | schedule(); | |
290 | } | |
291 | flush_signals(current); | |
292 | sys_close(nfd); | |
293 | return res; | |
294 | } | |
295 | ||
296 | void *packagelist_create(void) | |
297 | { | |
298 | struct packagelist_data *pkgl_dat; | |
299 | struct task_struct *packagelist_thread; | |
300 | ||
301 | pkgl_dat = kmalloc(sizeof(*pkgl_dat), GFP_KERNEL | __GFP_ZERO); | |
302 | if (!pkgl_dat) { | |
303 | printk(KERN_ERR "sdcardfs: creating kthread failed\n"); | |
304 | return ERR_PTR(-ENOMEM); | |
305 | } | |
306 | ||
307 | mutex_init(&pkgl_dat->hashtable_lock); | |
308 | hash_init(pkgl_dat->package_to_appid); | |
309 | ||
310 | packagelist_thread = kthread_run(packagelist_reader, (void *)pkgl_dat, "pkgld"); | |
311 | if (IS_ERR(packagelist_thread)) { | |
312 | printk(KERN_ERR "sdcardfs: creating kthread failed\n"); | |
313 | kfree(pkgl_dat); | |
314 | return packagelist_thread; | |
315 | } | |
316 | pkgl_dat->thread_id = packagelist_thread; | |
317 | ||
318 | printk(KERN_INFO "sdcardfs: created packagelist pkgld/%d\n", | |
319 | (int)pkgl_dat->thread_id->pid); | |
320 | ||
321 | return (void *)pkgl_dat; | |
322 | } | |
323 | ||
324 | void packagelist_destroy(void *pkgl_id) | |
325 | { | |
326 | struct packagelist_data *pkgl_dat = (struct packagelist_data *)pkgl_id; | |
327 | pid_t pkgl_pid = pkgl_dat->thread_id->pid; | |
328 | ||
329 | force_sig_info(SIGINT, SEND_SIG_PRIV, pkgl_dat->thread_id); | |
330 | kthread_stop(pkgl_dat->thread_id); | |
331 | remove_all_hashentrys(pkgl_dat); | |
332 | printk(KERN_INFO "sdcardfs: destroyed packagelist pkgld/%d\n", (int)pkgl_pid); | |
333 | kfree(pkgl_dat); | |
334 | } | |
335 | ||
336 | int packagelist_init(void) | |
337 | { | |
338 | hashtable_entry_cachep = | |
339 | kmem_cache_create("packagelist_hashtable_entry", | |
340 | sizeof(struct hashtable_entry), 0, 0, NULL); | |
341 | if (!hashtable_entry_cachep) { | |
342 | printk(KERN_ERR "sdcardfs: failed creating pkgl_hashtable entry slab cache\n"); | |
343 | return -ENOMEM; | |
344 | } | |
345 | ||
346 | return 0; | |
347 | } | |
348 | ||
349 | void packagelist_exit(void) | |
350 | { | |
351 | if (hashtable_entry_cachep) | |
352 | kmem_cache_destroy(hashtable_entry_cachep); | |
353 | } |