kmodloader: fix out-of-bound access when parsing .modinfo
[project/ubox.git] / kmodloader.c
1 /*
2  * Copyright (C) 2013 Felix Fietkau <nbd@openwrt.org>
3  * Copyright (C) 2013 John Crispin <blogic@openwrt.org>
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 #include <sys/syscall.h>
17 #include <sys/mman.h>
18 #include <sys/utsname.h>
19
20 #include <stdlib.h>
21 #include <unistd.h>
22 #include <sys/syscall.h>
23 #include <sys/types.h>
24 #include <values.h>
25 #include <errno.h>
26 #include <stdio.h>
27 #include <string.h>
28 #include <sys/stat.h>
29 #include <fcntl.h>
30 #include <libgen.h>
31 #include <glob.h>
32 #include <elf.h>
33
34 #include <libubox/avl.h>
35 #include <libubox/avl-cmp.h>
36 #include <libubox/utils.h>
37 #include <libubox/ulog.h>
38
39 #define DEF_MOD_PATH "/modules/%s/"
40
41 enum {
42         SCANNED,
43         PROBE,
44         LOADED,
45 };
46
47 struct module {
48         struct avl_node avl;
49
50         char *name;
51         char *depends;
52         char *opts;
53
54         int size;
55         int usage;
56         int state;
57         int error;
58 };
59
60 static struct avl_tree modules;
61
62 static char **module_folders = NULL;
63
64 static int init_module_folders(void)
65 {
66         int n = 0;
67         struct stat st;
68         struct utsname ver;
69         char *s, *e, *p, path[256], ldpath[256];
70
71         e = ldpath;
72         s = getenv("LD_LIBRARY_PATH");
73
74         if (s)
75                 e += snprintf(ldpath, sizeof(ldpath), "%s:", s);
76
77         e += snprintf(e, sizeof(ldpath) - (e - ldpath), "/lib");
78
79         uname(&ver);
80
81         for (s = p = ldpath; p <= e; p++) {
82                 if (*p != ':' && *p != '\0')
83                         continue;
84
85                 *p = 0;
86                 snprintf(path, sizeof(path), "%s" DEF_MOD_PATH, s, ver.release);
87
88                 if (!stat(path, &st) && S_ISDIR(st.st_mode)) {
89                         module_folders = realloc(module_folders, sizeof(p) * (n + 2));
90
91                         if (!module_folders)
92                                 return -1;
93
94                         module_folders[n++] = strdup(path);
95                 }
96
97                 s = p + 1;
98         }
99
100         if (!module_folders)
101                 return -1;
102
103         module_folders[n] = NULL;
104         return 0;
105 }
106
107 static struct module *find_module(const char *name)
108 {
109         struct module *m;
110         return avl_find_element(&modules, name, m, avl);
111 }
112
113 static void free_modules(void)
114 {
115         struct module *m, *tmp;
116
117         avl_remove_all_elements(&modules, m, avl, tmp)
118                 free(m);
119 }
120
121 static char* get_module_path(char *name)
122 {
123         char **p;
124         static char path[256];
125         struct stat s;
126
127         if (!stat(name, &s) && S_ISREG(s.st_mode))
128                 return name;
129
130         for (p = module_folders; *p; p++) {
131                 snprintf(path, sizeof(path), "%s%s.ko", *p, name);
132                 if (!stat(path, &s) && S_ISREG(s.st_mode))
133                         return path;
134         }
135
136         return NULL;
137 }
138
139 static char* get_module_name(char *path)
140 {
141         static char name[32];
142         char *t;
143
144         strncpy(name, basename(path), sizeof(name));
145
146         t = strstr(name, ".ko");
147         if (t)
148                 *t = '\0';
149
150         return name;
151 }
152
153 static int elf64_find_section(char *map, const char *section, unsigned int *offset, unsigned int *size)
154 {
155         const char *secnames;
156         Elf64_Ehdr *e;
157         Elf64_Shdr *sh;
158         int i;
159
160         e = (Elf64_Ehdr *) map;
161         sh = (Elf64_Shdr *) (map + e->e_shoff);
162
163         secnames = map + sh[e->e_shstrndx].sh_offset;
164         for (i = 0; i < e->e_shnum; i++) {
165                 if (!strcmp(section, secnames + sh[i].sh_name)) {
166                         *size = sh[i].sh_size;
167                         *offset = sh[i].sh_offset;
168                         return 0;
169                 }
170         }
171
172         return -1;
173 }
174
175 static int elf32_find_section(char *map, const char *section, unsigned int *offset, unsigned int *size)
176 {
177         const char *secnames;
178         Elf32_Ehdr *e;
179         Elf32_Shdr *sh;
180         int i;
181
182         e = (Elf32_Ehdr *) map;
183         sh = (Elf32_Shdr *) (map + e->e_shoff);
184
185         secnames = map + sh[e->e_shstrndx].sh_offset;
186         for (i = 0; i < e->e_shnum; i++) {
187                 if (!strcmp(section, secnames + sh[i].sh_name)) {
188                         *size = sh[i].sh_size;
189                         *offset = sh[i].sh_offset;
190                         return 0;
191                 }
192         }
193
194         return -1;
195 }
196
197 static int elf_find_section(char *map, const char *section, unsigned int *offset, unsigned int *size)
198 {
199         int clazz = map[EI_CLASS];
200
201         if (clazz == ELFCLASS32)
202                 return elf32_find_section(map, section, offset, size);
203         else if (clazz == ELFCLASS64)
204                 return elf64_find_section(map, section, offset, size);
205
206         ULOG_ERR("unknown elf format %d\n", clazz);
207
208         return -1;
209 }
210
211 static struct module *
212 alloc_module(const char *name, const char *depends, int size)
213 {
214         struct module *m;
215         char *_name, *_dep;
216
217         m = calloc_a(sizeof(*m),
218                 &_name, strlen(name) + 1,
219                 &_dep, depends ? strlen(depends) + 2 : 0);
220         if (!m)
221                 return NULL;
222
223         m->avl.key = m->name = strcpy(_name, name);
224         m->opts = 0;
225
226         if (depends) {
227                 m->depends = strcpy(_dep, depends);
228                 while (*_dep) {
229                         if (*_dep == ',')
230                                 *_dep = '\0';
231                         _dep++;
232                 }
233         }
234
235         m->size = size;
236         avl_insert(&modules, &m->avl);
237
238         return m;
239 }
240
241 static int scan_loaded_modules(void)
242 {
243         size_t buf_len = 0;
244         char *buf = NULL;
245         FILE *fp;
246
247         fp = fopen("/proc/modules", "r");
248         if (!fp) {
249                 ULOG_ERR("failed to open /proc/modules\n");
250                 return -1;
251         }
252
253         while (getline(&buf, &buf_len, fp) > 0) {
254                 struct module m;
255                 struct module *n;
256
257                 m.name = strtok(buf, " ");
258                 m.size = atoi(strtok(NULL, " "));
259                 m.usage = atoi(strtok(NULL, " "));
260                 m.depends = strtok(NULL, " ");
261
262                 if (!m.name || !m.depends)
263                         continue;
264
265                 n = alloc_module(m.name, m.depends, m.size);
266                 n->usage = m.usage;
267                 n->state = LOADED;
268         }
269         free(buf);
270         fclose(fp);
271
272         return 0;
273 }
274
275 static struct module* get_module_info(const char *module, const char *name)
276 {
277         int fd = open(module, O_RDONLY);
278         unsigned int offset, size;
279         char *map = MAP_FAILED, *strings, *dep = NULL;
280         struct module *m = NULL;
281         struct stat s;
282
283         if (fd < 0) {
284                 ULOG_ERR("failed to open %s\n", module);
285                 goto out;
286         }
287
288         if (fstat(fd, &s) == -1) {
289                 ULOG_ERR("failed to stat %s\n", module);
290                 goto out;
291         }
292
293         map = mmap(NULL, s.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
294         if (map == MAP_FAILED) {
295                 ULOG_ERR("failed to mmap %s\n", module);
296                 goto out;
297         }
298
299         if (elf_find_section(map, ".modinfo", &offset, &size)) {
300                 ULOG_ERR("failed to load the .modinfo section from %s\n", module);
301                 goto out;
302         }
303
304         strings = map + offset;
305         while (true) {
306                 char *sep;
307                 int len;
308
309                 while (!strings[0])
310                         strings++;
311                 if (strings >= map + offset + size)
312                         break;
313                 sep = strstr(strings, "=");
314                 if (!sep)
315                         break;
316                 len = sep - strings;
317                 sep++;
318                 if (!strncmp(strings, "depends=", len + 1))
319                         dep = sep;
320                 strings = &sep[strlen(sep)];
321         }
322
323         m = alloc_module(name, dep, s.st_size);
324
325         if (m)
326                 m->state = SCANNED;
327
328 out:
329         if (map != MAP_FAILED)
330                 munmap(map, s.st_size);
331
332         if (fd >= 0)
333                 close(fd);
334
335         return m;
336 }
337
338 static int scan_module_folder(const char *dir)
339 {
340         int gl_flags = GLOB_NOESCAPE | GLOB_MARK;
341         struct utsname ver;
342         char *path;
343         glob_t gl;
344         int j;
345
346         uname(&ver);
347         path = alloca(strlen(dir) + sizeof("*.ko") + 1);
348         sprintf(path, "%s*.ko", dir);
349
350         if (glob(path, gl_flags, NULL, &gl) < 0)
351                 return -1;
352
353         for (j = 0; j < gl.gl_pathc; j++) {
354                 char *name = get_module_name(gl.gl_pathv[j]);
355                 struct module *m;
356
357                 if (!name)
358                         continue;
359
360                 m = find_module(name);
361                 if (!m)
362                         get_module_info(gl.gl_pathv[j], name);
363         }
364
365         globfree(&gl);
366
367         return 0;
368 }
369
370 static int scan_module_folders(void)
371 {
372         int rv = 0;
373         char **p;
374
375         if (init_module_folders())
376                 return -1;
377
378         for (p = module_folders; *p; p++)
379                 rv |= scan_module_folder(*p);
380
381         return rv;
382 }
383
384 static int print_modinfo(char *module)
385 {
386         int fd = open(module, O_RDONLY);
387         unsigned int offset, size;
388         struct stat s;
389         char *map = MAP_FAILED, *strings;
390         int rv = -1;
391
392         if (fd < 0) {
393                 ULOG_ERR("failed to open %s\n", module);
394                 goto out;
395         }
396
397         if (fstat(fd, &s) == -1) {
398                 ULOG_ERR("failed to stat %s\n", module);
399                 goto out;
400         }
401
402         map = mmap(NULL, s.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
403         if (map == MAP_FAILED) {
404                 ULOG_ERR("failed to mmap %s\n", module);
405                 goto out;
406         }
407
408         if (elf_find_section(map, ".modinfo", &offset, &size)) {
409                 ULOG_ERR("failed to load the .modinfo section from %s\n", module);
410                 goto out;
411         }
412
413         strings = map + offset;
414         printf("module:\t\t%s\n", module);
415         while (true) {
416                 char *dup = NULL;
417                 char *sep;
418
419                 while (!strings[0])
420                         strings++;
421                 if (strings >= map + offset + size)
422                         break;
423                 sep = strstr(strings, "=");
424                 if (!sep)
425                         break;
426                 dup = strndup(strings, sep - strings);
427                 sep++;
428                 if (strncmp(strings, "parm", 4)) {
429                         if (strlen(dup) < 7)
430                                 printf("%s:\t\t%s\n",  dup, sep);
431                         else
432                                 printf("%s:\t%s\n",  dup, sep);
433                 }
434                 strings = &sep[strlen(sep)];
435                 if (dup)
436                         free(dup);
437         }
438
439         rv = 0;
440
441 out:
442         if (map != MAP_FAILED)
443                 munmap(map, s.st_size);
444
445         if (fd >= 0)
446                 close(fd);
447
448         return rv;
449 }
450
451 static int deps_available(struct module *m, int verbose)
452 {
453         char *dep;
454         int err = 0;
455
456         if (!m->depends || !strcmp(m->depends, "-") || !strcmp(m->depends, ""))
457                 return 0;
458
459         dep = m->depends;
460
461         while (*dep) {
462                 m = find_module(dep);
463
464                 if (verbose && !m)
465                         ULOG_ERR("missing dependency %s\n", dep);
466                 if (verbose && m && (m->state != LOADED))
467                         ULOG_ERR("dependency not loaded %s\n", dep);
468                 if (!m || (m->state != LOADED))
469                         err++;
470                 dep += strlen(dep) + 1;
471         }
472
473         return err;
474 }
475
476 static int insert_module(char *path, const char *options)
477 {
478         void *data = 0;
479         struct stat s;
480         int fd, ret = -1;
481
482         if (stat(path, &s)) {
483                 ULOG_ERR("missing module %s\n", path);
484                 return ret;
485         }
486
487         fd = open(path, O_RDONLY);
488         if (fd < 0) {
489                 ULOG_ERR("cannot open %s\n", path);
490                 return ret;
491         }
492
493         data = malloc(s.st_size);
494         if (read(fd, data, s.st_size) == s.st_size)
495                 ret = syscall(__NR_init_module, data, (unsigned long) s.st_size, options);
496         else
497                 ULOG_ERR("failed to read full module %s\n", path);
498
499         close(fd);
500         free(data);
501
502         return ret;
503 }
504
505 static void load_moddeps(struct module *_m)
506 {
507         char *dep;
508         struct module *m;
509
510         if (!strcmp(_m->depends, "-") || !strcmp(_m->depends, ""))
511                 return;
512
513         dep = _m->depends;
514
515         while (*dep) {
516                 m = find_module(dep);
517
518                 if (!m)
519                         ULOG_ERR("failed to find dependency %s\n", dep);
520                 if (m && (m->state != LOADED)) {
521                         m->state = PROBE;
522                         load_moddeps(m);
523                 }
524
525                 dep = dep + strlen(dep) + 1;
526         }
527 }
528
529 static int iterations = 0;
530 static int load_modprobe(void)
531 {
532         int loaded, todo;
533         struct module *m;
534
535         avl_for_each_element(&modules, m, avl)
536                 if (m->state == PROBE)
537                         load_moddeps(m);
538
539         do {
540                 loaded = 0;
541                 todo = 0;
542                 avl_for_each_element(&modules, m, avl) {
543                         if ((m->state == PROBE) && (!deps_available(m, 0))) {
544                                 if (!insert_module(get_module_path(m->name), (m->opts) ? (m->opts) : (""))) {
545                                         m->state = LOADED;
546                                         m->error = 0;
547                                         loaded++;
548                                         continue;
549                                 }
550                                 m->error = 1;
551                         }
552
553                         if ((m->state == PROBE) || m->error)
554                                 todo++;
555                 }
556                 iterations++;
557         } while (loaded);
558
559         return todo;
560 }
561
562 static int print_insmod_usage(void)
563 {
564         ULOG_INFO("Usage:\n\tinsmod filename [args]\n");
565
566         return -1;
567 }
568
569 static int print_usage(char *arg)
570 {
571         ULOG_INFO("Usage:\n\t%s module\n", arg);
572
573         return -1;
574 }
575
576 static int main_insmod(int argc, char **argv)
577 {
578         char *name, *cur, *options;
579         int i, ret, len;
580
581         if (argc < 2)
582                 return print_insmod_usage();
583
584         name = get_module_name(argv[1]);
585         if (!name) {
586                 ULOG_ERR("cannot find module - %s\n", argv[1]);
587                 return -1;
588         }
589
590         if (scan_loaded_modules())
591                 return -1;
592
593         if (find_module(name)) {
594                 ULOG_ERR("module is already loaded - %s\n", name);
595                 return -1;
596
597         }
598
599         free_modules();
600
601         for (len = 0, i = 2; i < argc; i++)
602                 len += strlen(argv[i]) + 1;
603
604         options = malloc(len);
605         options[0] = 0;
606         cur = options;
607         for (i = 2; i < argc; i++) {
608                 if (options[0]) {
609                         *cur = ' ';
610                         cur++;
611                 }
612                 cur += sprintf(cur, "%s", argv[i]);
613         }
614
615         if (init_module_folders()) {
616                 fprintf(stderr, "Failed to find the folder holding the modules\n");
617                 return -1;
618         }
619
620         if (get_module_path(argv[1])) {
621                 name = argv[1];
622         } else if (!get_module_path(name)) {
623                 fprintf(stderr, "Failed to find %s. Maybe it is a built in module ?\n", name);
624                 return -1;
625         }
626
627         ret = insert_module(get_module_path(name), options);
628         free(options);
629
630         if (ret)
631                 ULOG_ERR("failed to insert %s\n", get_module_path(name));
632
633         return ret;
634 }
635
636 static int main_rmmod(int argc, char **argv)
637 {
638         struct module *m;
639         char *name;
640         int ret;
641
642         if (argc != 2)
643                 return print_usage("rmmod");
644
645         if (scan_loaded_modules())
646                 return -1;
647
648         name = get_module_name(argv[1]);
649         m = find_module(name);
650         if (!m) {
651                 ULOG_ERR("module is not loaded\n");
652                 return -1;
653         }
654         ret = syscall(__NR_delete_module, m->name, 0);
655
656         if (ret)
657                 ULOG_ERR("unloading the module failed\n");
658
659         free_modules();
660
661         return ret;
662 }
663
664 static int main_lsmod(int argc, char **argv)
665 {
666         struct module *m;
667         char *dep;
668
669         if (scan_loaded_modules())
670                 return -1;
671
672         avl_for_each_element(&modules, m, avl)
673                 if (m->state == LOADED) {
674                         printf("%-20s%8d%3d ",
675                                 m->name, m->size, m->usage);
676                         if (m->depends && strcmp(m->depends, "-") && strcmp(m->depends, "")) {
677                                 dep = m->depends;
678                                 while (*dep) {
679                                         printf("%s", dep);
680                                         dep = dep + strlen(dep) + 1;
681                                         if (*dep)
682                                                 printf(",");
683                                 }
684                         }
685                         printf("\n");
686                 }
687
688         free_modules();
689
690         return 0;
691 }
692
693 static int main_modinfo(int argc, char **argv)
694 {
695         struct module *m;
696         char *name;
697
698         if (argc != 2)
699                 return print_usage("modinfo");
700
701         if (scan_module_folders())
702                 return -1;
703
704         name = get_module_name(argv[1]);
705         m = find_module(name);
706         if (!m) {
707                 ULOG_ERR("cannot find module - %s\n", argv[1]);
708                 return -1;
709         }
710
711         name = get_module_path(m->name);
712         if (!name) {
713                 ULOG_ERR("cannot find path of module - %s\n", m->name);
714                 return -1;
715         }
716
717         print_modinfo(name);
718
719         return 0;
720 }
721
722 static int main_modprobe(int argc, char **argv)
723 {
724         struct module *m;
725         char *name;
726         char *mod = NULL;
727         int i;
728
729         for (i = 1; i < argc; i++)
730                 if (argv[i][0] != '-') {
731                         mod = argv[i];
732                         break;
733                 }
734         if (!mod)
735                 return print_usage("modprobe");
736
737         if (scan_loaded_modules())
738                 return -1;
739
740         if (scan_module_folders())
741                 return -1;
742
743         name = get_module_name(mod);
744         m = find_module(name);
745         if (m && m->state == LOADED) {
746                 ULOG_ERR("%s is already loaded\n", name);
747                 return -1;
748         } else if (!m) {
749                 ULOG_ERR("failed to find a module named %s\n", name);
750         } else {
751                 int fail;
752
753                 m->state = PROBE;
754
755                 fail = load_modprobe();
756
757                 if (fail) {
758                         ULOG_ERR("%d module%s could not be probed\n",
759                                  fail, (fail == 1) ? ("") : ("s"));
760
761                         avl_for_each_element(&modules, m, avl)
762                                 if ((m->state == PROBE) || m->error)
763                                         ULOG_ERR("- %s\n", m->name);
764                 }
765         }
766
767         free_modules();
768
769         return 0;
770 }
771
772 static int main_loader(int argc, char **argv)
773 {
774         int gl_flags = GLOB_NOESCAPE | GLOB_MARK;
775         char *dir = "/etc/modules.d/";
776         struct module *m;
777         glob_t gl;
778         char *path;
779         int fail, j;
780
781         if (argc > 1)
782                 dir = argv[1];
783
784         path = malloc(strlen(dir) + 2);
785         strcpy(path, dir);
786         strcat(path, "*");
787
788         if (scan_loaded_modules()) {
789                 free (path);
790                 return -1;
791         }
792
793         if (scan_module_folders()) {
794                 free (path);
795                 return -1;
796         }
797
798         ULOG_INFO("loading kernel modules from %s\n", path);
799
800         if (glob(path, gl_flags, NULL, &gl) < 0)
801                 goto out;
802
803         for (j = 0; j < gl.gl_pathc; j++) {
804                 FILE *fp = fopen(gl.gl_pathv[j], "r");
805                 size_t mod_len = 0;
806                 char *mod = NULL;
807
808                 if (!fp) {
809                         ULOG_ERR("failed to open %s\n", gl.gl_pathv[j]);
810                         continue;
811                 }
812
813                 while (getline(&mod, &mod_len, fp) > 0) {
814                         char *nl = strchr(mod, '\n');
815                         struct module *m;
816                         char *opts;
817
818                         if (nl)
819                                 *nl = '\0';
820
821                         opts = strchr(mod, ' ');
822                         if (opts)
823                                 *opts++ = '\0';
824
825                         m = find_module(get_module_name(mod));
826                         if (!m || (m->state == LOADED))
827                                 continue;
828
829                         if (opts)
830                                 m->opts = strdup(opts);
831                         m->state = PROBE;
832                         if (basename(gl.gl_pathv[j])[0] - '0' <= 9)
833                                 load_modprobe();
834
835                 }
836                 free(mod);
837                 fclose(fp);
838         }
839
840         fail = load_modprobe();
841
842         if (fail) {
843                 ULOG_ERR("%d module%s could not be probed\n",
844                          fail, (fail == 1) ? ("") : ("s"));
845
846                 avl_for_each_element(&modules, m, avl)
847                         if ((m->state == PROBE) || (m->error))
848                                 ULOG_ERR("- %s - %d\n", m->name, deps_available(m, 1));
849         } else {
850                 ULOG_INFO("done loading kernel modules from %s\n", path);
851         }
852
853 out:
854         globfree(&gl);
855         free(path);
856
857         return 0;
858 }
859
860 static int avl_modcmp(const void *k1, const void *k2, void *ptr)
861 {
862         const char *s1 = k1;
863         const char *s2 = k2;
864
865         while (*s1 && ((*s1 == *s2) ||
866                        ((*s1 == '_') && (*s2 == '-')) ||
867                        ((*s1 == '-') && (*s2 == '_'))))
868         {
869                 s1++;
870                 s2++;
871         }
872
873         return *(const unsigned char *)s1 - *(const unsigned char *)s2;
874 }
875
876 int main(int argc, char **argv)
877 {
878         char *exec = basename(*argv);
879
880         avl_init(&modules, avl_modcmp, false, NULL);
881         if (!strcmp(exec, "insmod"))
882                 return main_insmod(argc, argv);
883
884         if (!strcmp(exec, "rmmod"))
885                 return main_rmmod(argc, argv);
886
887         if (!strcmp(exec, "lsmod"))
888                 return main_lsmod(argc, argv);
889
890         if (!strcmp(exec, "modinfo"))
891                 return main_modinfo(argc, argv);
892
893         if (!strcmp(exec, "modprobe"))
894                 return main_modprobe(argc, argv);
895
896         ulog_open(ULOG_KMSG, LOG_USER, "kmodloader");
897         return main_loader(argc, argv);
898 }