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

Sources/firmware-utils/src/lxlfw.c

  1 // SPDX-License-Identifier: GPL-2.0-or-later OR MIT
  2 /*
  3  * Luxul's firmware container format
  4  *
  5  * Copyright 2020 Legrand AV Inc.
  6  */
  7 
  8 #define _GNU_SOURCE
  9 
 10 #include <byteswap.h>
 11 #include <endian.h>
 12 #include <errno.h>
 13 #include <libgen.h>
 14 #include <stddef.h>
 15 #include <stdint.h>
 16 #include <stdio.h>
 17 #include <stdlib.h>
 18 #include <string.h>
 19 #include <unistd.h>
 20 
 21 #if __BYTE_ORDER == __BIG_ENDIAN
 22 #define cpu_to_le32(x)  bswap_32(x)
 23 #define cpu_to_le16(x)  bswap_16(x)
 24 #define le32_to_cpu(x)  bswap_32(x)
 25 #define le16_to_cpu(x)  bswap_16(x)
 26 #elif __BYTE_ORDER == __LITTLE_ENDIAN
 27 #define cpu_to_le32(x)  (x)
 28 #define cpu_to_le16(x)  (x)
 29 #define le32_to_cpu(x)  (x)
 30 #define le16_to_cpu(x)  (x)
 31 #endif
 32 
 33 #define min(a, b)                               \
 34         ({                                      \
 35                 __typeof__ (a) _a = (a);        \
 36                 __typeof__ (b) _b = (b);        \
 37                 _a < _b ? _a : _b;              \
 38         })
 39 
 40 #define max(a, b)                               \
 41         ({                                      \
 42                 __typeof__ (a) _a = (a);        \
 43                 __typeof__ (b) _b = (b);        \
 44                 _a > _b ? _a : _b;              \
 45         })
 46 
 47 #define MAX_SUPPORTED_VERSION                   3
 48 
 49 #define LXL_FLAGS_VENDOR_LUXUL                  0x00000001
 50 
 51 #define LXL_BLOB_CERTIFICATE                    0x0001
 52 #define LXL_BLOB_SIGNATURE                      0x0002
 53 
 54 struct lxl_hdr {
 55         char            magic[4];       /* "LXL#" */
 56         uint32_t        version;
 57         uint32_t        hdr_len;
 58         uint8_t         v0_end[0];
 59         /* Version: 1+ */
 60         uint32_t        flags;
 61         char            board[16];
 62         uint8_t         v1_end[0];
 63         /* Version: 2+ */
 64         uint8_t         release[4];
 65         uint8_t         v2_end[0];
 66         /* Version: 3+ */
 67         uint32_t        blobs_offset;
 68         uint32_t        blobs_len;
 69         uint8_t         v3_end[0];
 70 } __attribute__((packed));
 71 
 72 struct lxl_blob {
 73         char            magic[2];       /* "D#" */
 74         uint16_t        type;
 75         uint32_t        len;
 76         uint8_t         data[0];
 77 } __attribute__((packed));
 78 
 79 /**************************************************
 80  * Helpers
 81  **************************************************/
 82 
 83 static uint32_t lxlfw_hdr_len(uint32_t version)
 84 {
 85         switch (version) {
 86         case 0:
 87                 return offsetof(struct lxl_hdr, v0_end);
 88         case 1:
 89                 return offsetof(struct lxl_hdr, v1_end);
 90         case 2:
 91                 return offsetof(struct lxl_hdr, v2_end);
 92         case 3:
 93                 return offsetof(struct lxl_hdr, v3_end);
 94         default:
 95                 fprintf(stderr, "Unsupported version %d\n", version);
 96                 return 0;
 97         }
 98 }
 99 
