1 /*
2  * Copyright (c) 2008 Vreixo Formoso
3  * Copyright (c) 2010 - 2019 Thomas Schmitt
4  *
5  * This file is part of the libisofs project; you can redistribute it and/or
6  * modify it under the terms of the GNU General Public License version 2
7  * or later as published by the Free Software Foundation.
8  * See COPYING file for details.
9  */
10 
11 #ifdef HAVE_CONFIG_H
12 #include "../config.h"
13 #endif
14 
15 #include "libisofs.h"
16 #include "system_area.h"
17 #include "eltorito.h"
18 #include "filesrc.h"
19 #include "ecma119_tree.h"
20 #include "image.h"
21 #include "messages.h"
22 #include "ecma119.h"
23 #include "writer.h"
24 
25 #include <string.h>
26 #include <stdio.h>
27 #include <sys/types.h>
28 #include <sys/stat.h>
29 #include <unistd.h>
30 #include <fcntl.h>
31 
32 /* for gettimeofday() */
33 #include <sys/time.h>
34 
35 /* >>> Need ./configure test for uuid_generate() which checks for:
36        uuid_t, uuid_generate, the need for -luuid
37 */
38 /*
39 #define Libisofs_with_uuid_generatE 1
40 */
41 #ifdef Libisofs_with_uuid_generatE
42 #include <uuid/uuid.h>
43 #endif
44 
45 /* O_BINARY is needed for Cygwin but undefined elsewhere */
46 #ifndef O_BINARY
47 #define O_BINARY 0
48 #endif
49 
50 
51 /*
52  * Create a MBR for an isohybrid enabled ISOLINUX boot image.
53  * See libisofs/make_isohybrid_mbr.c
54  * Deprecated.
55  */
56 int make_isohybrid_mbr(int bin_lba, int *img_blocks, char *mbr, int flag);
57 
58 /*
59  * The New ISOLINUX MBR Producer.
60  * Be cautious with changing parameters. Only few combinations are tested.
61  *
62  */
63 int make_isolinux_mbr(uint32_t *img_blocks, Ecma119Image *t,
64                       int part_offset, int part_number, int fs_type,
65                       uint8_t *buf, int flag);
66 
67 /* Find out whether GPT and APM are desired by isohybrid
68    flag bit0 = register APM and GPT requests in Ecma119Image
69 */
70 int assess_isohybrid_gpt_apm(Ecma119Image *t, int *gpt_count, int gpt_idx[128],
71                              int *apm_count, int flag);
72 
73 
74 static int precompute_gpt(Ecma119Image *t);
75 
76 
77 /*
78  * @param flag bit0= img_blocks is start address rather than end address:
79                      do not subtract 1
80                bit1= img_blocks is counted in 512-byte units rather than 2 KiB
81  */
82 static
iso_compute_cyl_head_sec(uint64_t img_blocks,int hpc,int sph,uint32_t * end_lba,uint32_t * end_sec,uint32_t * end_head,uint32_t * end_cyl,int flag)83 void iso_compute_cyl_head_sec(uint64_t img_blocks, int hpc, int sph,
84                               uint32_t *end_lba, uint32_t *end_sec,
85                               uint32_t *end_head, uint32_t *end_cyl, int flag)
86 {
87     uint64_t secs;
88 
89     if(flag & 2)
90         secs = img_blocks;
91     else
92         secs = img_blocks * 4;
93     if (secs > (uint64_t) 0xfffffffc)
94       secs = 0xfffffffc;                   /* truncate rather than roll over */
95     if (flag & 1)
96         *end_lba = secs;                              /* first valid 512-lba */
97     else
98         secs = *end_lba = secs - 1;                    /* last valid 512-lba */
99     *end_cyl = secs / (sph * hpc);
100     secs -= *end_cyl * sph * hpc;
101     *end_head = secs / sph;
102     *end_sec = secs - *end_head * sph + 1;   /* Sector count starts by 1 */
103     if (*end_cyl >= 1024) {
104         *end_cyl = 1023;
105         *end_head = hpc - 1;
106         *end_sec = sph;
107     }
108 }
109 
110 /* @param flag bit0= The path contains instructions for the interval reader
111    @return ISO_SUCCESS     = ok, partition will be written
112            ISO_SUCCESS + 1 = interval which shall be kept in place
113            else : error code
114 */
compute_partition_size(Ecma119Image * t,char * disk_path,uint32_t * size,int flag)115 static int compute_partition_size(Ecma119Image *t, char *disk_path,
116                                   uint32_t *size, int flag)
117 {
118     int ret, keep;
119     off_t num;
120     struct stat stbuf;
121     struct iso_interval_reader *ivr;
122     off_t byte_count;
123 
124     if (flag & 1) {
125         ret = iso_interval_reader_new(t->image, disk_path,
126                                       &ivr, &byte_count, 0);
127         if (ret < 0)
128             return ret;
129         *size = (byte_count + BLOCK_SIZE - 1) / BLOCK_SIZE;
130         keep = iso_interval_reader_keep(t, ivr, 0);
131         iso_interval_reader_destroy(&ivr, 0);
132         if (keep < 0)
133             return keep;
134         return ISO_SUCCESS + (keep > 0);
135     }
136 
137     *size = 0;
138     ret = stat(disk_path, &stbuf);
139     if (ret == -1)
140         return ISO_BAD_PARTITION_FILE;
141     if (! S_ISREG(stbuf.st_mode))
142         return ISO_BAD_PARTITION_FILE;
143     num = ((stbuf.st_size + 2047) / 2048);
144     if (num > 0x3fffffff || num == 0)
145         return ISO_BAD_PARTITION_FILE;
146     *size = num;
147     return ISO_SUCCESS;
148 }
149 
150 /* Compute size and position of appended partitions.
151    @param flag bit0= Partitions inside ISO : update t->curblock
152 */
iso_compute_append_partitions(Ecma119Image * t,int flag)153 int iso_compute_append_partitions(Ecma119Image *t, int flag)
154 {
155     int ret, i, sa_type, cyl_align, cyl_size = 0;
156     int first_partition, last_partition;
157     uint32_t pos, size, add_pos = 0;
158     off_t start_byte, byte_count;
159     char msg[128];
160 
161     sa_type = (t->system_area_options >> 2) & 0x3f;
162     cyl_align = (t->system_area_options >> 8) & 0x3;
163     if (sa_type == 0 && cyl_align == 3) {
164         cyl_size = t->partition_heads_per_cyl * t->partition_secs_per_head;
165         if (cyl_size % 4)
166             cyl_size = 0;
167         else
168             cyl_size /= 4;
169     }
170 
171 #ifdef Libisofs_appended_partitions_inlinE
172 
173     pos = t->curblock;
174 
175 #else
176 
177     pos = (t->vol_space_size + t->opts->ms_block);
178 
179 #endif
180 
181     iso_tell_max_part_range(t->opts, &first_partition, &last_partition, 0);
182     for (i = 0; i < ISO_MAX_PARTITIONS; i++) {
183         if (t->opts->appended_partitions[i] == NULL)
184     continue;
185         if (t->opts->appended_partitions[i][0] == 0)
186     continue;
187         if (i + 1 > last_partition || i + 1 < first_partition) {
188             sprintf(msg,
189          "Partition number %d of appended partition is out of range [%d - %d]",
190                     i + 1, first_partition, last_partition);
191             iso_msgs_submit(0, msg, 0, "FAILURE", 0);
192             return ISO_BAD_PARTITION_NO;
193         }
194 
195         ret = compute_partition_size(t, t->opts->appended_partitions[i], &size,
196                                      t->opts->appended_part_flags[i]);
197         if (ret < 0)
198             return ret;
199         if (ret == ISO_SUCCESS + 1) {
200             /* Interval from imported_iso in add-on session */
201             t->appended_part_prepad[i] = 0;
202             ret = iso_interval_reader_start_size(t,
203                                                t->opts->appended_partitions[i],
204                                                &start_byte, &byte_count, 0);
205             if (ret < 0)
206                 return ret;
207             t->appended_part_start[i] = start_byte / 2048;
208             t->appended_part_size[i] = size;
209             t->opts->iso_mbr_part_type = 0;
210     continue;
211         }
212 
213         add_pos = 0;
214         if (sa_type == 3 && (pos % ISO_SUN_CYL_SIZE)) {
215             add_pos = ISO_SUN_CYL_SIZE - (pos % ISO_SUN_CYL_SIZE);
216         } else if (cyl_size > 0 && (pos % cyl_size)) {
217             add_pos = cyl_size - (pos % cyl_size);
218         }
219         t->appended_part_prepad[i] = add_pos;
220         t->appended_part_start[i] = pos + add_pos;
221 
222         if (cyl_size > 0 && (size % cyl_size)) {
223             /* Obey cylinder alignment (missing data will be written as
224                zeros by iso_write_partition_file()) */
225             size += cyl_size - (size % cyl_size);
226         }
227         t->appended_part_size[i] = size;
228         pos += add_pos + size;
229         t->total_size += (((off_t) add_pos) + size) * 2048;
230         if (flag & 1)
231             t->curblock = pos;
232     }
233     return ISO_SUCCESS;
234 }
235 
236 
mbr_part_slot_is_unused(uint8_t * slot)237 static int mbr_part_slot_is_unused(uint8_t *slot)
238 {
239     int i;
240 
241     for (i = 0; i < 16; i++)
242         if (slot[i] != 0)
243     break;
244     if (i >= 16)
245         return 1;
246     return 0;
247 }
248 
249 
250 /* @param flag
251                 bit1= partition_offset and partition_size are counted in
252                       blocks of 512 rather than 2048
253  */
write_mbr_partition_entry(int partition_number,int partition_type,uint64_t partition_offset,uint64_t partition_size,int sph,int hpc,uint8_t * buf,int flag)254 static int write_mbr_partition_entry(int partition_number, int partition_type,
255                   uint64_t partition_offset, uint64_t partition_size,
256                   int sph, int hpc, uint8_t *buf, int flag)
257 {
258     uint8_t *wpt;
259     uint32_t end_lba, end_sec, end_head, end_cyl;
260     uint32_t start_lba, start_sec, start_head, start_cyl;
261     uint32_t after_end;
262     int i;
263 
264     after_end = partition_offset + partition_size;
265     iso_compute_cyl_head_sec((uint64_t) partition_offset, hpc, sph,
266                              &start_lba, &start_sec, &start_head, &start_cyl,
267                              1 | (flag & 2));
268     iso_compute_cyl_head_sec((uint64_t) after_end, hpc, sph,
269                              &end_lba, &end_sec, &end_head, &end_cyl,
270                              (flag & 2));
271     wpt = buf + 446 + (partition_number - 1) * 16;
272 
273     /* Not bootable */
274     *(wpt++) = 0x00;
275 
276     /* C/H/S of the start */
277     *(wpt++) = start_head;
278     *(wpt++) = start_sec | ((start_cyl & 0x300) >> 2);
279     *(wpt++) = start_cyl & 0xff;
280 
281     /* (partition type) */
282     *(wpt++) = partition_type;
283 
284     /* 3 bytes of C/H/S end */
285     *(wpt++) = end_head;
286     *(wpt++) = end_sec | ((end_cyl & 0x300) >> 2);
287     *(wpt++) = end_cyl & 0xff;
288 
289     /* LBA start in little endian */
290     for (i = 0; i < 4; i++)
291        *(wpt++) = (start_lba >> (8 * i)) & 0xff;
292 
293     /* Number of sectors in partition, little endian */
294     end_lba = end_lba - start_lba + 1;
295     for (i = 0; i < 4; i++)
296        *(wpt++) = (end_lba >> (8 * i)) & 0xff;
297 
298     /* Afaik, partition tables are recognize donly with MBR signature */
299     buf[510] = 0x55;
300     buf[511] = 0xAA;
301 
302     return ISO_SUCCESS;
303 }
304 
305 
306 /* This is the gesture of grub-mkisofs --protective-msdos-label as explained by
307    Vladimir Serbinenko <phcoder@gmail.com>, 2 April 2010, on grub-devel@gnu.org
308    "Currently we use first and not last entry. You need to:
309     1) Zero-fill 446-510
310     2) Put 0x55, 0xAA into 510-512
311     3) Put 0x80 (for bootable partition), 0, 2, 0 (C/H/S of the start), 0xcd
312       (partition type), [3 bytes of C/H/S end], 0x01, 0x00, 0x00, 0x00 (LBA
313       start in little endian), [LBA end in little endian] at 446-462
314    "
315 
316    "C/H/S end" means the CHS address of the last block in the partition.
317    It seems that not "[LBA end in little endian]" but "number of blocks"
318    should go into bytes 458-461. But with a start lba of 1, this is the
319    same number.
320    See also http://en.wikipedia.org/wiki/Master_boot_record
321 
322    flag   bit0= do not write 0x55, 0xAA to 510,511
323           bit1= do not mark partition as bootable
324 */
325 static
make_grub_msdos_label(uint32_t img_blocks,int sph,int hpc,uint8_t part_type,uint8_t * buf,int flag)326 int make_grub_msdos_label(uint32_t img_blocks, int sph, int hpc,
327                           uint8_t part_type, uint8_t *buf, int flag)
328 {
329     uint8_t *wpt;
330     uint32_t end_lba, end_sec, end_head, end_cyl;
331     int i;
332 
333     iso_compute_cyl_head_sec((uint64_t) img_blocks, hpc, sph,
334                              &end_lba, &end_sec, &end_head, &end_cyl, 0);
335 
336     /* 1) Zero-fill 446-510 */
337     wpt = buf + 446;
338     memset(wpt, 0, 64);
339 
340     if (!(flag & 1)) {
341         /* 2) Put 0x55, 0xAA into 510-512 (actually 510-511) */
342         buf[510] = 0x55;
343         buf[511] = 0xAA;
344     }
345     if ((!(flag & 2)) && part_type != 0xee && part_type != 0xef) {
346       /* 3) Put 0x80 (for bootable partition), */
347       *(wpt++) = 0x80;
348     } else {
349       *(wpt++) = 0;
350     }
351 
352     /* 0, 2, 0 (C/H/S of the start), */
353     *(wpt++) = 0;
354     *(wpt++) = 2;
355     *(wpt++) = 0;
356 
357     /* 0xcd (partition type) */
358     *(wpt++) = part_type;
359 
360     /* [3 bytes of C/H/S end], */
361     *(wpt++) = end_head;
362     *(wpt++) = end_sec | ((end_cyl & 0x300) >> 2);
363     *(wpt++) = end_cyl & 0xff;
364 
365 
366     /* 0x01, 0x00, 0x00, 0x00 (LBA start in little endian), */
367     *(wpt++) = 0x01;
368     *(wpt++) = 0x00;
369     *(wpt++) = 0x00;
370     *(wpt++) = 0x00;
371 
372     /* [LBA end in little endian] */
373     for (i = 0; i < 4; i++)
374        *(wpt++) = (end_lba >> (8 * i)) & 0xff;
375 
376     /* at 446-462 */
377     if (wpt - buf != 462) {
378         fprintf(stderr,
379         "libisofs: program error in make_grub_msdos_label: \"assert 462\"\n");
380         return ISO_ASSERT_FAILURE;
381     }
382     return ISO_SUCCESS;
383 }
384 
385 
386 /* @param flag bit0= zeroize partitions entries 2, 3, 4
387                bit1= UEFI protective MBR: start LBA = 1
388 */
389 static
iso_offset_partition_start(uint32_t img_blocks,int post_part_pad,uint32_t partition_offset,int sph,int hpc,uint8_t * buf,int flag)390 int iso_offset_partition_start(uint32_t img_blocks, int post_part_pad,
391                                uint32_t partition_offset,
392                                int sph, int hpc, uint8_t *buf, int flag)
393 {
394     uint8_t *wpt;
395     uint32_t end_lba, end_sec, end_head, end_cyl;
396     uint32_t start_lba, start_sec, start_head, start_cyl;
397     uint64_t img_hd_blocks;
398     int i;
399 
400     iso_compute_cyl_head_sec((uint64_t) partition_offset, hpc, sph,
401                            &start_lba, &start_sec, &start_head, &start_cyl, 1);
402     img_hd_blocks = ((uint64_t) img_blocks) * 4 - post_part_pad / 512;
403     iso_compute_cyl_head_sec(img_hd_blocks, hpc, sph,
404                              &end_lba, &end_sec, &end_head, &end_cyl, 2);
405     if (flag & 2) {
406         start_lba = 1;
407         start_sec = 2;
408         start_head = start_cyl = 0;
409     }
410     wpt = buf + 446;
411 
412     /* Let pass only legal bootability values */
413     if (*wpt != 0 && *wpt != 0x80)
414         (*wpt) = 0;
415     wpt++;
416 
417     /* C/H/S of the start */
418     *(wpt++) = start_head;
419     *(wpt++) = start_sec | ((start_cyl & 0x300) >> 2);
420     *(wpt++) = start_cyl & 0xff;
421 
422     /* (partition type) */
423     wpt++;
424 
425     /* 3 bytes of C/H/S end */
426     *(wpt++) = end_head;
427     *(wpt++) = end_sec | ((end_cyl & 0x300) >> 2);
428     *(wpt++) = end_cyl & 0xff;
429 
430     /* LBA start in little endian */
431     for (i = 0; i < 4; i++)
432        *(wpt++) = (start_lba >> (8 * i)) & 0xff;
433 
434     /* Number of sectors in partition, little endian */
435     end_lba = end_lba - start_lba + 1;
436     for (i = 0; i < 4; i++)
437        *(wpt++) = (end_lba >> (8 * i)) & 0xff;
438 
439     if (wpt - buf != 462) {
440         fprintf(stderr,
441     "libisofs: program error in iso_offset_partition_start: \"assert 462\"\n");
442         return ISO_ASSERT_FAILURE;
443     }
444 
445     if (flag & 1) /* zeroize the other partition entries */
446         memset(wpt, 0, 3 * 16);
447 
448     return ISO_SUCCESS;
449 }
450 
451 
boot_nodes_from_iso_path(Ecma119Image * t,char * path,IsoNode ** iso_node,Ecma119Node ** ecma_node,char * purpose,int flag)452 static int boot_nodes_from_iso_path(Ecma119Image *t, char *path,
453                                    IsoNode **iso_node, Ecma119Node **ecma_node,
454                                    char *purpose, int flag)
455 {
456     int ret;
457 
458     ret = iso_tree_path_to_node(t->image, path, iso_node);
459     if (ret <= 0) {
460         iso_msg_submit(t->image->id, ISO_BOOT_FILE_MISSING, 0,
461                        "Cannot find in ISO image: %s '%s'", purpose, path);
462         return ISO_BOOT_FILE_MISSING;
463     }
464     if ((*iso_node)->type != LIBISO_FILE) {
465         iso_msg_submit(t->image->id, ISO_BOOT_IMAGE_NOT_VALID, 0,
466                        "Designated boot file is not a data file: '%s'", path);
467         return ISO_BOOT_IMAGE_NOT_VALID;
468     }
469 
470     *ecma_node= ecma119_search_iso_node(t, *iso_node);
471     if (*ecma_node == NULL) {
472         iso_msg_submit(t->image->id, ISO_BOOT_IMAGE_NOT_VALID, 0,
473                       "Program error: IsoFile has no Ecma119Node: '%s'", path);
474         return ISO_ASSERT_FAILURE;
475     } else {
476         if ((*ecma_node)->type != ECMA119_FILE) {
477             iso_msg_submit(t->image->id, ISO_BOOT_IMAGE_NOT_VALID, 0,
478               "Program error: Ecma119Node of IsoFile is no ECMA119_FILE: '%s'",
479                           path);
480             return ISO_ASSERT_FAILURE;
481         }
482     }
483     return ISO_SUCCESS;
484 }
485 
486 
487 /* This function was implemented according to doc/boot_sectors.txt section
488    "MIPS Volume Header" which was derived by Thomas Schmitt from
489    cdrkit-1.1.10/genisoimage/boot-mips.c by Steve McIntyre which is based
490    on work of Florian Lohoff and Thiemo Seufer who possibly learned from
491    documents of MIPS Computer Systems, Inc. and Silicon Graphics Computer
492    Systems, Inc.
493    This function itself is entirely under copyright (C) 2010 Thomas Schmitt.
494 */
make_mips_volume_header(Ecma119Image * t,uint8_t * buf,int flag)495 static int make_mips_volume_header(Ecma119Image *t, uint8_t *buf, int flag)
496 {
497     char *namept, *name_field;
498     uint32_t num_cyl, idx, blocks, num, checksum;
499     off_t image_size;
500     static uint32_t bps = 512, spt = 32;
501     Ecma119Node *ecma_node;
502     IsoNode *node;
503     IsoStream *stream;
504     off_t file_size;
505     uint32_t file_lba;
506     int ret;
507 
508     /* Bytes 512 to 32767 may come from image or external file */
509     memset(buf, 0, 512);
510 
511     image_size = t->curblock * 2048;
512 
513     /* 0 -   3 | 0x0be5a941 | Magic number */
514     iso_msb(buf, 0x0be5a941, 4);
515 
516     /* 28 -  29 |  num_cyl_l | Number of usable cylinder, lower two bytes */
517     num_cyl = (image_size + (bps * spt) - 1) / (bps * spt);
518     iso_msb(buf + 28, num_cyl & 0xffff, 2);
519 
520     /* 32 -  33 |          1 | Number of tracks per cylinder */
521     iso_msb(buf + 32, 1, 2);
522 
523     /* 35 -  35 |  num_cyl_h | Number of usable cylinders, high byte */
524     buf[35] = (num_cyl >> 16) & 0xff;
525 
526     /* 38 -  39 |         32 | Sectors per track */
527     iso_msb(buf + 38, spt, 2);
528 
529     /* 40 -  41 |        512 | Bytes per sector */
530     iso_msb(buf + 40, bps, 2);
531 
532     /* 44 -  47 | 0x00000034 | Controller characteristics */
533     iso_msb(buf + 44, 0x00000034, 4);
534 
535     /*  72 -  87 | ========== | Volume Directory Entry 1 */
536     /*  72 -  79 |  boot_name | Boot file basename */
537     /*  80 -  83 | boot_block | ISO 9660 LBA of boot file * 4 */
538     /*  84 -  87 | boot_bytes | File length in bytes */
539     /*  88 - 311 |          0 | Volume Directory Entries 2 to 15 */
540 
541     for (idx = 0; (int) idx < t->image->num_mips_boot_files; idx++) {
542         ret = boot_nodes_from_iso_path(t, t->image->mips_boot_file_paths[idx],
543                                        &node, &ecma_node, "MIPS boot file", 0);
544         if (ret < 0)
545             return ret;
546 
547         namept = (char *) iso_node_get_name(node);
548         name_field = (char *) (buf + (72 + 16 * idx));
549         strncpy(name_field, namept, 8);
550 
551         file_lba = ecma_node->info.file->sections[0].block;
552 
553         iso_msb(buf + (72 + 16 * idx) + 8, file_lba * 4, 4);
554 
555         stream = iso_file_get_stream((IsoFile *) node);
556         file_size = iso_stream_get_size(stream);
557 
558         /* genisoimage rounds up to full multiples of 2048.
559            libisofs did this too until 2020, but the arcload mips boot loader
560            throws error if the rounded size is stored here.
561            So now the exact bytecount gets stored.
562         */
563         iso_msb(buf + (72 + 16 * idx) + 12, file_size, 4);
564 
565     }
566 
567     /* 408 - 411 |  part_blks | Number of 512 byte blocks in partition */
568     blocks = (image_size + bps - 1) / bps;
569     iso_msb(buf + 408, blocks, 4);
570     /* 416 - 419 |          0 | Partition is volume header */
571     iso_msb(buf + 416, 0, 4);
572 
573     /* 432 - 435 |  part_blks | Number of 512 byte blocks in partition */
574     iso_msb(buf + 432, blocks, 4);
575     iso_msb(buf + 444, 6, 4);
576 
577     /* 504 - 507 |   head_chk | Volume header checksum
578                                 The two's complement of bytes 0 to 503 read
579                                 as big endian unsigned 32 bit:
580                                   sum(32-bit-words) + head_chk == 0
581     */
582     checksum = 0;
583     for (idx = 0; idx < 504; idx += 4) {
584         num = iso_read_msb(buf + idx, 4);
585         /* Addition modulo a natural number is commutative and associative.
586            Thus the inverse of a sum is the sum of the inverses of the addends.
587         */
588         checksum -= num;
589     }
590     iso_msb(buf + 504, checksum, 4);
591 
592     return ISO_SUCCESS;
593 }
594 
595 
596 /* The following two functions were implemented according to
597    doc/boot_sectors.txt section "MIPS Little Endian" which was derived
598    by Thomas Schmitt from
599    cdrkit-1.1.10/genisoimage/boot-mipsel.c by Steve McIntyre which is based
600    on work of Florian Lohoff and Thiemo Seufer,
601    and from <elf.h> by Free Software Foundation, Inc.
602 
603    Both functions are entirely under copyright (C) 2010 Thomas Schmitt.
604 */
605 
606 /**
607  * Read the necessary ELF information from the first MIPS boot file.
608  * This is done before image writing starts.
609  */
iso_read_mipsel_elf(Ecma119Image * t,int flag)610 int iso_read_mipsel_elf(Ecma119Image *t, int flag)
611 {
612     uint32_t phdr_adr, todo, count;
613     int ret;
614     uint8_t *elf_buf = NULL;
615     IsoNode *iso_node;
616     Ecma119Node *ecma_node;
617     IsoStream *stream;
618 
619     if (t->image->num_mips_boot_files <= 0)
620         {ret = ISO_SUCCESS; goto ex;}
621 
622     LIBISO_ALLOC_MEM(elf_buf, uint8_t, 2048);
623     ret = boot_nodes_from_iso_path(t, t->image->mips_boot_file_paths[0],
624                                    &iso_node, &ecma_node, "MIPS boot file", 0);
625     if (ret < 0)
626         goto ex;
627     stream = iso_file_get_stream((IsoFile *) iso_node);
628 
629     ret = iso_stream_open(stream);
630     if (ret < 0) {
631         iso_msg_submit(t->image->id, ret, 0,
632                        "Cannot open designated MIPS boot file '%s'",
633                        t->image->mips_boot_file_paths[0]);
634         goto ex;
635     }
636     ret = iso_stream_read(stream, elf_buf, 32);
637     if (ret != 32) {
638 cannot_read:;
639         iso_stream_close(stream);
640         iso_msg_submit(t->image->id, ret, 0,
641                        "Cannot read from designated MIPS boot file '%s'",
642                        t->image->mips_boot_file_paths[0]);
643         goto ex;
644     }
645 
646 
647     /*  24 -  27 |    e_entry | Entry point virtual address */
648     t->mipsel_e_entry = iso_read_lsb(elf_buf + 24, 4);
649 
650     /* 28 -  31 |    e_phoff | Program header table file offset */
651     phdr_adr = iso_read_lsb(elf_buf + 28, 4);
652 
653     /* Skip stream up to byte address phdr_adr */
654     todo = phdr_adr - 32;
655     while (todo > 0) {
656         if (todo > 2048)
657             count = 2048;
658         else
659             count = todo;
660         todo -= count;
661         ret = iso_stream_read(stream, elf_buf, count);
662         if (ret != (int) count)
663             goto cannot_read;
664     }
665     ret = iso_stream_read(stream, elf_buf, 20);
666     if (ret != 20)
667         goto cannot_read;
668 
669     /*  4 -   7 |   p_offset | Segment file offset */
670     t->mipsel_p_offset = iso_read_lsb(elf_buf + 4, 4);
671 
672     /*  8 -  11 |    p_vaddr | Segment virtual address */
673     t->mipsel_p_vaddr = iso_read_lsb(elf_buf + 8, 4);
674 
675     /* 16 -  19 |   p_filesz | Segment size in file */
676     t->mipsel_p_filesz = iso_read_lsb(elf_buf + 16, 4);
677 
678     iso_stream_close(stream);
679     ret = ISO_SUCCESS;
680 ex:;
681     LIBISO_FREE_MEM(elf_buf);
682     return ret;
683 }
684 
685 
686 /**
687  * Write DEC Bootblock from previously read ELF parameters.
688  * This is done when image writing has already begun.
689  */
make_mipsel_boot_block(Ecma119Image * t,uint8_t * buf,int flag)690 static int make_mipsel_boot_block(Ecma119Image *t, uint8_t *buf, int flag)
691 {
692     int ret;
693     uint32_t seg_size, seg_start;
694     IsoNode *iso_node;
695     Ecma119Node *ecma_node;
696 
697     /* Bytes 512 to 32767 may come from image or external file */
698     memset(buf, 0, 512);
699 
700     if (t->image->num_mips_boot_files <= 0)
701         return ISO_SUCCESS;
702 
703     ret = boot_nodes_from_iso_path(t, t->image->mips_boot_file_paths[0],
704                                    &iso_node, &ecma_node, "MIPS boot file", 0);
705     if (ret < 0)
706         return ret;
707 
708     /*  8 -  11 | 0x0002757a | Magic number */
709     iso_lsb(buf + 8, 0x0002757a, 4);
710 
711     /* 12 -  15 |          1 | Mode  1: Multi extent boot */
712     iso_lsb(buf + 12, 1, 4);
713 
714     /* 16 -  19 |   load_adr | Load address */
715     iso_lsb(buf + 16, t->mipsel_p_vaddr, 4);
716 
717     /* 20 -  23 |   exec_adr | Execution address */
718     iso_lsb(buf + 20, t->mipsel_e_entry, 4);
719 
720     /* 24 -  27 |   seg_size | Segment size in file. */
721     seg_size = (t->mipsel_p_filesz + 511) / 512;
722     iso_lsb(buf + 24, seg_size, 4);
723 
724     /* 28 -  31 |  seg_start | Segment file offset */
725     seg_start = ecma_node->info.file->sections[0].block * 4
726                 + (t->mipsel_p_offset + 511) / 512;
727     iso_lsb(buf + 28, seg_start, 4);
728 
729     return ISO_SUCCESS;
730 }
731 
732 
733 /* The following two functions were implemented according to
734    doc/boot_sectors.txt section "SUN Disk Label and boot images" which
735    was derived by Thomas Schmitt from
736      cdrtools-2.01.01a77/mkisofs/sunlabel.h
737      cdrtools-2.01.01a77/mkisofs/mkisofs.8
738      by Joerg Schilling
739 
740    Both functions are entirely under copyright (C) 2010 Thomas Schmitt.
741 */
742 
743 /* @parm flag bit0= copy from next lower valid partition table entry
744  */
write_sun_partition_entry(int partition_number,char * appended_partitions[],uint32_t partition_offset[],uint32_t partition_size[],uint32_t cyl_size,uint8_t * buf,int flag)745 static int write_sun_partition_entry(int partition_number,
746                   char *appended_partitions[],
747                   uint32_t partition_offset[], uint32_t partition_size[],
748                   uint32_t cyl_size, uint8_t *buf, int flag)
749 {
750     uint8_t *wpt;
751     int read_idx, i;
752 
753     if (partition_number < 1 || partition_number > 8)
754         return ISO_ASSERT_FAILURE;
755 
756     /* 142 - 173 | ========== | 8 partition entries of 4 bytes */
757     wpt = buf + 142 + (partition_number - 1) * 4;
758     if (partition_number == 1)
759         iso_msb(wpt, 4, 2);                            /* 4 = User partition */
760     else
761         iso_msb(wpt, 2, 2);            /* 2 = Root partition with boot image */
762     iso_msb(wpt + 2, 0x10, 2);              /* Permissions: 0x10 = read-only */
763 
764     /* 444 - 507 | ========== | Partition table */
765     wpt = buf + 444 + (partition_number - 1) * 8;
766     read_idx = partition_number - 1;
767     if (flag & 1) {
768         /* Search next lower valid partition table entry. #1 is default */
769         for (read_idx = partition_number - 2; read_idx > 0; read_idx--)
770             if (appended_partitions[read_idx] != NULL)
771                 if (appended_partitions[read_idx][0] != 0)
772         break;
773     }
774     iso_msb(wpt, partition_offset[read_idx] / (uint32_t) ISO_SUN_CYL_SIZE, 4);
775     iso_msb(wpt + 4, partition_size[read_idx] * 4, 4);
776 
777     /* 510 - 511 |   checksum | The result of exoring 2-byte words 0 to 254 */
778     buf[510] = buf[511] = 0;
779     for (i = 0; i < 510; i += 2) {
780         buf[510] ^= buf[i];
781         buf[511] ^= buf[i + 1];
782     }
783 
784     return ISO_SUCCESS;
785 }
786 
787 /**
788  * Write SUN Disk Label with ISO in partition 1 and unused 2 to 8
789  */
make_sun_disk_label(Ecma119Image * t,uint8_t * buf,int flag)790 static int make_sun_disk_label(Ecma119Image *t, uint8_t *buf, int flag)
791 {
792     int ret, i, l;
793     uint64_t blk;
794 
795     /* Bytes 512 to 32767 may come from image or external file */
796     memset(buf, 0, 512);
797 
798     /* 0 - 127 |      label | ASCII Label */
799     if (t->opts->ascii_disc_label[0]) {
800         for (l = 0; l < 128 && t->opts->ascii_disc_label[l] != 0; l++);
801         if (l > 0)
802             memcpy((char *) buf, t->opts->ascii_disc_label, l);
803     } else {
804         strcpy((char *) buf,
805                "CD-ROM Disc with Sun sparc boot created by libisofs");
806     }
807 
808     /* 128 - 131 |          1 | Layout version */
809     iso_msb(buf + 128, 1, 4);
810 
811     /* 140 - 141 |          8 | Number of partitions */
812     iso_msb(buf + 140, 8, 2);
813 
814     /* 188 - 191 | 0x600ddeee | vtoc sanity */
815     iso_msb(buf + 188, 0x600ddeee, 4);
816 
817     /* 420 - 421 |        350 | Rotations per minute */
818     iso_msb(buf + 420, 350, 2);
819 
820     /* 422 - 423 |       2048 | Number of physical cylinders (fixely 640 MB) */
821     iso_msb(buf + 422, 2048, 2);
822 
823     /* 430 - 431 |          1 | interleave factor */
824     iso_msb(buf + 430, 1, 2);
825 
826     /* 432 - 433 |       2048 | Number of data cylinders (fixely 640 MB) */
827     iso_msb(buf + 432, 2048, 2);
828 
829     /* 436 - 437 |          1 | Number of heads per cylinder (1 cyl = 320 kB)*/
830     iso_msb(buf + 436, 1, 2);
831 
832     /* 438 - 439 |        640 | Number of sectors per head (1 head = 320 kB) */
833     iso_msb(buf + 438, 640, 2);
834 
835     /* 508 - 509 |     0xdabe | Magic Number */
836     iso_msb(buf + 508, 0xdabe, 2);
837 
838     if (t->sparc_core_src != NULL) {
839         /* May be used for grub-sparc. */
840         blk= ((uint64_t) t->sparc_core_src->sections[0].block) *
841              (uint64_t) 2048;
842         for (i = 0; i < 8; i++)
843             buf[Libisofs_grub2_sparc_patch_adr_poS + i] = blk >> ((7 - i) * 8);
844         iso_msb(buf + Libisofs_grub2_sparc_patch_size_poS,
845                 t->sparc_core_src->sections[0].size, 4);
846     }
847 
848     /* Set partition 1 to describe ISO image and compute checksum */
849     t->appended_part_start[0] = 0;
850     t->appended_part_size[0] = t->curblock;
851     ret = write_sun_partition_entry(1, t->opts->appended_partitions,
852                   t->appended_part_start, t->appended_part_size,
853                   ISO_SUN_CYL_SIZE, buf, 0);
854     if (ret < 0)
855         return ret;
856     return ISO_SUCCESS;
857 }
858 
859 
hppa_palo_get_filepar(Ecma119Image * t,char * path,uint32_t * adr,uint32_t * len,int flag)860 static int hppa_palo_get_filepar(Ecma119Image *t, char *path,
861                                  uint32_t *adr, uint32_t *len, int flag)
862 {
863     int ret;
864     IsoNode *iso_node;
865     Ecma119Node *ecma_node;
866     off_t adr64;
867 
868     ret = boot_nodes_from_iso_path(t, path,
869                              &iso_node, &ecma_node, "HP-PA PALO boot file", 0);
870     if (ret < 0)
871         return ret;
872     if (iso_node_get_type(iso_node) != LIBISO_FILE) {
873         iso_msg_submit(t->image->id, ISO_HPPA_PALO_NOTREG, 0,
874                        "HP-PA PALO file is not a data file");
875         return ISO_HPPA_PALO_NOTREG;
876     }
877     adr64 = ((off_t) 2048) * (off_t) ecma_node->info.file->sections[0].block;
878     if (adr64 > 0x7fffffff) {
879         iso_msg_submit(t->image->id, ISO_HPPA_PALO_OFLOW, 0,
880                        "HP-PA PALO boot address exceeds 2 GB");
881         return ISO_HPPA_PALO_OFLOW;
882     }
883     *adr = adr64;
884     *len = ecma_node->info.file->sections[0].size;
885     return ISO_SUCCESS;
886 }
887 
888 
889 /**
890  * Write HP-PA PALO boot sector. See doc/boot_sectors.txt
891  *
892  * learned from  cdrkit-1.1.10/genisoimage/boot-hppa.c
893  * by Steve McIntyre <steve@einval.com>
894  *    who states "Heavily inspired by palo"
895  * Public mail conversations with Helge Deller, beginning with
896  *    https://lists.debian.org/debian-hppa/2014/01/msg00016.html
897  * http://git.kernel.org/cgit/linux/kernel/git/deller/palo.git/tree/lib/
898  *    (especially struct firstblock in common.h and struct partition in part.h)
899  *
900  */
make_hppa_palo_sector(Ecma119Image * t,uint8_t * buf,int hdrversion,int flag)901 static int make_hppa_palo_sector(Ecma119Image *t, uint8_t *buf, int hdrversion,
902                                  int flag)
903 {
904     int ret;
905     IsoImage *img;
906     uint32_t adr, len;
907 
908     img = t->image;
909     if (img->hppa_cmdline == NULL && img->hppa_bootloader == NULL &&
910         img->hppa_kernel_32 == NULL && img->hppa_kernel_64 == NULL &&
911         img->hppa_ramdisk == NULL)
912         return ISO_SUCCESS;
913     if (img->hppa_cmdline == NULL || img->hppa_bootloader == NULL ||
914         img->hppa_kernel_32 == NULL || img->hppa_kernel_64 == NULL ||
915         img->hppa_ramdisk == NULL) {
916         iso_msg_submit(img->id, ISO_HPPA_PALO_INCOMPL, 0,
917                        "Incomplete HP-PA PALO boot parameters");
918         return ISO_HPPA_PALO_INCOMPL;
919     }
920     if (hdrversion == 4) {
921         /* Bytes 256 to 32767 may come from loaded ISO image or external file */
922         memset(buf, 0, 256);
923     } else if(hdrversion == 5) {
924         memset(buf, 0, 512);
925         memset(buf + 1024, 0, 1024);
926     } else {
927         iso_msg_submit(img->id, ISO_WRONG_ARG_VALUE, 0,
928                     "Unsupported HP-PA PALO header version %d (can do 4 or 5)",
929                        hdrversion);
930         return ISO_WRONG_ARG_VALUE;
931     }
932 
933     /* Magic */
934     iso_msb(buf + 0, 0x8000, 2);
935     /* Name of boot loader */
936     memcpy(buf + 2, "PALO", 5);
937     /* Version */
938     buf[7] = hdrversion;
939 
940     /* Byte address and byte count of the "HPPA 32-bit kernel" file
941     */
942     ret = hppa_palo_get_filepar(t, img->hppa_kernel_32, &adr, &len, 0);
943     if (ret < 0)
944         return ret;
945     iso_msb(buf +  8, adr, 4);
946     iso_msb(buf + 12, len, 4);
947 
948     /* Byte address and byte count of the "HPPA ramdisk" file
949     */
950     ret = hppa_palo_get_filepar(t, img->hppa_ramdisk, &adr, &len, 0);
951     if (ret < 0)
952         return ret;
953     iso_msb(buf + 16, adr, 4);
954     iso_msb(buf + 20, len, 4);
955 
956     if (hdrversion == 4) {
957         /* "Command line" */
958         if (strlen(img->hppa_cmdline) > 127) {
959             iso_msg_submit(img->id, ISO_HPPA_PALO_CMDLEN, 0,
960                            "HP-PA PALO command line too long");
961             return ISO_HPPA_PALO_CMDLEN;
962         }
963         memcpy(buf + 24, img->hppa_cmdline, strlen(img->hppa_cmdline) + 1);
964     }
965 
966     /* Byte address and byte count of the "HPPA 64-bit kernel" file
967     */
968     ret = hppa_palo_get_filepar(t, img->hppa_kernel_64, &adr, &len, 0);
969     if (ret < 0)
970         return ret;
971     iso_msb(buf + 232, adr, 4);
972     iso_msb(buf + 236, len, 4);
973 
974     /* Byte address and byte count of the "HPPA bootloader" file
975     */
976     ret = hppa_palo_get_filepar(t, img->hppa_bootloader, &adr, &len, 0);
977     if (ret < 0)
978         return ret;
979     iso_msb(buf + 240, adr, 4);
980     iso_msb(buf + 244, len, 4);
981 
982     if (hdrversion == 5) {
983         if (strlen(img->hppa_cmdline) > 1023) {
984             iso_msg_submit(img->id, ISO_HPPA_PALO_CMDLEN, 0,
985                            "HP-PA PALO command line too long");
986             return ISO_HPPA_PALO_CMDLEN;
987         }
988         memcpy(buf + 1024, img->hppa_cmdline, strlen(img->hppa_cmdline) + 1);
989     }
990     return ISO_SUCCESS;
991 }
992 
993 
994 /**
995  * Write DEC Alpha boot sector. See doc/boot_sectors.txt
996  *
997  * learned from  cdrkit-1.1.10/genisoimage/boot-alpha.c
998  * by Steve McIntyre <steve@einval.com>
999  *    who states "Heavily inspired by isomarkboot by David Mosberger in 1996"
1000  *
1001  */
make_dec_alpha_sector(Ecma119Image * t,uint8_t * buf,int flag)1002 static int make_dec_alpha_sector(Ecma119Image *t, uint8_t *buf, int flag)
1003 {
1004     int ret, i;
1005     IsoImage *img;
1006     IsoNode *iso_node;
1007     Ecma119Node *ecma_node;
1008     uint64_t size, lba, checksum = 0;
1009 
1010     img = t->image;
1011     if (img->alpha_boot_image == NULL)
1012         return ISO_SUCCESS;
1013     ret = boot_nodes_from_iso_path(t, img->alpha_boot_image,
1014                               &iso_node, &ecma_node, "DEC Alpha boot file", 0);
1015     if (ret < 0)
1016         return ret;
1017     memset(buf, 0, 512);
1018     strcpy((char *) buf, "Linux/Alpha aboot for ISO filesystem.");
1019     lba = ecma_node->info.file->sections[0].block * 4;
1020     size = ecma_node->info.file->sections[0].size / 512 +
1021            !!(ecma_node->info.file->sections[0].size % 512);
1022     iso_lsb(buf + 480, size & 0xffffffff, 4);
1023     iso_lsb(buf + 484, (size >> 32) & 0xffffffff, 4);
1024     iso_lsb(buf + 488, lba & 0xffffffff, 4);
1025     iso_lsb(buf + 492, (lba >> 32) & 0xffffffff, 4);
1026     for (i = 0; i < 63; i++)
1027        checksum += iso_read_lsb64(buf + 8 * i);
1028     iso_lsb(buf + 504, checksum & 0xffffffff, 4);
1029     iso_lsb(buf + 508, (checksum >> 32) & 0xffffffff, 4);
1030     return ISO_SUCCESS;
1031 }
1032 
1033 /* Convenience frontend for iso_register_apm_entry().
1034    name and type are 0-terminated strings.
1035 */
iso_quick_apm_entry(struct iso_apm_partition_request ** req_array,int * apm_req_count,uint32_t start_block,uint32_t block_count,char * name,char * type)1036 int iso_quick_apm_entry(struct iso_apm_partition_request **req_array,
1037                         int *apm_req_count,
1038                         uint32_t start_block, uint32_t block_count,
1039                         char *name, char *type)
1040 {
1041     int ret, l;
1042     struct iso_apm_partition_request *entry;
1043 
1044     entry = calloc(1, sizeof(struct iso_apm_partition_request));
1045     if (entry == NULL)
1046         return ISO_OUT_OF_MEM;
1047     entry->start_block = start_block;
1048     entry->block_count = block_count;
1049     for (l = 0; l < 32 && name[l] != 0; l++);
1050     if (l > 0)
1051         memcpy((char *) entry->name, name, l);
1052     for (l = 0; l < 32 && type[l] != 0; l++);
1053     if (l > 0)
1054         memcpy((char *) entry->type, type, l);
1055     entry->req_status = 0;
1056     ret = iso_register_apm_entry(req_array, apm_req_count, entry, 0);
1057     free(entry);
1058     return ret;
1059 }
1060 
1061 
iso_find_gpt_entry(struct iso_gpt_partition_request ** req_array,int gpt_req_count,uint64_t start_block,uint64_t block_count,int * index,int flag)1062 static int iso_find_gpt_entry(struct iso_gpt_partition_request **req_array,
1063                         int gpt_req_count,
1064                         uint64_t start_block, uint64_t block_count,
1065                         int *index, int flag)
1066 {
1067     struct iso_gpt_partition_request *entry;
1068 
1069     for (*index = 0; *index < gpt_req_count; (*index)++) {
1070         entry = req_array[*index];
1071         if (entry->start_block == start_block &&
1072             entry->block_count == block_count)
1073             return 1;
1074     }
1075     *index = -1;
1076     return 0;
1077 }
1078 
1079 
1080 /* Convenience frontend for iso_register_gpt_entry().
1081    name has to be already encoded as UTF-16LE.
1082 */
iso_quick_gpt_entry(struct iso_gpt_partition_request ** req_array,int * gpt_req_count,uint64_t start_block,uint64_t block_count,uint8_t type_guid[16],uint8_t partition_guid[16],uint64_t flags,uint8_t name[72])1083 int iso_quick_gpt_entry(struct iso_gpt_partition_request **req_array,
1084                         int *gpt_req_count,
1085                         uint64_t start_block, uint64_t block_count,
1086                         uint8_t type_guid[16], uint8_t partition_guid[16],
1087                         uint64_t flags, uint8_t name[72])
1088 {
1089     int ret;
1090     struct iso_gpt_partition_request *entry;
1091 
1092     entry = calloc(1, sizeof(struct iso_gpt_partition_request));
1093     if (entry == NULL)
1094         return ISO_OUT_OF_MEM;
1095     entry->start_block = start_block;
1096     entry->block_count = block_count;
1097     memcpy(entry->type_guid, type_guid, 16);
1098     memcpy(entry->partition_guid, partition_guid, 16);
1099     entry->flags = flags;
1100     memcpy(entry->name, name, 72);
1101     entry->req_status = 0;
1102     ret = iso_register_gpt_entry(req_array, gpt_req_count, entry, 0);
1103     free(entry);
1104     return ret;
1105 }
1106 
1107 
iso_quick_mbr_entry(struct iso_mbr_partition_request ** req_array,int * mbr_req_count,uint64_t start_block,uint64_t block_count,uint8_t type_byte,uint8_t status_byte,int desired_slot)1108 int iso_quick_mbr_entry(struct iso_mbr_partition_request **req_array,
1109                         int *mbr_req_count,
1110                         uint64_t start_block, uint64_t block_count,
1111                         uint8_t type_byte, uint8_t status_byte,
1112                         int desired_slot)
1113 {
1114     int ret;
1115     struct iso_mbr_partition_request *entry;
1116 
1117     ret = iso_mbr_entry_slot_is_free(req_array, *mbr_req_count, desired_slot);
1118     if (ret < 0)
1119         desired_slot = 0;
1120     else if (ret == 0)
1121         return ISO_BOOT_MBR_COLLISION;
1122 
1123     entry = calloc(1, sizeof(struct iso_mbr_partition_request));
1124     if (entry == NULL)
1125         return ISO_OUT_OF_MEM;
1126     entry->start_block = start_block;
1127     entry->block_count = block_count;
1128     entry->type_byte = type_byte;
1129     entry->status_byte = status_byte;
1130     entry->desired_slot = desired_slot;
1131     ret = iso_register_mbr_entry(req_array, mbr_req_count, entry, 0);
1132     free(entry);
1133     return ret;
1134 }
1135 
1136 
iso_mbr_entry_slot_is_free(struct iso_mbr_partition_request ** req_array,int mbr_req_count,int slot)1137 int iso_mbr_entry_slot_is_free(struct iso_mbr_partition_request **req_array,
1138                                int mbr_req_count, int slot)
1139 {
1140     int i;
1141 
1142     if (slot < 0 || slot > ISO_MBR_ENTRIES_MAX)
1143         return -1;
1144     if (slot == 0)
1145         return 1;
1146     for (i = 0; i < mbr_req_count; i++)
1147         if (req_array[i]->desired_slot == slot)
1148             return 0;
1149     return 1;
1150 }
1151 
1152 
1153 /**
1154  * Compare the block interval positions of two iso_apm_partition_request
1155  */
1156 static
cmp_partition_request(const void * f1,const void * f2)1157 int cmp_partition_request(const void *f1, const void *f2)
1158 {
1159     struct iso_partition_request {
1160        uint64_t start_block;
1161        uint64_t block_count;
1162     } *r1, *r2;
1163 
1164     r1 = *((struct iso_partition_request **) f1);
1165     r2 = *((struct iso_partition_request **) f2);
1166     if (r1->start_block < r2->start_block)
1167         return -1;
1168     if (r1->start_block > r2->start_block)
1169         return 1;
1170 
1171     /* In case of overlapping the largest partition shall be first */
1172     if (r1->block_count > r2->block_count)
1173         return -1;
1174     if (r1->block_count < r2->block_count)
1175         return 1;
1176     return 0;
1177 }
1178 
1179 
1180 /* @param flag bit0= This is the entry in block 1. Its blocks are already in
1181                      the desired apm_block_size unit. Set block_fac to 1.
1182                      Set flags to 3 rather than 0x13.
1183 */
iso_write_apm_entry(Ecma119Image * t,int apm_block_size,struct iso_apm_partition_request * req,uint8_t * buf,int map_entries,int flag)1184 static int iso_write_apm_entry(Ecma119Image *t, int apm_block_size,
1185                                struct iso_apm_partition_request *req,
1186                                uint8_t *buf, int map_entries, int flag)
1187 {
1188     uint8_t *wpt;
1189     uint32_t flags;
1190     int block_fac;
1191 
1192     if ((flag & 1) || (t->apm_req_flags & 4))
1193         block_fac = 1;
1194     else
1195         block_fac = 2048 / apm_block_size;
1196 
1197     memset(buf, 0, apm_block_size);
1198     wpt = buf;
1199 
1200     /* Signature */
1201     wpt[0] = 'P'; wpt[1] = 'M';
1202     wpt+= 2;
1203     /* reserved */
1204     wpt += 2;
1205     /* Number of partition entries */
1206     iso_msb(wpt, (uint32_t) map_entries, 4);
1207     wpt += 4;
1208     /* Physical block start of partition */
1209     iso_msb(wpt, (uint32_t) (req->start_block * block_fac), 4);
1210     wpt += 4;
1211     /* Physical block count of partition */
1212     iso_msb(wpt, (uint32_t) (req->block_count * block_fac), 4);
1213     wpt += 4;
1214     /* Partition name */
1215     memcpy(wpt, req->name, 32);
1216     wpt += 32;
1217     /* Type string */
1218     memcpy(wpt, req->type, 32);
1219     wpt += 32;
1220     /* Logical block start */
1221     iso_msb(wpt, (uint32_t) 0, 4);
1222     wpt += 4;
1223     /* Logical block count */
1224     iso_msb(wpt, (uint32_t) (req->block_count * block_fac), 4);
1225     wpt += 4;
1226     /* Status flags : bit0= entry is valid , bit1= entry is allocated
1227                       bit4= partition is readable , bit5= partition is writable
1228                       bit30= automatic mount (legacy Mac)
1229     */
1230     if (flag & 1) {
1231         flags = 3;
1232     } else {
1233         flags = 0x13;
1234         if (strncmp((char *) req->type, "Apple_HFS", 9) == 0 &&
1235             req->type[9] == 0)
1236             flags |= 0x40000000;
1237     }
1238     iso_msb(wpt, flags, 4);
1239     wpt += 4;
1240 
1241     /* boot_block , boot_bytes , processor , reserved : are all 0 */
1242 
1243     return ISO_SUCCESS;
1244 }
1245 
1246 
1247 /* Sort and fill gaps in requested APM */
fill_apm_gaps(Ecma119Image * t,uint32_t img_blocks)1248 static int fill_apm_gaps(Ecma119Image *t, uint32_t img_blocks)
1249 {
1250     int i, ret, gap_counter = 0, up_to;
1251     uint32_t part_end, goal, block_fac = 1;
1252     char gap_name[33];
1253 
1254     if (t->apm_req_flags & 4) {
1255         if (t->opts->apm_block_size == 0)
1256             t->opts->apm_block_size = 2048;
1257         block_fac = 2048 / t->opts->apm_block_size;
1258     }
1259 
1260     /* Find out whether an entry with start_block <= 1 is requested */
1261     for (i = 0; i < t->apm_req_count; i++) {
1262         if (t->apm_req[i]->start_block <= 1)
1263     break;
1264     }
1265     if (i >= t->apm_req_count) {
1266         ret = iso_quick_apm_entry(t->apm_req, &(t->apm_req_count),
1267                                   1, 0, "Apple", "Apple_partition_map");
1268         if (ret < 0)
1269             return ret;
1270     }
1271 
1272     qsort(t->apm_req, t->apm_req_count,
1273         sizeof(struct iso_apm_partition_request *), cmp_partition_request);
1274 
1275     if (t->opts->part_like_isohybrid)
1276         return 1; /* No filling, only sorting */
1277 
1278     /* t->apm_req_count will grow during the loop */
1279     up_to = t->apm_req_count + 1;
1280     for (i = 1; i < up_to; i++) {
1281         if (i < up_to - 1)
1282             goal = (uint32_t) t->apm_req[i]->start_block;
1283         else
1284             goal = img_blocks * block_fac;
1285         if (i == 1) {
1286             /* Description of APM itself */
1287             /* Actual APM size is not yet known. Protection begins at PVD */
1288             part_end = 16 * block_fac;
1289             if (goal < part_end && goal> 1)
1290                     part_end = goal;
1291         } else {
1292             part_end = t->apm_req[i - 1]->start_block +
1293                        t->apm_req[i - 1]->block_count;
1294         }
1295         if (part_end > goal) {
1296             iso_msg_submit(t->image->id, ISO_BOOT_APM_OVERLAP, 0,
1297                "Program error: APM partitions %d and %d overlap by %lu blocks",
1298                i - 1, i, part_end - goal);
1299             return ISO_BOOT_APM_OVERLAP;
1300         }
1301 
1302         if (t->apm_req_flags & 2) /* Do not fill gaps */
1303     continue;
1304 
1305         if (part_end < goal || i == up_to - 1) { /* Always add a final entry */
1306             sprintf(gap_name, "Gap%d", gap_counter);
1307             gap_counter++;
1308             ret = iso_quick_apm_entry(t->apm_req, &(t->apm_req_count),
1309                                       part_end, goal - part_end,
1310                                       gap_name, "ISO9660_data");
1311             if (ret < 0)
1312                 return ret;
1313             /* Mark as automatically placed filler request */
1314             t->apm_req[t->apm_req_count - 1]->req_status |= 1;
1315         }
1316     }
1317 
1318     /* Merge list of gap partitions with list of already sorted entries */
1319     if (!(t->apm_req_flags & 2)) /* No gaps were filled */
1320         qsort(t->apm_req, t->apm_req_count,
1321             sizeof(struct iso_apm_partition_request *), cmp_partition_request);
1322 
1323     return 1;
1324 }
1325 
1326 
rectify_apm(Ecma119Image * t)1327 static int rectify_apm(Ecma119Image *t)
1328 {
1329     int ret;
1330 
1331 #ifdef NIX
1332     /* Disabled */
1333 
1334     /* <<< ts B20526 : Dummy mock-up */
1335     if (t->apm_req_count <= 0) {
1336         /*
1337         ret = iso_quick_apm_entry(t->apm_req, &(t->apm_req_count),
1338                                   16, 20, "Test1_name_16_20", "Test1_type");
1339         / * >>> Caution: Size 90 causes intentional partition overlap error * /
1340         ret = iso_quick_apm_entry(t->apm_req, &(t->apm_req_count),
1341                                   30, 90, "BAD_30_90_BAD", "Test1_type");
1342         */
1343         ret = iso_quick_apm_entry(t->apm_req, &(t->apm_req_count),
1344                                   30, 20, "Test1_name_30_20", "Test1_type");
1345         if (ret < 0)
1346             return ret;
1347         ret = iso_quick_apm_entry(t->apm_req, &(t->apm_req_count),
1348                                  100, 400, "Test2_name_100_400", "Test2_type");
1349         if (ret < 0)
1350             return ret;
1351     }
1352 #endif /* NIX */
1353 
1354     if (t->apm_req_count == 0)
1355         return 1;
1356 
1357     if (t->gpt_req_count > 0 &&
1358         t->opts->apm_block_size != 2048 && t->apm_req_count > 0) {
1359         iso_msgs_submit(0,
1360                 "GPT and APM requested. APM block size would have to be 2048.",
1361                         0, "FAILURE", 0);
1362         return ISO_BOOT_APM_GPT_BSIZE;
1363     }
1364     if (t->apm_req_count > 0) {
1365         ret = fill_apm_gaps(t, t->curblock);
1366         if (ret < 0)
1367             return ret;
1368     }
1369     return 1;
1370 }
1371 
1372 
1373 /* flag bit0= do not write Block0
1374 */
iso_write_apm(Ecma119Image * t,uint32_t img_blocks,uint8_t * buf,int flag)1375 static int iso_write_apm(Ecma119Image *t, uint32_t img_blocks, uint8_t *buf,
1376                          int flag)
1377 {
1378     int i, ret;
1379     uint32_t block_fac = 1;
1380     /* This is a micro mock-up of an APM Block0
1381        and also harmless x86 machine code.
1382     */
1383     static uint8_t block0_template[8] = {
1384         0x45, 0x52, 0x02, 0x00, 0xeb, 0x02, 0xff, 0xff
1385     };
1386 
1387     if (t->apm_req_count <= 0)
1388         return 2;
1389 
1390     if (t->opts->apm_block_size == 0) {
1391         /* One cannot be sure that all GPT partitions are registered
1392            already. So it is necessary to choose the block size which is
1393            combinable with GPT but not mountable on Linux.
1394         */
1395         t->opts->apm_block_size = 2048;
1396     }
1397 
1398     if (t->apm_req_flags & 4)
1399         block_fac = 2048 / t->opts->apm_block_size;
1400 
1401     if (!(t->apm_req_flags & 2)) {
1402         /* Gaps have been filled. Care for the final one */
1403         /* Adjust last partition to img_size. This size was not known when the
1404            number of APM partitions was determined.
1405         */
1406         if (img_blocks * block_fac <
1407             t->apm_req[t->apm_req_count - 1]->start_block)
1408             t->apm_req[t->apm_req_count - 1]->block_count = 0;
1409         else
1410             t->apm_req[t->apm_req_count - 1]->block_count =
1411                                  img_blocks * block_fac -
1412                                  t->apm_req[t->apm_req_count - 1]->start_block;
1413         /* If it is still empty, remove it */
1414         if(t->apm_req[t->apm_req_count - 1]->block_count == 0) {
1415           free(t->apm_req[t->apm_req_count - 1]);
1416           t->apm_req_count--;
1417         }
1418     }
1419 
1420     /* If block size is larger than 512, then not all 63 entries will fit */
1421     if ((t->apm_req_count + 1) * t->opts->apm_block_size > 32768)
1422         return ISO_BOOT_TOO_MANY_APM;
1423 
1424     /* Block 1 describes the APM itself */
1425     t->apm_req[0]->start_block = 1;
1426     t->apm_req[0]->block_count = t->apm_req_count;
1427 
1428     if (!(flag & 1)) {
1429       /* Write APM block 0. Very sparse, not to overwrite much of
1430          possible MBR.
1431       */
1432       memcpy(buf, block0_template, 8);
1433       buf[2]= (t->opts->apm_block_size >> 8) & 0xff;
1434       buf[3]= 0;
1435     }
1436 
1437     /* Write APM Block 1 to t->apm_req_count */
1438     for (i = 0; i < t->apm_req_count; i++) {
1439         ret = iso_write_apm_entry(t, t->opts->apm_block_size, t->apm_req[i],
1440                      buf + (i + 1) * t->opts->apm_block_size, t->apm_req_count,
1441                      i == 0);
1442         if (ret < 0)
1443             return ret;
1444     }
1445     return ISO_SUCCESS;
1446 }
1447 
1448 
iso_write_mbr(Ecma119Image * t,uint32_t img_blocks,uint8_t * buf)1449 static int iso_write_mbr(Ecma119Image *t, uint32_t img_blocks, uint8_t *buf)
1450 {
1451     int i, ret, req_of_slot[ISO_MBR_ENTRIES_MAX], q, j;
1452 
1453 #ifdef NIX
1454     /* Disabled */
1455 
1456     /* <<< Dummy mock-up */
1457     if (t->mbr_req_count <= 0) {
1458         ret = iso_quick_mbr_entry(t->mbr_req, &(t->mbr_req_count),
1459                                   (uint64_t) 0, (uint64_t) 0, 0xee, 0, 0);
1460         if (ret < 0)
1461             return ret;
1462         ret = iso_quick_mbr_entry(t->mbr_req, &(t->mbr_req_count),
1463                                   ((uint64_t) 100) * 4, (uint64_t) 0,
1464                                   0x0c, 0x80, 1);
1465         if (ret < 0)
1466             return ret;
1467     }
1468 #endif /* NIX */
1469 
1470     if (t->mbr_req_count <= 0)
1471         return 2;
1472 
1473     /* >>> Sort by start block ? */
1474 
1475     /* Adjust partition ends */
1476     for (i = 0; i < t->mbr_req_count; i++) {
1477         if (i > 0) {
1478             if (t->mbr_req[i]->start_block <= t->mbr_req[i - 1]->start_block &&
1479                 !(t->mbr_req[i]->block_count == 0 &&
1480                   t->mbr_req[i]->start_block ==
1481                                              t->mbr_req[i - 1]->start_block))
1482                 return ISO_BOOT_MBR_OVERLAP;
1483             if (t->mbr_req[i - 1]->start_block +
1484                    t->mbr_req[i - 1]->block_count > t->mbr_req[i]->start_block)
1485                 return ISO_BOOT_MBR_OVERLAP;
1486         }
1487         if (t->mbr_req[i]->block_count != 0)
1488     continue;
1489         if (i < t->mbr_req_count - 1)
1490             t->mbr_req[i]->block_count = t->mbr_req[i + 1]->start_block -
1491                                          t->mbr_req[i]->start_block;
1492         else
1493             t->mbr_req[i]->block_count = ((uint64_t) img_blocks) * 4 -
1494                                          t->mbr_req[i]->start_block;
1495     }
1496 
1497     /* Assign requested entries to slot numbers */
1498     for (i = 0; i < ISO_MBR_ENTRIES_MAX; i++)
1499         req_of_slot[i] = -1;
1500     for (i = 0; i < t->mbr_req_count; i++) {
1501         if (t->mbr_req[i]->desired_slot < 1 ||
1502             t->mbr_req[i]->desired_slot > ISO_MBR_ENTRIES_MAX)
1503     continue;
1504         if (req_of_slot[t->mbr_req[i]->desired_slot - 1] >= 0)
1505             return ISO_BOOT_MBR_COLLISION;
1506         req_of_slot[t->mbr_req[i]->desired_slot - 1] = i;
1507     }
1508     for (i = 0; i < t->mbr_req_count; i++) {
1509         if (t->mbr_req[i]->desired_slot > 0)
1510     continue;
1511         for (j = 0; j < ISO_MBR_ENTRIES_MAX; j++)
1512              if (req_of_slot[j] < 0)
1513         break;
1514         if (j >= ISO_MBR_ENTRIES_MAX)
1515             return ISO_BOOT_TOO_MANY_MBR;
1516         req_of_slot[j] = i;
1517     }
1518 
1519     /* Write partition slots */
1520     for (i = 0; i < ISO_MBR_ENTRIES_MAX; i++) {
1521         memset(buf + 446 + i * 16, 0, 16);
1522         q = req_of_slot[i];
1523         if (q < 0)
1524     continue;
1525         if (t->mbr_req[q]->block_count == 0)
1526     continue;
1527         ret = write_mbr_partition_entry(i + 1, (int) t->mbr_req[q]->type_byte,
1528                   t->mbr_req[q]->start_block, t->mbr_req[q]->block_count,
1529                   t->partition_secs_per_head, t->partition_heads_per_cyl,
1530                   buf, 2);
1531         if (ret < 0)
1532             return ret;
1533         buf[446 + i * 16] = t->mbr_req[q]->status_byte;
1534     }
1535     return ISO_SUCCESS;
1536 }
1537 
1538 
iso_write_gpt_entry(Ecma119Image * t,uint8_t * buf,uint8_t type_guid[16],uint8_t part_uuid[16],uint64_t start_lba,uint64_t end_lba,uint64_t flags,uint8_t name[72])1539 static void iso_write_gpt_entry(Ecma119Image *t, uint8_t *buf,
1540                                 uint8_t type_guid[16], uint8_t part_uuid[16],
1541                                 uint64_t start_lba, uint64_t end_lba,
1542                                 uint64_t flags, uint8_t name[72])
1543 {
1544     char *wpt;
1545     int i;
1546 
1547     wpt = (char *) buf;
1548     memcpy(wpt, type_guid, 16);
1549     wpt += 16;
1550     for (i = 0; i < 16; i++)
1551         if (part_uuid[i])
1552     break;
1553     if (i == 16) {
1554         if (!t->gpt_disk_guid_set)
1555             iso_gpt_uuid(t, t->gpt_disk_guid);
1556         t->gpt_disk_guid_set = 1;
1557         iso_gpt_uuid(t, part_uuid);
1558     }
1559     memcpy(wpt, part_uuid, 16);
1560     wpt += 16;
1561     iso_lsb_to_buf(&wpt, start_lba & 0xffffffff, 4, 0);
1562     iso_lsb_to_buf(&wpt, (start_lba >> 32) & 0xffffffff, 4, 0);
1563     iso_lsb_to_buf(&wpt, end_lba & 0xffffffff, 4, 0);
1564     iso_lsb_to_buf(&wpt, (end_lba >> 32) & 0xffffffff, 4, 0);
1565     iso_lsb_to_buf(&wpt, flags & 0xffffffff, 4, 0);
1566     iso_lsb_to_buf(&wpt, (flags >> 32) & 0xffffffff, 4, 0);
1567     memcpy(wpt, name, 72);
1568 }
1569 
1570 
iso_write_gpt_header_block(Ecma119Image * t,uint32_t img_blocks,uint8_t * buf,uint32_t max_entries,uint32_t part_start,uint32_t p_arr_crc)1571 int iso_write_gpt_header_block(Ecma119Image *t, uint32_t img_blocks,
1572                                uint8_t *buf, uint32_t max_entries,
1573                                uint32_t part_start, uint32_t p_arr_crc)
1574 {
1575     static char *sig = "EFI PART";
1576     static char revision[4] = {0x00, 0x00, 0x01, 0x00};
1577     char *wpt;
1578     uint32_t crc;
1579     off_t back_lba;
1580 
1581     memset(buf, 0, 512);
1582     wpt = (char *) buf;
1583 
1584     /* >>> Make signature adjustable */
1585     memcpy(wpt, sig, 8); /* no trailing 0 */
1586     wpt += 8;
1587 
1588     memcpy(wpt, revision, 4);
1589     wpt += 4;
1590     iso_lsb_to_buf(&wpt, 92, 4, 0);
1591 
1592     /* CRC will be inserted later */
1593     wpt += 4;
1594 
1595     /* reserved */
1596     iso_lsb_to_buf(&wpt, 0, 4, 0);
1597     /* Own LBA low 32 */
1598     iso_lsb_to_buf(&wpt, 1, 4, 0);
1599     /* Own LBA high 32 */
1600     iso_lsb_to_buf(&wpt, 0, 4, 0);
1601 
1602     /* Backup header LBA is 1 hd block before backup GPT area end */
1603     back_lba = t->gpt_backup_end * 4 - 1;
1604     iso_lsb_to_buf(&wpt, (uint32_t) (back_lba & 0xffffffff), 4, 1);
1605     iso_lsb_to_buf(&wpt, (uint32_t) (back_lba >> 32), 4, 1);
1606 
1607     /* First usable LBA for partitions (4 entries per hd block) */
1608     iso_lsb_to_buf(&wpt, part_start + max_entries / 4, 4, 0);
1609     iso_lsb_to_buf(&wpt, 0, 4, 0);
1610 
1611     /* Last usable LBA for partitions is 1 hd block before first backup entry*/
1612     iso_lsb_to_buf(&wpt,
1613                    (uint32_t) ((back_lba - max_entries / 4 - 1) & 0xffffffff),
1614                    4, 1);
1615     iso_lsb_to_buf(&wpt,
1616                    (uint32_t) ((back_lba - max_entries / 4 - 1) >> 32), 4, 1);
1617 
1618     /* Disk GUID */
1619     if (!t->gpt_disk_guid_set)
1620         iso_gpt_uuid(t, t->gpt_disk_guid);
1621     t->gpt_disk_guid_set = 1;
1622     memcpy(wpt, t->gpt_disk_guid, 16);
1623     wpt += 16;
1624 
1625     /* Partition entries start */
1626     iso_lsb_to_buf(&wpt, part_start, 4, 0);
1627     iso_lsb_to_buf(&wpt, 0, 4, 0);
1628 
1629     /* Number of partition entries */
1630     iso_lsb_to_buf(&wpt, max_entries, 4, 0);
1631 
1632     /* Size of a partition entry */
1633     iso_lsb_to_buf(&wpt, 128, 4, 0);
1634 
1635     /* CRC-32 of the partition array */
1636     iso_lsb_to_buf(&wpt, p_arr_crc, 4, 0);
1637 
1638 
1639     /* <<< Only for a first test */
1640     if (wpt - (char *) buf != 92) {
1641         iso_msgs_submit(0,
1642                    "program error : write_gpt_header_block : wpt != 92",
1643                    0, "FATAL", 0);
1644         return ISO_ISOLINUX_CANT_PATCH;
1645     }
1646 
1647     /* CRC-32 of this header while head_crc is 0 */
1648     crc = iso_crc32_gpt((unsigned char *) buf, 92, 0);
1649     wpt = ((char *) buf) + 16;
1650     iso_lsb_to_buf(&wpt, crc, 4, 0);
1651 
1652     return ISO_SUCCESS;
1653 }
1654 
1655 
1656 /* Only for up to 36 characters ISO-8859-1 (or ASCII) input */
iso_ascii_utf_16le(uint8_t gap_name[72])1657 void iso_ascii_utf_16le(uint8_t gap_name[72])
1658 {
1659     int i;
1660 
1661     for (i = strlen((char *) gap_name) - 1; i >= 0; i--) {
1662         gap_name[2 * i] = gap_name[i];
1663         gap_name[2 * i + 1] = 0;
1664     }
1665 }
1666 
1667 
intvl_overlap(uint64_t start1,uint64_t end1,uint64_t start2,uint64_t end2,int second)1668 static int intvl_overlap(uint64_t start1, uint64_t end1,
1669                          uint64_t start2, uint64_t end2, int second)
1670 {
1671     if (start1 >= start2 && start1 <= end2)
1672         return 1;
1673     if (end1 >= start2 && end1 <= end2)
1674         return 1;
1675     if (!second)
1676         return intvl_overlap(start2, end2, start1, end1, 1);
1677     return 0;
1678 }
1679 
1680 
1681 /* Check APM HFS+ partitions whether they would fit in gaps.
1682    If so, add them as GPT partitions, too.
1683  */
iso_copy_apmhfs_to_gpt(Ecma119Image * t,int flag)1684 static int iso_copy_apmhfs_to_gpt(Ecma119Image *t, int flag)
1685 {
1686     int a, i, counter = 0, ret;
1687     uint64_t bfac = 4;
1688     static uint8_t hfs_plus_uuid[16] = {
1689         0x00, 0x53, 0x46, 0x48, 0x00, 0x00, 0xaa, 0x11,
1690         0xaa, 0x11, 0x00, 0x30, 0x65, 0x43, 0xec, 0xac
1691     };
1692     static uint8_t zero_uuid[16] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
1693     uint8_t gpt_name[72];
1694     static uint64_t gpt_flags = (((uint64_t) 1) << 60) | 1;
1695 
1696     if ((t->apm_req_flags & 4) && t->opts->apm_block_size / 512 > 0)
1697         bfac = t->opts->apm_block_size / 512;
1698 
1699     for (a = 0; a < t->apm_req_count; a++) {
1700         if (strcmp((char *) t->apm_req[a]->type, "Apple_HFS") != 0)
1701     continue;
1702         for (i = 0; i < t->gpt_req_count; i++)
1703             if (intvl_overlap(t->apm_req[a]->start_block * bfac,
1704                               (t->apm_req[a]->start_block +
1705                                t->apm_req[a]->block_count - 1) * bfac,
1706                               t->gpt_req[i]->start_block,
1707                               t->gpt_req[i]->start_block +
1708                               t->gpt_req[i]->block_count - 1, 0))
1709         break;
1710         if (i >= t->gpt_req_count) {
1711             memset(gpt_name, 0, 72);
1712             counter++;
1713             if (counter > 1)
1714                 sprintf((char *) gpt_name, "HFSPLUS_%d", counter);
1715             else
1716                 sprintf((char *) gpt_name, "HFSPLUS");
1717             iso_ascii_utf_16le(gpt_name);
1718             ret = iso_quick_gpt_entry(t->gpt_req, &(t->gpt_req_count),
1719                                       t->apm_req[a]->start_block * bfac,
1720                                       t->apm_req[a]->block_count * bfac,
1721                                       hfs_plus_uuid, zero_uuid,
1722                                       gpt_flags, gpt_name);
1723             if (ret < 0)
1724                 return ret;
1725         }
1726     }
1727     return 1;
1728 }
1729 
1730 
iso_write_gpt(Ecma119Image * t,uint32_t img_blocks,uint8_t * buf)1731 static int iso_write_gpt(Ecma119Image *t, uint32_t img_blocks, uint8_t *buf)
1732 {
1733     static uint8_t basic_data_uuid[16] = {
1734         0xa2, 0xa0, 0xd0, 0xeb, 0xe5, 0xb9, 0x33, 0x44,
1735         0x87, 0xc0, 0x68, 0xb6, 0xb7, 0x26, 0x99, 0xc7
1736     };
1737 
1738     uint32_t p_arr_crc = 0;
1739     uint64_t start_lba, end_lba, goal, part_end, next_end, backup_end_lba;
1740     int ret, i, gap_counter = 0, up_to;
1741     struct iso_gpt_partition_request *req;
1742     uint8_t gpt_name[72];
1743     static uint8_t zero_uuid[16] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
1744     static uint8_t *type_guid;
1745     static uint64_t gpt_flags = (((uint64_t) 1) << 60) | 1;
1746 
1747     if (t->gpt_req_count == 0)
1748         return 2;
1749     backup_end_lba = ((uint64_t) t->gpt_backup_end - t->gpt_backup_size) * 4;
1750 
1751     ret = iso_copy_apmhfs_to_gpt(t, 0);
1752     if (ret <= 0)
1753         return ret;
1754 
1755     /* Sort and fill gaps */
1756     qsort(t->gpt_req, t->gpt_req_count,
1757         sizeof(struct iso_gpt_partition_request *), cmp_partition_request);
1758     /* t->gpt_req_count will grow during the loop */
1759     up_to = t->gpt_req_count + 1;
1760     goal = 0;
1761     part_end = 0;
1762 
1763     if (t->opts->part_like_isohybrid)
1764         up_to = 0; /* No gap filling */
1765 
1766     for (i = 0; i < up_to; i++) {
1767         if (i < up_to - 1) {
1768             goal = t->gpt_req[i]->start_block;
1769         } else {
1770             goal = ((uint64_t) img_blocks) * 4;
1771             if (goal > backup_end_lba)
1772                 goal = backup_end_lba;
1773         }
1774         if (i == 0) {
1775             if (goal <= 16 * 4)
1776     continue;
1777             next_end = 16 * 4;
1778         } else {
1779             next_end = t->gpt_req[i - 1]->start_block +
1780                        t->gpt_req[i - 1]->block_count;
1781         }
1782         if (next_end > part_end)
1783             part_end = next_end;
1784         if (part_end > goal) {
1785             if (!(t->gpt_req_flags & 1)) {
1786                 iso_msg_submit(t->image->id, ISO_BOOT_GPT_OVERLAP, 0,
1787                "Program error: GPT partitions %d and %d overlap by %.f blocks",
1788                                i - 1, i, (double) (part_end - goal));
1789                 return ISO_BOOT_GPT_OVERLAP;
1790             }
1791         } else if (part_end < goal) {
1792             memset(gpt_name, 0, 72);
1793             type_guid = basic_data_uuid;
1794             if (goal == t->vol_space_size * (uint64_t) 4 &&
1795                 part_end == t->opts->partition_offset * (uint64_t) 4) {
1796                 sprintf((char *) gpt_name, "ISO9660");
1797                 if (t->opts->iso_gpt_flag & 1)
1798                     type_guid = t->opts->iso_gpt_type_guid;
1799             } else {
1800                 sprintf((char *) gpt_name, "Gap%d", gap_counter);
1801             }
1802             iso_ascii_utf_16le(gpt_name);
1803             gap_counter++;
1804             ret = iso_quick_gpt_entry(t->gpt_req, &(t->gpt_req_count),
1805                                       part_end, goal - part_end,
1806                                       type_guid, zero_uuid,
1807                                       gpt_flags, gpt_name);
1808             if (ret < 0)
1809                 return ret;
1810             /* Mark as automatically placed filler request */
1811             t->gpt_req[t->gpt_req_count - 1]->req_status |= 1;
1812         }
1813     }
1814     /* Merge list of gap partitions with list of already sorted entries */
1815     qsort(t->gpt_req, t->gpt_req_count,
1816         sizeof(struct iso_gpt_partition_request *), cmp_partition_request);
1817 
1818     if ((int) t->gpt_max_entries < t->gpt_req_count)
1819         return ISO_BOOT_TOO_MANY_GPT;
1820 
1821     /* Write the GPT entries to buf */
1822     for (i = 0; i < t->gpt_req_count; i++) {
1823         req = t->gpt_req[i];
1824         start_lba = req->start_block;
1825         end_lba = req->start_block + req->block_count;
1826         if (req->start_block == t->opts->partition_offset * ((uint64_t) 4) &&
1827             req->block_count == ((uint64_t) 4) * 0xffffffff)
1828             end_lba = t->vol_space_size * 4;
1829         if (end_lba > backup_end_lba)
1830             end_lba = backup_end_lba;
1831         end_lba = end_lba - 1;
1832         iso_write_gpt_entry(t, buf + 512 * t->gpt_part_start + 128 * i,
1833                             req->type_guid, req->partition_guid,
1834                             start_lba, end_lba, req->flags, req->name);
1835     }
1836     for (; i < (int) t->gpt_max_entries; i++)
1837         memset(buf + 512 * t->gpt_part_start + 128 * i, 0, 128);
1838 
1839     p_arr_crc = iso_crc32_gpt((unsigned char *) buf + 512 * t->gpt_part_start,
1840                               128 * t->gpt_max_entries, 0);
1841     ret = iso_write_gpt_header_block(t, img_blocks, buf + 512,
1842                                      t->gpt_max_entries,
1843                                      t->gpt_part_start, p_arr_crc);
1844     if (ret < 0)
1845         return ret;
1846     return ISO_SUCCESS;
1847 }
1848 
1849 
1850 /* Add a dummy MBR partition of type 0 with boot flag */
iso_dummy_mbr_partition(uint8_t * buf,int mode)1851 static void iso_dummy_mbr_partition(uint8_t *buf, int mode)
1852 {
1853     int i;
1854                              /* bootable , start 0/0/1, type 0x00, end 0/0/1,
1855                                 start LBA 0, block count 1 */
1856     static uint8_t dummy_entry[16] = {
1857                               0x80, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00,
1858                               0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00 };
1859 
1860     for (i = 0; i < 4; i++) {
1861         if (mbr_part_slot_is_unused(buf + 446 + 16 * i)) {
1862             memcpy(buf + 446 + 16 * i, dummy_entry, 16);
1863             return;
1864         }
1865     }
1866     /* Abundance of 0xee and 0xef partitions. No other one free. */
1867     for (i = 0; i < 4; i++) {
1868         if (buf[446 + 16 * i + 4] != 0xef) {
1869             buf[446 + 16 * i] |= 0x80;
1870             return;
1871         }
1872     }
1873     i = 3;
1874     buf[446 + 16 * i] |= 0x80;
1875 }
1876 
1877 
1878 /* @param flag
1879           bit0= t->opts->ms_block is not counted in t->total_size
1880 */
iso_write_system_area(Ecma119Image * t,uint8_t * buf,int flag)1881 int iso_write_system_area(Ecma119Image *t, uint8_t *buf, int flag)
1882 {
1883     int ret, int_img_blocks, sa_type, i, will_append = 0, do_isohybrid = 0;
1884     int first_partition = 1, last_partition = 4, apm_flag, part_type = 0;
1885     int gpt_count = 0, gpt_idx[128], apm_count = 0, no_boot_mbr = 0;
1886     int offset_flag = 0, risk_of_ee = 0;
1887     uint32_t img_blocks, gpt_blocks, mbrp1_blocks, pml_blocks;
1888     uint64_t blk;
1889     uint8_t *wpt;
1890 
1891     if ((t == NULL) || (buf == NULL)) {
1892         return ISO_NULL_POINTER;
1893     }
1894 
1895     /* set buf to 0s */
1896     memset(buf, 0, 16 * BLOCK_SIZE);
1897 
1898     sa_type = (t->system_area_options >> 2) & 0x3f;
1899 
1900     iso_tell_max_part_range(t->opts, &first_partition, &last_partition, 0);
1901     for (i = first_partition - 1; i <= last_partition - 1; i++)
1902         if (t->opts->appended_partitions[i] != NULL) {
1903             will_append = 1;
1904     break;
1905         }
1906 
1907 #ifdef Libisofs_appended_partitions_inlinE
1908     img_blocks = t->vol_space_size;
1909 #else
1910     img_blocks = t->curblock;
1911 #endif
1912 
1913     if (t->system_area_data != NULL) {
1914         /* Write more or less opaque boot image */
1915         memcpy(buf, t->system_area_data, 16 * BLOCK_SIZE);
1916 
1917     } else if (sa_type == 0 && t->catalog != NULL &&
1918                (t->catalog->bootimages[0]->isolinux_options & 0x0a) == 0x02) {
1919         /* Check for isolinux image with magic number of 3.72 and produce
1920            an MBR from our built-in template. (Deprecated since 31 Mar 2010)
1921         */
1922         if (t->bootsrc[0] == NULL)
1923             return iso_msg_submit(t->image->id, ISO_BOOT_IMAGE_NOT_VALID, 0,
1924       "Cannot refer by isohybrid MBR to data outside of ISO 9660 filesystem.");
1925         if (img_blocks < 0x80000000) {
1926             int_img_blocks= img_blocks;
1927         } else {
1928             int_img_blocks= 0x7ffffff0;
1929         }
1930         ret = make_isohybrid_mbr(t->bootsrc[0]->sections[0].block,
1931                                  &int_img_blocks, (char*)buf, 0);
1932         if (ret != 1) {
1933             /* error, it should never happen */
1934             return ISO_ASSERT_FAILURE;
1935         }
1936         return ISO_SUCCESS;
1937     }
1938 
1939     /* If APM entries were submitted to iso_register_apm_entry(), then they
1940        get sprinkled over the system area after the system area template was
1941        loaded and before any other data get inserted.
1942        Note that if APM and MBR get combined, then the first 8 bytes of the MBR
1943        template must be replaceable by:
1944           {0x45, 0x52, 0x08 0x00, 0xeb, 0x02, 0xff, 0xff}
1945 
1946        >>> ts B20526
1947        >>> This does not care for eventual image enlargements in last minute.
1948        >>> A sa_type, that does this, will have to adjust the last APM entry
1949        >>> if exactness matters.
1950     */
1951 
1952     apm_flag = 0;
1953     if (sa_type == 0 && (t->system_area_options & 3) == 2) {
1954         do_isohybrid = 1;
1955 
1956         /* >>> Coordinate with partprepend writer */
1957         /* <<< provisory trap */
1958         if (t->mbr_req_count > 0)
1959             return ISO_BOOT_MBR_OVERLAP;
1960 
1961         /* If own APM is desired, set flag bit0 to prevent writing of Block0
1962            which would interfere with the own Block0 of isohybrid.
1963         */
1964         ret = assess_isohybrid_gpt_apm(t, &gpt_count, gpt_idx, &apm_count, 0);
1965         if (ret < 0)
1966             return ret;
1967         if (apm_count > 0)
1968             apm_flag |= 1;
1969     }
1970 
1971     ret = iso_write_apm(t, img_blocks, buf, apm_flag);
1972     if (ret < 0) {
1973         iso_msg_submit(t->image->id, ret, 0,
1974                        "Cannot set up Apple Partition Map");
1975         return ret;
1976     }
1977     ret = iso_write_mbr(t, img_blocks, buf);
1978     if (ret < 0) {
1979         iso_msg_submit(t->image->id, ret, 0,
1980                        "Cannot set up MBR partition table");
1981         return ret;
1982     }
1983     if (t->mbr_req_count > 0) {
1984         if (sa_type != 0)
1985             return ISO_NON_MBR_SYS_AREA;
1986         risk_of_ee = 1;
1987     }
1988 
1989     if (t->gpt_backup_outside)
1990         gpt_blocks = t->total_size / BLOCK_SIZE +
1991                      (flag & 1) * t->opts->ms_block;
1992     else
1993         gpt_blocks = img_blocks;
1994     ret = iso_write_gpt(t, gpt_blocks, buf);
1995     if (ret < 0) {
1996         iso_msg_submit(t->image->id, ret, 0, "Cannot set up GPT");
1997         return ret;
1998     }
1999 
2000     if (sa_type == 0 && (t->system_area_options & 1)) {
2001         if (t->mbr_req_count == 0){
2002             /* Write GRUB protective msdos label, i.e. a simple partition
2003                table */
2004             if (t->gpt_req_count > 0 && ! t->opts->part_like_isohybrid) {
2005                 part_type = 0xee;
2006                 pml_blocks = gpt_blocks;
2007             } else {
2008                 part_type = 0xcd;
2009                 if (t->opts->iso_mbr_part_type >= 0 &&
2010                     t->opts->iso_mbr_part_type <= 255)
2011                     part_type= t->opts->iso_mbr_part_type;
2012                 pml_blocks = img_blocks;
2013             }
2014             ret = make_grub_msdos_label(pml_blocks, t->partition_secs_per_head,
2015                                         t->partition_heads_per_cyl,
2016                                         (uint8_t) part_type, buf, 0);
2017             if (ret != ISO_SUCCESS) /* error should never happen */
2018                return ISO_ASSERT_FAILURE;
2019             risk_of_ee = 1;
2020         } else if (t->gpt_req_count > 0) {
2021 
2022            /* >>> ??? change first partition type to 0xee */;
2023 
2024         }
2025     } else if (do_isohybrid) {
2026         /* Patch externally provided system area as isohybrid MBR */
2027         if (t->catalog == NULL || t->system_area_data == NULL) {
2028             /* isohybrid makes only sense together with ISOLINUX boot image
2029                and externally provided System Area.
2030             */
2031             return ISO_ISOLINUX_CANT_PATCH;
2032         }
2033 
2034         if (gpt_count > 0 || apm_count > 0)
2035             part_type = 0x00;
2036         else {
2037             part_type = 0x17;
2038             if (t->opts->iso_mbr_part_type >= 0 &&
2039                 t->opts->iso_mbr_part_type <= 255)
2040                 part_type= t->opts->iso_mbr_part_type;
2041         }
2042 
2043         if (t->opts->appended_as_gpt && t->have_appended_partitions) {
2044             part_type = 0xee;
2045             risk_of_ee = 1;
2046             img_blocks = gpt_blocks;
2047             no_boot_mbr = 2;
2048         }
2049 
2050         /* >>> ??? Why is partition_offset 0 here ?
2051                    It gets adjusted later by iso_offset_partition_start()
2052                    Would it harm to give the real offset here ?
2053         */;
2054 
2055         ret = make_isolinux_mbr(&img_blocks, t, 0, 1, part_type, buf,
2056                                 1 | no_boot_mbr);
2057         if (ret != 1)
2058             return ret;
2059     } else if (sa_type == 1) {
2060         ret = make_mips_volume_header(t, buf, 0);
2061         if (ret != ISO_SUCCESS)
2062             return ret;
2063     } else if (sa_type == 2) {
2064         ret = make_mipsel_boot_block(t, buf, 0);
2065         if (ret != ISO_SUCCESS)
2066             return ret;
2067     } else if (sa_type == 3) {
2068         ret = make_sun_disk_label(t, buf, 0);
2069         if (ret != ISO_SUCCESS)
2070             return ret;
2071     } else if (sa_type == 4 || sa_type == 5) {
2072         /* (By coincidence, sa_type and PALO header versions match) */
2073         ret = make_hppa_palo_sector(t, buf, sa_type, 0);
2074         if (ret != ISO_SUCCESS)
2075             return ret;
2076     } else if (sa_type == 6) {
2077         ret = make_dec_alpha_sector(t, buf, 0);
2078         if (ret != ISO_SUCCESS)
2079             return ret;
2080     } else if ((t->opts->partition_offset > 0 || will_append) &&
2081                sa_type == 0 && t->mbr_req_count == 0) {
2082         /* Write a simple partition table. */
2083         part_type = 0xcd;
2084         if (t->opts->iso_mbr_part_type >= 0 &&
2085             t->opts->iso_mbr_part_type <= 255)
2086             part_type= t->opts->iso_mbr_part_type;
2087         ret = make_grub_msdos_label(img_blocks, t->partition_secs_per_head,
2088                                     t->partition_heads_per_cyl,
2089                                     (uint8_t) part_type, buf, 2);
2090         if (ret != ISO_SUCCESS) /* error should never happen */
2091             return ISO_ASSERT_FAILURE;
2092         risk_of_ee = 1;
2093         if (t->opts->appended_as_gpt && t->have_appended_partitions) {
2094 
2095             /* >>> ??? Do this in any case of  t->gpt_req_count > ? */;
2096 
2097             /* Re-write partition entry 1 : protective MBR for GPT */
2098             part_type = 0xee;
2099             risk_of_ee = 1;
2100             ret = write_mbr_partition_entry(1, part_type,
2101                         (uint64_t) 1, ((uint64_t) gpt_blocks) * 4 - 1,
2102                         t->partition_secs_per_head, t->partition_heads_per_cyl,
2103                         buf, 2);
2104             if (ret < 0)
2105                 return ret;
2106         } else if (t->opts->partition_offset == 0) {
2107             /* Re-write partition entry 1 : start at 0, type Linux */
2108             blk = ((uint64_t) img_blocks) * 4 - t->post_iso_part_pad / 512;
2109             part_type = 0x83;
2110             if (t->opts->iso_mbr_part_type >= 0 &&
2111                 t->opts->iso_mbr_part_type <= 255)
2112                 part_type= t->opts->iso_mbr_part_type;
2113             ret = write_mbr_partition_entry(1, part_type, (uint64_t) 0, blk,
2114                         t->partition_secs_per_head, t->partition_heads_per_cyl,
2115                         buf, 2);
2116             if (ret < 0)
2117                 return ret;
2118         }
2119     }
2120 
2121     /* Check for protective MBR in mbr_req and adjust to GPT size */
2122     if (t->gpt_req_count > 0 && sa_type == 0 && t->mbr_req_count == 1) {
2123         if (t->mbr_req[0]->type_byte == 0xee && buf[450] == 0xee &&
2124             t->mbr_req[0]->desired_slot <= 1) {
2125             part_type = 0xee;
2126             risk_of_ee = 1;
2127             ret = write_mbr_partition_entry(1, part_type,
2128                         (uint64_t) 1, ((uint64_t) gpt_blocks) * 4 - 1,
2129                         t->partition_secs_per_head, t->partition_heads_per_cyl,
2130                         buf, 2);
2131             if (ret < 0)
2132                 return ret;
2133         }
2134     }
2135 
2136     if (t->opts->partition_offset > 0 && sa_type == 0 &&
2137         t->mbr_req_count == 0) {
2138         /* Adjust partition table to partition offset.
2139            With t->mbr_req_count > 0 this has already been done,
2140         */
2141 
2142 #ifndef Libisofs_appended_partitions_inlinE
2143 
2144         img_blocks = t->curblock;          /* value might have been altered */
2145 
2146 #else
2147 
2148         /* A change of t->curblock does not matter in this case */
2149 
2150 #endif
2151 
2152         if (part_type == 0xee && t->gpt_req_count > 0) {
2153             mbrp1_blocks = t->total_size / BLOCK_SIZE +
2154                            (flag & 1) * t->opts->ms_block;
2155             offset_flag |= 2 | 1; /* protective MBR, no other partitions */
2156         } else {
2157             mbrp1_blocks = img_blocks;
2158         }
2159         ret = iso_offset_partition_start(mbrp1_blocks, t->post_iso_part_pad,
2160                                          t->opts->partition_offset,
2161                                          t->partition_secs_per_head,
2162                                          t->partition_heads_per_cyl, buf,
2163                                          offset_flag);
2164         if (ret != ISO_SUCCESS) /* error should never happen */
2165             return ISO_ASSERT_FAILURE;
2166     }
2167 
2168     /* This possibly overwrites the non-mbr_req partition table entries
2169        made so far. Overwriting those from t->mbr_req is not allowed.
2170     */
2171     if (sa_type == 3 ||
2172         !(t->opts->appended_as_gpt || t->opts->appended_as_apm)) {
2173         for (i = first_partition - 1; i <= last_partition - 1; i++) {
2174             if (t->opts->appended_partitions[i] == NULL)
2175         continue;
2176             if (i < t->mbr_req_count)
2177                 return ISO_BOOT_MBR_COLLISION;
2178             if (sa_type == 3) {
2179                 ret = write_sun_partition_entry(i + 1,
2180                         t->opts->appended_partitions,
2181                         t->appended_part_start, t->appended_part_size,
2182                         ISO_SUN_CYL_SIZE,
2183                         buf, t->opts->appended_partitions[i][0] == 0);
2184             } else {
2185                 ret = write_mbr_partition_entry(i + 1,
2186                         t->opts->appended_part_types[i],
2187                         (uint64_t) t->appended_part_start[i],
2188                         (uint64_t) t->appended_part_size[i],
2189                         t->partition_secs_per_head, t->partition_heads_per_cyl,
2190                         buf, 0);
2191             }
2192             if (ret < 0)
2193                 return ret;
2194         }
2195     }
2196 
2197     if (sa_type == 0 && (t->system_area_options & 0x4000) && !do_isohybrid) {
2198         /* Patch MBR for GRUB2 */
2199 	if (t->num_bootsrc <= 0)
2200             return iso_msg_submit(t->image->id, ISO_BOOT_IMAGE_NOT_VALID, 0,
2201                           "No boot image found as jump target for GRUB2 MBR.");
2202         if (t->bootsrc[0] == NULL)
2203             return iso_msg_submit(t->image->id, ISO_BOOT_IMAGE_NOT_VALID, 0,
2204           "Cannot refer by GRUB2 MBR to data outside of ISO 9660 filesystem.");
2205         blk = t->bootsrc[0]->sections[0].block * 4 +
2206                                                 Libisofs_grub2_mbr_patch_offsT;
2207         wpt = buf + Libisofs_grub2_mbr_patch_poS;
2208         for (i = 0; i < 8; i++)
2209              wpt[i] = blk >> (i * 8);
2210     }
2211 
2212     /* Prevent partition type 0xee if no GPT emerged */
2213 
2214     /* >>> ??? check for GPT magic number at byte 512 ff. ? */;
2215 
2216     if (sa_type == 0 && ((t->system_area_options & 3) || risk_of_ee) &&
2217         (t->opts->part_like_isohybrid || t->gpt_req_count == 0) &&
2218         t->opts->iso_mbr_part_type != 0xee) {
2219         for (i = 0; i < 4; i++) {
2220             if (buf[446 + 16 * i + 4] == 0xee) {
2221                 iso_msgs_submit(0,
2222                             "Prevented partition type 0xEE in MBR without GPT",
2223                             0, "WARNING", 0);
2224                 part_type = 0xcd;
2225                 if (t->opts->iso_mbr_part_type >= 0 &&
2226                     t->opts->iso_mbr_part_type <= 255)
2227                     part_type= t->opts->iso_mbr_part_type;
2228                 buf[446 + 16 * i + 4] = (uint8_t) part_type;
2229             }
2230         }
2231     }
2232 
2233     if (sa_type == 0 && (
2234         (t->system_area_options & 3) ||
2235         (t->system_area_options & (1 << 14)) ||
2236         (((t->system_area_options >> 10) & 15) != 1 &&
2237          (t->system_area_options & (1 << 15)))
2238         )) {
2239         /* This is an MBR which shall have a bootable/active flag
2240            protective-msdos-label, isohybrid, grub2-mbr, mbr-force-bootable
2241          */
2242         for (i = 0; i < 4; i++)
2243             if (buf[446 + 16 * i] & 0x80)
2244         break;
2245         if (i >= 4) { /* no bootable/active flag set yet */
2246             for (i = 0; i < 4; i++) {
2247                 if ((!mbr_part_slot_is_unused(buf + 446 + 16 * i)) &&
2248                     buf[446 + 16 * i + 4] != 0xee &&
2249                     buf[446 + 16 * i + 4] != 0xef) {
2250                     buf[446 + 16 * i] |= 0x80;
2251             break;
2252                 }
2253             }
2254             if (i >= 4) { /* still no bootable/active flag set */
2255                 if (t->system_area_options & (1 << 15)) /* Force it */
2256                     iso_dummy_mbr_partition(buf, 0);
2257             }
2258         }
2259     }
2260 
2261     if ((((t->system_area_options >> 2) & 0x3f) == 0 &&
2262          (t->system_area_options & 3) == 1) ||
2263         t->opts->partition_offset > 0) {
2264         /* Protective MBR || partition offset
2265            ISO will not be a partition or add-on session.
2266            It can span the whole image.
2267         */
2268         t->pvd_size_is_total_size = 1;
2269     }
2270 
2271     return ISO_SUCCESS;
2272 }
2273 
2274 /* Choose *heads_per_cyl so that
2275    - *heads_per_cyl * secs_per_head * 1024 >= imgsize / 512
2276    - *heads_per_cyl * secs_per_head is divisible by 4
2277    - it is as small as possible (to reduce alignment overhead)
2278    - it is <= 255
2279    @return 1= success , 0= cannot achieve goals
2280 */
2281 static
try_sph(off_t imgsize,int secs_per_head,int * heads_per_cyl,int flag)2282 int try_sph(off_t imgsize, int secs_per_head, int *heads_per_cyl, int flag)
2283 {
2284     off_t hd_blocks, hpc;
2285 
2286     hd_blocks= imgsize / 512;
2287     hpc = hd_blocks / secs_per_head / 1024;
2288     if (hpc * secs_per_head * 1024 < hd_blocks)
2289         hpc++;
2290     if ((secs_per_head % 4) == 0) {
2291         ;
2292     } else if ((secs_per_head % 2) == 0) {
2293         hpc += (hpc % 2);
2294     } else if(hpc % 4) {
2295         hpc += 4 - (hpc % 4);
2296     }
2297     if (hpc > 255)
2298         return 0;
2299     *heads_per_cyl = hpc;
2300     return 1;
2301 }
2302 
iso_align_isohybrid(Ecma119Image * t,int flag)2303 int iso_align_isohybrid(Ecma119Image *t, int flag)
2304 {
2305     int sa_type, ret, always_align;
2306     uint32_t img_blocks;
2307     off_t imgsize, cylsize = 0, frac;
2308     char *msg = NULL;
2309 
2310 #ifdef Libisofs_part_align_writeR
2311     int fap, lap, app_part_count;
2312 #endif
2313 
2314     LIBISO_ALLOC_MEM(msg, char, 160);
2315     sa_type = (t->system_area_options >> 2) & 0x3f;
2316     if (sa_type != 0)
2317         {ret = ISO_SUCCESS; goto ex;}
2318     always_align = (t->system_area_options >> 8) & 3;
2319 
2320     if (!t->gpt_backup_outside) {
2321         /* Take into account the backup GPT */;
2322         ret = precompute_gpt(t);
2323         if (ret < 0)
2324             goto ex;
2325     }
2326 
2327 #ifdef Libisofs_part_align_writeR
2328 
2329     /* If partitions get appended then t->opts->tail_blocks and
2330        t->gpt_backup_size come after the alignment padding.
2331     */
2332     app_part_count = iso_count_appended_partitions(t, &fap, &lap);
2333     img_blocks = t->curblock;
2334     if (app_part_count == 0)
2335         img_blocks += t->opts->tail_blocks + t->gpt_backup_size;
2336 
2337 #else
2338 
2339     img_blocks = t->curblock + t->opts->tail_blocks + t->gpt_backup_size;
2340 
2341 #endif
2342 
2343     imgsize = ((off_t) img_blocks) * (off_t) 2048;
2344     if ((!(t->opts->appended_as_gpt && t->have_appended_partitions))
2345         && ((t->system_area_options & 3) || always_align)
2346         && (off_t) (t->partition_heads_per_cyl * t->partition_secs_per_head
2347                     * 1024) * (off_t) 512 < imgsize) {
2348         /* Choose small values which can represent the image size */
2349         /* First try 32 sectors per head */
2350         ret = try_sph(imgsize, 32, &(t->partition_heads_per_cyl), 0);
2351         if (ret == 1) {
2352             t->partition_secs_per_head = 32;
2353         } else {
2354             /* Did not work with 32. Try 63 */
2355             t->partition_secs_per_head = 63;
2356             ret = try_sph(imgsize, 63, &(t->partition_heads_per_cyl), 0);
2357             if (ret != 1)
2358                 t->partition_heads_per_cyl = 255;
2359         }
2360         cylsize = t->partition_heads_per_cyl * t->partition_secs_per_head *512;
2361         frac = imgsize % cylsize;
2362         sprintf(msg, "Automatically adjusted MBR geometry to %d/%d/%d",
2363                       (int) (imgsize / cylsize + !!frac),
2364                       t->partition_heads_per_cyl, t->partition_secs_per_head);
2365         iso_msgs_submit(0, msg, 0, "NOTE", 0);
2366     }
2367 
2368     if (always_align == 2)
2369         {ret = ISO_SUCCESS; goto ex;}
2370 
2371     cylsize = 0;
2372     if (t->catalog != NULL &&
2373                (t->catalog->bootimages[0]->isolinux_options & 0x0a) == 0x02) {
2374         /* Check for isolinux image with magic number of 3.72 and produce
2375            an MBR from our built-in template. (Deprecated since 31 Mar 2010)
2376         */
2377         if (img_blocks >= 0x40000000)
2378             {ret = ISO_SUCCESS; goto ex;}
2379         cylsize = 64 * 32 * 512;
2380 
2381     } else if (t->system_area_options & 2) {
2382         /* Patch externally provided system area as isohybrid MBR */
2383         if (t->catalog == NULL || t->system_area_data == NULL) {
2384             /* isohybrid makes only sense together with ISOLINUX boot image
2385                and externally provided System Area.
2386             */
2387             {ret = ISO_ISOLINUX_CANT_PATCH; goto ex;}
2388         }
2389         cylsize = t->partition_heads_per_cyl * t->partition_secs_per_head
2390                   * 512;
2391     } else if (always_align) {
2392         cylsize = t->partition_heads_per_cyl * t->partition_secs_per_head
2393                   * 512;
2394     }
2395     if (cylsize == 0)
2396         {ret = ISO_SUCCESS; goto ex;}
2397     if (((double) imgsize) / (double) cylsize > 1024.0) {
2398         iso_msgs_submit(0,
2399                   "Image size exceeds 1024 cylinders. Cannot align partition.",
2400                   0, "WARNING", 0);
2401         iso_msgs_submit(0,
2402                "There are said to be BIOSes which will not boot this via MBR.",
2403                0, "WARNING", 0);
2404         {ret = ISO_SUCCESS; goto ex;}
2405     }
2406 
2407     frac = imgsize % cylsize;
2408     imgsize += (frac > 0 ? cylsize - frac : 0);
2409 
2410     frac = imgsize - ((off_t) img_blocks) * (off_t) 2048;
2411     if (frac == 0)
2412         {ret = ISO_SUCCESS; goto ex;}
2413     t->post_iso_part_pad = 0;
2414     if (frac % 2048) {
2415         t->post_iso_part_pad = 2048 - frac % 2048;
2416         sprintf(msg,
2417  "Cylinder aligned image size is not divisible by 2048. Have to add %d bytes.",
2418                 t->post_iso_part_pad);
2419         iso_msgs_submit(0, msg, 0, "WARNING", 0);
2420     }
2421 
2422 #ifdef Libisofs_part_align_writeR
2423 
2424     t->part_align_blocks = (frac + 2047) / 2048;
2425 
2426 #else
2427 
2428     t->opts->tail_blocks += (frac + 2047) / 2048;
2429 
2430 #endif /* ! Libisofs_part_align_writeR */
2431 
2432     ret = ISO_SUCCESS;
2433 ex:;
2434     LIBISO_FREE_MEM(msg);
2435     return ret;
2436 }
2437 
2438 
iso_register_apm_entry(struct iso_apm_partition_request ** req_array,int * apm_req_count,struct iso_apm_partition_request * req,int flag)2439 int iso_register_apm_entry(struct iso_apm_partition_request **req_array,
2440                            int *apm_req_count,
2441                            struct iso_apm_partition_request *req, int flag)
2442 {
2443     struct iso_apm_partition_request *entry;
2444 
2445     if (*apm_req_count >= ISO_APM_ENTRIES_MAX)
2446         return ISO_BOOT_TOO_MANY_APM;
2447     entry = calloc(1, sizeof(struct iso_apm_partition_request));
2448     if (entry == NULL)
2449         return ISO_OUT_OF_MEM;
2450 
2451     memcpy(entry, req, sizeof(struct iso_apm_partition_request));
2452     req_array[*apm_req_count] = entry;
2453     (*apm_req_count)++;
2454     return ISO_SUCCESS;
2455 }
2456 
2457 
iso_register_mbr_entry(struct iso_mbr_partition_request ** req_array,int * mbr_req_count,struct iso_mbr_partition_request * req,int flag)2458 int iso_register_mbr_entry(struct iso_mbr_partition_request **req_array,
2459                            int *mbr_req_count,
2460                            struct iso_mbr_partition_request *req, int flag)
2461 {
2462     struct iso_mbr_partition_request *entry;
2463 
2464     if (*mbr_req_count >= ISO_MBR_ENTRIES_MAX)
2465         return ISO_BOOT_TOO_MANY_MBR;
2466     entry = calloc(1, sizeof(struct iso_mbr_partition_request));
2467     if (entry == NULL)
2468         return ISO_OUT_OF_MEM;
2469 
2470     memcpy(entry, req, sizeof(struct iso_mbr_partition_request));
2471     req_array[*mbr_req_count] = entry;
2472     (*mbr_req_count)++;
2473     return ISO_SUCCESS;
2474 }
2475 
iso_register_gpt_entry(struct iso_gpt_partition_request ** req_array,int * gpt_req_count,struct iso_gpt_partition_request * req,int flag)2476 int iso_register_gpt_entry(struct iso_gpt_partition_request **req_array,
2477                            int *gpt_req_count,
2478                            struct iso_gpt_partition_request *req, int flag)
2479 {
2480     struct iso_gpt_partition_request *entry;
2481 
2482     if (*gpt_req_count >= ISO_GPT_ENTRIES_MAX)
2483         return ISO_BOOT_TOO_MANY_GPT;
2484     entry = calloc(1, sizeof(struct iso_gpt_partition_request));
2485     if (entry == NULL)
2486         return ISO_OUT_OF_MEM;
2487 
2488     memcpy(entry, req, sizeof(struct iso_gpt_partition_request));
2489     req_array[*gpt_req_count] = entry;
2490     (*gpt_req_count)++;
2491     return ISO_SUCCESS;
2492 }
2493 
2494 #ifdef Libisofs_with_uuid_generatE
2495 
swap_uuid(void * u_pt)2496 static void swap_uuid(void *u_pt)
2497 {
2498      uint8_t tr, *u;
2499 
2500      u = (uint8_t *) u_pt;
2501      tr = u[0]; u[0] = u[3]; u[3] = tr;
2502      tr = u[1]; u[1] = u[2]; u[2] = tr;
2503      tr = u[4]; u[4] = u[5]; u[5] = tr;
2504      tr = u[6]; u[6] = u[7]; u[7] = tr;
2505 }
2506 
2507 #endif /* Libisofs_with_uuid_generatE */
2508 
2509 
2510 /* CRC-32 as of GPT and Ethernet.
2511    Parameters are deduced from a table driven implementation in isohybrid.c
2512 */
iso_crc32_gpt(unsigned char * data,int count,int flag)2513 uint32_t iso_crc32_gpt(unsigned char *data, int count, int flag)
2514 {
2515     unsigned int acc, top, result = 0;
2516     long int i;
2517 
2518     /* Chosen so that the CRC of 0 bytes of input is 0x00000000 */
2519     acc = 0x46af6449;
2520 
2521     /* Process data bits and flush numerator by 32 zero bits */
2522     for (i = 0; i < count * 8 + 32; i++) {
2523         top = acc & 0x80000000;
2524         acc = (acc << 1);
2525         if (i < count * 8)
2526             /* The least significant bits of input bytes get processed first */
2527             acc |= ((data[i / 8] >> (i % 8)) & 1);
2528         if (top)
2529             /* Division by the generating polynomial */
2530             acc ^= 0x04c11db7;
2531     }
2532     /* Mirror residue bits */
2533     for (i = 0; i < 32; i++)
2534         if (acc & (1 << i))
2535             result |= 1 << (31 - i);
2536     /* Return bit complement */
2537     return result ^ 0xffffffff;
2538 }
2539 
iso_mark_guid_version_4(uint8_t * u)2540 void iso_mark_guid_version_4(uint8_t *u)
2541 {
2542     /* Mark as UUID version 4. RFC 4122 says u[6], but UEFI prescribes
2543        bytes 6 and 7 to be swapped.
2544     */
2545     u[7] = (u[7] & 0x0f) | 0x40;
2546 
2547     /* Variant is "1 0 x" as described in RFC 4122.
2548     */
2549     u[8] = (u[8] & 0x3f) | 0x80;
2550 
2551     return;
2552 }
2553 
iso_generate_gpt_guid(uint8_t guid[16])2554 void iso_generate_gpt_guid(uint8_t guid[16])
2555 {
2556 
2557 #ifdef Libisofs_with_uuid_generatE
2558 
2559     uuid_t u;
2560 
2561     uuid_generate(u);
2562     swap_uuid((void *) u);
2563     memcpy(guid, u, 16);
2564 
2565 #else
2566 
2567     uint8_t *u;
2568     /* produced by uuid_generate() and byte-swapped to UEFI specs */
2569     static uint8_t uuid_template[16] = {
2570         0xee, 0x29, 0x9d, 0xfc, 0x65, 0xcc, 0x7c, 0x40,
2571         0x92, 0x61, 0x5b, 0xcd, 0x6f, 0xed, 0x08, 0x34
2572     };
2573     uint32_t rnd, salt;
2574     struct timeval tv;
2575     pid_t pid;
2576     int i, ret, fd;
2577 
2578     u = guid;
2579 
2580     /* First try /dev/urandom
2581     */
2582     fd = open("/dev/urandom", O_RDONLY | O_BINARY);
2583     if (fd == -1)
2584         goto fallback;
2585     ret = read(fd, u, 16);
2586     if (ret != 16) {
2587         close(fd);
2588         goto fallback;
2589     }
2590     close(fd);
2591     iso_mark_guid_version_4(u);
2592     return;
2593 
2594 
2595 fallback:;
2596     pid = getpid();
2597     salt = iso_crc32_gpt((unsigned char *) &guid, sizeof(uint8_t *), 0) ^ pid;
2598 
2599     /* This relies on the uniqueness of the template and the rareness of
2600        bootable ISO image production via libisofs. Estimated 48 bits of
2601        entropy should influence the production of a single day.
2602        So first collisions are to be expected with about 16 million images
2603        per day.
2604     */
2605     memcpy(u, uuid_template, 16);
2606     gettimeofday(&tv, NULL);
2607     for (i = 0; i < 4; i++)
2608         u[i] = (salt >> (8 * i)) & 0xff;
2609     for (i = 0; i < 2; i++)
2610         u[4 + i] = (pid >> (8 * i)) & 0xff;
2611     u[6] = ((salt >> 8) ^ (pid >> 16)) & 0xff;
2612     rnd = ((0xffffff & tv.tv_sec) << 8) |
2613           (((tv.tv_usec >> 16) ^ (salt & 0xf0)) & 0xff);
2614     for (i = 0; i < 4; i++)
2615         u[10 + i] ^= (rnd >> (8 * i)) & 0xff;
2616     u[14] ^= (tv.tv_usec >> 8) & 0xff;
2617     u[15] ^= tv.tv_usec & 0xff;
2618 
2619     iso_mark_guid_version_4(u);
2620     return;
2621 
2622 #endif /* ! Libisofs_with_uuid_generatE */
2623 
2624 }
2625 
iso_gpt_uuid(Ecma119Image * t,uint8_t uuid[16])2626 void iso_gpt_uuid(Ecma119Image *t, uint8_t uuid[16])
2627 {
2628     if (t->gpt_uuid_counter == 0)
2629         iso_generate_gpt_guid(t->gpt_uuid_base);
2630 
2631     memcpy(uuid, t->gpt_uuid_base, 16);
2632 
2633     /* Previous implementation changed only byte 9. So i expand it by applying
2634        the counter in little-endian style.
2635     */
2636     uuid[9] ^= t->gpt_uuid_counter & 0xff;
2637     uuid[10] ^= (t->gpt_uuid_counter >> 8) & 0xff;
2638     uuid[11] ^= (t->gpt_uuid_counter >> 16) & 0xff;
2639     uuid[12] ^= (t->gpt_uuid_counter >> 24) & 0xff;
2640     t->gpt_uuid_counter++;
2641     return;
2642 }
2643 
assess_appended_gpt(Ecma119Image * t,int flag)2644 int assess_appended_gpt(Ecma119Image *t, int flag)
2645 {
2646     static uint8_t basic_data_uuid[16] = {
2647         0xa2, 0xa0, 0xd0, 0xeb, 0xe5, 0xb9, 0x33, 0x44,
2648         0x87, 0xc0, 0x68, 0xb6, 0xb7, 0x26, 0x99, 0xc7
2649     };
2650     static uint8_t efi_sys_uuid[16] = {
2651        0x28, 0x73, 0x2a, 0xc1, 0x1f, 0xf8, 0xd2, 0x11,
2652        0xba, 0x4b, 0x00, 0xa0, 0xc9, 0x3e, 0xc9, 0x3b
2653     };
2654     static uint8_t hfs_plus_uuid[16] = {
2655         0x00, 0x53, 0x46, 0x48, 0x00, 0x00, 0xaa, 0x11,
2656         0xaa, 0x11, 0x00, 0x30, 0x65, 0x43, 0xec, 0xac
2657     };
2658     static uint8_t zero_uuid[16] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
2659     int i, ret, do_apm = 0, do_gpt = 0, index, already_in_gpt = 0;
2660     uint8_t gpt_name[72], *type_uuid;
2661     char apm_type[33];
2662 
2663 #ifndef Libisofs_appended_partitions_inlinE
2664     if (!t->gpt_backup_outside)
2665         return 2;
2666 #endif
2667 
2668     if ((t->apm_req_count > 0 && t->opts->part_like_isohybrid) ||
2669        (t->have_appended_partitions && t->opts->appended_as_apm))
2670        do_apm = 1;
2671     if (t->gpt_req_count > 0 ||
2672         (t->have_appended_partitions && t->opts->appended_as_gpt))
2673        do_gpt = 1;
2674 
2675     if (do_apm == 0 && do_gpt == 0)
2676             return 2;
2677 
2678     /* Represent appended partitions */
2679     for (i = 0; i <= 3; i++) {
2680         if (t->opts->appended_partitions[i] == NULL)
2681     continue;
2682         if (do_apm) {
2683             memset(gpt_name, 0, 32);
2684             sprintf((char *) gpt_name, "Appended%d", i + 1);
2685             strcpy(apm_type, "Data");
2686             if (t->opts->appended_part_gpt_flags[i] & 1) {
2687                 if (memcmp(t->opts->appended_part_type_guids[i], hfs_plus_uuid,
2688                            16) == 0)
2689                     strcpy(apm_type, "Apple_HFS");
2690             }
2691             ret = iso_quick_apm_entry(t->apm_req, &(t->apm_req_count),
2692                             t->appended_part_start[i] * t->hfsp_iso_block_fac,
2693                             t->appended_part_size[i] * t->hfsp_iso_block_fac,
2694                             (char *) gpt_name, apm_type);
2695             if (ret < 0)
2696                 return ret;
2697         }
2698         if (do_gpt)
2699             already_in_gpt = iso_find_gpt_entry(t->gpt_req, t->gpt_req_count,
2700                                     ((uint64_t) t->appended_part_start[i]) * 4,
2701                                     ((uint64_t) t->appended_part_size[i]) * 4,
2702                                     &index, 0);
2703         if (do_gpt && !already_in_gpt) {
2704             memset(gpt_name, 0, 72);
2705             sprintf((char *) gpt_name, "Appended%d", i + 1);
2706             iso_ascii_utf_16le(gpt_name);
2707             if (t->opts->appended_part_gpt_flags[i] & 1)
2708                 type_uuid = t->opts->appended_part_type_guids[i];
2709             else if (t->opts->appended_part_types[i] == 0xef)
2710                 type_uuid = efi_sys_uuid;
2711             else
2712                 type_uuid = basic_data_uuid;
2713             ret = iso_quick_gpt_entry(t->gpt_req, &(t->gpt_req_count),
2714                                   ((uint64_t) t->appended_part_start[i]) * 4,
2715                                   ((uint64_t) t->appended_part_size[i]) * 4,
2716                                   type_uuid, zero_uuid,
2717                                   (uint64_t) 0, gpt_name);
2718             if (ret < 0)
2719                 return ret;
2720         }
2721     }
2722     return ISO_SUCCESS;
2723 }
2724 
2725 /* Probably already called by tail_writer_compute_data_blocks via
2726    iso_align_isohybrid
2727 */
precompute_gpt(Ecma119Image * t)2728 static int precompute_gpt(Ecma119Image *t)
2729 {
2730     uint32_t gpt_part_start;
2731     int ret, sa_type;
2732     int gpt_count, gpt_idx[128], apm_count;
2733 
2734     /* Avoid repetition by  gpt_tail_writer_compute_data_blocks */
2735     t->gpt_is_computed = 1;
2736 
2737 
2738     /* Assess APM and GPT requests of isohybrid */
2739     sa_type = (t->system_area_options >> 2) & 0x3f;
2740     if (sa_type == 0 && (t->system_area_options & 3) == 2) {
2741 
2742         /* >>> ISOHYBRID :
2743                Shall isohybrid be combinable with other APM and GPT requesters ?
2744         */;
2745         /* <<< provisorily: Not compatible */
2746         ret = assess_isohybrid_gpt_apm(t, &gpt_count, gpt_idx, &apm_count, 0);
2747         if (ret < 0)
2748             return ret;
2749         if (t->gpt_req_count > 0 && gpt_count > 0)
2750             return ISO_BOOT_GPT_OVERLAP;
2751         if (t->apm_req_count > 0 && apm_count > 0)
2752             return ISO_BOOT_APM_OVERLAP;
2753         /* Register the GPT and APM partition entries */
2754         ret = assess_isohybrid_gpt_apm(t, &gpt_count, gpt_idx, &apm_count, 1);
2755         if (ret < 0)
2756             return ret;
2757     }
2758 
2759     /* With part_like_isohybrid:
2760        If no GPT is registered yet, and MBR, but neither CHRP nor ISOLINUX
2761        isohybrid is desired, then try to apply the isohybrid GPT and APM flags
2762        nevertheless. Avoid an overall ISO image GPT partition.
2763     */
2764     if (t->opts->part_like_isohybrid && t->gpt_req_count <= 0 &&
2765         ((t->system_area_options >> 2) & 0x3f) == 0 &&
2766         ((t->system_area_options >> 10) & 0xf) != 1 &&
2767         (!(t->system_area_options & 2))) {
2768 
2769         ret = assess_isohybrid_gpt_apm(t, &gpt_count, gpt_idx, &apm_count,
2770                                        1 | ((t->apm_req_count > 0) << 1) | 4);
2771         if (ret <= 0)
2772             return ret;
2773         t->apm_req_flags |= 2; /* Do not fill APM gaps,
2774                                   do not adjust final APM partition size */
2775     }
2776 
2777     /* Assess impact of appended partitions on GPT */
2778     ret = assess_appended_gpt(t, 0);
2779     if (ret < 0)
2780         return ret;
2781 
2782     /* Rectify APM requests early in order to learn the size of GPT.
2783        iso_write_apm() relies on this being already done here.
2784        So perform even if no GPT is required.
2785     */
2786     ret = rectify_apm(t);
2787     if (ret < 0)
2788         return ret;
2789 
2790 #ifdef NIX
2791     /* Disabled */
2792 
2793     /* <<< ts B20526 : Dummy mock-up */
2794     if (t->gpt_req_count <= 0) {
2795 
2796         /* <<< ??? Move to system_area.h and publish as macro ?
2797                    Or to make_isohybrid_mbr.c ?
2798         */
2799         static uint8_t hfs_uuid[16] = {
2800             0x00, 0x53, 0x46, 0x48, 0x00, 0x00, 0xaa, 0x11,
2801             0xaa, 0x11, 0x00, 0x30, 0x65, 0x43, 0xec, 0xac
2802         };
2803         static uint8_t basic_data_uuid[16] = {
2804             0xa2, 0xa0, 0xd0, 0xeb, 0xe5, 0xb9, 0x33, 0x44,
2805             0x87, 0xc0, 0x68, 0xb6, 0xb7, 0x26, 0x99, 0xc7
2806         };
2807 
2808         uint8_t gpt_name[72];
2809         static uint8_t zero_uuid[16] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
2810         static uint64_t gpt_flags = (((uint64_t) 1) << 60) | 1;
2811 
2812         memset(gpt_name, 0, 72);
2813         gpt_name[0] = 'T'; gpt_name[2] = '1';
2814         strcpy((char *) gpt_name, "GPT Test 1");
2815         iso_ascii_utf_16le(gpt_name);
2816         /*
2817         ret = iso_quick_gpt_entry(t->gpt_req, &(t->gpt_req_count),
2818                                   (uint64_t) (16 * 4),  (uint64_t) (20 * 4),
2819                                   hfs_uuid, zero_uuid, gpt_flags, gpt_name);
2820         / * Caution: Size 90 causes intentional partition overlap error * /
2821         ret = iso_quick_gpt_entry(t->gpt_req, &(t->gpt_req_count),
2822                                   (uint64_t) (30 * 4), (uint64_t) (90 * 4),
2823                                   hfs_uuid, zero_uuid,
2824                                   gpt_flags, gpt_name);
2825         */
2826         ret = iso_quick_gpt_entry(t->gpt_req, &(t->gpt_req_count),
2827                                   (uint64_t) (30 * 4),  (uint64_t) (40 * 4),
2828                                   hfs_uuid, zero_uuid,
2829                                   gpt_flags, gpt_name);
2830         if (ret < 0)
2831             return ret;
2832         strcpy((char *) gpt_name, "GPT Test 2");
2833         iso_ascii_utf_16le(gpt_name);
2834         ret = iso_quick_gpt_entry(t->gpt_req, &(t->gpt_req_count),
2835                                   (uint64_t) (110 * 4),  (uint64_t) (60 * 4),
2836                                   basic_data_uuid, zero_uuid,
2837                                   gpt_flags, gpt_name);
2838         if (ret < 0)
2839             return ret;
2840     }
2841 #endif /* NIX */
2842 
2843     /* Is a GPT requested ? */
2844     t->gpt_backup_end = 0;
2845     t->gpt_max_entries = 0;
2846     if (t->gpt_req_count == 0)
2847         return ISO_SUCCESS;
2848 
2849     /* Determine GPT partition start in System Area, */
2850     gpt_part_start = 0;
2851     if (t->apm_req_count > 0) {
2852         if (t->opts->apm_block_size == 0)
2853             t->opts->apm_block_size = 2048;
2854         gpt_part_start = (t->apm_req_count + 1) *
2855                          (t->opts->apm_block_size / 512);
2856     }
2857     if (gpt_part_start < 2)
2858         gpt_part_start = 2;
2859     else if (gpt_part_start >= 64)
2860         return ISO_BOOT_TOO_MANY_GPT;
2861     t->gpt_part_start = gpt_part_start;
2862 
2863     /* Necessary number of 2K blocks */
2864     t->gpt_max_entries = (64 - t->gpt_part_start) * 4;
2865     t->gpt_backup_size = ((t->gpt_max_entries / 4 + 1) * 512 + 2047) / 2048;
2866 
2867     return ISO_SUCCESS;
2868 }
2869 
2870 
gpt_tail_writer_compute_data_blocks(IsoImageWriter * writer)2871 int gpt_tail_writer_compute_data_blocks(IsoImageWriter *writer)
2872 {
2873     Ecma119Image *t;
2874     int ret;
2875 
2876     if (writer == NULL)
2877         return ISO_ASSERT_FAILURE;
2878     t = writer->target;
2879 
2880     if (! t->gpt_is_computed) {
2881         ret = precompute_gpt(t);
2882         if (ret < 0)
2883             return ret;
2884     }
2885 
2886     if (t->gpt_backup_outside) {
2887         t->total_size += t->gpt_backup_size * 2048;
2888         /* The ISO block number after the backup GPT header */
2889         t->gpt_backup_end = t->total_size / BLOCK_SIZE + t->opts->ms_block;
2890     } else {
2891         t->curblock += t->gpt_backup_size;
2892         /* The ISO block number after the backup GPT header */
2893         t->gpt_backup_end = t->curblock;
2894     }
2895 
2896     return ISO_SUCCESS;
2897 }
2898 
2899 
gpt_tail_writer_write_vol_desc(IsoImageWriter * writer)2900 int gpt_tail_writer_write_vol_desc(IsoImageWriter *writer)
2901 {
2902     return ISO_SUCCESS;
2903 }
2904 
2905 
gpt_tail_writer_write_data(IsoImageWriter * writer)2906 static int gpt_tail_writer_write_data(IsoImageWriter *writer)
2907 {
2908     Ecma119Image *t;
2909     uint8_t *head, *new_head, *entries;
2910     uint8_t *backup_buf = NULL;
2911     uint32_t crc, i;
2912     uint64_t part_start;
2913     int ret;
2914 
2915     t = writer->target;
2916     if (t->gpt_backup_end == 0 || t->gpt_max_entries == 0)
2917         return ISO_SUCCESS; /* No backup GPT area reserved by compute_data() */
2918 
2919     backup_buf = calloc(1, t->gpt_backup_size * 2048);
2920     if (backup_buf == NULL)
2921         return ISO_OUT_OF_MEM;
2922     memset(backup_buf, 0, t->gpt_backup_size * 2048);
2923 
2924     /* Check whether GPT header block came through */
2925     head = t->sys_area_as_written + 512;
2926     if (strncmp((char *) head, "EFI PART", 8) != 0) {
2927 tampered_head:;
2928         /* Send error message but do not prevent further image production */
2929         iso_msgs_submit(0,
2930                  "GPT header block was altered before writing to System Area.",
2931                  0, "FAILURE", 0);
2932         goto write_zeros;
2933     }
2934     for (i = 92; i < 512; i++)
2935         if (head[i])
2936             goto tampered_head;
2937 
2938     /* Patch memorized header block */
2939     new_head = backup_buf + t->gpt_backup_size * 2048 - 512;
2940     memcpy(new_head, head, 512);
2941     /* Exchange "Location of this header" and "Location of header backup" */
2942     memcpy(new_head + 24, head + 32, 8);
2943     memcpy(new_head + 32, head + 24, 8);
2944     /* Point to the backup partition entries */
2945     part_start = ((uint64_t) t->gpt_backup_end) * 4
2946                  - 1 - t->gpt_max_entries / 4;
2947     iso_lsb(new_head + 72, part_start & 0xffffffff, 4);
2948     iso_lsb(new_head + 76, (part_start >> 32) & 0xffffffff, 4);
2949 
2950     /* Compute new header CRC */
2951     memset(new_head + 16, 0, 4);
2952     crc = iso_crc32_gpt((unsigned char *) new_head, 92, 0);
2953     iso_lsb(new_head + 16, crc, 4);
2954 
2955     /* Copy GPT entries */
2956     entries = t->sys_area_as_written + t->gpt_part_start * 512;
2957     memcpy(new_head - t->gpt_max_entries * 128,
2958            entries, t->gpt_max_entries * 128);
2959 
2960     ret = iso_write(t, backup_buf, t->gpt_backup_size * 2048);
2961     free(backup_buf);
2962     if (ret < 0)
2963         return ret;
2964 
2965     if (!t->gpt_backup_outside) {
2966 
2967         /* >>> Why isn't t->curblock updated ? */;
2968 
2969     }
2970     return ISO_SUCCESS;
2971 
2972 write_zeros:;
2973     ret = iso_write(t, backup_buf, t->gpt_backup_size * 2048);
2974     free(backup_buf);
2975     if (ret < 0)
2976         return ret;
2977     return ISO_SUCCESS;
2978 }
2979 
2980 
gpt_tail_writer_free_data(IsoImageWriter * writer)2981 static int gpt_tail_writer_free_data(IsoImageWriter *writer)
2982 {
2983     return ISO_SUCCESS;
2984 }
2985 
2986 
gpt_tail_writer_create(Ecma119Image * target)2987 int gpt_tail_writer_create(Ecma119Image *target)
2988 {
2989     IsoImageWriter *writer;
2990 
2991     writer = calloc(1, sizeof(IsoImageWriter));
2992     if (writer == NULL) {
2993         return ISO_OUT_OF_MEM;
2994     }
2995     writer->compute_data_blocks = gpt_tail_writer_compute_data_blocks;
2996     writer->write_vol_desc = gpt_tail_writer_write_vol_desc;
2997     writer->write_data = gpt_tail_writer_write_data;
2998     writer->free_data = gpt_tail_writer_free_data;
2999     writer->data = NULL;
3000     writer->target = target;
3001 
3002     /* add this writer to image */
3003     target->writers[target->nwriters++] = writer;
3004 
3005     return ISO_SUCCESS;
3006 }
3007 
3008 
3009 /* ----------------------  Partition Prepend Writer --------------------- */
3010 
3011 
partprepend_writer_compute_data_blocks(IsoImageWriter * writer)3012 static int partprepend_writer_compute_data_blocks(IsoImageWriter *writer)
3013 {
3014     Ecma119Image *t;
3015     IsoFileSrc *src;
3016     int ret, will_have_gpt = 0, with_chrp = 0, i, part_type, keep;
3017     static uint8_t zero_uuid[16] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
3018     static uint64_t gpt_flags = (((uint64_t) 1) << 60) | 1;
3019     uint8_t gpt_name[72];
3020     uint64_t part_start;
3021     off_t start_byte, byte_count;
3022 
3023     /* <<< ??? Move to system_area.h and publish as macro ? */
3024     static uint8_t efi_sys_uuid[16] = {
3025        0x28, 0x73, 0x2a, 0xc1, 0x1f, 0xf8, 0xd2, 0x11,
3026        0xba, 0x4b, 0x00, 0xa0, 0xc9, 0x3e, 0xc9, 0x3b
3027     };
3028 
3029     if (writer == NULL)
3030         return ISO_ASSERT_FAILURE;
3031     t = writer->target;
3032 
3033     with_chrp = ((t->system_area_options & 0x3cff) == 0x0400);
3034     if (t->opts->efi_boot_partition != NULL ||
3035         t->gpt_req_count > 0) /* Might not catch all cases with GPT */
3036         will_have_gpt = 1;
3037 
3038     if (t->opts->efi_boot_partition != NULL) {
3039         keep = 0;
3040         if (t->efi_boot_part_filesrc != NULL) {
3041             /* A file in the emerging ISO image shall store its content
3042                as prepended partition.
3043                Install absolute block addresses and determine partition size.
3044             */
3045             src = t->efi_boot_part_filesrc;
3046             t->efi_boot_part_size = 0;
3047             for (i = 0; i < src->nsections; i++) {
3048                 src->sections[i].block = t->curblock + t->efi_boot_part_size;
3049                 t->efi_boot_part_size += (src->sections[i].size + 2047) / 2048;
3050             }
3051             part_start = t->curblock * 4;
3052         } else {
3053             ret = compute_partition_size(t, t->opts->efi_boot_partition,
3054                                          &(t->efi_boot_part_size),
3055                                          t->opts->efi_boot_part_flag & 1);
3056             if (ret < 0)
3057                 return ret;
3058             part_start = t->curblock * 4;
3059             if (ret == ISO_SUCCESS + 1) {
3060                 /* Interval from imported_iso in add-on session will be kept */
3061                 ret = iso_interval_reader_start_size(t,
3062                                                   t->opts->efi_boot_partition,
3063                                                   &start_byte, &byte_count, 0);
3064                 if (ret < 0)
3065                     return ret;
3066                 part_start = start_byte / 512;
3067                 keep = 1;
3068             }
3069         }
3070         memset(gpt_name, 0, 72);
3071         strcpy((char *) gpt_name, "EFI boot partition");
3072         iso_ascii_utf_16le(gpt_name);
3073         ret = iso_quick_gpt_entry(t->gpt_req, &(t->gpt_req_count), part_start,
3074                                  ((uint64_t) t->efi_boot_part_size) * 4,
3075                                  efi_sys_uuid, zero_uuid, gpt_flags, gpt_name);
3076         if (ret < 0)
3077             return ret;
3078         if (!keep)
3079             t->curblock += t->efi_boot_part_size;
3080     }
3081 
3082     if (with_chrp) {
3083         /* CHRP is not compatible with any other partition in MBR */
3084         if (t->opts->prep_partition != NULL || t->opts->fat || will_have_gpt ||
3085             t->mbr_req_count > 0)
3086             return ISO_BOOT_MBR_OVERLAP;
3087         ret = iso_quick_mbr_entry(t->mbr_req, &(t->mbr_req_count),
3088                                   (uint64_t) 0, (uint64_t) 0, 0x96, 0x80, 0);
3089         if (ret < 0)
3090             return ret;
3091         return ISO_SUCCESS;
3092     }
3093 
3094     part_start = t->curblock * 4;
3095     keep = 0;
3096     if (t->opts->prep_partition != NULL) {
3097         ret = compute_partition_size(t, t->opts->prep_partition,
3098                                      &(t->prep_part_size),
3099                                      t->opts->prep_part_flag & 1);
3100         if (ret < 0)
3101             return ret;
3102         if (ret == ISO_SUCCESS + 1) {
3103             /* Interval from imported_iso in add-on session will be kept */
3104             ret = iso_interval_reader_start_size(t,
3105                                                  t->opts->prep_partition,
3106                                                  &start_byte, &byte_count, 0);
3107             if (ret < 0)
3108                 return ret;
3109             part_start = start_byte / 512;
3110             keep = 1;
3111         }
3112     }
3113     if (t->prep_part_size > 0 || t->opts->fat || will_have_gpt) {
3114         /* Protecting MBR entry for ISO start or whole ISO */
3115         part_type = 0xcd;
3116         if (t->opts->iso_mbr_part_type >= 0 &&
3117             t->opts->iso_mbr_part_type <= 255)
3118             part_type= t->opts->iso_mbr_part_type;
3119         if (will_have_gpt)
3120             part_type = 0xee;
3121         ret = iso_quick_mbr_entry(t->mbr_req, &(t->mbr_req_count),
3122                                   will_have_gpt ? (uint64_t) 1 :
3123                                   ((uint64_t) t->opts->partition_offset) * 4,
3124                                   (uint64_t) 0, part_type, 0, 0);
3125         if (ret < 0)
3126             return ret;
3127     }
3128     if (t->prep_part_size > 0) {
3129         ret = iso_quick_mbr_entry(t->mbr_req, &(t->mbr_req_count), part_start,
3130                                   ((uint64_t) t->prep_part_size) * 4,
3131                                   0x41, 0, 0);
3132         if (ret < 0)
3133             return ret;
3134         if (!keep) {
3135             t->curblock += t->prep_part_size;
3136             part_start = t->curblock * 4;
3137         } else {
3138             part_start += t->prep_part_size * 4;
3139         }
3140     } else {
3141         part_start = t->curblock * 4;
3142     }
3143     if (t->prep_part_size > 0 || t->opts->fat) {
3144         /* FAT partition or protecting MBR entry for ISO end */
3145         ret = iso_quick_mbr_entry(t->mbr_req, &(t->mbr_req_count),
3146                                   part_start, (uint64_t) 0,
3147                                   t->opts->fat ? 0x0c : 0xcd, 0, 0);
3148         if (ret < 0)
3149             return ret;
3150     }
3151 
3152     return ISO_SUCCESS;
3153 }
3154 
3155 
partprepend_writer_write_vol_desc(IsoImageWriter * writer)3156 static int partprepend_writer_write_vol_desc(IsoImageWriter *writer)
3157 {
3158     return ISO_SUCCESS;
3159 }
3160 
3161 
partprepend_writer_write_data(IsoImageWriter * writer)3162 static int partprepend_writer_write_data(IsoImageWriter *writer)
3163 {
3164     Ecma119Image *t;
3165     int ret;
3166 
3167     t = writer->target;
3168 
3169     if (t->opts->efi_boot_partition != NULL && t->efi_boot_part_size) {
3170 
3171         if (t->efi_boot_part_filesrc != NULL) {
3172             ret = iso_filesrc_write_data(t, t->efi_boot_part_filesrc,
3173                                          NULL, NULL, 0);
3174         } else {
3175             ret = iso_write_partition_file(t, t->opts->efi_boot_partition,
3176                                        (uint32_t) 0, t->efi_boot_part_size,
3177                                        t->opts->efi_boot_part_flag & 1);
3178         }
3179         if (ret < 0)
3180             return ret;
3181     }
3182     if (t->opts->prep_partition != NULL && t->prep_part_size) {
3183         ret = iso_write_partition_file(t, t->opts->prep_partition,
3184                                        (uint32_t) 0, t->prep_part_size,
3185                                        t->opts->prep_part_flag & 1);
3186         if (ret < 0)
3187             return ret;
3188     }
3189 
3190     return ISO_SUCCESS;
3191 }
3192 
3193 
partprepend_writer_free_data(IsoImageWriter * writer)3194 static int partprepend_writer_free_data(IsoImageWriter *writer)
3195 {
3196     return ISO_SUCCESS;
3197 }
3198 
3199 
partprepend_writer_create(Ecma119Image * target)3200 int partprepend_writer_create(Ecma119Image *target)
3201 {
3202     IsoImageWriter *writer;
3203 
3204     writer = calloc(1, sizeof(IsoImageWriter));
3205     if (writer == NULL) {
3206         return ISO_OUT_OF_MEM;
3207     }
3208 
3209     writer->compute_data_blocks = partprepend_writer_compute_data_blocks;
3210     writer->write_vol_desc = partprepend_writer_write_vol_desc;
3211     writer->write_data = partprepend_writer_write_data;
3212     writer->free_data = partprepend_writer_free_data;
3213     writer->data = NULL;
3214     writer->target = target;
3215 
3216     /* add this writer to image */
3217     target->writers[target->nwriters++] = writer;
3218 
3219     return ISO_SUCCESS;
3220 }
3221 
3222 
3223 #ifdef Libisofs_appended_partitions_inlinE
3224 
3225 /* ----------------- Inline Partition Append Writer ------------------ */
3226 
3227 
partappend_writer_compute_data_blocks(IsoImageWriter * writer)3228 static int partappend_writer_compute_data_blocks(IsoImageWriter *writer)
3229 {
3230     int ret;
3231 
3232     ret = iso_compute_append_partitions(writer->target, 1);
3233     return ret;
3234 }
3235 
3236 
partappend_writer_write_vol_desc(IsoImageWriter * writer)3237 static int partappend_writer_write_vol_desc(IsoImageWriter *writer)
3238 {
3239     return ISO_SUCCESS;
3240 }
3241 
3242 
partappend_writer_write_data(IsoImageWriter * writer)3243 static int partappend_writer_write_data(IsoImageWriter *writer)
3244 {
3245     Ecma119Image *target;
3246     int res, first_partition = 1, last_partition = 0;
3247     int i;
3248 
3249     target = writer->target;
3250 
3251     /* Append partition data */
3252     iso_tell_max_part_range(target->opts,
3253                             &first_partition, &last_partition, 0);
3254 
3255     for (i = first_partition - 1; i <= last_partition - 1; i++) {
3256         if (target->opts->appended_partitions[i] == NULL)
3257     continue;
3258         if (target->opts->appended_partitions[i][0] == 0)
3259     continue;
3260         res = iso_write_partition_file(target,
3261                                        target->opts->appended_partitions[i],
3262                                        target->appended_part_prepad[i],
3263                                        target->appended_part_size[i],
3264                                      target->opts->appended_part_flags[i] & 1);
3265         if (res < 0)
3266             return res;
3267         target->curblock += target->appended_part_size[i];
3268     }
3269     return ISO_SUCCESS;
3270 }
3271 
3272 
partappend_writer_free_data(IsoImageWriter * writer)3273 static int partappend_writer_free_data(IsoImageWriter *writer)
3274 {
3275     return ISO_SUCCESS;
3276 }
3277 
3278 
partappend_writer_create(Ecma119Image * target)3279 int partappend_writer_create(Ecma119Image *target)
3280 {
3281     IsoImageWriter *writer;
3282 
3283     writer = calloc(1, sizeof(IsoImageWriter));
3284     if (writer == NULL) {
3285         return ISO_OUT_OF_MEM;
3286     }
3287 
3288     writer->compute_data_blocks = partappend_writer_compute_data_blocks;
3289     writer->write_vol_desc = partappend_writer_write_vol_desc;
3290     writer->write_data = partappend_writer_write_data;
3291     writer->free_data = partappend_writer_free_data;
3292     writer->data = NULL;
3293     writer->target = target;
3294 
3295     /* add this writer to image */
3296     target->writers[target->nwriters++] = writer;
3297 
3298     return ISO_SUCCESS;
3299 }
3300 
3301 #endif /* Libisofs_appended_partitions_inlinE */
3302 
3303 
iso_delete_gpt_apm_fillers(Ecma119Image * target,int flag)3304 void iso_delete_gpt_apm_fillers(Ecma119Image *target, int flag)
3305 {
3306     int i, widx;
3307 
3308     /* Dispose the requests with req_status bit0 */
3309     for (i = 0; i < target->gpt_req_count; i++) {
3310         if (target->gpt_req[i]->req_status & 1) {
3311             free(target->gpt_req[i]);
3312             target->gpt_req[i] = NULL;
3313         }
3314     }
3315     /* Densify the request arrays */
3316     widx = 0;
3317     for (i = 0; i < target->gpt_req_count; i++) {
3318         if (target->gpt_req[i] != NULL) {
3319             target->gpt_req[widx] = target->gpt_req[i];
3320             widx++;
3321         }
3322     }
3323     target->gpt_req_count = widx;
3324 
3325     /* And again for APM */
3326     for (i = 0; i < target->apm_req_count; i++) {
3327         if (target->apm_req[i]->req_status & 1) {
3328             free(target->apm_req[i]);
3329             target->apm_req[i] = NULL;
3330         }
3331     }
3332     widx = 0;
3333     for (i = 0; i < target->apm_req_count; i++) {
3334         if (target->apm_req[i] != NULL) {
3335             target->apm_req[widx] = target->apm_req[i];
3336             widx++;
3337         }
3338     }
3339     target->apm_req_count = widx;
3340 }
3341 
3342