1 /*
2  * Copyright (C) 2007-2014 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include <errno.h>
18 #include <fnmatch.h>
19 #include <stddef.h>
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <sys/stat.h>
23 #include <sys/types.h>
24 
25 #include <fcntl.h>
26 #include <dirent.h>
27 #include <unistd.h>
28 #include <string.h>
29 
30 #include <sys/socket.h>
31 #include <sys/un.h>
32 #include <linux/netlink.h>
33 
34 #include <selinux/selinux.h>
35 #include <selinux/label.h>
36 #include <selinux/android.h>
37 #include <selinux/avc.h>
38 
39 #include <private/android_filesystem_config.h>
40 #include <sys/time.h>
41 #include <sys/wait.h>
42 
43 #include <android-base/file.h>
44 #include <cutils/list.h>
45 #include <cutils/uevent.h>
46 
47 #include "devices.h"
48 #include "ueventd_parser.h"
49 #include "util.h"
50 #include "log.h"
51 
52 #define SYSFS_PREFIX    "/sys"
53 static const char *firmware_dirs[] = { "/etc/firmware",
54                                        "/vendor/firmware",
55                                        "/firmware/image" };
56 
57 extern struct selabel_handle *sehandle;
58 
59 static int device_fd = -1;
60 
61 struct uevent {
62     const char *action;
63     const char *path;
64     const char *subsystem;
65     const char *firmware;
66     const char *partition_name;
67     const char *device_name;
68     int partition_num;
69     int major;
70     int minor;
71 };
72 
73 struct perms_ {
74     char *name;
75     char *attr;
76     mode_t perm;
77     unsigned int uid;
78     unsigned int gid;
79     unsigned short prefix;
80     unsigned short wildcard;
81 };
82 
83 struct perm_node {
84     struct perms_ dp;
85     struct listnode plist;
86 };
87 
88 struct platform_node {
89     char *name;
90     char *path;
91     int path_len;
92     struct listnode list;
93 };
94 
95 static list_declare(sys_perms);
96 static list_declare(dev_perms);
97 static list_declare(platform_names);
98 
add_dev_perms(const char * name,const char * attr,mode_t perm,unsigned int uid,unsigned int gid,unsigned short prefix,unsigned short wildcard)99 int add_dev_perms(const char *name, const char *attr,
100                   mode_t perm, unsigned int uid, unsigned int gid,
101                   unsigned short prefix,
102                   unsigned short wildcard) {
103     struct perm_node *node = (perm_node*) calloc(1, sizeof(*node));
104     if (!node)
105         return -ENOMEM;
106 
107     node->dp.name = strdup(name);
108     if (!node->dp.name)
109         return -ENOMEM;
110 
111     if (attr) {
112         node->dp.attr = strdup(attr);
113         if (!node->dp.attr)
114             return -ENOMEM;
115     }
116 
117     node->dp.perm = perm;
118     node->dp.uid = uid;
119     node->dp.gid = gid;
120     node->dp.prefix = prefix;
121     node->dp.wildcard = wildcard;
122 
123     if (attr)
124         list_add_tail(&sys_perms, &node->plist);
125     else
126         list_add_tail(&dev_perms, &node->plist);
127 
128     return 0;
129 }
130 
fixup_sys_perms(const char * upath)131 void fixup_sys_perms(const char *upath)
132 {
133     char buf[512];
134     struct listnode *node;
135     struct perms_ *dp;
136 
137     /* upaths omit the "/sys" that paths in this list
138      * contain, so we add 4 when comparing...
139      */
140     list_for_each(node, &sys_perms) {
141         dp = &(node_to_item(node, struct perm_node, plist))->dp;
142         if (dp->prefix) {
143             if (strncmp(upath, dp->name + 4, strlen(dp->name + 4)))
144                 continue;
145         } else if (dp->wildcard) {
146             if (fnmatch(dp->name + 4, upath, FNM_PATHNAME) != 0)
147                 continue;
148         } else {
149             if (strcmp(upath, dp->name + 4))
150                 continue;
151         }
152 
153         if ((strlen(upath) + strlen(dp->attr) + 6) > sizeof(buf))
154             break;
155 
156         snprintf(buf, sizeof(buf), "/sys%s/%s", upath, dp->attr);
157         INFO("fixup %s %d %d 0%o\n", buf, dp->uid, dp->gid, dp->perm);
158         chown(buf, dp->uid, dp->gid);
159         chmod(buf, dp->perm);
160     }
161 
162     // Now fixup SELinux file labels
163     int len = snprintf(buf, sizeof(buf), "/sys%s", upath);
164     if ((len < 0) || ((size_t) len >= sizeof(buf))) {
165         // Overflow
166         return;
167     }
168     if (access(buf, F_OK) == 0) {
169         INFO("restorecon_recursive: %s\n", buf);
170         restorecon_recursive(buf);
171     }
172 }
173 
perm_path_matches(const char * path,struct perms_ * dp)174 static bool perm_path_matches(const char *path, struct perms_ *dp)
175 {
176     if (dp->prefix) {
177         if (strncmp(path, dp->name, strlen(dp->name)) == 0)
178             return true;
179     } else if (dp->wildcard) {
180         if (fnmatch(dp->name, path, FNM_PATHNAME) == 0)
181             return true;
182     } else {
183         if (strcmp(path, dp->name) == 0)
184             return true;
185     }
186 
187     return false;
188 }
189 
get_device_perm(const char * path,const char ** links,unsigned * uid,unsigned * gid)190 static mode_t get_device_perm(const char *path, const char **links,
191                 unsigned *uid, unsigned *gid)
192 {
193     struct listnode *node;
194     struct perm_node *perm_node;
195     struct perms_ *dp;
196 
197     /* search the perms list in reverse so that ueventd.$hardware can
198      * override ueventd.rc
199      */
200     list_for_each_reverse(node, &dev_perms) {
201         bool match = false;
202 
203         perm_node = node_to_item(node, struct perm_node, plist);
204         dp = &perm_node->dp;
205 
206         if (perm_path_matches(path, dp)) {
207             match = true;
208         } else {
209             if (links) {
210                 int i;
211                 for (i = 0; links[i]; i++) {
212                     if (perm_path_matches(links[i], dp)) {
213                         match = true;
214                         break;
215                     }
216                 }
217             }
218         }
219 
220         if (match) {
221             *uid = dp->uid;
222             *gid = dp->gid;
223             return dp->perm;
224         }
225     }
226     /* Default if nothing found. */
227     *uid = 0;
228     *gid = 0;
229     return 0600;
230 }
231 
make_device(const char * path,const char *,int block,int major,int minor,const char ** links)232 static void make_device(const char *path,
233                         const char */*upath*/,
234                         int block, int major, int minor,
235                         const char **links)
236 {
237     unsigned uid;
238     unsigned gid;
239     mode_t mode;
240     dev_t dev;
241     char *secontext = NULL;
242 
243     mode = get_device_perm(path, links, &uid, &gid) | (block ? S_IFBLK : S_IFCHR);
244 
245     if (selabel_lookup_best_match(sehandle, &secontext, path, links, mode)) {
246         ERROR("Device '%s' not created; cannot find SELinux label (%s)\n",
247                 path, strerror(errno));
248         return;
249     }
250     setfscreatecon(secontext);
251 
252     dev = makedev(major, minor);
253     /* Temporarily change egid to avoid race condition setting the gid of the
254      * device node. Unforunately changing the euid would prevent creation of
255      * some device nodes, so the uid has to be set with chown() and is still
256      * racy. Fixing the gid race at least fixed the issue with system_server
257      * opening dynamic input devices under the AID_INPUT gid. */
258     setegid(gid);
259     /* If the node already exists update its SELinux label to handle cases when
260      * it was created with the wrong context during coldboot procedure. */
261     if (mknod(path, mode, dev) && (errno == EEXIST)) {
262         if (lsetfilecon(path, secontext)) {
263             ERROR("Cannot set '%s' SELinux label on '%s' device (%s)\n",
264                     secontext, path, strerror(errno));
265         }
266     }
267     chown(path, uid, -1);
268     setegid(AID_ROOT);
269 
270     freecon(secontext);
271     setfscreatecon(NULL);
272 }
273 
add_platform_device(const char * path)274 static void add_platform_device(const char *path)
275 {
276     int path_len = strlen(path);
277     struct platform_node *bus;
278     const char *name = path;
279 
280     if (!strncmp(path, "/devices/", 9)) {
281         name += 9;
282         if (!strncmp(name, "platform/", 9))
283             name += 9;
284     }
285 
286     INFO("adding platform device %s (%s)\n", name, path);
287 
288     bus = (platform_node*) calloc(1, sizeof(struct platform_node));
289     bus->path = strdup(path);
290     bus->path_len = path_len;
291     bus->name = bus->path + (name - path);
292     list_add_tail(&platform_names, &bus->list);
293 }
294 
295 /*
296  * given a path that may start with a platform device, find the length of the
297  * platform device prefix.  If it doesn't start with a platform device, return
298  * 0.
299  */
find_platform_device(const char * path)300 static struct platform_node *find_platform_device(const char *path)
301 {
302     int path_len = strlen(path);
303     struct listnode *node;
304     struct platform_node *bus;
305 
306     list_for_each_reverse(node, &platform_names) {
307         bus = node_to_item(node, struct platform_node, list);
308         if ((bus->path_len < path_len) &&
309                 (path[bus->path_len] == '/') &&
310                 !strncmp(path, bus->path, bus->path_len))
311             return bus;
312     }
313 
314     return NULL;
315 }
316 
remove_platform_device(const char * path)317 static void remove_platform_device(const char *path)
318 {
319     struct listnode *node;
320     struct platform_node *bus;
321 
322     list_for_each_reverse(node, &platform_names) {
323         bus = node_to_item(node, struct platform_node, list);
324         if (!strcmp(path, bus->path)) {
325             INFO("removing platform device %s\n", bus->name);
326             free(bus->path);
327             list_remove(node);
328             free(bus);
329             return;
330         }
331     }
332 }
333 
334 /* Given a path that may start with a PCI device, populate the supplied buffer
335  * with the PCI domain/bus number and the peripheral ID and return 0.
336  * If it doesn't start with a PCI device, or there is some error, return -1 */
find_pci_device_prefix(const char * path,char * buf,ssize_t buf_sz)337 static int find_pci_device_prefix(const char *path, char *buf, ssize_t buf_sz)
338 {
339     const char *start, *end;
340 
341     if (strncmp(path, "/devices/pci", 12))
342         return -1;
343 
344     /* Beginning of the prefix is the initial "pci" after "/devices/" */
345     start = path + 9;
346 
347     /* End of the prefix is two path '/' later, capturing the domain/bus number
348      * and the peripheral ID. Example: pci0000:00/0000:00:1f.2 */
349     end = strchr(start, '/');
350     if (!end)
351         return -1;
352     end = strchr(end + 1, '/');
353     if (!end)
354         return -1;
355 
356     /* Make sure we have enough room for the string plus null terminator */
357     if (end - start + 1 > buf_sz)
358         return -1;
359 
360     strncpy(buf, start, end - start);
361     buf[end - start] = '\0';
362     return 0;
363 }
364 
parse_event(const char * msg,struct uevent * uevent)365 static void parse_event(const char *msg, struct uevent *uevent)
366 {
367     uevent->action = "";
368     uevent->path = "";
369     uevent->subsystem = "";
370     uevent->firmware = "";
371     uevent->major = -1;
372     uevent->minor = -1;
373     uevent->partition_name = NULL;
374     uevent->partition_num = -1;
375     uevent->device_name = NULL;
376 
377         /* currently ignoring SEQNUM */
378     while(*msg) {
379         if(!strncmp(msg, "ACTION=", 7)) {
380             msg += 7;
381             uevent->action = msg;
382         } else if(!strncmp(msg, "DEVPATH=", 8)) {
383             msg += 8;
384             uevent->path = msg;
385         } else if(!strncmp(msg, "SUBSYSTEM=", 10)) {
386             msg += 10;
387             uevent->subsystem = msg;
388         } else if(!strncmp(msg, "FIRMWARE=", 9)) {
389             msg += 9;
390             uevent->firmware = msg;
391         } else if(!strncmp(msg, "MAJOR=", 6)) {
392             msg += 6;
393             uevent->major = atoi(msg);
394         } else if(!strncmp(msg, "MINOR=", 6)) {
395             msg += 6;
396             uevent->minor = atoi(msg);
397         } else if(!strncmp(msg, "PARTN=", 6)) {
398             msg += 6;
399             uevent->partition_num = atoi(msg);
400         } else if(!strncmp(msg, "PARTNAME=", 9)) {
401             msg += 9;
402             uevent->partition_name = msg;
403         } else if(!strncmp(msg, "DEVNAME=", 8)) {
404             msg += 8;
405             uevent->device_name = msg;
406         }
407 
408         /* advance to after the next \0 */
409         while(*msg++)
410             ;
411     }
412 
413     if (LOG_UEVENTS) {
414         INFO("event { '%s', '%s', '%s', '%s', %d, %d }\n",
415              uevent->action, uevent->path, uevent->subsystem,
416              uevent->firmware, uevent->major, uevent->minor);
417     }
418 }
419 
get_character_device_symlinks(struct uevent * uevent)420 static char **get_character_device_symlinks(struct uevent *uevent)
421 {
422     const char *parent;
423     char *slash;
424     char **links;
425     int link_num = 0;
426     int width;
427     struct platform_node *pdev;
428 
429     pdev = find_platform_device(uevent->path);
430     if (!pdev)
431         return NULL;
432 
433     links = (char**) malloc(sizeof(char *) * 2);
434     if (!links)
435         return NULL;
436     memset(links, 0, sizeof(char *) * 2);
437 
438     /* skip "/devices/platform/<driver>" */
439     parent = strchr(uevent->path + pdev->path_len, '/');
440     if (!parent)
441         goto err;
442 
443     if (!strncmp(parent, "/usb", 4)) {
444         /* skip root hub name and device. use device interface */
445         while (*++parent && *parent != '/');
446         if (*parent)
447             while (*++parent && *parent != '/');
448         if (!*parent)
449             goto err;
450         slash = strchr(++parent, '/');
451         if (!slash)
452             goto err;
453         width = slash - parent;
454         if (width <= 0)
455             goto err;
456 
457         if (asprintf(&links[link_num], "/dev/usb/%s%.*s", uevent->subsystem, width, parent) > 0)
458             link_num++;
459         else
460             links[link_num] = NULL;
461         mkdir("/dev/usb", 0755);
462     }
463     else {
464         goto err;
465     }
466 
467     return links;
468 err:
469     free(links);
470     return NULL;
471 }
472 
get_block_device_symlinks(struct uevent * uevent)473 static char **get_block_device_symlinks(struct uevent *uevent)
474 {
475     const char *device;
476     struct platform_node *pdev;
477     char *slash;
478     const char *type;
479     char buf[256];
480     char link_path[256];
481     int link_num = 0;
482     char *p;
483 
484     pdev = find_platform_device(uevent->path);
485     if (pdev) {
486         device = pdev->name;
487         type = "platform";
488     } else if (!find_pci_device_prefix(uevent->path, buf, sizeof(buf))) {
489         device = buf;
490         type = "pci";
491     } else {
492         return NULL;
493     }
494 
495     char **links = (char**) malloc(sizeof(char *) * 4);
496     if (!links)
497         return NULL;
498     memset(links, 0, sizeof(char *) * 4);
499 
500     INFO("found %s device %s\n", type, device);
501 
502     snprintf(link_path, sizeof(link_path), "/dev/block/%s/%s", type, device);
503 
504     if (uevent->partition_name) {
505         p = strdup(uevent->partition_name);
506         sanitize(p);
507         if (strcmp(uevent->partition_name, p))
508             NOTICE("Linking partition '%s' as '%s'\n", uevent->partition_name, p);
509         if (asprintf(&links[link_num], "%s/by-name/%s", link_path, p) > 0)
510             link_num++;
511         else
512             links[link_num] = NULL;
513         free(p);
514     }
515 
516     if (uevent->partition_num >= 0) {
517         if (asprintf(&links[link_num], "%s/by-num/p%d", link_path, uevent->partition_num) > 0)
518             link_num++;
519         else
520             links[link_num] = NULL;
521     }
522 
523     slash = strrchr(uevent->path, '/');
524     if (asprintf(&links[link_num], "%s/%s", link_path, slash + 1) > 0)
525         link_num++;
526     else
527         links[link_num] = NULL;
528 
529     return links;
530 }
531 
handle_device(const char * action,const char * devpath,const char * path,int block,int major,int minor,char ** links)532 static void handle_device(const char *action, const char *devpath,
533         const char *path, int block, int major, int minor, char **links)
534 {
535     int i;
536 
537     if(!strcmp(action, "add")) {
538         make_device(devpath, path, block, major, minor, (const char **)links);
539         if (links) {
540             for (i = 0; links[i]; i++)
541                 make_link_init(devpath, links[i]);
542         }
543     }
544 
545     if(!strcmp(action, "remove")) {
546         if (links) {
547             for (i = 0; links[i]; i++)
548                 remove_link(devpath, links[i]);
549         }
550         unlink(devpath);
551     }
552 
553     if (links) {
554         for (i = 0; links[i]; i++)
555             free(links[i]);
556         free(links);
557     }
558 }
559 
handle_platform_device_event(struct uevent * uevent)560 static void handle_platform_device_event(struct uevent *uevent)
561 {
562     const char *path = uevent->path;
563 
564     if (!strcmp(uevent->action, "add"))
565         add_platform_device(path);
566     else if (!strcmp(uevent->action, "remove"))
567         remove_platform_device(path);
568 }
569 
parse_device_name(struct uevent * uevent,unsigned int len)570 static const char *parse_device_name(struct uevent *uevent, unsigned int len)
571 {
572     const char *name;
573 
574     /* if it's not a /dev device, nothing else to do */
575     if((uevent->major < 0) || (uevent->minor < 0))
576         return NULL;
577 
578     /* do we have a name? */
579     name = strrchr(uevent->path, '/');
580     if(!name)
581         return NULL;
582     name++;
583 
584     /* too-long names would overrun our buffer */
585     if(strlen(name) > len) {
586         ERROR("DEVPATH=%s exceeds %u-character limit on filename; ignoring event\n",
587                 name, len);
588         return NULL;
589     }
590 
591     return name;
592 }
593 
handle_block_device_event(struct uevent * uevent)594 static void handle_block_device_event(struct uevent *uevent)
595 {
596     const char *base = "/dev/block/";
597     const char *name;
598     char devpath[96];
599     char **links = NULL;
600 
601     name = parse_device_name(uevent, 64);
602     if (!name)
603         return;
604 
605     snprintf(devpath, sizeof(devpath), "%s%s", base, name);
606     make_dir(base, 0755);
607 
608     if (!strncmp(uevent->path, "/devices/", 9))
609         links = get_block_device_symlinks(uevent);
610 
611     handle_device(uevent->action, devpath, uevent->path, 1,
612             uevent->major, uevent->minor, links);
613 }
614 
615 #define DEVPATH_LEN 96
616 
assemble_devpath(char * devpath,const char * dirname,const char * devname)617 static bool assemble_devpath(char *devpath, const char *dirname,
618         const char *devname)
619 {
620     int s = snprintf(devpath, DEVPATH_LEN, "%s/%s", dirname, devname);
621     if (s < 0) {
622         ERROR("failed to assemble device path (%s); ignoring event\n",
623                 strerror(errno));
624         return false;
625     } else if (s >= DEVPATH_LEN) {
626         ERROR("%s/%s exceeds %u-character limit on path; ignoring event\n",
627                 dirname, devname, DEVPATH_LEN);
628         return false;
629     }
630     return true;
631 }
632 
mkdir_recursive_for_devpath(const char * devpath)633 static void mkdir_recursive_for_devpath(const char *devpath)
634 {
635     char dir[DEVPATH_LEN];
636     char *slash;
637 
638     strcpy(dir, devpath);
639     slash = strrchr(dir, '/');
640     *slash = '\0';
641     mkdir_recursive(dir, 0755);
642 }
643 
handle_generic_device_event(struct uevent * uevent)644 static void handle_generic_device_event(struct uevent *uevent)
645 {
646     const char *base;
647     const char *name;
648     char devpath[DEVPATH_LEN] = {0};
649     char **links = NULL;
650 
651     name = parse_device_name(uevent, 64);
652     if (!name)
653         return;
654 
655     struct ueventd_subsystem *subsystem =
656             ueventd_subsystem_find_by_name(uevent->subsystem);
657 
658     if (subsystem) {
659         const char *devname;
660 
661         switch (subsystem->devname_src) {
662         case DEVNAME_UEVENT_DEVNAME:
663             devname = uevent->device_name;
664             break;
665 
666         case DEVNAME_UEVENT_DEVPATH:
667             devname = name;
668             break;
669 
670         default:
671             ERROR("%s subsystem's devpath option is not set; ignoring event\n",
672                     uevent->subsystem);
673             return;
674         }
675 
676         if (!assemble_devpath(devpath, subsystem->dirname, devname))
677             return;
678         mkdir_recursive_for_devpath(devpath);
679     } else if (!strncmp(uevent->subsystem, "usb", 3)) {
680          if (!strcmp(uevent->subsystem, "usb")) {
681             if (uevent->device_name) {
682                 if (!assemble_devpath(devpath, "/dev", uevent->device_name))
683                     return;
684                 mkdir_recursive_for_devpath(devpath);
685              }
686              else {
687                  /* This imitates the file system that would be created
688                   * if we were using devfs instead.
689                   * Minors are broken up into groups of 128, starting at "001"
690                   */
691                  int bus_id = uevent->minor / 128 + 1;
692                  int device_id = uevent->minor % 128 + 1;
693                  /* build directories */
694                  make_dir("/dev/bus", 0755);
695                  make_dir("/dev/bus/usb", 0755);
696                  snprintf(devpath, sizeof(devpath), "/dev/bus/usb/%03d", bus_id);
697                  make_dir(devpath, 0755);
698                  snprintf(devpath, sizeof(devpath), "/dev/bus/usb/%03d/%03d", bus_id, device_id);
699              }
700          } else {
701              /* ignore other USB events */
702              return;
703          }
704      } else if (!strncmp(uevent->subsystem, "graphics", 8)) {
705          base = "/dev/graphics/";
706          make_dir(base, 0755);
707      } else if (!strncmp(uevent->subsystem, "drm", 3)) {
708          base = "/dev/dri/";
709          make_dir(base, 0755);
710      } else if (!strncmp(uevent->subsystem, "oncrpc", 6)) {
711          base = "/dev/oncrpc/";
712          make_dir(base, 0755);
713      } else if (!strncmp(uevent->subsystem, "adsp", 4)) {
714          base = "/dev/adsp/";
715          make_dir(base, 0755);
716      } else if (!strncmp(uevent->subsystem, "msm_camera", 10)) {
717          base = "/dev/msm_camera/";
718          make_dir(base, 0755);
719      } else if(!strncmp(uevent->subsystem, "input", 5)) {
720          base = "/dev/input/";
721          make_dir(base, 0755);
722      } else if(!strncmp(uevent->subsystem, "mtd", 3)) {
723          base = "/dev/mtd/";
724          make_dir(base, 0755);
725      } else if(!strncmp(uevent->subsystem, "sound", 5)) {
726          base = "/dev/snd/";
727          make_dir(base, 0755);
728      } else if(!strncmp(uevent->subsystem, "misc", 4) &&
729                  !strncmp(name, "log_", 4)) {
730          INFO("kernel logger is deprecated\n");
731          base = "/dev/log/";
732          make_dir(base, 0755);
733          name += 4;
734      } else
735          base = "/dev/";
736      links = get_character_device_symlinks(uevent);
737 
738      if (!devpath[0])
739          snprintf(devpath, sizeof(devpath), "%s%s", base, name);
740 
741      handle_device(uevent->action, devpath, uevent->path, 0,
742              uevent->major, uevent->minor, links);
743 }
744 
handle_device_event(struct uevent * uevent)745 static void handle_device_event(struct uevent *uevent)
746 {
747     if (!strcmp(uevent->action,"add") || !strcmp(uevent->action, "change") || !strcmp(uevent->action, "online"))
748         fixup_sys_perms(uevent->path);
749 
750     if (!strncmp(uevent->subsystem, "block", 5)) {
751         handle_block_device_event(uevent);
752     } else if (!strncmp(uevent->subsystem, "platform", 8)) {
753         handle_platform_device_event(uevent);
754     } else {
755         handle_generic_device_event(uevent);
756     }
757 }
758 
load_firmware(int fw_fd,int loading_fd,int data_fd)759 static int load_firmware(int fw_fd, int loading_fd, int data_fd)
760 {
761     struct stat st;
762     long len_to_copy;
763     int ret = 0;
764 
765     if(fstat(fw_fd, &st) < 0)
766         return -1;
767     len_to_copy = st.st_size;
768 
769     write(loading_fd, "1", 1);  /* start transfer */
770 
771     while (len_to_copy > 0) {
772         char buf[PAGE_SIZE];
773         ssize_t nr;
774 
775         nr = read(fw_fd, buf, sizeof(buf));
776         if(!nr)
777             break;
778         if(nr < 0) {
779             ret = -1;
780             break;
781         }
782         if (!android::base::WriteFully(data_fd, buf, nr)) {
783             ret = -1;
784             break;
785         }
786         len_to_copy -= nr;
787     }
788 
789     if(!ret)
790         write(loading_fd, "0", 1);  /* successful end of transfer */
791     else
792         write(loading_fd, "-1", 2); /* abort transfer */
793 
794     return ret;
795 }
796 
is_booting(void)797 static int is_booting(void)
798 {
799     return access("/dev/.booting", F_OK) == 0;
800 }
801 
process_firmware_event(struct uevent * uevent)802 static void process_firmware_event(struct uevent *uevent)
803 {
804     char *root, *loading, *data;
805     int l, loading_fd, data_fd, fw_fd;
806     size_t i;
807     int booting = is_booting();
808 
809     INFO("firmware: loading '%s' for '%s'\n",
810          uevent->firmware, uevent->path);
811 
812     l = asprintf(&root, SYSFS_PREFIX"%s/", uevent->path);
813     if (l == -1)
814         return;
815 
816     l = asprintf(&loading, "%sloading", root);
817     if (l == -1)
818         goto root_free_out;
819 
820     l = asprintf(&data, "%sdata", root);
821     if (l == -1)
822         goto loading_free_out;
823 
824     loading_fd = open(loading, O_WRONLY|O_CLOEXEC);
825     if(loading_fd < 0)
826         goto data_free_out;
827 
828     data_fd = open(data, O_WRONLY|O_CLOEXEC);
829     if(data_fd < 0)
830         goto loading_close_out;
831 
832 try_loading_again:
833     for (i = 0; i < ARRAY_SIZE(firmware_dirs); i++) {
834         char *file = NULL;
835         l = asprintf(&file, "%s/%s", firmware_dirs[i], uevent->firmware);
836         if (l == -1)
837             goto data_free_out;
838         fw_fd = open(file, O_RDONLY|O_CLOEXEC);
839         free(file);
840         if (fw_fd >= 0) {
841             if(!load_firmware(fw_fd, loading_fd, data_fd))
842                 INFO("firmware: copy success { '%s', '%s' }\n", root, uevent->firmware);
843             else
844                 INFO("firmware: copy failure { '%s', '%s' }\n", root, uevent->firmware);
845             break;
846         }
847     }
848     if (fw_fd < 0) {
849         if (booting) {
850             /* If we're not fully booted, we may be missing
851              * filesystems needed for firmware, wait and retry.
852              */
853             usleep(100000);
854             booting = is_booting();
855             goto try_loading_again;
856         }
857         INFO("firmware: could not open '%s': %s\n", uevent->firmware, strerror(errno));
858         write(loading_fd, "-1", 2);
859         goto data_close_out;
860     }
861 
862     close(fw_fd);
863 data_close_out:
864     close(data_fd);
865 loading_close_out:
866     close(loading_fd);
867 data_free_out:
868     free(data);
869 loading_free_out:
870     free(loading);
871 root_free_out:
872     free(root);
873 }
874 
handle_firmware_event(struct uevent * uevent)875 static void handle_firmware_event(struct uevent *uevent)
876 {
877     pid_t pid;
878 
879     if(strcmp(uevent->subsystem, "firmware"))
880         return;
881 
882     if(strcmp(uevent->action, "add"))
883         return;
884 
885     /* we fork, to avoid making large memory allocations in init proper */
886     pid = fork();
887     if (!pid) {
888         process_firmware_event(uevent);
889         _exit(EXIT_SUCCESS);
890     } else if (pid < 0) {
891         ERROR("could not fork to process firmware event: %s\n", strerror(errno));
892     }
893 }
894 
895 #define UEVENT_MSG_LEN  2048
handle_device_fd()896 void handle_device_fd()
897 {
898     char msg[UEVENT_MSG_LEN+2];
899     int n;
900     while ((n = uevent_kernel_multicast_recv(device_fd, msg, UEVENT_MSG_LEN)) > 0) {
901         if(n >= UEVENT_MSG_LEN)   /* overflow -- discard */
902             continue;
903 
904         msg[n] = '\0';
905         msg[n+1] = '\0';
906 
907         struct uevent uevent;
908         parse_event(msg, &uevent);
909 
910         if (selinux_status_updated() > 0) {
911             struct selabel_handle *sehandle2;
912             sehandle2 = selinux_android_file_context_handle();
913             if (sehandle2) {
914                 selabel_close(sehandle);
915                 sehandle = sehandle2;
916             }
917         }
918 
919         handle_device_event(&uevent);
920         handle_firmware_event(&uevent);
921     }
922 }
923 
924 /* Coldboot walks parts of the /sys tree and pokes the uevent files
925 ** to cause the kernel to regenerate device add events that happened
926 ** before init's device manager was started
927 **
928 ** We drain any pending events from the netlink socket every time
929 ** we poke another uevent file to make sure we don't overrun the
930 ** socket's buffer.
931 */
932 
do_coldboot(DIR * d)933 static void do_coldboot(DIR *d)
934 {
935     struct dirent *de;
936     int dfd, fd;
937 
938     dfd = dirfd(d);
939 
940     fd = openat(dfd, "uevent", O_WRONLY);
941     if(fd >= 0) {
942         write(fd, "add\n", 4);
943         close(fd);
944         handle_device_fd();
945     }
946 
947     while((de = readdir(d))) {
948         DIR *d2;
949 
950         if(de->d_type != DT_DIR || de->d_name[0] == '.')
951             continue;
952 
953         fd = openat(dfd, de->d_name, O_RDONLY | O_DIRECTORY);
954         if(fd < 0)
955             continue;
956 
957         d2 = fdopendir(fd);
958         if(d2 == 0)
959             close(fd);
960         else {
961             do_coldboot(d2);
962             closedir(d2);
963         }
964     }
965 }
966 
coldboot(const char * path)967 static void coldboot(const char *path)
968 {
969     DIR *d = opendir(path);
970     if(d) {
971         do_coldboot(d);
972         closedir(d);
973     }
974 }
975 
device_init()976 void device_init() {
977     sehandle = selinux_android_file_context_handle();
978     selinux_status_open(true);
979 
980     /* is 256K enough? udev uses 16MB! */
981     device_fd = uevent_open_socket(256*1024, true);
982     if (device_fd == -1) {
983         return;
984     }
985     fcntl(device_fd, F_SETFL, O_NONBLOCK);
986 
987     if (access(COLDBOOT_DONE, F_OK) == 0) {
988         NOTICE("Skipping coldboot, already done!\n");
989         return;
990     }
991 
992     Timer t;
993     coldboot("/sys/class");
994     coldboot("/sys/block");
995     coldboot("/sys/devices");
996     close(open(COLDBOOT_DONE, O_WRONLY|O_CREAT|O_CLOEXEC, 0000));
997     NOTICE("Coldboot took %.2fs.\n", t.duration());
998 }
999 
get_device_fd()1000 int get_device_fd()
1001 {
1002     return device_fd;
1003 }
1004