[FIX] SVACE issue #27673
[kernel/swap-modules.git] / preload / preload_debugfs.c
1 #include <linux/kernel.h>
2 #include <linux/debugfs.h>
3 #include <linux/err.h>
4 #include <linux/fs.h>
5 #include <linux/module.h>
6 #include <linux/slab.h>
7 #include <linux/spinlock.h>
8 #include <linux/limits.h>
9 #include <asm/uaccess.h>
10 #include <master/swap_debugfs.h>
11 #include "preload.h"
12 #include "preload_debugfs.h"
13 #include "preload_module.h"
14 #include "preload_control.h"
15 #include "preload_storage.h"
16
17 static const char PRELOAD_FOLDER[] = "preload";
18 static const char PRELOAD_LOADER[] = "loader";
19 static const char PRELOAD_LOADER_OFFSET[] = "loader_offset";
20 static const char PRELOAD_LOADER_PATH[] = "loader_path";
21 static const char PRELOAD_TARGET[] = "target_binaries";
22 static const char PRELOAD_IGNORED[] = "ignored_binaries";
23 static const char PRELOAD_BINARIES_LIST[] = "bins_list";
24 static const char PRELOAD_BINARIES_ADD[] = "bins_add";
25 static const char PRELOAD_BINARIES_REMOVE[] = "bins_remove";
26 static const char PRELOAD_CALLER[] = "caller";
27 static const char PRELOAD_HANDLERS_PATH[] = "handlers_path";
28 static const char PRELOAD_LINKER_DATA[] = "linker";
29 static const char PRELOAD_LINKER_PATH[] = "linker_path";
30 static const char PRELOAD_LINKER_R_DEBUG_OFFSET[] = "r_debug_offset";
31
32 struct loader_info {
33         char *path;
34         unsigned long offset;
35         struct dentry *dentry;
36 };
37
38 static struct dentry *preload_root;
39 static struct loader_info __loader_info;
40
41
42 static struct dentry *target_list = NULL;
43 static struct dentry *target_add = NULL;
44 static struct dentry *target_remove = NULL;
45 static struct dentry *ignored_list = NULL;
46 static struct dentry *ignored_add = NULL;
47 static struct dentry *ignored_remove = NULL;
48
49 static unsigned long r_debug_offset = 0;
50 static DEFINE_SPINLOCK(__dentry_lock);
51
52 static inline void dentry_lock(void)
53 {
54         spin_lock(&__dentry_lock);
55 }
56
57 static inline void dentry_unlock(void)
58 {
59         spin_unlock(&__dentry_lock);
60 }
61
62
63 static void set_loader_file(char *path)
64 {
65         __loader_info.path = path;
66         dentry_lock();
67         __loader_info.dentry = get_dentry(__loader_info.path);
68         dentry_unlock();
69 }
70
71 struct dentry *preload_debugfs_get_loader_dentry(void)
72 {
73         struct dentry *dentry;
74
75         dentry_lock();
76         dentry = __loader_info.dentry;
77         dentry_unlock();
78
79         return dentry;
80 }
81
82 unsigned long preload_debugfs_get_loader_offset(void)
83 {
84         /* TODO Think about sync */
85         return __loader_info.offset;
86 }
87
88 static void clean_loader_info(void)
89 {
90         if (__loader_info.path != NULL)
91                 kfree(__loader_info.path);
92         __loader_info.path = NULL;
93
94         dentry_lock();
95         if (__loader_info.dentry != NULL)
96                 put_dentry(__loader_info.dentry);
97
98         __loader_info.dentry = NULL;
99         __loader_info.offset = 0;
100
101         dentry_unlock();
102 }
103
104 struct dentry *debugfs_create_ptr(const char *name, mode_t mode,
105                                   struct dentry *parent,
106                                   unsigned long *value)
107 {
108         struct dentry *dentry;
109
110 #if BITS_PER_LONG == 32
111         dentry = debugfs_create_x32(name, mode, parent, (u32 *)value);
112 #elif BITS_PER_LONG == 64
113         dentry = debugfs_create_x64(name, mode, parent, (u64 *)value);
114 #else
115 #error Unsupported BITS_PER_LONG value
116 #endif
117
118         return dentry;
119 }
120
121
122 /* ===========================================================================
123  * =                              LOADER PATH                                =
124  * ===========================================================================
125  */
126
127 static ssize_t loader_path_write(struct file *file, const char __user *buf,
128                                  size_t len, loff_t *ppos)
129 {
130         ssize_t ret;
131         char *path;
132
133         if (preload_module_is_running())
134                 return -EBUSY;
135
136         clean_loader_info();
137
138         path = kmalloc(len, GFP_KERNEL);
139         if (path == NULL) {
140                 return -ENOMEM;
141         }
142
143         if (copy_from_user(path, buf, len)) {
144                 ret = -EINVAL;
145                 goto err;
146         }
147
148         path[len - 1] = '\0';
149         set_loader_file(path);
150         ret = len;
151
152         return ret;
153 err:
154         kfree(path);
155         return ret;
156 }
157
158
159 static const struct file_operations loader_path_file_ops = {
160         .owner = THIS_MODULE,
161         .write = loader_path_write,
162 };
163
164
165 /* ===========================================================================
166  * =                                BIN PATH                                 =
167  * ===========================================================================
168  */
169
170 static ssize_t bin_add_write(struct file *file, const char __user *buf,
171                            size_t len, loff_t *ppos)
172 {
173         ssize_t ret;
174         char *path;
175
176         path = kmalloc(len, GFP_KERNEL);
177         if (path == NULL) {
178                 ret = -ENOMEM;
179                 goto bin_add_write_out;
180         }
181
182         if (copy_from_user(path, buf, len)) {
183                 ret = -EINVAL;
184                 goto bin_add_write_out;
185         }
186
187         path[len - 1] = '\0';
188
189         if (file->f_path.dentry == target_add)
190                 ret = preload_control_add_instrumented_binary(path);
191         else if (file->f_path.dentry == ignored_add)
192                 ret = preload_control_add_ignored_binary(path);
193         else {
194                 /* Should never occur */
195                 printk(PRELOAD_PREFIX "%s() called for invalid file %s!\n", __func__,
196                        file->f_path.dentry->d_name.name);
197                 ret = -EINVAL;
198                 goto bin_add_write_out;
199         }
200
201
202         if (ret != 0) {
203                 printk(PRELOAD_PREFIX "Cannot add binary %s\n", path);
204                 ret = -EINVAL;
205                 goto bin_add_write_out;
206         }
207
208         ret = len;
209
210 bin_add_write_out:
211         kfree(path);
212
213         return ret;
214 }
215
216 static ssize_t bin_remove_write(struct file *file, const char __user *buf,
217                               size_t len, loff_t *ppos)
218 {
219         ssize_t ret;
220
221         if (file->f_path.dentry == target_remove)
222                 ret = preload_control_clean_instrumented_bins();
223         else if (file->f_path.dentry == ignored_remove)
224                 ret = preload_control_clean_ignored_bins();
225         else {
226                 /* Should never occur */
227                 printk(PRELOAD_PREFIX "%s() called for invalid file %s!\n", __func__,
228                        file->f_path.dentry->d_name.name);
229                 ret = -EINVAL;
230                 goto bin_remove_write_out;
231         }
232
233         if (ret != 0) {
234                 printk(PRELOAD_PREFIX "Error during clean!\n");
235                 ret = -EINVAL;
236                 goto bin_remove_write_out;
237         }
238
239         ret = len;
240
241 bin_remove_write_out:
242         return ret;
243 }
244
245 static ssize_t bin_list_read(struct file *file, char __user *usr_buf,
246                                  size_t count, loff_t *ppos)
247 {
248         unsigned int i;
249         unsigned int files_cnt = 0;
250         ssize_t len = 0, tmp, ret = 0;
251         char **filenames = NULL;
252         char *buf = NULL;
253         char *ptr = NULL;
254
255         if (file->f_path.dentry == target_list) {
256                 files_cnt = preload_control_get_target_names(&filenames);
257         } else if (file->f_path.dentry == ignored_list) {
258                 files_cnt = preload_control_get_ignored_names(&filenames);
259         } else {
260                 /* Should never occur */
261                 printk(PRELOAD_PREFIX "%s() called for invalid file %s!\n", __func__,
262                        file->f_path.dentry->d_name.name);
263                 ret = 0;
264                 goto bin_list_read_out;
265         }
266
267         if (files_cnt == 0) {
268                 printk(PRELOAD_PREFIX "Cannot read binaries names!\n");
269                 ret = 0;
270                 goto bin_list_read_fail;
271         }
272
273         for (i = 0; i < files_cnt; i++)
274                 len += strlen(filenames[i]);
275
276         buf = kmalloc(len + files_cnt, GFP_KERNEL);
277         if (buf == NULL) {
278                 ret = 0;
279                 goto bin_list_read_fail;
280         }
281
282         ptr = buf;
283
284         for (i = 0; i < files_cnt; i++) {
285                 tmp = strlen(filenames[i]);
286                 memcpy(ptr, filenames[i], tmp);
287                 ptr += tmp;
288                 *ptr = '\n';
289                 ptr += 1;
290         }
291
292         ret = simple_read_from_buffer(usr_buf, count, ppos, buf, len);
293
294         kfree(buf);
295
296 bin_list_read_fail:
297         if (file->f_path.dentry == target_list) {
298                 preload_control_release_target_names(&filenames);
299         } else if (file->f_path.dentry == ignored_list)  {
300                 preload_control_release_ignored_names(&filenames);
301         } else {
302                 /* Should never occur */
303                 printk(PRELOAD_PREFIX "%s() called for invalid file %s!\n", __func__,
304                        file->f_path.dentry->d_name.name);
305                 ret = 0;
306         }
307
308 bin_list_read_out:
309         return ret;
310 }
311
312 static const struct file_operations bin_list_file_ops = {
313         .owner = THIS_MODULE,
314         .read = bin_list_read
315 };
316
317 static const struct file_operations bin_add_file_ops = {
318         .owner = THIS_MODULE,
319         .write = bin_add_write,
320 };
321
322 static const struct file_operations bin_remove_file_ops = {
323         .owner = THIS_MODULE,
324         .write = bin_remove_write,
325 };
326
327
328 /* ===========================================================================
329  * =                            LINKER PATH                                  =
330  * ===========================================================================
331  */
332
333
334 static ssize_t linker_path_write(struct file *file, const char __user *buf,
335                                   size_t len, loff_t *ppos)
336 {
337         ssize_t ret;
338         char *path;
339
340         path = kmalloc(len, GFP_KERNEL);
341         if (path == NULL) {
342                 ret = -ENOMEM;
343                 goto linker_path_write_out;
344         }
345
346         if (copy_from_user(path, buf, len)) {
347                 ret = -EINVAL;
348                 goto linker_path_write_out;
349         }
350
351         path[len - 1] = '\0';
352
353         if (preload_storage_set_linker_info(path) != 0) {
354                 printk(PRELOAD_PREFIX "Cannot set linker path %s\n", path);
355                 ret = -EINVAL;
356                 goto linker_path_write_out;
357         }
358
359         ret = len;
360
361 linker_path_write_out:
362         kfree(path);
363
364         return ret;
365 }
366
367 static const struct file_operations linker_path_file_ops = {
368         .owner = THIS_MODULE,
369         .write = linker_path_write,
370 };
371
372
373 /* ===========================================================================
374  * =                           HANDLERS PATH                                 =
375  * ===========================================================================
376  */
377
378
379 static ssize_t handlers_path_write(struct file *file, const char __user *buf,
380                                    size_t len, loff_t *ppos)
381 {
382         ssize_t ret;
383         char *path;
384
385         path = kmalloc(len, GFP_KERNEL);
386         if (path == NULL) {
387                 ret = -ENOMEM;
388                 goto handlers_path_write_out;
389         }
390
391         if (copy_from_user(path, buf, len)) {
392                 ret = -EINVAL;
393                 goto handlers_path_write_out;
394         }
395
396         path[len - 1] = '\0';
397
398         if (preload_storage_set_handlers_info(path) != 0) {
399                 printk(PRELOAD_PREFIX "Cannot set handler path %s\n", path);
400                 ret = -EINVAL;
401                 goto handlers_path_write_out;
402         }
403
404         ret = len;
405
406 handlers_path_write_out:
407         kfree(path);
408
409         return ret;
410 }
411
412 static const struct file_operations handlers_path_file_ops = {
413         .owner = THIS_MODULE,
414         .write = handlers_path_write,
415 };
416
417
418
419
420 unsigned long preload_debugfs_r_debug_offset(void)
421 {
422         return r_debug_offset;
423 }
424
425 int preload_debugfs_init(void)
426 {
427         struct dentry *swap_dentry, *root, *loader, *open_p, *lib_path,
428                   *target_path, *ignored_path, *linker_dir, *linker_path,
429                   *linker_offset, *handlers_path;
430         int ret;
431
432         ret = -ENODEV;
433         if (!debugfs_initialized())
434                 goto fail;
435
436         ret = -ENOENT;
437         swap_dentry = swap_debugfs_getdir();
438         if (!swap_dentry)
439                 goto fail;
440
441         ret = -ENOMEM;
442         root = debugfs_create_dir(PRELOAD_FOLDER, swap_dentry);
443         if (IS_ERR_OR_NULL(root))
444                 goto fail;
445
446         preload_root = root;
447
448         loader = debugfs_create_dir(PRELOAD_LOADER, root);
449         if (IS_ERR_OR_NULL(root)) {
450                 ret = -ENOMEM;
451                 goto remove;
452         }
453
454         open_p = debugfs_create_ptr(PRELOAD_LOADER_OFFSET, PRELOAD_DEFAULT_PERMS,
455                                     loader, &__loader_info.offset);
456         if (IS_ERR_OR_NULL(open_p)) {
457                 ret = -ENOMEM;
458                 goto remove;
459         }
460
461         lib_path = debugfs_create_file(PRELOAD_LOADER_PATH, PRELOAD_DEFAULT_PERMS,
462                                        loader, NULL, &loader_path_file_ops);
463         if (IS_ERR_OR_NULL(lib_path)) {
464                 ret = -ENOMEM;
465                 goto remove;
466         }
467
468         target_path = debugfs_create_dir(PRELOAD_TARGET, root);
469         if (IS_ERR_OR_NULL(target_path)) {
470                 ret = -ENOMEM;
471                 goto remove;
472         }
473
474         target_list = debugfs_create_file(PRELOAD_BINARIES_LIST,
475                                           PRELOAD_DEFAULT_PERMS, target_path, NULL,
476                                           &bin_list_file_ops);
477         if (IS_ERR_OR_NULL(target_list)) {
478                 ret = -ENOMEM;
479                 goto remove;
480         }
481
482         target_add = debugfs_create_file(PRELOAD_BINARIES_ADD,
483                                          PRELOAD_DEFAULT_PERMS, target_path, NULL,
484                                          &bin_add_file_ops);
485         if (IS_ERR_OR_NULL(target_add)) {
486                 ret = -ENOMEM;
487                 goto remove;
488         }
489
490         target_remove = debugfs_create_file(PRELOAD_BINARIES_REMOVE,
491                                             PRELOAD_DEFAULT_PERMS, target_path,
492                                             NULL, &bin_remove_file_ops);
493         if (IS_ERR_OR_NULL(target_remove)) {
494                 ret = -ENOMEM;
495                 goto remove;
496         }
497
498         ignored_path = debugfs_create_dir(PRELOAD_IGNORED, root);
499         if (IS_ERR_OR_NULL(ignored_path)) {
500                 ret = -ENOMEM;
501                 goto remove;
502         }
503
504         ignored_list = debugfs_create_file(PRELOAD_BINARIES_LIST,
505                                            PRELOAD_DEFAULT_PERMS, ignored_path,
506                                            NULL, &bin_list_file_ops);
507         if (IS_ERR_OR_NULL(ignored_list)) {
508                 ret = -ENOMEM;
509                 goto remove;
510         }
511
512         ignored_add = debugfs_create_file(PRELOAD_BINARIES_ADD,
513                                           PRELOAD_DEFAULT_PERMS, ignored_path, NULL,
514                                           &bin_add_file_ops);
515         if (IS_ERR_OR_NULL(ignored_add)) {
516                 ret = -ENOMEM;
517                 goto remove;
518         }
519
520         ignored_remove = debugfs_create_file(PRELOAD_BINARIES_REMOVE,
521                                              PRELOAD_DEFAULT_PERMS, ignored_path, NULL,
522                                              &bin_remove_file_ops);
523         if (IS_ERR_OR_NULL(ignored_remove)) {
524                 ret = -ENOMEM;
525                 goto remove;
526         }
527
528         linker_dir = debugfs_create_dir(PRELOAD_LINKER_DATA, root);
529         if (IS_ERR_OR_NULL(linker_dir)) {
530                 ret = -ENOMEM;
531                 goto remove;
532         }
533
534         linker_path = debugfs_create_file(PRELOAD_LINKER_PATH,
535                                           PRELOAD_DEFAULT_PERMS, linker_dir, NULL,
536                                           &linker_path_file_ops);
537         if (IS_ERR_OR_NULL(linker_path)) {
538                 ret = -ENOMEM;
539                 goto remove;
540         }
541
542         linker_offset = debugfs_create_ptr(PRELOAD_LINKER_R_DEBUG_OFFSET,
543                                            PRELOAD_DEFAULT_PERMS, linker_dir,
544                                            &r_debug_offset);
545         if (IS_ERR_OR_NULL(linker_offset)) {
546                 ret = -ENOMEM;
547                 goto remove;
548         }
549
550         handlers_path = debugfs_create_file(PRELOAD_HANDLERS_PATH,
551                                             PRELOAD_DEFAULT_PERMS, root, NULL,
552                                             &handlers_path_file_ops);
553         if (IS_ERR_OR_NULL(handlers_path)) {
554                 ret = -ENOMEM;
555                 goto remove;
556         }
557
558         return 0;
559
560 remove:
561
562         debugfs_remove_recursive(root);
563
564 fail:
565         printk(PRELOAD_PREFIX "Debugfs initialization failure: %d\n", ret);
566
567         return ret;
568 }
569
570 void preload_debugfs_exit(void)
571 {
572         if (preload_root)
573                 debugfs_remove_recursive(preload_root);
574         target_list = NULL;
575         target_add = NULL;
576         target_remove = NULL;
577         ignored_list = NULL;
578         ignored_add = NULL;
579         ignored_remove = NULL;
580         preload_root = NULL;
581
582         preload_module_set_not_ready();
583         clean_loader_info();
584 }