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