• source navigation  • diff markup  • identifier search  • freetext search  • 

Sources/firmware-utils/src/jcgimage.c

  1 // SPDX-License-Identifier: GPL-2.0-or-later
  2 /*
  3  * jcgimage - Create a JCG firmware image
  4  *
  5  * Copyright (C) 2015 Reinhard Max <reinhard@m4x.de>
  6  * Copyright (C) 2019 Davide Fioravanti <pantanastyle@gmail.com>
  7  */
  8 
  9 /*
 10  * JCG firmware update images consist of a 512 byte header and a
 11  * modified uImage (details below) as the payload.
 12  *
 13  * The payload is obfuscated by XORing it with a key that is generated
 14  * from parts of the header. Fortunately only non-essential parts of
 15  * the header are used for this and zeroing them results in a zero
 16  * key, effectively disabling the obfuscation and allowing us to use
 17  * clear text payloads.
 18  *
 19  * The mandatory parts of the header are:
 20  *
 21  * - A magic string of "YSZJ" at offset 0.
 22  * - A value of 1 at offset 39 (header format version?)
 23  * - A CRC32 checksum of the payload at offset 504.
 24  * - A CRC32 checksum of the header at offset 508.
 25  *
 26  * An image constructed by these rules will be accepted by JCG's
 27  * U-Boot in resuce mode via TFTP and the payload will be written to
 28  * the flash starting at offset 0x00050000.
 29  *
 30  * JCG's U-Boot does check the content or size of the payload
 31  * image. If it is too large, it wraps around and overwrites U-Boot,
 32  * requiring JTAG to revive the board. To prevent such bricking from
 33  * happening, this tool refuses to build such overlong images.
 34  *
 35  * Using -m is possible to set the maximum size of the payload.
 36  * Otherwise the default MAXSIZE will be used.
 37  * For an 8Mb flash, the corresponding maxsize is:
 38  * 8 * 1024 * 1024 - 5 * 64 * 1024 = 8388608 - 327680 = 8060928
 39  *
 40  * Two more conditions have to be met for a JCG image to be accepted
 41  * as a valid update by the web interface of the stock firware:
 42  *
 43  *   - The bytes at offsets 109 and 111 in the header must be a binary
 44  *   representation of the first two components of the firmware
 45  *   version as displayed in the update web form, or it will be
 46  *   rejected as "incorrect product".
 47  *
 48  *   - The payload must start with a valid uImage header whose data
 49  *   CRC checksum matches the whole rest of the update file rather
 50  *   than just the number of bytes specified in the size field of the
 51  *   header.
 52  *
 53  * This last condition is met by JCG's original firmware images,
 54  * because they have both, kernel and rootfs inside the uImage and
 55  * abuse the last four bytes of the name field to record the offset of
 56  * the file system from the start of the uImage header. This tool
 57  * produces such images when called with -k and -r, which are meant to
 58  * repack the original firmware after modifying the file systen,
 59  * e.g. to add debugging tools and enable shell access.
 60  *
 61  * In contrast, OpenWrt sysupgrade images consist of a uImage that
 62  * only contains the kernel and has the rootfs appended to it. Hence,
 63  * the CRC over kernel and file system does not match the one in the
 64  * uImage header. Fixing this by adjusting the uImage header is not
 65  * possible, because it makes the uImage unusable for booting. Instead
 66  * we append four "patch" bytes to the end of the file system, that
 67  * are calculated to force the checksum of kernel+fs to be the same as
 68  * for the kernel alone.
 69  *
 70  */
 71 
 72 #include <zlib.h>
 73 #include <stdio.h>
 74 #include <string.h>
 75 #include <sys/types.h>
 76 #include <sys/stat.h>
 77 #include <fcntl.h>
 78 #include <unistd.h>
 79 #include <libgen.h>
 80 #include <stdlib.h>
 81 #include <errno.h>
 82 #include <err.h>
 83 #include <time.h>
 84 #include <sys/mman.h>
 85 #include <arpa/inet.h>
 86 #include <assert.h>
 87 #include <inttypes.h>
 88 
 89 /*
 90  * JCG Firmware image header
 91  */
 92 #define JH_MAGIC 0x59535a4a        /* "YSZJ" */
 93 struct jcg_header {
 94         uint32_t jh_magic;
 95         uint8_t  jh_version[32];   /* Firmware version string.
 96                                       Fill with zeros to avoid encryption  */
 97         uint32_t jh_type;          /* must be 1                            */
 98         uint8_t  jh_info[64];      /* Firmware info string. Fill with
 99                                       zeros to avoid encryption            */
100         uint32_t jh_time;          /* Image creation time in seconds since
101                                     * the Epoch. Does not seem to be used
102                                     * by the stock firmware.               */
103         uint16_t jh_major;         /* Major fimware version                */
104         uint16_t jh_minor;         /* Minor fimrmware version              */
105         uint8_t  jh_unknown[392];  /* Apparently unused and all zeros      */
106         uint32_t jh_dcrc;          /* CRC checksum of the payload          */
107         uint32_t jh_hcrc;          /* CRC checksum of the header           */
108 };
109 
110 /*
111  * JCG uses a modified uImage header that replaces the last four bytes
112  * of the image name with the length of the kernel in the image.
113  */
114 #define IH_MAGIC    0x27051956    /* Image Magic Number     */
115 #define IH_NMLEN    28            /* Image Name Length      */
116 
117 struct uimage_header {
118         uint32_t    ih_magic;         /* Image Header Magic Number   */
119         uint32_t    ih_hcrc;          /* Image Header CRC Checksum   */
120         uint32_t    ih_time;          /* Image Creation Timestamp    */
121         uint32_t    ih_size;          /* Image Data Size             */
122         uint32_t    ih_load;          /* Data     Load  Address      */
123         uint32_t    ih_ep;            /* Entry Point Address         */
124         uint32_t    ih_dcrc;          /* Image Data CRC Checksum     */
125         uint8_t     ih_os;            /* Operating System            */
126         uint8_t     ih_arch;          /* CPU architecture            */
127         uint8_t     ih_type;          /* Image Type                  */
128         uint8_t     ih_comp;          /* Compression Type            */
129         uint8_t     ih_name[IH_NMLEN];/* Image Name                  */
130         uint32_t    ih_fsoff;         /* Offset of the file system
131                                          partition from the start of
132                                          the header                  */
133 };
134 
135 /*
136  * Open the named file and return its size and file descriptor.
137  * Exit in case of errors.
138  */
139 int
140 opensize(char *name, size_t *size)
141 {
142         struct stat s;
143         int fd = open(name, O_RDONLY);
144         if (fd < 0)
145                 err(1, "cannot open \"%s\"", name);
146 
147         if (fstat(fd, &s) == -1)
148                 err(1, "cannot stat \"%s\"", name);
149 
150         *size = s.st_size;
151         return fd;
152 }
153 
154 static time_t source_date_epoch = -1;
155 static void set_source_date_epoch() {
156         char *env = getenv("SOURCE_DATE_EPOCH");
157         char *endptr = env;
158         errno = 0;
159         if (env && *env) {
160                 source_date_epoch = strtoull(env, &endptr, 10);
161                 if (errno || (endptr && *endptr != '\0')) {
162                         fprintf(stderr, "Invalid SOURCE_DATE_EPOCH");
163                         exit(1);
164                 }
165         }
166 }
167 
168 /*
169  * Write the JCG header
170  */
171 void
172 mkjcgheader(struct jcg_header *h, size_t psize, char *version)
173 {
174         uLong crc;
175         uint16_t major = 0, minor = 0;
176         void *payload = (void *)h + sizeof(*h);
177         time_t t;
178 
179         if (source_date_epoch != -1)
180                 t = source_date_epoch;
181         else if ((time(&t) == (time_t)(-1)))
182                 err(1, "time call failed");
183 
184 
185         if (version != NULL)
186                 if (sscanf(version, "%hu.%hu", &major, &minor) != 2)
187                         err(1, "cannot parse version \"%s\"", version);
188 
189         memset(h, 0, sizeof(*h));
190         h->jh_magic = htonl(JH_MAGIC);
191         h->jh_type  = htonl(1);
192         h->jh_time  = htonl(t);
193         h->jh_major = htons(major);
194         h->jh_minor = htons(minor);
195 
196         /* CRC over JCG payload (uImage) */
197         crc = crc32(0L, Z_NULL, 0);
198         crc = crc32(crc, payload, psize);
199         h->jh_dcrc  = htonl(crc);
200 
201         /* CRC over JCG header */
202         crc = crc32(0L, Z_NULL, 0);
203         crc = crc32(crc, (void *)h, sizeof(*h));
204         h->jh_hcrc  = htonl(crc);
205 }
206 
207 /*
208  * Write the uImage header
209  */
210 void
211 mkuheader(struct uimage_header *h, size_t ksize, size_t fsize)
212 {
213         uLong crc;
214         void *payload = (void *)h + sizeof(*h);
215 
216         // printf("mkuheader: %p, %zd, %zd\n", h, ksize, fsize);
217         memset(h, 0, sizeof(*h));
218         h->ih_magic = htonl(IH_MAGIC);
219         h->ih_time  = htonl(time(NULL));
220         h->ih_size  = htonl(ksize + fsize);
221         h->ih_load  = htonl(0x80000000);
222         h->ih_ep    = htonl(0x80292000);
223         h->ih_os    = 0x05;
224         h->ih_arch  = 0x05;
225         h->ih_type  = 0x02;
226         h->ih_comp  = 0x03;
227         h->ih_fsoff = htonl(sizeof(*h) + ksize);
228         strcpy((char *)h->ih_name, "Linux Kernel Image");
229 
230         /* CRC over uImage payload (kernel and file system) */
231         crc = crc32(0L, Z_NULL, 0);
232         crc = crc32(crc, payload, ntohl(h->ih_size));
233         h->ih_dcrc  = htonl(crc);
234         printf("CRC1: %08lx\n", crc);
235 
236         /* CRC over uImage header */
237         crc = crc32(0L, Z_NULL, 0);
238         crc = crc32(crc, (void *)h, sizeof(*h));
239         h->ih_hcrc  = htonl(crc);
240         printf("CRC2: %08lx\n", crc);
241 }
242 
243 /*
244  * Calculate a "patch" value and write it into the last four bytes of
245  * buf, so that the CRC32 checksum of the whole buffer is dcrc.
246  *
247  * Based on: SAR-PR-2006-05: Reversing CRC – Theory and Practice.
248  * Martin Stigge, Henryk Plötz, Wolf Müller, Jens-Peter Redlich.
249  * http://sar.informatik.hu-berlin.de/research/publications/#SAR-PR-2006-05
250  */
251 void
252 craftcrc(uint32_t dcrc, uint8_t *buf, size_t len)
253 {
254         int i;
255         uint32_t a;
256         uint32_t patch = 0;
257         uint32_t crc = crc32(0L, Z_NULL, 0);
258 
259         a = ~dcrc;
260         for (i = 0; i < 32; i++) {
261                 if (patch & 1)
262                         patch = (patch >> 1) ^ 0xedb88320L;
263                 else
264                         patch >>= 1;
265 
266                 if (a & 1)
267                         patch ^= 0x5b358fd3L;
268 
269                 a >>= 1;
270         }
271         patch ^= ~crc32(crc, buf, len - 4);
272         for (i = 0; i < 4; i++) {
273                 buf[len - 4 + i] = patch & 0xff;
274                 patch >>= 8;
275         }
276         /* Verify that we actually get the desired result */
277         crc = crc32(0L, Z_NULL, 0);
278         crc = crc32(crc, buf, len);
279         if (crc != dcrc)
280                 errx(1, "CRC patching is broken: wanted %08x, but got %08x.",
281                      dcrc, crc);
282 
283 }
284 
285 void
286 usage() {
287         fprintf(stderr, "Usage:\n"
288                 "jcgimage -o outfile -u uImage [-m maxsize] [-v version]\n"
289                 "jcgimage -o outfile -k kernel -f rootfs [-m maxsize] [-v version]\n");
290         exit(1);
291 }
292 
293 #define MODE_UNKNOWN 0
294 #define MODE_UIMAGE 1
295 #define MODE_KR 2
296 
297 /* The output image must not be larger than 4MiB - 5*64kiB */
298 #define MAXSIZE (size_t)(4 * 1024 * 1024 - 5 * 64 * 1024)
299 
300 int
301 main(int argc, char **argv)
302 {
303         struct jcg_header *jh;
304         struct uimage_header *uh;
305         int c;
306         char *imagefile = NULL;
307         char *file1 = NULL;
308         char *file2 = NULL;
309         char *version = NULL;
310         size_t maxsize = MAXSIZE;
311         char *endptr;
312         int mode = MODE_UNKNOWN;
313         int fdo, fd1, fd2;
314         size_t size1, size2, sizeu, sizeo, off1, off2;
315         void *map;
316 
317         /* Make sure the headers have the right size */
318         assert(sizeof(struct jcg_header) == 512);
319         assert(sizeof(struct uimage_header) == 64);
320         set_source_date_epoch();
321 
322         while ((c = getopt(argc, argv, "o:k:f:u:v:m:h")) != -1) {
323                 switch (c) {
324                 case 'o':
325                         imagefile = optarg;
326                         break;
327                 case 'k':
328                         if (mode == MODE_UIMAGE)
329                                 errx(1,"-k cannot be combined with -u");
330 
331                         mode = MODE_KR;
332                         file1 = optarg;
333                         break;
334                 case 'f':
335                         if (mode == MODE_UIMAGE)
336                                 errx(1,"-f cannot be combined with -u");
337 
338                         mode = MODE_KR;
339                         file2 = optarg;
340                         break;
341                 case 'u':
342                         if (mode == MODE_KR)
343                                 errx(1,"-u cannot be combined with -k and -r");
344 
345                         mode = MODE_UIMAGE;
346                         file1 = optarg;
347                         break;
348                 case 'm':
349                         if (optarg != NULL)
350                                 maxsize = strtoimax(optarg, &endptr, 10);
351 
352                         break;
353                 case 'v':
354                         version = optarg;
355                         break;
356                 case 'h':
357                 default:
358                         usage();
359                 }
360         }
361         if (optind != argc)
362                 errx(1, "illegal arg \"%s\"", argv[optind]);
363 
364         if (imagefile == NULL)
365                 errx(1, "no output file specified");
366 
367         if (mode == MODE_UNKNOWN)
368                 errx(1, "specify either -u or -k and -r");
369 
370         if (mode == MODE_KR) {
371                 if (file1 == NULL || file2 == NULL)
372                         errx(1, "need -k and -r");
373 
374                 fd2 = opensize(file2, &size2);
375         }
376         fd1 = opensize(file1, &size1);
377         if (mode == MODE_UIMAGE) {
378                 off1 = sizeof(*jh);
379                 sizeu = size1 + 4;
380                 sizeo = sizeof(*jh) + sizeu;
381         } else {
382                 off1 = sizeof(*jh) + sizeof(*uh);
383                 off2 = sizeof(*jh) + sizeof(*uh) + size1;
384                 sizeu = sizeof(*uh) + size1 + size2;
385                 sizeo = sizeof(*jh) + sizeu;
386         }
387 
388         if (sizeo > maxsize)
389                 errx(1, "payload too large: %zd > %zd\n", sizeo, maxsize);
390 
391 
392         fdo = open(imagefile, O_RDWR | O_CREAT | O_TRUNC, 00644);
393         if (fdo < 0)
394                 err(1, "cannot open \"%s\"", imagefile);
395 
396 
397         if (ftruncate(fdo, sizeo) == -1)
398                 err(1, "cannot grow \"%s\" to %zd bytes", imagefile, sizeo);
399 
400         map = mmap(NULL, sizeo, PROT_READ|PROT_WRITE, MAP_SHARED, fdo, 0);
401         uh = map + sizeof(*jh);
402         if (map == MAP_FAILED)
403                 err(1, "cannot mmap \"%s\"", imagefile);
404 
405 
406         if (read(fd1, map + off1, size1) != size1)
407                 err(1, "cannot copy %s", file1);
408 
409 
410         if (mode == MODE_KR) {
411                 if (read(fd2, map+off2, size2) != size2)
412                         err(1, "cannot copy %s", file2);
413 
414                 mkuheader(uh, size1, size2);
415         } else if (mode == MODE_UIMAGE)
416                 craftcrc(ntohl(uh->ih_dcrc), (void*)uh + sizeof(*uh),
417                          sizeu - sizeof(*uh));
418 
419         mkjcgheader(map, sizeu, version);
420         munmap(map, sizeo);
421         close(fdo);
422         return 0;
423 }
424 

This page was automatically generated by LXR 0.3.1.  •  OpenWrt