100 /**
101  * lxlfw_open - open Luxul firmware file and validate it
102  *
103  * @pathname: Luxul firmware file
104  * @hdr: struct to read to
105  */
106 static FILE *lxlfw_open(const char *pathname, struct lxl_hdr *hdr)
107 {
108         size_t v0_len = lxlfw_hdr_len(0);
109         size_t min_hdr_len;
110         uint32_t version;
111         uint32_t hdr_len;
112         size_t bytes;
113         FILE *lxl;
114 
115         lxl = fopen(pathname, "r");
116         if (!lxl) {
117                 fprintf(stderr, "Could not open \"%s\" file\n", pathname);
118                 goto err_out;
119         }
120 
121         bytes = fread(hdr, 1, v0_len, lxl);
122         if (bytes != v0_len) {
123                 fprintf(stderr, "Input file too small to use Luxul format\n");
124                 goto err_close;
125         }
126 
127         if (memcmp(hdr->magic, "LXL#", 4)) {
128                 fprintf(stderr, "File <file> does not use Luxul's format\n");
129                 goto err_close;
130         }
131 
132         version = le32_to_cpu(hdr->version);
133 
134         min_hdr_len = lxlfw_hdr_len(min(version, MAX_SUPPORTED_VERSION));
135 
136         bytes = fread(((uint8_t *)hdr) + v0_len, 1, min_hdr_len - v0_len, lxl);
137         if (bytes != min_hdr_len - v0_len) {
138                 fprintf(stderr, "Input file too small for header version %d\n", version);
139                 goto err_close;
140         }
141 
142         hdr_len = le32_to_cpu(hdr->hdr_len);
143 
144         if (hdr_len < min_hdr_len) {
145                 fprintf(stderr, "Header length mismatch: 0x%x (expected: 0x%zx)\n", hdr_len, min_hdr_len);
146                 goto err_close;
147         }
148 
149         if (version >= 3 && hdr->blobs_offset && hdr->blobs_len) {
150                 uint32_t blobs_end = le32_to_cpu(hdr->blobs_offset) + le32_to_cpu(hdr->blobs_len);
151 
152                 if (blobs_end > hdr_len) {
153                         fprintf(stderr, "Blobs section ends beyond header end: 0x%x (max: 0x%x)\n", blobs_end, hdr_len);
154                         goto err_close;
155                 }
156         }
157 
158         return lxl;
159 
160 err_close:
161         fclose(lxl);
162 err_out:
163         return NULL;
164 }
165 
166 /**
167  * lxlfw_copy_data - read data from one stream and write to another
168  *
169  * @from: input stream
170  * @to: output stream
171  * @size: amount of bytes to copy (0 to copy all data)
172  */
173 static ssize_t lxlfw_copy_data(FILE *from, FILE *to, size_t size)
174 {
175         int copy_all = size == 0;
176         char buf[512];
177         size_t ret = 0;
178 
179         while (copy_all || size) {
180                 size_t to_read = copy_all ? sizeof(buf) : min(size, sizeof(buf));
181                 size_t bytes;
182 
183                 bytes = fread(buf, 1, to_read, from);
184                 if (bytes == 0 && copy_all) {
185                         break;
186                 } else if (bytes <= 0) {
187                         fprintf(stderr, "Failed to read data\n");
188                         return -EIO;
189                 }
190 
191                 if (fwrite(buf, 1, bytes, to) != bytes) {
192                         fprintf(stderr, "Failed to write data\n");
193                         return -EIO;
194                 }
195 
196                 if (!copy_all)
197                         size -= bytes;
198                 ret += bytes;
199         }
200 
201         return ret;
202 }
203 
204 /**
205  * lxlfw_write_blob - read data from external file and write blob to stream
206  *
207  * @lxl: stream to write to
208  * @type: blob type
209  * @pathname: external file pathname to read blob data from
210  */
211 static ssize_t lxlfw_write_blob(FILE *lxl, uint16_t type, const char *pathname)
212 {
213         struct lxl_blob blob = {
214                 .magic = { 'D', '#' },
215                 .type = cpu_to_le16(type),
216         };
217         char buf[512];
218         size_t blob_data_len;
219         size_t bytes;
220         FILE *data;
221 
222         data = fopen(pathname, "r");
223         if (!data) {
224                 fprintf(stderr, "Could not open input file %s\n", pathname);
225                 return -EIO;
226         }
227 
228         blob_data_len = 0;
229         fseek(lxl, sizeof(blob), SEEK_CUR);
230         while ((bytes = fread(buf, 1, sizeof(buf), data)) > 0) {
231                 if (fwrite(buf, 1, bytes, lxl) != bytes) {
232                         fprintf(stderr, "Could not copy %zu bytes from input file\n", bytes);
233                         fclose(data);
234                         return -EIO;
235                 }
236                 blob_data_len += bytes;
237         }
238 
239         fclose(data);
240 
241         blob.len = cpu_to_le32(blob_data_len);
242 
243         fseek(lxl, -(blob_data_len + sizeof(blob)), SEEK_CUR);
244         bytes = fwrite(&blob, 1, sizeof(blob), lxl);
245         if (bytes != sizeof(blob)) {
246                 fprintf(stderr, "Could not write Luxul's header\n");
247                 return -EIO;
248         }
249 
250         fseek(lxl, blob_data_len, SEEK_CUR);
251 
252         return blob_data_len + sizeof(blob);
253 }
254 
255 /**************************************************
256  * Info
257  **************************************************/
258 
259 static int lxlfw_info(int argc, char **argv) {
260         struct lxl_hdr hdr;
261         uint32_t version;
262         char board[17];
263         int err = 0;
264         FILE *lxl;
265         int flags;
266 
267         if (argc < 3) {
268                 fprintf(stderr, "Missing <file> argument\n");
269                 err = -EINVAL;
270                 goto out;
271         }
272 
273         lxl = lxlfw_open(argv[2], &hdr);
274         if (!lxl) {
275                 fprintf(stderr, "Could not open \"%s\" Luxul firmware\n", argv[2]);
276                 err = -ENOENT;
277                 goto out;
278         }
279 
280         version = le32_to_cpu(hdr.version);
281 
282         printf("Format version:\t%d\n", version);
283         printf("Header length:\t%d\n", le32_to_cpu(hdr.hdr_len));
284         if (version >= 1) {
285                 printf("Flags:\t\t");
286                 flags = le32_to_cpu(hdr.flags);
287                 if (flags & LXL_FLAGS_VENDOR_LUXUL)
288                         printf("VENDOR_LUXUL ");
289                 printf("\n");
290                 memcpy(board, hdr.board, sizeof(hdr.board));
291                 board[16] = '\0';
292                 printf("Board:\t\t%s\n", board);
293         }
294         if (version >= 2) {
295                 printf("Release:\t");
296                 if (hdr.release[0] || hdr.release[1] || hdr.release[2] || hdr.release[3]) {
297                         printf("%hu.%hu.%hu", hdr.release[0], hdr.release[1], hdr.release[2]);
298                         if (hdr.release[3])
299                                 printf(".%hu", hdr.release[3]);
300                 }
301                 printf("\n");
302         }
303         if (version >= 3) {
304                 printf("Blobs offset:\t%d\n", le32_to_cpu(hdr.blobs_offset));
305                 printf("Blobs length:\t%d\n", le32_to_cpu(hdr.blobs_len));
306         }
307 
308         if (version >= 3 && hdr.blobs_offset) {
309                 size_t offset;
310 
311                 fseek(lxl, le32_to_cpu(hdr.blobs_offset), SEEK_SET);
312                 for (offset = 0; offset < le32_to_cpu(hdr.blobs_len); ) {
313                         struct lxl_blob blob;
314                         size_t bytes;
315                         size_t len;
316 
317                         bytes = fread(&blob, 1, sizeof(blob), lxl);
318                         if (bytes != sizeof(blob)) {
319                                 fprintf(stderr, "Failed to read blob section\n");
320                                 err = -ENXIO;
321                                 goto err_close;
322                         }
323 
324                         len = le32_to_cpu(blob.len);
325 
326                         printf("\n");
327                         printf("Blob\n");
328                         printf("Magic:\t\t%s\n", blob.magic);
329                         printf("Type:\t\t0x%04x\n", le16_to_cpu(blob.type));
330                         printf("Length:\t\t%zu\n", len);
331 
332                         offset += sizeof(blob) + len;
333                         fseek(lxl, len, SEEK_CUR);
334                 }
335 
336                 if (offset != le32_to_cpu(hdr.blobs_len)) {
337                         printf("\n");
338                         fprintf(stderr, "Blobs size (0x%zx) doesn't match declared length (0x%x)\n", offset, le32_to_cpu(hdr.blobs_len));
339                 }
340         }
341 
342 err_close:
343         fclose(lxl);
344 out:
345         return err;
346 }
347 
348 /**************************************************
349  * Extract
350  **************************************************/
351 
352 static int lxlfw_extract(int argc, char **argv) {
353         struct lxl_hdr hdr;
354         char *out_path = NULL;
355         ssize_t bytes;
356         int err = 0;
357         FILE *lxl;
358         FILE *out;
359         int c;
360 
361         if (argc < 3) {
362                 fprintf(stderr, "Missing <file> argument\n");
363                 err = -EINVAL;
364                 goto out;
365         }
366 
367         optind = 3;
368         while ((c = getopt(argc, argv, "O:")) != -1) {
369                 switch (c) {
370                 case 'O':
371                         out_path = optarg;
372                         break;
373                 }
374         }
375 
376         if (!out_path) {
377                 fprintf(stderr, "Missing output file path\n");
378                 err = -EINVAL;
379                 goto out;
380         }
381 
382         lxl = lxlfw_open(argv[2], &hdr);
383         if (!lxl) {
384                 fprintf(stderr, "Failed to open \"%s\" Luxul firmware\n", argv[2]);
385                 err = -ENOENT;
386                 goto out;
387         }
388 
389         fseek(lxl, le32_to_cpu(hdr.hdr_len), SEEK_SET);
390 
391         if (!strcmp(out_path, "-")) {
392                 out = stdout;
393         } else {
394                 out = fopen(out_path, "w+");
395                 if (!out) {
396                         fprintf(stderr, "Failed to open \"%s\" file\n", out_path);
397                         err = -EIO;
398                         goto err_close_lxl;
399                 }
400         }
401 
402         bytes = lxlfw_copy_data(lxl, out, 0);
403         if (bytes < 0) {
404                 fprintf(stderr, "Failed to copy image: %zd\n", bytes);
405                 err = -EIO;
406                 goto err_close_lxl;
407         }
408 
409         if (out != stdout) {
410                 fclose(out);
411         }
412 
413 err_close_lxl:
414         fclose(lxl);
415 out:
416         return err;
417 }
418 
419 /**************************************************
420  * Blobs
421  **************************************************/
422 
423 /**
424  * lxlfw_blob_save - save blob data to external file
425  *
426  * @lxl: Luxul firmware FILE with position seeked to blob data
427  * @len: blob data length
428  * @path: external file pathname to write
429  */
430 static int lxlfw_blob_save(FILE *lxl, size_t len, const char *path) {
431         char buf[256];
432         size_t bytes;
433         FILE *out;
434         int err = 0;
435 
436         out = fopen(path, "w+");
437         if (!out) {
438                 fprintf(stderr, "Could not open \"%s\" file\n", path);
439                 err = -EIO;
440                 goto err_out;
441         }
442 
443         while (len && (bytes = fread(buf, 1, min(len, sizeof(buf)), lxl)) > 0) {
444                 if (fwrite(buf, 1, bytes, out) != bytes) {
445                         fprintf(stderr, "Could not copy %zu bytes from input file\n", bytes);
446                         err = -EIO;
447                         goto err_close_out;
448                 }
449                 len -= bytes;
450         }
451 
452         if (len) {
453                 fprintf(stderr, "Could not copy all signature\n");
454                 err = -EIO;
455                 goto err_close_out;
456         }
457 
458 err_close_out:
459         fclose(out);
460 err_out:
461         return err;
462 }
463 
464 static int lxlfw_blobs(int argc, char **argv) {
465         char *certificate_path = NULL;
466         char *signature_path = NULL;
467         struct lxl_hdr hdr;
468         uint32_t version;
469         size_t offset;
470         size_t bytes;
471         int err = 0;
472         FILE *lxl;
473         int c;
474 
475         if (argc < 3) {
476                 fprintf(stderr, "Missing <file> argument\n");
477                 err = -EINVAL;
478                 goto out;
479         }
480 
481         optind = 3;
482         while ((c = getopt(argc, argv, "c:s:")) != -1) {
483                 switch (c) {
484                 case 'c':
485                         certificate_path = optarg;
486                         break;
487                 case 's':
488                         signature_path = optarg;
489                         break;
490                 }
491         }
492 
493         if (!certificate_path && !signature_path) {
494                 fprintf(stderr, "Missing info on blobs to extract\n");
495                 err = -EINVAL;
496                 goto out;
497         }
498 
499         lxl = lxlfw_open(argv[2], &hdr);
500         if (!lxl) {
501                 fprintf(stderr, "Failed to open \"%s\" Luxul firmware\n", argv[2]);
502                 err = -ENOENT;
503                 goto out;
504         }
505 
506         version = le32_to_cpu(hdr.version);
507 
508         if (version < 3 || !hdr.blobs_offset) {
509                 fprintf(stderr, "File <file> doesn't contain any blobs\n");
510                 err = -ENOENT;
511                 goto err_close;
512         }
513 
514         fseek(lxl, le32_to_cpu(hdr.blobs_offset), SEEK_SET);
515         for (offset = 0; offset < le32_to_cpu(hdr.blobs_len); ) {
516                 struct lxl_blob blob;
517                 uint16_t type;
518                 size_t len;
519 
520                 bytes = fread(&blob, 1, sizeof(blob), lxl);
521                 if (bytes != sizeof(blob)) {
522                         fprintf(stderr, "Failed to read blob section\n");
523                         err = -ENXIO;
524                         goto err_close;
525                 }
526                 offset += bytes;
527 
528                 if (memcmp(blob.magic, "D#", 2)) {
529                         fprintf(stderr, "Failed to parse blob section\n");
530                         err = -ENXIO;
531                         goto err_close;
532                 }
533 
534                 type = le16_to_cpu(blob.type);
535                 len = le32_to_cpu(blob.len);
536 
537                 if (type == LXL_BLOB_CERTIFICATE && certificate_path) {
538                         err = lxlfw_blob_save(lxl, len, certificate_path);
539                         certificate_path = NULL;
540                 } else if (type == LXL_BLOB_SIGNATURE && signature_path) {
541                         err = lxlfw_blob_save(lxl, len, signature_path);
542                         signature_path = NULL;
543                 } else {
544                         fseek(lxl, len, SEEK_CUR);
545                 }
546                 if (err) {
547                         fprintf(stderr, "Failed to save blob section\n");
548                         goto err_close;
549                 }
550                 offset += len;
551         }
552 
553         if (certificate_path) {
554                 fprintf(stderr, "Failed to find certificate blob\n");
555                 err = -ENOENT;
556         }
557         if (signature_path) {
558                 fprintf(stderr, "Failed to find signature blob\n");
559                 err = -ENOENT;
560         }
561 
562 err_close:
563         fclose(lxl);
564 out:
565         return err;
566 }
567 
568 /**************************************************
569  * Create
570  **************************************************/
571 
572 static int lxlfw_create(int argc, char **argv) {
573         struct lxl_hdr hdr = {
574                 .magic = { 'L', 'X', 'L', '#' },
575         };
576         char *certificate_path = NULL;
577         char *signature_path = NULL;
578         char *in_path = NULL;
579         uint32_t version = 0;
580         uint32_t hdr_raw_len;   /* Header length without blobs */
581         uint32_t hdr_len;       /* Header length with blobs */
582         uint32_t blobs_len;
583         ssize_t bytes;
584         int err = 0;
585         FILE *lxl;
586         FILE *in;
587         int c;
588 
589         if (argc < 3) {
590                 fprintf(stderr, "Missing <file> argument\n");
591                 err = -EINVAL;
592                 goto out;
593         }
594 
595         optind = 3;
596         while ((c = getopt(argc, argv, "i:lb:r:")) != -1) {
597                 switch (c) {
598                 case 'i':
599                         in_path = optarg;
600                         break;
601                 case 'l':
602                         hdr.flags |= cpu_to_le32(LXL_FLAGS_VENDOR_LUXUL);
603                         version = max(version, 1);
604                         break;
605                 case 'b':
606                         memcpy(hdr.board, optarg, strlen(optarg) > 16 ? 16 : strlen(optarg));
607                         version = max(version, 1);
608                         break;
609                 case 'r':
610                         if (sscanf(optarg, "%hhu.%hhu.%hhu.%hhu", &hdr.release[0], &hdr.release[1], &hdr.release[2], &hdr.release[3]) < 1) {
611                                 fprintf(stderr, "Failed to parse release number \"%s\"\n", optarg);
612                                 err = -EINVAL;
613                                 goto out;
614                         }
615                         version = max(version, 2);
616                         break;
617                 case 'c':
618                         certificate_path = optarg;
619                         version = max(version, 3);
620                         break;
621                 case 's':
622                         signature_path = optarg;
623                         version = max(version, 3);
624                         break;
625                 }
626         }
627 
628         hdr_raw_len = lxlfw_hdr_len(version);
629         hdr_len = hdr_raw_len;
630 
631         if (!in_path) {
632                 fprintf(stderr, "Missing input file argument\n");
633                 err = -EINVAL;
634                 goto out;
635         }
636 
637         in = fopen(in_path, "r");
638         if (!in) {
639                 fprintf(stderr, "Could not open input file %s\n", in_path);
640                 err = -EIO;
641                 goto out;
642         }
643 
644         lxl = fopen(argv[2], "w+");
645         if (!lxl) {
646                 fprintf(stderr, "Could not open \"%s\" file\n", argv[2]);
647                 err = -EIO;
648                 goto err_close_in;
649         }
650 
651         /* Write blobs */
652 
653         blobs_len = 0;
654 
655         fseek(lxl, hdr_raw_len, SEEK_SET);
656         if (certificate_path) {
657                 bytes = lxlfw_write_blob(lxl, LXL_BLOB_CERTIFICATE, certificate_path);
658                 if (bytes <= 0) {
659                         fprintf(stderr, "Failed to write certificate\n");
660                         goto err_close_lxl;
661                 }
662                 blobs_len += bytes;
663         }
664         if (signature_path) {
665                 bytes = lxlfw_write_blob(lxl, LXL_BLOB_SIGNATURE, signature_path);
666                 if (bytes <= 0) {
667                         fprintf(stderr, "Failed to write signature\n");
668                         goto err_close_lxl;
669                 }
670                 blobs_len += bytes;
671         }
672 
673         if (blobs_len) {
674                 hdr.blobs_offset = cpu_to_le32(hdr_raw_len);
675                 hdr.blobs_len = cpu_to_le32(blobs_len);
676                 hdr_len += blobs_len;
677         }
678 
679         /* Write header */
680 
681         hdr.version = cpu_to_le32(version);
682         hdr.hdr_len = cpu_to_le32(hdr_len);
683 
684         fseek(lxl, 0, SEEK_SET);
685         bytes = fwrite(&hdr, 1, hdr_raw_len, lxl);
686         if (bytes != hdr_raw_len) {
687                 fprintf(stderr, "Could not write Luxul's header\n");
688                 err = -EIO;
689                 goto err_close_lxl;
690         }
691 
692         /* Write input data */
693 
694         fseek(lxl, 0, SEEK_END);
695         bytes = lxlfw_copy_data(in, lxl, 0);
696         if (bytes < 0) {
697                 fprintf(stderr, "Could not copy %zu bytes from input file\n", bytes);
698                 err = -EIO;
699                 goto err_close_lxl;
700         }
701 
702 err_close_lxl:
703         fclose(lxl);
704 err_close_in:
705         fclose(in);
706 out:
707         return err;
708 }
709 
710 /**************************************************
711  * Insert
712  **************************************************/
713 
714 static int lxlfw_insert(int argc, char **argv) {
715         struct lxl_hdr hdr = { };
716         char *certificate_path = NULL;
717         char *signature_path = NULL;
718         char *tmp_path = NULL;
719         uint32_t version = 0;
720         uint32_t hdr_raw_len;   /* Header length without blobs */
721         uint32_t hdr_len;       /* Header length with blobs */
722         uint32_t blobs_len;
723         ssize_t bytes;
724         char *path;
725         FILE *lxl;
726         FILE *tmp;
727         int fd;
728         int c;
729         int err = 0;
730 
731         if (argc < 3) {
732                 fprintf(stderr, "Missing <file> argument\n");
733                 err = -EINVAL;
734                 goto out;
735         }
736 
737         optind = 3;
738         while ((c = getopt(argc, argv, "c:s:")) != -1) {
739                 switch (c) {
740                 case 'c':
741                         certificate_path = optarg;
742                         break;
743                 case 's':
744                         signature_path = optarg;
745                         break;
746                 }
747         }
748 
749         if (!certificate_path && !signature_path) {
750                 fprintf(stderr, "Missing info on blobs to insert\n");
751                 err = -EINVAL;
752                 goto out;
753         }
754 
755         lxl = lxlfw_open(argv[2], &hdr);
756         if (!lxl) {
757                 fprintf(stderr, "Failed to open \"%s\" Luxul firmware\n", argv[2]);
758                 err = -ENOENT;
759                 goto out;
760         }
761 
762         version = le32_to_cpu(hdr.version);
763         if (version > MAX_SUPPORTED_VERSION) {
764                 fprintf(stderr, "Unsupported <file> version %d\n", version);
765                 err = -EIO;
766                 goto err_close_lxl;
767         }
768 
769         version = max(version, 3);
770 
771         hdr_raw_len = lxlfw_hdr_len(version);
772         hdr_len = hdr_raw_len;
773 
774         /* Temporary file */
775 
776         path = strdup(argv[2]);
777         if (!path) {
778                 err = -ENOMEM;
779                 goto err_close_lxl;
780         }
781         asprintf(&tmp_path, "%s/lxlfwXXXXXX", dirname(path));
782         free(path);
783         if (!tmp_path) {
784                 err = -ENOMEM;
785                 goto err_close_lxl;
786         }
787 
788         fd = mkstemp(tmp_path);
789         if (fd < 0) {
790                 err = -errno;
791                 fprintf(stderr, "Failed to open temporary file\n");
792                 goto err_free_path;
793         }
794         tmp = fdopen(fd, "w+");
795 
796         /* Blobs */
797 
798         fseek(tmp, hdr_raw_len, SEEK_SET);
799         blobs_len = 0;
800 
801         /* Copy old blobs */
802 
803         if (hdr.blobs_offset) {
804                 size_t offset;
805 
806                 fseek(lxl, le32_to_cpu(hdr.blobs_offset), SEEK_SET);
807                 for (offset = 0; offset < le32_to_cpu(hdr.blobs_len); ) {
808                         struct lxl_blob blob;
809                         uint16_t type;
810                         size_t len;
811 
812                         bytes = fread(&blob, 1, sizeof(blob), lxl);
813                         if (bytes != sizeof(blob)) {
814                                 fprintf(stderr, "Failed to read blob section\n");
815                                 err = -ENXIO;
816                                 goto err_close_tmp;
817                         }
818 
819                         type = le16_to_cpu(blob.type);
820                         len = le32_to_cpu(blob.len);
821 
822                         /* Don't copy blobs that have to be replaced */
823                         if ((type == LXL_BLOB_CERTIFICATE && certificate_path) ||
824                             (type == LXL_BLOB_SIGNATURE && signature_path)) {
825                                 fseek(lxl, len, SEEK_CUR);
826                         } else {
827                                 fseek(lxl, -sizeof(blob), SEEK_CUR);
828                                 bytes = lxlfw_copy_data(lxl, tmp, sizeof(blob) + len);
829                                 if (bytes != sizeof(blob) + len) {
830                                         fprintf(stderr, "Failed to copy original blob\n");
831                                         err = -EIO;
832                                         goto err_close_tmp;
833                                 }
834                                 blobs_len += sizeof(blob) + len;
835                         }
836 
837                         offset += sizeof(blob) + len;
838                 }
839         }
840 
841         /* Write new blobs */
842 
843         if (certificate_path) {
844                 bytes = lxlfw_write_blob(tmp, LXL_BLOB_CERTIFICATE, certificate_path);
845                 if (bytes <= 0) {
846                         fprintf(stderr, "Failed to write certificate\n");
847                         goto err_close_tmp;
848                 }
849                 blobs_len += bytes;
850         }
851         if (signature_path) {
852                 bytes = lxlfw_write_blob(tmp, LXL_BLOB_SIGNATURE, signature_path);
853                 if (bytes <= 0) {
854                         fprintf(stderr, "Failed to write signature\n");
855                         goto err_close_tmp;
856                 }
857                 blobs_len += bytes;
858         }
859 
860         hdr.blobs_offset = cpu_to_le32(hdr_raw_len);
861         hdr.blobs_len = cpu_to_le32(blobs_len);
862         hdr_len += blobs_len;
863 
864         /* Write header */
865 
866         hdr.version = cpu_to_le32(version);
867         hdr.hdr_len = cpu_to_le32(hdr_len);
868 
869         fseek(tmp, 0, SEEK_SET);
870         bytes = fwrite(&hdr, 1, hdr_raw_len, tmp);
871         if (bytes != hdr_raw_len) {
872                 fprintf(stderr, "Could not write Luxul's header\n");
873                 err = -EIO;
874                 goto err_close_tmp;
875         }
876 
877         /* Write original data */
878 
879         fseek(tmp, 0, SEEK_END);
880         bytes = lxlfw_copy_data(lxl, tmp, 0);
881         if (bytes < 0) {
882                 fprintf(stderr, "Failed to copy original file\n");
883                 err = -EIO;
884                 goto err_close_tmp;
885         }
886 
887         fclose(tmp);
888 
889         fclose(lxl);
890 
891         /* Replace original file */
892 
893         if (rename(tmp_path, argv[2])) {
894                 err = -errno;
895                 fprintf(stderr, "Failed to rename %s: %d\n", tmp_path, err);
896                 unlink(tmp_path);
897                 goto out;
898         }
899 
900         return 0;
901 
902 err_close_tmp:
903         fclose(tmp);
904 err_free_path:
905         free(tmp_path);
906 err_close_lxl:
907         fclose(lxl);
908 out:
909         return err;
910 }
911 
912 /**************************************************
913  * Start
914  **************************************************/
915 
916 static void usage() {
917         printf("Usage:\n");
918         printf("\n");
919         printf("Get info about Luxul firmware:\n");
920         printf("\tlxlfw info <file>\n");
921         printf("\n");
922         printf("Extract image from Luxul firmware:\n");
923         printf("\tlxlfw extract <file> [options]\n");
924         printf("\t-O file\t\t\t\toutput file (- for stdout)\n");
925         printf("\n");
926         printf("Extract blobs from Luxul firmware:\n");
927         printf("\tlxlfw blobs <file> [options]\n");
928         printf("\t-c file\t\t\t\tcertificate output file\n");
929         printf("\t-s file\t\t\t\tsignature output file\n");
930         printf("\n");
931         printf("Create new Luxul firmware:\n");
932         printf("\tlxlfw create <file> [options]\n");
933         printf("\t-i file\t\t\t\tinput file for Luxul's firmware container\n");
934         printf("\t-l\t\t\t\tmark firmware as created by Luxul company (DON'T USE)\n");
935         printf("\t-b board\t\t\tboard (device) name\n");
936         printf("\t-r release\t\t\trelease number (e.g. 5.1.0, 7.1.0.2)\n");
937         printf("\t-c file\t\t\t\tcertificate file\n");
938         printf("\t-s file\t\t\t\tsignature file\n");
939         printf("\n");
940         printf("Insert blob to Luxul firmware:\n");
941         printf("\tlxlfw insert <file> [options]\n");
942         printf("\t-c file\t\t\t\tcertificate file\n");
943         printf("\t-s file\t\t\t\tsignature file\n");
944 
945 }
946 
947 int main(int argc, char **argv) {
948         if (argc > 1) {
949                 if (!strcmp(argv[1], "info"))
950                         return lxlfw_info(argc, argv);
951                 else if (!strcmp(argv[1], "extract"))
952                         return lxlfw_extract(argc, argv);
953                 else if (!strcmp(argv[1], "blobs"))
954                         return lxlfw_blobs(argc, argv);
955                 else if (!strcmp(argv[1], "create"))
956                         return lxlfw_create(argc, argv);
957                 else if (!strcmp(argv[1], "insert"))
958                         return lxlfw_insert(argc, argv);
959         }
960 
961         usage();
962         return 0;
963 }
964 

This page was automatically generated by LXR 0.3.1.  •  OpenWrt