1 /*
2  * Copyright (c) 2013 Google, Inc.
3  *
4  * Use of this source code is governed by a MIT-style
5  * license that can be found in the LICENSE file or at
6  * https://opensource.org/licenses/MIT
7  */
8 #include <lib/buildsig.h>
9 
10 #include <lk/debug.h>
11 #include <lk/err.h>
12 #include <stdint.h>
13 #include <stdio.h>
14 #include <string.h>
15 #include <lk/compiler.h>
16 #include <lib/version.h>
17 #include <lk/console_cmd.h>
18 
19 #define MAGIC  ((uint32_t)'BSIG')
20 #define MAGIC2 (~MAGIC)
21 #define MAGIC3 ((uint32_t)'BSG2')
22 
23 struct buildsig {
24     uint32_t magic;
25 
26     const lk_version_t *version;
27 
28     uint32_t magic2;
29 
30     uint32_t buildtype;
31     uint32_t start;
32     uint32_t end;
33     uint32_t crc32;
34 
35     uint32_t magic3;
36 };
37 
38 extern char __rom_start;
39 extern char __rom_end;
40 
41 const struct buildsig buildsig __SECTION(".text.boot") = {
42     .magic = MAGIC,
43     .version = &lk_version,
44     .magic2 = MAGIC2,
45 #if WITH_APP_BOOTLOADER
46     .buildtype = 1, /* TODO: pull from systemwide headers */
47 #else
48     .buildtype = 0,
49 #endif
50     .start = (uint32_t) &__rom_start,
51     .end = (uint32_t) &__rom_end,
52     .crc32 = 0, /* filled in via an external tool */
53     .magic3 = MAGIC3
54 };
55 
buildsig_search(const void * _ptr,size_t search_len,size_t max_len,const lk_version_t ** version)56 status_t buildsig_search(const void *_ptr, size_t search_len, size_t max_len, const lk_version_t **version) {
57     if (max_len < search_len)
58         return ERR_INVALID_ARGS;
59 
60     if (max_len < sizeof(lk_version_t))
61         return ERR_INVALID_ARGS;
62 
63     /* search for the build signature on 4 byte boundaries */
64     const uint32_t *ptr = _ptr;
65     for (size_t pos = 0; pos < search_len / 4; pos++) {
66         const struct buildsig *sig = (void *)&ptr[pos];
67 
68         /* see if the buildsig's magic matches */
69         if (sig->magic != MAGIC || sig->magic2 != MAGIC2)
70             continue;
71 
72         /* make sure the pointer to the version struct makes sense */
73         if ((size_t)sig->version - (size_t)ptr > max_len - sizeof(lk_version_t))
74             continue;
75 
76         /* validate the strings in the version struct make sense */
77         /* ensure they lie within the search area (ptr .. ptr+max_len) */
78 #define VALIDSTR(str) \
79         (((size_t)(str) >= (size_t)ptr) && (((size_t)(str) - (size_t)ptr) < max_len))
80         if (!VALIDSTR(sig->version->arch))
81             continue;
82         if (!VALIDSTR(sig->version->platform))
83             continue;
84         if (!VALIDSTR(sig->version->target))
85             continue;
86         if (!VALIDSTR(sig->version->project))
87             continue;
88         if (!VALIDSTR(sig->version->buildid))
89             continue;
90 #undef VALIDSTR
91 
92         *version = sig->version;
93         return NO_ERROR;
94     }
95 
96     return ERR_NOT_FOUND;
97 }
98 
99 extern char __rom_start;
100 
cmd_buildsig(int argc,const console_cmd_args * argv)101 static int cmd_buildsig(int argc, const console_cmd_args *argv) {
102     if (argc < 2) {
103 //notenoughargs:
104         printf("not enough args\n");
105 usage:
106         printf("usage: %s dump [offset]\n", argv[0].str);
107         return -1;
108     }
109 
110     if (!strcmp(argv[1].str, "dump")) {
111         const void *offset = &__rom_start;
112         if (argc >= 3) {
113             offset = argv[2].p;
114         }
115 
116         const lk_version_t *v;
117         status_t err = buildsig_search(offset, DEFAULT_BUILDSIG_SEARCH_LEN, 256*1024, &v);
118         if (err < 0) {
119             printf("could not find build signature\n");
120             return ERR_NOT_FOUND;
121         }
122 
123         printf("found signature:\n");
124         printf("\tarch: %s\n\tplatform: %s\n\ttarget: %s\n\tproject: %s\n\tbuildid: %s\n",
125                v->arch, v->platform, v->target, v->project, v->buildid);
126     } else {
127         goto usage;
128     }
129 
130     return NO_ERROR;
131 }
132 
133 
134 STATIC_COMMAND_START
135 #if LK_DEBUGLEVEL > 1
136 STATIC_COMMAND("buildsig", "scan for and dump build signature", &cmd_buildsig)
137 #endif
138 STATIC_COMMAND_END(buildid);
139 
140