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

Sources/firmware-utils/src/uimage_padhdr.c

  1 // SPDX-License-Identifier: GPL-2.0-only
  2 /*
  3  * uimage_padhdr.c : add zero paddings after the tail of uimage header
  4  *
  5  * Copyright (C) 2019 NOGUCHI Hiroshi <drvlabo@gmail.com>
  6  */
  7 
  8 #include <stdio.h>
  9 #include <errno.h>
 10 #include <unistd.h>
 11 #include <stdlib.h>
 12 #include <string.h>
 13 #include <fcntl.h>
 14 #include <sys/stat.h>
 15 #include <arpa/inet.h>
 16 #include <zlib.h>
 17 
 18 
 19 /* from u-boot/include/image.h */
 20 #define IH_MAGIC        0x27051956      /* Image Magic Number           */
 21 #define IH_NMLEN                32      /* Image Name Length            */
 22 
 23 /*
 24  * Legacy format image header,
 25  * all data in network byte order (aka natural aka bigendian).
 26  */
 27 typedef struct image_header {
 28         uint32_t        ih_magic;       /* Image Header Magic Number    */
 29         uint32_t        ih_hcrc;        /* Image Header CRC Checksum    */
 30         uint32_t        ih_time;        /* Image Creation Timestamp     */
 31         uint32_t        ih_size;        /* Image Data Size              */
 32         uint32_t        ih_load;        /* Data  Load  Address          */
 33         uint32_t        ih_ep;          /* Entry Point Address          */
 34         uint32_t        ih_dcrc;        /* Image Data CRC Checksum      */
 35         uint8_t         ih_os;          /* Operating System             */
 36         uint8_t         ih_arch;        /* CPU architecture             */
 37         uint8_t         ih_type;        /* Image Type                   */
 38         uint8_t         ih_comp;        /* Compression Type             */
 39         uint8_t         ih_name[IH_NMLEN];      /* Image Name           */
 40 } image_header_t;
 41 
 42 
 43 /* default padding size */
 44 #define IH_PAD_BYTES            (32)
 45 
 46 /* maximum number of -x / -s patch entries */
 47 #define MAX_PATCHES             64
 48 
 49 typedef struct {
 50         size_t          offset; /* byte offset within the padding area */
 51         uint8_t         *data;
 52         size_t          len;
 53 } patch_entry_t;
 54 
 55 static patch_entry_t patches[MAX_PATCHES];
 56 static int num_patches = 0;
 57 
 58 static void free_patches(void)
 59 {
 60         int i;
 61 
 62         for (i = 0; i < num_patches; i++) {
 63                 free(patches[i].data);
 64                 patches[i].data = NULL;
 65         }
 66         num_patches = 0;
 67 }
 68 
 69 /*
 70  * Helper to add a validated patch entry.
 71  * Takes ownership of `data` on success.
 72  */
 73 static int add_patch(size_t offset, uint8_t *data, size_t len)
 74 {
 75         if (num_patches >= MAX_PATCHES) {
 76                 fprintf(stderr, "Too many patch entries (max %d)\n", MAX_PATCHES);
 77                 free(data);
 78                 return -1;
 79         }
 80 
 81         patches[num_patches].offset = offset;
 82         patches[num_patches].data   = data;
 83         patches[num_patches].len    = len;
 84         num_patches++;
 85         return 0;
 86 }
 87 
 88 /*
 89  * Parse offset from argument prefix.
 90  * Returns pointer to the start of the payload data, or NULL on error.
 91  */
 92 static const char *
 93 parse_offset(const char *arg, const char *opt_name, size_t *offset_out)
 94 {
 95         const char *colon;
 96         long offset;
 97         char *endptr;
 98 
 99         colon = strchr(arg, ':');
100         if (!colon) {
101                 fprintf(stderr, "Invalid %s argument (expected offset:value): %s\n", opt_name, arg);
102                 return NULL;
103         }
104 
105         errno = 0;
106         offset = strtol(arg, &endptr, 0);
107         if (errno || endptr == arg || endptr != colon || offset < 0) {
108                 fprintf(stderr, "Invalid offset in %s argument: %s\n", opt_name, arg);
109                 return NULL;
110         }
111 
112         *offset_out = (size_t)offset;
113         return colon + 1;
114 }
115 
116 static int hex_to_nibble(char c)
117 {
118         if (c >= '' && c <= '9')
119                 return c - '';
120         if (c >= 'a' && c <= 'f')
121                 return c - 'a' + 10;
122         if (c >= 'A' && c <= 'F')
123                 return c - 'A' + 10;
124         return -1;
125 }
126 
127 /*
128  * Parse "offset:hexstring" and add patch.
129  */
130 static int
131 add_hex_patch(const char *arg)
132 {
133         const char *hexstr;
134         size_t offset;
135         size_t hexlen;
136         uint8_t *data;
137         size_t i;
138 
139         hexstr = parse_offset(arg, "-x", &offset);
140         if (!hexstr)
141                 return -1;
142 
143         hexlen = strlen(hexstr);
144         if (hexlen == 0 || hexlen % 2 != 0) {
145                 fprintf(stderr, "Hex string must have even number of digits: %s\n", hexstr);
146                 return -1;
147         }
148 
149         data = malloc(hexlen / 2);
150         if (!data) {
151                 fprintf(stderr, "Memory allocation failed\n");
152                 return -1;
153         }
154 
155         for (i = 0; i < hexlen / 2; i++) {
156                 int high = hex_to_nibble(hexstr[2 * i]);
157                 int low = hex_to_nibble(hexstr[2 * i + 1]);
158 
159                 if (high < 0 || low < 0) {
160                         fprintf(stderr, "Invalid hex byte at position %zu: %.2s\n",
161                                 i, hexstr + 2 * i);
162                         free(data);
163                         return -1;
164                 }
165                 data[i] = (uint8_t)((high << 4) | low);
166         }
167 
168         return add_patch(offset, data, hexlen / 2);
169 }
170 
171 /*
172  * Parse "offset:string" and add patch.
173  */
174 static int
175 add_str_patch(const char *arg)
176 {
177         const char *str;
178         size_t offset;
179         size_t slen;
180         uint8_t *data;
181 
182         str = parse_offset(arg, "-s", &offset);
183         if (!str)
184                 return -1;
185 
186         slen = strlen(str);
187         if (slen == 0) {
188                 fprintf(stderr, "Empty string in -s argument: %s\n", arg);
189                 return -1;
190         }
191 
192         data = malloc(slen);
193         if (!data) {
194                 fprintf(stderr, "Memory allocation failed\n");
195                 return -1;
196         }
197         memcpy(data, str, slen);
198 
199         return add_patch(offset, data, slen);
200 }
201 
202 static void usage(char *prog)
203 {
204         fprintf(stderr,
205                 "%s -i <input_uimage_file> -o <output_file> [-l <padding bytes>]\n"
206                 "   [-x offset:hexstring] [-s offset:string]\n"
207                 "\n"
208                 "  -l <bytes>         Total padding size appended after the uImage header\n"
209                 "                     (default: %d bytes, zero-filled)\n"
210                 "  -x offset:hexstr   Write hex bytes at <offset> within the padding\n"
211                 "                     (can be repeated; hex digits must be even count)\n"
212                 "  -s offset:string   Write ASCII string at <offset> within the padding\n"
213                 "                     (can be repeated; string is NOT NUL-terminated)\n"
214                 "\n"
215                 "Offsets are relative to the start of the padding area.\n"
216                 "Patches are validated so they do not exceed the padding size.\n",
217                 prog, IH_PAD_BYTES);
218 }
219 
220 int main(int argc, char *argv[])
221 {
222         struct stat statbuf;
223         u_int8_t *filebuf = NULL;
224         int ifd = -1;
225         int ofd = -1;
226         ssize_t rsz;
227         u_int32_t crc_recalc;
228         image_header_t *imgh;
229         int opt;
230         char *infname = NULL;
231         char *outfname = NULL;
232         int padsz = IH_PAD_BYTES;
233         int ltmp;
234         int i;
235         int ret = 1;
236 
237         while ((opt = getopt(argc, argv, "i:o:l:x:s:")) != -1) {
238                 switch (opt) {
239                 case 'i':
240                         infname = optarg;
241                         break;
242                 case 'o':
243                         outfname = optarg;
244                         break;
245                 case 'l':
246                         ltmp = strtol(optarg, NULL, 0);
247                         if (ltmp > 0)
248                                 padsz = ltmp;
249                         break;
250                 case 'x':
251                         if (add_hex_patch(optarg) < 0)
252                                 goto out;
253                         break;
254                 case 's':
255                         if (add_str_patch(optarg) < 0)
256                                 goto out;
257                         break;
258                 default:
259                         break;
260                 }
261         }
262 
263         if (!infname || !outfname) {
264                 usage(argv[0]);
265                 goto out;
266         }
267 
268         /* Validate all patches fit inside the padding area (with overflow protection) */
269         for (i = 0; i < num_patches; i++) {
270                 if (patches[i].offset > (size_t)padsz ||
271                     patches[i].len > (size_t)padsz - patches[i].offset) {
272                         fprintf(stderr,
273                                 "Patch %d (offset=%zu len=%zu) overflows "
274                                 "padding size %d\n",
275                                 i,
276                                 patches[i].offset,
277                                 patches[i].len,
278                                 padsz);
279                         goto out;
280                 }
281         }
282 
283         ifd = open(infname, O_RDONLY);
284         if (ifd < 0) {
285                 fprintf(stderr,
286                         "could not open input file. (errno = %d)\n", errno);
287                 goto out;
288         }
289 
290         ofd = open(outfname, O_WRONLY | O_CREAT, 0644);
291         if (ofd < 0) {
292                 fprintf(stderr,
293                         "could not open output file. (errno = %d)\n", errno);
294                 goto out;
295         }
296 
297         if (fstat(ifd, &statbuf) < 0) {
298                 fprintf(stderr,
299                         "could not fstat input file. (errno = %d)\n", errno);
300                 goto out;
301         }
302 
303         filebuf = malloc(statbuf.st_size + padsz);
304         if (!filebuf) {
305                 fprintf(stderr, "buffer allocation failed\n");
306                 goto out;
307         }
308 
309         rsz = read(ifd, filebuf, sizeof(*imgh));
310         if (rsz != sizeof(*imgh)) {
311                 fprintf(stderr,
312                         "could not read input file (errno = %d).\n", errno);
313                 goto out;
314         }
315 
316         memset(&(filebuf[sizeof(*imgh)]), 0, padsz);
317 
318         /* Apply patches into the padding area (before checksum) */
319         for (i = 0; i < num_patches; i++) {
320                 memcpy(&filebuf[sizeof(*imgh) + patches[i].offset],
321                        patches[i].data,
322                        patches[i].len);
323         }
324 
325         rsz = read(ifd, &(filebuf[sizeof(*imgh) + padsz]),
326                                 statbuf.st_size - sizeof(*imgh));
327         if (rsz != (int32_t)(statbuf.st_size - sizeof(*imgh))) {
328                 fprintf(stderr,
329                         "could not read input file (errno = %d).\n", errno);
330                 goto out;
331         }
332 
333         imgh = (image_header_t *)filebuf;
334 
335         imgh->ih_hcrc = 0;
336         crc_recalc = crc32(0, filebuf, sizeof(*imgh) + padsz);
337         imgh->ih_hcrc = htonl(crc_recalc);
338 
339         rsz = write(ofd, filebuf, statbuf.st_size + padsz);
340         if (rsz != (int32_t)statbuf.st_size + padsz) {
341                 fprintf(stderr,
342                         "could not write output file (errnor = %d).\n", errno);
343                 goto out;
344         }
345 
346         ret = 0;
347 
348 out:
349         if (ifd >= 0)
350                 close(ifd);
351         if (ofd >= 0)
352                 close(ofd);
353         free_patches();
354         free(filebuf);
355 
356         return ret;
357 }
358 

This page was automatically generated by LXR 0.3.1.  •  OpenWrt