blob: f11591da141df35c767d73ef9225575dbd9634b7 [file] [log] [blame]
Daniel Campello35c9e242015-07-20 16:23:50 -07001/*
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 "strtok.h"
Daniel Campellod1d080c2015-07-20 16:27:37 -070023#include <linux/hashtable.h>
Daniel Campello35c9e242015-07-20 16:23:50 -070024#include <linux/syscalls.h>
25#include <linux/kthread.h>
26#include <linux/inotify.h>
27#include <linux/delay.h>
28
29#define STRING_BUF_SIZE (512)
30
31struct hashtable_entry {
Daniel Campellod1d080c2015-07-20 16:27:37 -070032 struct hlist_node hlist;
33 void *key;
Daniel Campello5d3b4162015-07-20 16:33:46 -070034 unsigned int value;
Daniel Campello35c9e242015-07-20 16:23:50 -070035};
36
37struct packagelist_data {
38 DECLARE_HASHTABLE(package_to_appid,8);
39 DECLARE_HASHTABLE(appid_with_rw,7);
40 struct mutex hashtable_lock;
41 struct task_struct *thread_id;
42 gid_t write_gid;
43 char *strtok_last;
44 char read_buf[STRING_BUF_SIZE];
45 char event_buf[STRING_BUF_SIZE];
46 char app_name_buf[STRING_BUF_SIZE];
47 char gids_buf[STRING_BUF_SIZE];
48};
49
50static struct kmem_cache *hashtable_entry_cachep;
51
52/* Path to system-provided mapping of package name to appIds */
53static const char* const kpackageslist_file = "/data/system/packages.list";
54/* Supplementary groups to execute with */
55static const gid_t kgroups[1] = { AID_PACKAGE_INFO };
56
Daniel Campello5d3b4162015-07-20 16:33:46 -070057static unsigned int str_hash(const char *key) {
Daniel Campello35c9e242015-07-20 16:23:50 -070058 int i;
59 unsigned int h = strlen(key);
60 char *data = (char *)key;
61
62 for (i = 0; i < strlen(key); i++) {
63 h = h * 31 + *data;
64 data++;
65 }
66 return h;
67}
68
Daniel Campello5d3b4162015-07-20 16:33:46 -070069static int contain_appid_key(struct packagelist_data *pkgl_dat, unsigned int appid) {
Daniel Campellod1d080c2015-07-20 16:27:37 -070070 struct hashtable_entry *hash_cur;
Daniel Campello35c9e242015-07-20 16:23:50 -070071
Daniel Campello5d3b4162015-07-20 16:33:46 -070072 hash_for_each_possible(pkgl_dat->appid_with_rw, hash_cur, hlist, appid)
73 if ((void *)(uintptr_t)appid == hash_cur->key)
Daniel Campellod1d080c2015-07-20 16:27:37 -070074 return 1;
Daniel Campello5d3b4162015-07-20 16:33:46 -070075
Daniel Campello35c9e242015-07-20 16:23:50 -070076 return 0;
77}
78
79/* Return if the calling UID holds sdcard_rw. */
80int get_caller_has_rw_locked(void *pkgl_id, derive_t derive) {
81 struct packagelist_data *pkgl_dat = (struct packagelist_data *)pkgl_id;
82 appid_t appid;
83 int ret;
84
85 /* No additional permissions enforcement */
86 if (derive == DERIVE_NONE) {
87 return 1;
88 }
89
Daniel Campellod1d080c2015-07-20 16:27:37 -070090 appid = multiuser_get_app_id(from_kuid(&init_user_ns, current_fsuid()));
Daniel Campello35c9e242015-07-20 16:23:50 -070091 mutex_lock(&pkgl_dat->hashtable_lock);
Daniel Campello5d3b4162015-07-20 16:33:46 -070092 ret = contain_appid_key(pkgl_dat, appid);
Daniel Campello35c9e242015-07-20 16:23:50 -070093 mutex_unlock(&pkgl_dat->hashtable_lock);
94 return ret;
95}
96
97appid_t get_appid(void *pkgl_id, const char *app_name)
98{
99 struct packagelist_data *pkgl_dat = (struct packagelist_data *)pkgl_id;
100 struct hashtable_entry *hash_cur;
Daniel Campello5d3b4162015-07-20 16:33:46 -0700101 unsigned int hash = str_hash(app_name);
Daniel Campello35c9e242015-07-20 16:23:50 -0700102 appid_t ret_id;
103
104 //printk(KERN_INFO "sdcardfs: %s: %s, %u\n", __func__, (char *)app_name, hash);
105 mutex_lock(&pkgl_dat->hashtable_lock);
Daniel Campellod1d080c2015-07-20 16:27:37 -0700106 hash_for_each_possible(pkgl_dat->package_to_appid, hash_cur, hlist, hash) {
Daniel Campello35c9e242015-07-20 16:23:50 -0700107 //printk(KERN_INFO "sdcardfs: %s: %s\n", __func__, (char *)hash_cur->key);
108 if (!strcasecmp(app_name, hash_cur->key)) {
109 ret_id = (appid_t)hash_cur->value;
110 mutex_unlock(&pkgl_dat->hashtable_lock);
111 //printk(KERN_INFO "=> app_id: %d\n", (int)ret_id);
112 return ret_id;
113 }
114 }
115 mutex_unlock(&pkgl_dat->hashtable_lock);
116 //printk(KERN_INFO "=> app_id: %d\n", 0);
117 return 0;
118}
119
120/* Kernel has already enforced everything we returned through
121 * derive_permissions_locked(), so this is used to lock down access
122 * even further, such as enforcing that apps hold sdcard_rw. */
123int check_caller_access_to_name(struct inode *parent_node, const char* name,
124 derive_t derive, int w_ok, int has_rw) {
125
126 /* Always block security-sensitive files at root */
127 if (parent_node && SDCARDFS_I(parent_node)->perm == PERM_ROOT) {
128 if (!strcasecmp(name, "autorun.inf")
129 || !strcasecmp(name, ".android_secure")
130 || !strcasecmp(name, "android_secure")) {
131 return 0;
132 }
133 }
134
135 /* No additional permissions enforcement */
136 if (derive == DERIVE_NONE) {
137 return 1;
138 }
139
140 /* Root always has access; access for any other UIDs should always
141 * be controlled through packages.list. */
Daniel Campellod1d080c2015-07-20 16:27:37 -0700142 if (from_kuid(&init_user_ns, current_fsuid()) == 0) {
Daniel Campello35c9e242015-07-20 16:23:50 -0700143 return 1;
144 }
145
146 /* If asking to write, verify that caller either owns the
147 * parent or holds sdcard_rw. */
148 if (w_ok) {
149 if (parent_node &&
Daniel Campellod1d080c2015-07-20 16:27:37 -0700150 (from_kuid(&init_user_ns, current_fsuid()) ==
151 SDCARDFS_I(parent_node)->d_uid)) {
Daniel Campello35c9e242015-07-20 16:23:50 -0700152 return 1;
153 }
154 return has_rw;
155 }
156
157 /* No extra permissions to enforce */
158 return 1;
159}
160
161/* This function is used when file opening. The open flags must be
162 * checked before calling check_caller_access_to_name() */
163int open_flags_to_access_mode(int open_flags) {
164 if((open_flags & O_ACCMODE) == O_RDONLY) {
165 return 0; /* R_OK */
166 } else if ((open_flags & O_ACCMODE) == O_WRONLY) {
167 return 1; /* W_OK */
168 } else {
169 /* Probably O_RDRW, but treat as default to be safe */
170 return 1; /* R_OK | W_OK */
171 }
172}
173
Daniel Campello5d3b4162015-07-20 16:33:46 -0700174static int insert_str_to_int(struct packagelist_data *pkgl_dat, char *key,
175 unsigned int value)
176{
Daniel Campello35c9e242015-07-20 16:23:50 -0700177 struct hashtable_entry *hash_cur;
178 struct hashtable_entry *new_entry;
Daniel Campello35c9e242015-07-20 16:23:50 -0700179 unsigned int hash = str_hash(key);
180
181 //printk(KERN_INFO "sdcardfs: %s: %s: %d, %u\n", __func__, (char *)key, value, hash);
Daniel Campellod1d080c2015-07-20 16:27:37 -0700182 hash_for_each_possible(pkgl_dat->package_to_appid, hash_cur, hlist, hash) {
Daniel Campello35c9e242015-07-20 16:23:50 -0700183 if (!strcasecmp(key, hash_cur->key)) {
184 hash_cur->value = value;
185 return 0;
186 }
187 }
188 new_entry = kmem_cache_alloc(hashtable_entry_cachep, GFP_KERNEL);
189 if (!new_entry)
190 return -ENOMEM;
191 new_entry->key = kstrdup(key, GFP_KERNEL);
192 new_entry->value = value;
193 hash_add(pkgl_dat->package_to_appid, &new_entry->hlist, hash);
194 return 0;
195}
196
197static void remove_str_to_int(struct hashtable_entry *h_entry) {
198 //printk(KERN_INFO "sdcardfs: %s: %s: %d\n", __func__, (char *)h_entry->key, h_entry->value);
199 kfree(h_entry->key);
200 kmem_cache_free(hashtable_entry_cachep, h_entry);
201}
202
Daniel Campello5d3b4162015-07-20 16:33:46 -0700203static int insert_int_to_null(struct packagelist_data *pkgl_dat, unsigned int key,
204 unsigned int value)
205{
Daniel Campello35c9e242015-07-20 16:23:50 -0700206 struct hashtable_entry *hash_cur;
207 struct hashtable_entry *new_entry;
Daniel Campello35c9e242015-07-20 16:23:50 -0700208
209 //printk(KERN_INFO "sdcardfs: %s: %d: %d\n", __func__, (int)key, value);
Daniel Campello5d3b4162015-07-20 16:33:46 -0700210 hash_for_each_possible(pkgl_dat->appid_with_rw, hash_cur, hlist, key) {
211 if ((void *)(uintptr_t)key == hash_cur->key) {
Daniel Campello35c9e242015-07-20 16:23:50 -0700212 hash_cur->value = value;
213 return 0;
214 }
215 }
216 new_entry = kmem_cache_alloc(hashtable_entry_cachep, GFP_KERNEL);
217 if (!new_entry)
218 return -ENOMEM;
Daniel Campello5d3b4162015-07-20 16:33:46 -0700219 new_entry->key = (void *)(uintptr_t)key;
Daniel Campello35c9e242015-07-20 16:23:50 -0700220 new_entry->value = value;
Daniel Campello5d3b4162015-07-20 16:33:46 -0700221 hash_add(pkgl_dat->appid_with_rw, &new_entry->hlist, key);
Daniel Campello35c9e242015-07-20 16:23:50 -0700222 return 0;
223}
224
225static void remove_int_to_null(struct hashtable_entry *h_entry) {
226 //printk(KERN_INFO "sdcardfs: %s: %d: %d\n", __func__, (int)h_entry->key, h_entry->value);
227 kmem_cache_free(hashtable_entry_cachep, h_entry);
228}
229
230static void remove_all_hashentrys(struct packagelist_data *pkgl_dat)
231{
232 struct hashtable_entry *hash_cur;
Daniel Campello35c9e242015-07-20 16:23:50 -0700233 struct hlist_node *h_t;
234 int i;
235
Daniel Campellod1d080c2015-07-20 16:27:37 -0700236 hash_for_each_safe(pkgl_dat->package_to_appid, i, h_t, hash_cur, hlist)
Daniel Campello35c9e242015-07-20 16:23:50 -0700237 remove_str_to_int(hash_cur);
Daniel Campellod1d080c2015-07-20 16:27:37 -0700238 hash_for_each_safe(pkgl_dat->appid_with_rw, i, h_t, hash_cur, hlist)
239 remove_int_to_null(hash_cur);
Daniel Campello35c9e242015-07-20 16:23:50 -0700240
241 hash_init(pkgl_dat->package_to_appid);
242 hash_init(pkgl_dat->appid_with_rw);
243}
244
245static int read_package_list(struct packagelist_data *pkgl_dat) {
246 int ret;
247 int fd;
248 int read_amount;
249
250 printk(KERN_INFO "sdcardfs: read_package_list\n");
251
252 mutex_lock(&pkgl_dat->hashtable_lock);
253
254 remove_all_hashentrys(pkgl_dat);
255
256 fd = sys_open(kpackageslist_file, O_RDONLY, 0);
257 if (fd < 0) {
258 printk(KERN_ERR "sdcardfs: failed to open package list\n");
259 mutex_unlock(&pkgl_dat->hashtable_lock);
260 return fd;
261 }
262
263 while ((read_amount = sys_read(fd, pkgl_dat->read_buf,
264 sizeof(pkgl_dat->read_buf))) > 0) {
Daniel Campello5d3b4162015-07-20 16:33:46 -0700265 unsigned int appid;
Daniel Campello35c9e242015-07-20 16:23:50 -0700266 char *token;
267 int one_line_len = 0;
268 int additional_read;
269 unsigned long ret_gid;
270
271 while (one_line_len < read_amount) {
272 if (pkgl_dat->read_buf[one_line_len] == '\n') {
273 one_line_len++;
274 break;
275 }
276 one_line_len++;
277 }
278 additional_read = read_amount - one_line_len;
279 if (additional_read > 0)
280 sys_lseek(fd, -additional_read, SEEK_CUR);
281
Daniel Campello5d3b4162015-07-20 16:33:46 -0700282 if (sscanf(pkgl_dat->read_buf, "%s %u %*d %*s %*s %s",
Daniel Campello35c9e242015-07-20 16:23:50 -0700283 pkgl_dat->app_name_buf, &appid,
284 pkgl_dat->gids_buf) == 3) {
285 ret = insert_str_to_int(pkgl_dat, pkgl_dat->app_name_buf, appid);
286 if (ret) {
287 sys_close(fd);
288 mutex_unlock(&pkgl_dat->hashtable_lock);
289 return ret;
290 }
291
292 token = strtok_r(pkgl_dat->gids_buf, ",", &pkgl_dat->strtok_last);
293 while (token != NULL) {
294 if (!kstrtoul(token, 10, &ret_gid) &&
295 (ret_gid == pkgl_dat->write_gid)) {
Daniel Campello5d3b4162015-07-20 16:33:46 -0700296 ret = insert_int_to_null(pkgl_dat, appid, 1);
Daniel Campello35c9e242015-07-20 16:23:50 -0700297 if (ret) {
298 sys_close(fd);
299 mutex_unlock(&pkgl_dat->hashtable_lock);
300 return ret;
301 }
302 break;
303 }
304 token = strtok_r(NULL, ",", &pkgl_dat->strtok_last);
305 }
306 }
307 }
308
309 sys_close(fd);
310 mutex_unlock(&pkgl_dat->hashtable_lock);
311 return 0;
312}
313
314static int packagelist_reader(void *thread_data)
315{
316 struct packagelist_data *pkgl_dat = (struct packagelist_data *)thread_data;
317 struct inotify_event *event;
318 bool active = false;
319 int event_pos;
320 int event_size;
321 int res = 0;
322 int nfd;
323
324 allow_signal(SIGINT);
325
326 nfd = sys_inotify_init();
327 if (nfd < 0) {
328 printk(KERN_ERR "sdcardfs: inotify_init failed: %d\n", nfd);
329 return nfd;
330 }
331
332 while (!kthread_should_stop()) {
333 if (signal_pending(current)) {
334 ssleep(1);
335 continue;
336 }
337
338 if (!active) {
339 res = sys_inotify_add_watch(nfd, kpackageslist_file, IN_DELETE_SELF);
340 if (res < 0) {
341 if (res == -ENOENT || res == -EACCES) {
342 /* Framework may not have created yet, sleep and retry */
343 printk(KERN_ERR "sdcardfs: missing packages.list; retrying\n");
344 ssleep(2);
345 printk(KERN_ERR "sdcardfs: missing packages.list_end; retrying\n");
346 continue;
347 } else {
348 printk(KERN_ERR "sdcardfs: inotify_add_watch failed: %d\n", res);
349 goto interruptable_sleep;
350 }
351 }
352 /* Watch above will tell us about any future changes, so
353 * read the current state. */
354 res = read_package_list(pkgl_dat);
355 if (res) {
356 printk(KERN_ERR "sdcardfs: read_package_list failed: %d\n", res);
357 goto interruptable_sleep;
358 }
359 active = true;
360 }
361
362 event_pos = 0;
363 res = sys_read(nfd, pkgl_dat->event_buf, sizeof(pkgl_dat->event_buf));
364 if (res < (int) sizeof(*event)) {
365 if (res == -EINTR)
366 continue;
367 printk(KERN_ERR "sdcardfs: failed to read inotify event: %d\n", res);
368 goto interruptable_sleep;
369 }
370
371 while (res >= (int) sizeof(*event)) {
372 event = (struct inotify_event *) (pkgl_dat->event_buf + event_pos);
373
374 printk(KERN_INFO "sdcardfs: inotify event: %08x\n", event->mask);
375 if ((event->mask & IN_IGNORED) == IN_IGNORED) {
376 /* Previously watched file was deleted, probably due to move
377 * that swapped in new data; re-arm the watch and read. */
378 active = false;
379 }
380
381 event_size = sizeof(*event) + event->len;
382 res -= event_size;
383 event_pos += event_size;
384 }
385 continue;
386
387interruptable_sleep:
388 set_current_state(TASK_INTERRUPTIBLE);
389 schedule();
390 }
391 flush_signals(current);
392 sys_close(nfd);
393 return res;
394}
395
396void * packagelist_create(gid_t write_gid)
397{
398 struct packagelist_data *pkgl_dat;
399 struct task_struct *packagelist_thread;
400
401 pkgl_dat = kmalloc(sizeof(*pkgl_dat), GFP_KERNEL | __GFP_ZERO);
402 if (!pkgl_dat) {
403 printk(KERN_ERR "sdcardfs: creating kthread failed\n");
404 return ERR_PTR(-ENOMEM);
405 }
406
407 mutex_init(&pkgl_dat->hashtable_lock);
408 hash_init(pkgl_dat->package_to_appid);
409 hash_init(pkgl_dat->appid_with_rw);
410 pkgl_dat->write_gid = write_gid;
411
412 packagelist_thread = kthread_run(packagelist_reader, (void *)pkgl_dat, "pkgld");
413 if (IS_ERR(packagelist_thread)) {
414 printk(KERN_ERR "sdcardfs: creating kthread failed\n");
415 kfree(pkgl_dat);
416 return packagelist_thread;
417 }
418 pkgl_dat->thread_id = packagelist_thread;
419
420 printk(KERN_INFO "sdcardfs: created packagelist pkgld/%d\n",
421 (int)pkgl_dat->thread_id->pid);
422
423 return (void *)pkgl_dat;
424}
425
426void packagelist_destroy(void *pkgl_id)
427{
428 struct packagelist_data *pkgl_dat = (struct packagelist_data *)pkgl_id;
429 pid_t pkgl_pid = pkgl_dat->thread_id->pid;
430
431 force_sig_info(SIGINT, SEND_SIG_PRIV, pkgl_dat->thread_id);
432 kthread_stop(pkgl_dat->thread_id);
433 remove_all_hashentrys(pkgl_dat);
434 printk(KERN_INFO "sdcardfs: destroyed packagelist pkgld/%d\n", (int)pkgl_pid);
435 kfree(pkgl_dat);
436}
437
438int packagelist_init(void)
439{
440 hashtable_entry_cachep =
441 kmem_cache_create("packagelist_hashtable_entry",
442 sizeof(struct hashtable_entry), 0, 0, NULL);
443 if (!hashtable_entry_cachep) {
444 printk(KERN_ERR "sdcardfs: failed creating pkgl_hashtable entry slab cache\n");
445 return -ENOMEM;
446 }
447
448 return 0;
449}
450
451void packagelist_exit(void)
452{
453 if (hashtable_entry_cachep)
454 kmem_cache_destroy(hashtable_entry_cachep);
455}
456
457