1 /*
2  * Copyright (c) 2007 Vreixo Formoso
3  * Copyright (c) 2010 - 2016 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 "eltorito.h"
17 #include "fsource.h"
18 #include "filesrc.h"
19 #include "image.h"
20 #include "messages.h"
21 #include "writer.h"
22 #include "ecma119.h"
23 
24 #include <stdlib.h>
25 #include <string.h>
26 #include <stdio.h>
27 
28 /**
29  * This table should be written with the actual values at offset
30  * 8 of boot image, when used ISOLINUX boot loader
31  */
32 struct boot_info_table {
33     uint8_t bi_pvd              BP(1, 4);  /* LBA of primary volume descriptor */
34     uint8_t bi_file             BP(5, 8);  /* LBA of boot file */
35     uint8_t bi_length           BP(9, 12); /* Length of boot file */
36     uint8_t bi_csum             BP(13, 16); /* Checksum of boot file */
37     uint8_t bi_reserved         BP(17, 56); /* Reserved */
38 };
39 
40 /**
41  * Structure for each one of the four entries in a partition table on a
42  * hard disk image.
43  */
44 struct partition_desc {
45     uint8_t boot_ind;
46     uint8_t begin_chs[3];
47     uint8_t type;
48     uint8_t end_chs[3];
49     uint8_t start[4];
50     uint8_t size[4];
51 };
52 
53 /**
54  * Structures for a Master Boot Record of a hard disk image.
55  */
56 struct hard_disc_mbr {
57     uint8_t code_area[440];
58     uint8_t opt_disk_sg[4];
59     uint8_t pad[2];
60     struct partition_desc partition[4];
61     uint8_t sign1;
62     uint8_t sign2;
63 };
64 
65 /* API */
el_torito_set_boot_platform_id(ElToritoBootImage * bootimg,uint8_t id)66 int el_torito_set_boot_platform_id(ElToritoBootImage *bootimg, uint8_t id)
67 {
68     bootimg->platform_id = id;
69     return 1;
70 }
71 
72 /* API */
el_torito_get_boot_platform_id(ElToritoBootImage * bootimg)73 int el_torito_get_boot_platform_id(ElToritoBootImage *bootimg)
74 {
75     return bootimg->platform_id;
76 }
77 
78 /**
79  * Sets the load segment for the initial boot image. This is only for
80  * no emulation boot images, and is a NOP for other image types.
81  */
el_torito_set_load_seg(ElToritoBootImage * bootimg,short segment)82 void el_torito_set_load_seg(ElToritoBootImage *bootimg, short segment)
83 {
84     if (bootimg->type != 0)
85         return;
86     if (segment < 0)
87         bootimg->load_seg = 0x1000 + segment;
88     else
89         bootimg->load_seg = segment;
90 }
91 
92 /* API */
el_torito_get_load_seg(ElToritoBootImage * bootimg)93 int el_torito_get_load_seg(ElToritoBootImage *bootimg)
94 {
95    return (int) bootimg->load_seg;
96 }
97 
98 /**
99  * Sets the number of sectors (512b) to be load at load segment during
100  * the initial boot procedure. This is only for no emulation boot images,
101  * and is a NOP for other image types.
102  */
el_torito_set_load_size(ElToritoBootImage * bootimg,short sectors)103 void el_torito_set_load_size(ElToritoBootImage *bootimg, short sectors)
104 {
105     if (bootimg->type != 0)
106         return;
107     if (sectors < 0)
108         bootimg->load_size = 0x10000 + sectors;
109     else
110         bootimg->load_size = sectors;
111 }
112 
113 /* API */
el_torito_get_load_size(ElToritoBootImage * bootimg)114 int el_torito_get_load_size(ElToritoBootImage *bootimg)
115 {
116     return (int) bootimg->load_size;
117 }
118 
119 /* API */
el_torito_set_full_load(ElToritoBootImage * bootimg,int mode)120 void el_torito_set_full_load(ElToritoBootImage *bootimg, int mode)
121 {
122     if (bootimg->type != 0)
123         return;
124     bootimg->load_size_full= !!mode;
125 }
126 
127 /* API */
el_torito_get_full_load(ElToritoBootImage * bootimg)128 int el_torito_get_full_load(ElToritoBootImage *bootimg)
129 {
130     return bootimg->load_size_full;
131 }
132 
133 
134 /**
135  * Marks the specified boot image as not bootable
136  */
el_torito_set_no_bootable(ElToritoBootImage * bootimg)137 void el_torito_set_no_bootable(ElToritoBootImage *bootimg)
138 {
139     bootimg->bootable = 0;
140 }
141 
142 /* API */
el_torito_get_bootable(ElToritoBootImage * bootimg)143 int el_torito_get_bootable(ElToritoBootImage *bootimg)
144 {
145     return !!bootimg->bootable;
146 }
147 
148 /* API */
el_torito_set_id_string(ElToritoBootImage * bootimg,uint8_t id_string[28])149 int el_torito_set_id_string(ElToritoBootImage *bootimg, uint8_t id_string[28])
150 {
151     memcpy(bootimg->id_string, id_string, 28);
152     return 1;
153 }
154 
155 /* API */
el_torito_get_id_string(ElToritoBootImage * bootimg,uint8_t id_string[28])156 int el_torito_get_id_string(ElToritoBootImage *bootimg, uint8_t id_string[28])
157 {
158 
159     memcpy(id_string, bootimg->id_string, 28);
160     return 1;
161 }
162 
163 /* API */
el_torito_set_selection_crit(ElToritoBootImage * bootimg,uint8_t crit[20])164 int el_torito_set_selection_crit(ElToritoBootImage *bootimg, uint8_t crit[20])
165 {
166     memcpy(bootimg->selection_crit, crit, 20);
167     return 1;
168 }
169 
170 /* API */
el_torito_get_selection_crit(ElToritoBootImage * bootimg,uint8_t crit[20])171 int el_torito_get_selection_crit(ElToritoBootImage *bootimg, uint8_t crit[20])
172 {
173 
174     memcpy(crit, bootimg->selection_crit, 20);
175     return 1;
176 }
177 
178 /* API */
el_torito_seems_boot_info_table(ElToritoBootImage * bootimg,int flag)179 int el_torito_seems_boot_info_table(ElToritoBootImage *bootimg, int flag)
180 {
181     switch (flag & 15) {
182     case 0:
183         return bootimg->seems_boot_info_table;
184     case 1:
185         return bootimg->seems_grub2_boot_info;
186     }
187     return 0;
188 }
189 
190 /**
191  * Specifies that this image needs to be patched. This involves the writing
192  * of a 56 bytes boot information table at offset 8 of the boot image file.
193  * The original boot image file won't be modified.
194  * This is needed for isolinux boot images.
195  */
el_torito_patch_isolinux_image(ElToritoBootImage * bootimg)196 void el_torito_patch_isolinux_image(ElToritoBootImage *bootimg)
197 {
198     bootimg->isolinux_options |= 0x01;
199 }
200 
201 
202 /**
203  * Specifies options for IsoLinux boot images. This should only be used with
204  * isolinux boot images.
205  *
206  * @param options
207  *        bitmask style flag. The following values are defined:
208  *
209  *        bit 0 -> 1 to path the image, 0 to not
210  *                 Patching the image involves the writing of a 56 bytes
211  *                 boot information table at offset 8 of the boot image file.
212  *                 The original boot image file won't be modified. This is needed
213  *                 to allow isolinux images to be bootable.
214  *        bit 1 -> 1 to generate an hybrid image, 0 to not
215  *                 An hybrid image is a boot image that boots from either CD/DVD
216  *                 media or from USB sticks. For that, you should use an isolinux
217  *                 image that supports hybrid mode. Recent images support this.
218  * @return
219  *      1 if success, < 0 on error
220  * @since 0.6.12
221  */
el_torito_set_isolinux_options(ElToritoBootImage * bootimg,int options,int flag)222 int el_torito_set_isolinux_options(ElToritoBootImage *bootimg, int options, int flag)
223 {
224     bootimg->isolinux_options = (options & 0x03ff);
225     bootimg->seems_boot_info_table = !!(options & 1);
226     bootimg->seems_grub2_boot_info = !!(options & (1 << 9));
227     return ISO_SUCCESS;
228 }
229 
230 /* API */
el_torito_get_isolinux_options(ElToritoBootImage * bootimg,int flag)231 int el_torito_get_isolinux_options(ElToritoBootImage *bootimg, int flag)
232 {
233     return bootimg->isolinux_options & 0x03ff;
234 }
235 
236 /* API */
el_torito_get_boot_media_type(ElToritoBootImage * bootimg,enum eltorito_boot_media_type * media_type)237 int el_torito_get_boot_media_type(ElToritoBootImage *bootimg,
238                                   enum eltorito_boot_media_type *media_type)
239 {
240     if (bootimg) {
241         switch (bootimg->type) {
242         case 1:
243         case 2:
244         case 3:
245             *media_type = ELTORITO_FLOPPY_EMUL;
246             return 1;
247         case 4:
248             *media_type = ELTORITO_HARD_DISC_EMUL;
249             return 1;
250         case 0:
251             *media_type = ELTORITO_NO_EMUL;
252             return 1;
253         default:
254             /* should never happen */
255             return ISO_ASSERT_FAILURE;
256             break;
257         }
258     }
259     return ISO_WRONG_ARG_VALUE;
260 }
261 
262 static
iso_tree_add_boot_node(IsoDir * parent,const char * name,IsoBoot ** boot)263 int iso_tree_add_boot_node(IsoDir *parent, const char *name, IsoBoot **boot)
264 {
265     IsoBoot *node;
266     IsoNode **pos;
267     time_t now;
268     int ret;
269 
270     if (parent == NULL || name == NULL || boot == NULL) {
271         return ISO_NULL_POINTER;
272     }
273     if (boot) {
274         *boot = NULL;
275     }
276 
277     /* check if the name is valid */
278     ret = iso_node_is_valid_name(name);
279     if (ret < 0)
280         return ret;
281 
282     /* find place where to insert */
283     pos = &(parent->children);
284     while (*pos != NULL && strcmp((*pos)->name, name) < 0) {
285         pos = &((*pos)->next);
286     }
287     if (*pos != NULL && !strcmp((*pos)->name, name)) {
288         /* a node with same name already exists */
289         return ISO_NODE_NAME_NOT_UNIQUE;
290     }
291 
292     node = calloc(1, sizeof(IsoBoot));
293     if (node == NULL) {
294         return ISO_OUT_OF_MEM;
295     }
296 
297     node->node.refcount = 1;
298     node->node.type = LIBISO_BOOT;
299     node->node.name = strdup(name);
300     if (node->node.name == NULL) {
301         free(node);
302         return ISO_OUT_OF_MEM;
303     }
304     node->lba = 0;
305     node->size = 0;
306     node->content = NULL;
307 
308     /* attributes from parent */
309     node->node.mode = S_IFREG | (parent->node.mode & 0444);
310     node->node.uid = parent->node.uid;
311     node->node.gid = parent->node.gid;
312     node->node.hidden = parent->node.hidden;
313 
314     /* current time */
315     iso_nowtime(&now, 0);
316     node->node.atime = now;
317     node->node.ctime = now;
318     node->node.mtime = now;
319 
320     /* add to dir */
321     node->node.parent = parent;
322     node->node.next = *pos;
323     *pos = (IsoNode*)node;
324 
325     if (boot) {
326         *boot = node;
327     }
328     return ++parent->nchildren;
329 }
330 
331 /* Get start and size from "%d_start_%lus_size_%lud" */
332 static
iso_parse_start_size(char * text,unsigned long * part_start,unsigned long * part_size)333 void iso_parse_start_size(char *text, unsigned long *part_start,
334                           unsigned long *part_size)
335 {
336     char *cpt;
337     unsigned long start, size;
338 
339     cpt = strchr(text, '_');
340     if (cpt == NULL)
341         return;
342     if (strncmp(cpt, "_start_", 7) != 0)
343         return;
344     sscanf(cpt + 7, "%lu", &start);
345     cpt = strchr(cpt + 7, '_');
346     if (cpt == NULL)
347         return;
348     if (*(cpt - 1) != 's')
349         return;
350     if (strncmp(cpt, "_size_", 6) != 0)
351         return;
352     sscanf(cpt + 6, "%lu", &size);
353     for (cpt = cpt + 6; *cpt >= '0' && *cpt <= '9'; cpt++);
354     if (*cpt != 'd')
355         return;
356 
357     *part_start = start;
358     *part_size = size;
359 }
360 
361 static
create_image(IsoImage * image,const char * image_path,enum eltorito_boot_media_type type,struct el_torito_boot_image ** bootimg,IsoFile ** bootnode)362 int create_image(IsoImage *image, const char *image_path,
363                  enum eltorito_boot_media_type type,
364                  struct el_torito_boot_image **bootimg,
365                  IsoFile **bootnode)
366 {
367     int ret;
368     struct el_torito_boot_image *boot;
369     int boot_media_type = 0;
370     int load_sectors = 0; /* number of sector to load */
371     int part_idx = -1;
372     unsigned long part_start = 0, part_size = 0;
373     unsigned char partition_type = 0;
374     off_t size;
375     IsoNode *imgfile = NULL;
376     IsoStream *stream = NULL;
377 
378     *bootnode = NULL;
379 
380     if (strncmp(image_path, "--interval:appended_partition_", 30) == 0) {
381         /* --interval:appended_partition_N... */
382         if (type != ELTORITO_NO_EMUL) {
383 
384             /* >>> ??? lift this ban by making a temporary IsoStream from
385                        partition source, determine size,
386                        and read ELTORITO_HARD_DISC_EMUL MBR ?
387              */
388 
389             iso_msg_submit(image->id, ISO_BOOT_IMAGE_NOT_VALID, 0,
390                            "Appended partition cannot serve as El Torito boot image with FD/HD emulation");
391             return ISO_BOOT_IMAGE_NOT_VALID;
392         }
393         sscanf(image_path + 30, "%d", &part_idx);
394         if (part_idx < 1 || part_idx > ISO_MAX_PARTITIONS) {
395             iso_msg_submit(image->id, ISO_BOOT_IMAGE_NOT_VALID, 0,
396           "Appended partition index for El Torito boot image is out of range");
397             return ISO_BOOT_IMAGE_NOT_VALID;
398         }
399         iso_parse_start_size((char *) (image_path + 30),
400                               &part_start, &part_size);
401         part_idx--;
402         size = 1;
403     } else {
404         ret = iso_tree_path_to_node(image, image_path, &imgfile);
405         if (ret < 0) {
406             return ret;
407         }
408         if (ret == 0) {
409             iso_msg_submit(image->id, ISO_NODE_DOESNT_EXIST, 0,
410                        "El Torito boot image file missing in ISO image: '%s'",
411                        image_path);
412             return ISO_NODE_DOESNT_EXIST;
413         }
414 
415         if (imgfile->type != LIBISO_FILE) {
416             return ISO_BOOT_IMAGE_NOT_VALID;
417         }
418         *bootnode = (IsoFile *) imgfile;
419 
420         stream = ((IsoFile*)imgfile)->stream;
421 
422         /* we need to read the image at least two times */
423         if (!iso_stream_is_repeatable(stream)) {
424             return ISO_BOOT_IMAGE_NOT_VALID;
425         }
426 
427         size = iso_stream_get_size(stream);
428     }
429     if (size <= 0) {
430         iso_msg_submit(image->id, ISO_BOOT_IMAGE_NOT_VALID, 0,
431                        "Boot image file is empty");
432         return ISO_BOOT_IMAGE_NOT_VALID;
433     }
434 
435     switch (type) {
436     case ELTORITO_FLOPPY_EMUL:
437         switch (size) {
438         case 1200 * 1024:
439             boot_media_type = 1; /* 1.2 meg diskette */
440             break;
441         case 1440 * 1024:
442             boot_media_type = 2; /* 1.44 meg diskette */
443             break;
444         case 2880 * 1024:
445             boot_media_type = 3; /* 2.88 meg diskette */
446             break;
447         default:
448             iso_msg_submit(image->id, ISO_BOOT_IMAGE_NOT_VALID, 0,
449                           "Invalid image size %d Kb. Must be one of 1.2, 1.44"
450                           "or 2.88 Mb", iso_stream_get_size(stream) / 1024);
451             return ISO_BOOT_IMAGE_NOT_VALID;
452             break;
453         }
454         /* it seems that for floppy emulation we need to load
455          * a single sector (512b) */
456         load_sectors = 1;
457         break;
458     case ELTORITO_HARD_DISC_EMUL:
459         {
460         size_t i;
461         struct hard_disc_mbr mbr;
462         int used_partition;
463 
464         /* read the MBR on disc and get the type of the partition */
465         ret = iso_stream_open(stream);
466         if (ret < 0) {
467             iso_msg_submit(image->id, ISO_BOOT_IMAGE_NOT_VALID, ret,
468                           "Can't open image file.");
469             return ret;
470         }
471         ret = iso_stream_read(stream, &mbr, sizeof(mbr));
472         iso_stream_close(stream);
473         if (ret != sizeof(mbr)) {
474             iso_msg_submit(image->id, ISO_BOOT_IMAGE_NOT_VALID, 0,
475                           "Can't read MBR from image file.");
476             return ret < 0 ? ret : (int) ISO_FILE_READ_ERROR;
477         }
478 
479         /* check valid MBR signature */
480         if ( mbr.sign1 != 0x55 || mbr.sign2 != 0xAA ) {
481             iso_msg_submit(image->id, ISO_BOOT_IMAGE_NOT_VALID, 0,
482                           "Invalid MBR. Wrong signature.");
483             return (int) ISO_BOOT_IMAGE_NOT_VALID;
484         }
485 
486         /* ensure single partition */
487         used_partition = -1;
488         for (i = 0; i < 4; ++i) {
489             if (mbr.partition[i].type != 0) {
490                 /* it's an used partition */
491                 if (used_partition != -1) {
492                     iso_msg_submit(image->id, ISO_BOOT_IMAGE_NOT_VALID, 0,
493                                   "Invalid MBR. At least 2 partitions: %d and "
494                                   "%d, are being used\n", used_partition, i);
495                     return ISO_BOOT_IMAGE_NOT_VALID;
496                 } else
497                     used_partition = i;
498             }
499         }
500         partition_type = mbr.partition[used_partition].type;
501         }
502         boot_media_type = 4;
503 
504         /* only load the MBR */
505         load_sectors = 1;
506         break;
507     case ELTORITO_NO_EMUL:
508         boot_media_type = 0;
509         break;
510     }
511 
512     boot = calloc(1, sizeof(struct el_torito_boot_image));
513     if (boot == NULL) {
514         return ISO_OUT_OF_MEM;
515     }
516     boot->image = (IsoFile*)imgfile;
517     boot->appended_idx = part_idx;
518     boot->appended_start = part_start;
519     boot->appended_size = part_size;
520     if (imgfile != NULL)
521         iso_node_ref(imgfile); /* get our ref */
522     boot->bootable = 1;
523     boot->seems_boot_info_table = 0;
524     boot->seems_grub2_boot_info = 0;
525     boot->seems_isohybrid_capable = 0;
526     boot->isolinux_options = 0;
527     boot->type = boot_media_type;
528     boot->partition_type = partition_type;
529     boot->load_seg = 0;
530     boot->load_size = load_sectors;
531     boot->load_size_full = 0;
532     boot->platform_id = 0; /* 80x86 */
533     memset(boot->id_string, 0, sizeof(boot->id_string));
534     memset(boot->selection_crit, 0, sizeof(boot->selection_crit));
535     *bootimg = boot;
536 
537     return ISO_SUCCESS;
538 }
539 
iso_image_set_boot_image(IsoImage * image,const char * image_path,enum eltorito_boot_media_type type,const char * catalog_path,ElToritoBootImage ** boot)540 int iso_image_set_boot_image(IsoImage *image, const char *image_path,
541                              enum eltorito_boot_media_type type,
542                              const char *catalog_path,
543                              ElToritoBootImage **boot)
544 {
545     int ret, i;
546     struct el_torito_boot_catalog *catalog;
547     ElToritoBootImage *boot_image= NULL;
548     IsoBoot *cat_node= NULL;
549     IsoFile *boot_node;
550 
551     if (image == NULL || image_path == NULL || catalog_path == NULL) {
552         return ISO_NULL_POINTER;
553     }
554     if (image->bootcat != NULL) {
555         return ISO_IMAGE_ALREADY_BOOTABLE;
556     }
557 
558     /* create the node for the catalog */
559     {
560         IsoDir *parent;
561         char *catdir = NULL, *catname = NULL;
562         catdir = strdup(catalog_path);
563         if (catdir == NULL) {
564             return ISO_OUT_OF_MEM;
565         }
566 
567         /* get both the dir and the name */
568         catname = strrchr(catdir, '/');
569         if (catname == NULL)
570             catname = catdir;
571         if (catname == catdir) {
572             /* we are appending catalog to root node */
573             parent = image->root;
574         } else {
575             IsoNode *p;
576             catname[0] = '\0';
577             ret = iso_tree_path_to_node(image, catdir, &p);
578             if (ret <= 0) {
579                 iso_msg_submit(image->id, ISO_NODE_DOESNT_EXIST, 0,
580          "Cannot find directory for El Torito boot catalog in ISO image: '%s'",
581                                catdir);
582                 free(catdir);
583                 return ret < 0 ? ret : (int) ISO_NODE_DOESNT_EXIST;
584             }
585             if (p->type != LIBISO_DIR) {
586                 free(catdir);
587                 return ISO_WRONG_ARG_VALUE;
588             }
589             parent = (IsoDir*)p;
590         }
591         if (catname[0] == '/' || catname[0] == 0)
592             catname++;
593         ret = iso_tree_add_boot_node(parent, catname, &cat_node);
594         free(catdir);
595         if (ret < 0) {
596             return ret;
597         }
598     }
599 
600     /* create the boot image */
601     ret = create_image(image, image_path, type, &boot_image, &boot_node);
602     if (ret < 0) {
603         goto boot_image_cleanup;
604     }
605 
606     /* creates the catalog with the given image */
607     catalog = calloc(1, sizeof(struct el_torito_boot_catalog));
608     if (catalog == NULL) {
609         ret = ISO_OUT_OF_MEM;
610         goto boot_image_cleanup;
611     }
612     catalog->num_bootimages = 1;
613     catalog->bootimages[0] = boot_image;
614     for (i = 1; i < Libisofs_max_boot_imageS; i++)
615         catalog->bootimages[i] = NULL;
616     catalog->node = cat_node;
617     catalog->sort_weight = 1000000000;                          /* very high */
618     if (boot_node != NULL)
619         if (!(boot_node->explicit_weight || boot_node->from_old_session))
620             boot_node->sort_weight = 2;
621     iso_node_ref((IsoNode*)cat_node);
622     image->bootcat = catalog;
623 
624     if (boot) {
625         *boot = boot_image;
626     }
627 
628     return ISO_SUCCESS;
629 
630 boot_image_cleanup:;
631     if (cat_node) {
632         iso_node_take((IsoNode*)cat_node);
633         iso_node_unref((IsoNode*)cat_node);
634     }
635     if (boot_image) {
636         if (boot_image->image != NULL)
637             iso_node_unref((IsoNode*)boot_image->image);
638         free(boot_image);
639     }
640     return ret;
641 }
642 
643 /**
644  * Get the boot catalog and the El-Torito default boot image of an ISO image.
645  *
646  * This can be useful, for example, to check if a volume read from a previous
647  * session or an existing image is bootable. It can also be useful to get
648  * the image and catalog tree nodes. An application would want those, for
649  * example, to prevent the user removing it.
650  *
651  * Both nodes are owned by libisofs and should not be freed. You can get your
652  * own ref with iso_node_ref(). You can can also check if the node is already
653  * on the tree by getting its parent (note that when reading El-Torito info
654  * from a previous image, the nodes might not be on the tree even if you haven't
655  * removed them). Remember that you'll need to get a new ref
656  * (with iso_node_ref()) before inserting them again to the tree, and probably
657  * you will also need to set the name or permissions.
658  *
659  * @param image
660  *      The image from which to get the boot image.
661  * @param boot
662  *      If not NULL, it will be filled with a pointer to the boot image, if
663  *      any. That  object is owned by the IsoImage and should not be freed by
664  *      the user, nor dereferenced once the last reference to the IsoImage was
665  *      disposed via iso_image_unref().
666  * @param imgnode
667  *      When not NULL, it will be filled with the image tree node. No extra ref
668  *      is added, you can use iso_node_ref() to get one if you need it.
669  * @param catnode
670  *      When not NULL, it will be filled with the catnode tree node. No extra
671  *      ref is added, you can use iso_node_ref() to get one if you need it.
672  * @return
673  *      1 on success, 0 is the image is not bootable (i.e., it has no El-Torito
674  *      image), < 0 error.
675  */
iso_image_get_boot_image(IsoImage * image,ElToritoBootImage ** boot,IsoFile ** imgnode,IsoBoot ** catnode)676 int iso_image_get_boot_image(IsoImage *image, ElToritoBootImage **boot,
677                              IsoFile **imgnode, IsoBoot **catnode)
678 {
679     if (image == NULL) {
680         return ISO_NULL_POINTER;
681     }
682     if (image->bootcat == NULL) {
683         return 0;
684     }
685 
686     /* ok, image is bootable */
687     if (boot) {
688         *boot = image->bootcat->bootimages[0];
689     }
690     if (imgnode) {
691         *imgnode = image->bootcat->bootimages[0]->image;
692     }
693     if (catnode) {
694         *catnode = image->bootcat->node;
695     }
696     return ISO_SUCCESS;
697 }
698 
iso_image_get_bootcat(IsoImage * image,IsoBoot ** catnode,uint32_t * lba,char ** content,off_t * size)699 int iso_image_get_bootcat(IsoImage *image, IsoBoot **catnode, uint32_t *lba,
700                           char **content, off_t *size)
701 {
702     IsoBoot *bootcat;
703 
704     *catnode = NULL;
705     *lba = 0;
706     *content = NULL;
707     *size = 0;
708     bootcat = image->bootcat->node;
709     if (bootcat == NULL)
710         return 0;
711     *catnode = bootcat;
712     *lba = bootcat->lba;
713     if (bootcat->size > 0 && bootcat->content != NULL) {
714         *content = calloc(1, bootcat->size);
715         if (*content == NULL)
716             return ISO_OUT_OF_MEM;
717         memcpy(*content, bootcat->content, bootcat->size);
718     }
719     if (*content != NULL)
720         *size = bootcat->size;
721     return 1;
722 }
723 
iso_image_get_all_boot_imgs(IsoImage * image,int * num_boots,ElToritoBootImage *** boots,IsoFile *** bootnodes,int flag)724 int iso_image_get_all_boot_imgs(IsoImage *image, int *num_boots,
725                ElToritoBootImage ***boots, IsoFile ***bootnodes, int flag)
726 {
727     int i;
728     struct el_torito_boot_catalog *cat;
729 
730     if (image == NULL)
731         return ISO_NULL_POINTER;
732     if (image->bootcat == NULL)
733         return 0;
734     cat = image->bootcat;
735     *num_boots = cat->num_bootimages;
736     *boots = NULL;
737     *bootnodes = NULL;
738     if (*num_boots <= 0)
739         return 0;
740     *boots = calloc(*num_boots, sizeof(ElToritoBootImage *));
741     *bootnodes = calloc(*num_boots, sizeof(IsoFile *));
742     if(*boots == NULL || *bootnodes == NULL) {
743         if (*boots != NULL)
744             free(*boots);
745         if (*bootnodes != NULL)
746             free(*bootnodes);
747         *boots = NULL;
748         *bootnodes = NULL;
749         return ISO_OUT_OF_MEM;
750     }
751     for (i = 0; i < *num_boots; i++) {
752         (*boots)[i] = cat->bootimages[i];
753         (*bootnodes)[i] = image->bootcat->bootimages[i]->image;
754     }
755     return 1;
756 }
757 
758 /**
759  * Removes the El-Torito bootable image.
760  *
761  * The IsoBoot node that acts as placeholder for the catalog is also removed
762  * for the image tree, if there.
763  * If the image is not bootable (don't have el-torito boot image) this function
764  * just returns.
765  */
iso_image_remove_boot_image(IsoImage * image)766 void iso_image_remove_boot_image(IsoImage *image)
767 {
768     if (image == NULL || image->bootcat == NULL)
769         return;
770 
771     /*
772      * remove catalog node from its parent and dispose it
773      * (another reference is with the catalog)
774      */
775     if (iso_node_get_parent((IsoNode*) image->bootcat->node) != NULL) {
776         iso_node_take((IsoNode*) image->bootcat->node);
777         iso_node_unref((IsoNode*) image->bootcat->node);
778     }
779 
780     /* free boot catalog and image, including references to nodes */
781     el_torito_boot_catalog_free(image->bootcat);
782     image->bootcat = NULL;
783 }
784 
785 /* API */
iso_image_add_boot_image(IsoImage * image,const char * image_path,enum eltorito_boot_media_type type,int flag,ElToritoBootImage ** boot)786 int iso_image_add_boot_image(IsoImage *image, const char *image_path,
787                              enum eltorito_boot_media_type type, int flag,
788                              ElToritoBootImage **boot)
789 {
790     int ret;
791     struct el_torito_boot_catalog *catalog = image->bootcat;
792     ElToritoBootImage *boot_img;
793     IsoFile *boot_node;
794 
795     if(catalog == NULL)
796       return ISO_BOOT_NO_CATALOG;
797     if (catalog->num_bootimages >= Libisofs_max_boot_imageS)
798         return ISO_BOOT_IMAGE_OVERFLOW;
799     ret = create_image(image, image_path, type, &boot_img, &boot_node);
800     if (ret < 0)
801         return ret;
802     if (boot_node != NULL)
803         if (!(boot_node->explicit_weight || boot_node->from_old_session))
804             boot_node->sort_weight = 2;
805     catalog->bootimages[catalog->num_bootimages] = boot_img;
806     catalog->num_bootimages++;
807     if (boot != NULL)
808         *boot = boot_img;
809     return 1;
810 }
811 
812 /* API */
iso_image_set_boot_catalog_weight(IsoImage * image,int sort_weight)813 int iso_image_set_boot_catalog_weight(IsoImage *image, int sort_weight)
814 {
815     if (image->bootcat == NULL)
816         return 0;
817     image->bootcat->sort_weight = sort_weight;
818     return 1;
819 }
820 
821 /* API */
iso_image_set_boot_catalog_hidden(IsoImage * image,int hide_attrs)822 int iso_image_set_boot_catalog_hidden(IsoImage *image, int hide_attrs)
823 {
824     if (image->bootcat == NULL)
825         return 0;
826     if (image->bootcat->node == NULL)
827         return 0;
828     iso_node_set_hidden((IsoNode *) image->bootcat->node, hide_attrs);
829     return 1;
830 }
831 
832 
el_torito_boot_catalog_free(struct el_torito_boot_catalog * cat)833 void el_torito_boot_catalog_free(struct el_torito_boot_catalog *cat)
834 {
835     struct el_torito_boot_image *image;
836     int i;
837 
838     if (cat == NULL) {
839         return;
840     }
841 
842     for (i = 0; i < Libisofs_max_boot_imageS; i++) {
843         image = cat->bootimages[i];
844         if (image == NULL)
845     continue;
846         if ((IsoNode*)image->image != NULL)
847             iso_node_unref((IsoNode*)image->image);
848         free(image);
849     }
850     if ((IsoNode*)cat->node != NULL)
851         iso_node_unref((IsoNode*)cat->node);
852     free(cat);
853 }
854 
855 /**
856  * Stream that generates the contents of a El-Torito catalog.
857  */
858 struct catalog_stream
859 {
860     Ecma119Image *target;
861     uint8_t buffer[BLOCK_SIZE];
862     int offset; /* -1 if stream is not opened */
863 };
864 
865 static void
write_validation_entry(uint8_t * buf,uint8_t platform_id,uint8_t id_string[24])866 write_validation_entry(uint8_t *buf, uint8_t platform_id,
867                        uint8_t id_string[24])
868 {
869     size_t i;
870     int checksum;
871 
872     struct el_torito_validation_entry *ve =
873         (struct el_torito_validation_entry*)buf;
874     ve->header_id[0] = 1;
875     ve->platform_id[0] = platform_id;
876     memcpy(ve->id_string, id_string, sizeof(ve->id_string));
877     ve->key_byte1[0] = 0x55;
878     ve->key_byte2[0] = 0xAA;
879     /* calculate the checksum, to ensure sum of all words is 0 */
880     checksum = 0;
881     for (i = 0; i < sizeof(struct el_torito_validation_entry); i += 2) {
882         checksum -= (int16_t) ((buf[i+1] << 8) | buf[i]);
883     }
884     iso_lsb(ve->checksum, checksum, 2);
885 }
886 
887 static void
write_section_header(uint8_t * buf,Ecma119Image * t,int idx,int num_entries)888 write_section_header(uint8_t *buf, Ecma119Image *t, int idx, int num_entries)
889 {
890     char *id_string;
891 
892     struct el_torito_section_header *e =
893         (struct el_torito_section_header *) buf;
894 
895     /* 0x90 = more section headers follow , 0x91 = final section */
896     e->header_indicator[0] =
897                       0x90 + (idx == t->catalog->num_bootimages - num_entries);
898     e->platform_id[0] = t->catalog->bootimages[idx]->platform_id;
899     e->num_entries[0] = num_entries & 0xff;
900     e->num_entries[1] = (num_entries >> 8) & 0xff;;
901     id_string = (char *) e->id_string;
902     memcpy(id_string,  t->catalog->bootimages[idx]->id_string,
903            sizeof(e->id_string));
904 }
905 
906 static int
write_section_load_size(struct el_torito_boot_image * img,struct el_torito_section_entry * se,uint16_t load_size,off_t full_byte_size,int flag)907 write_section_load_size(struct el_torito_boot_image *img,
908                         struct el_torito_section_entry *se,
909                         uint16_t load_size, off_t full_byte_size, int flag)
910 {
911     uint16_t size;
912     off_t blocks;
913 
914     size= load_size;
915     if(img->type == 0 && img->load_size_full) {
916         blocks= ((full_byte_size + 2047) / 2048) * 4;
917         if (blocks > 65535) {
918             if (img->platform_id == 0xef)
919                 size= 0;
920             else
921                 size= 65535;
922         } else if(blocks <= 0) {
923             size= 1;
924         } else {
925             size= blocks;
926         }
927     }
928     iso_lsb(se->sec_count, size, 2);
929     return(1);
930 }
931 
932 /**
933  * Write one section entry.
934  * Usable for the Default Entry
935  * and for Section Entries with Selection criteria type == 0
936  */
937 static
write_section_entry(uint8_t * buf,Ecma119Image * t,int idx)938 int write_section_entry(uint8_t *buf, Ecma119Image *t, int idx)
939 {
940     struct el_torito_boot_image *img;
941     struct el_torito_section_entry *se =
942         (struct el_torito_section_entry*)buf;
943     int app_idx, mode = 0;
944 
945     img = t->catalog->bootimages[idx];
946 
947     se->boot_indicator[0] = img->bootable ? 0x88 : 0x00;
948     se->boot_media_type[0] = img->type;
949     iso_lsb(se->load_seg, img->load_seg, 2);
950     se->system_type[0] = img->partition_type;
951 
952     if (t->boot_appended_idx[idx] >= 0)
953         if (t->appended_part_size[t->boot_appended_idx[idx]] > 0)
954             mode = 2; /* appended partition */
955     if (mode == 0 && t->opts->appendable &&
956         (t->boot_intvl_start[idx] > 0 || t->boot_intvl_size[idx] > 0) &&
957          t->boot_intvl_start[idx] + (t->boot_intvl_size[idx] + 3) / 4 <=
958          t->opts->ms_block)
959         mode = 1; /* image interval */
960     if (mode == 0 && t->boot_appended_idx[idx] >= 0) {
961         iso_msg_submit(t->image->id, ISO_BOOT_IMAGE_NOT_VALID, 0,
962           "Appended partition which shall serve as boot image does not exist");
963         return ISO_BOOT_IMAGE_NOT_VALID;
964     }
965 
966     if (mode == 1) {
967         if (t->boot_intvl_start[idx] + (t->boot_intvl_size[idx] + 3) / 4 >
968             t->total_size / 2048 + t->opts->ms_block - t->eff_partition_offset
969            ) {
970             iso_msg_submit(t->image->id, ISO_BOOT_IMAGE_NOT_VALID, 0,
971      "Block interval which shall serve as boot image is outside result range");
972             return ISO_BOOT_IMAGE_NOT_VALID;
973         }
974 
975         /* >>> check for non-automatic load size */;
976 
977         if (t->boot_intvl_size[idx] > 65535) {
978             if (img->platform_id == 0xef)
979                 iso_lsb(se->sec_count, 0, 2);
980             else
981                 iso_lsb(se->sec_count, 65535, 2);
982         } else {
983             if (t->boot_intvl_size[idx] == 0) {
984                 iso_msg_submit(t->image->id, ISO_BOOT_IMAGE_NOT_VALID, 0,
985                "Block interval which shall serve as boot image has zero size");
986                 return ISO_BOOT_IMAGE_NOT_VALID;
987             }
988             iso_lsb(se->sec_count, t->boot_intvl_size[idx], 2);
989         }
990         iso_lsb(se->block, t->boot_intvl_start[idx], 4);
991     } else if (mode == 2) {
992         app_idx = t->boot_appended_idx[idx];
993 
994         /* >>> check for non-automatic load size */;
995 
996         if (t->appended_part_size[app_idx] * 4 > 65535) {
997             if (img->platform_id == 0xef)
998                 iso_lsb(se->sec_count, 0, 2);
999             else
1000                 iso_lsb(se->sec_count, 65535, 2);
1001         } else {
1002             iso_lsb(se->sec_count, t->appended_part_size[app_idx] * 4, 2);
1003         }
1004         iso_lsb(se->block, t->appended_part_start[app_idx], 4);
1005     } else {
1006         write_section_load_size(img, se, (uint16_t) img->load_size,
1007                                 (off_t) t->bootsrc[idx]->sections[0].size, 0);
1008         iso_lsb(se->block, t->bootsrc[idx]->sections[0].block, 4);
1009     }
1010 
1011     se->selec_criteria[0] = img->selection_crit[0];
1012     memcpy(se->vendor_sc, img->selection_crit + 1, 19);
1013     return ISO_SUCCESS;
1014 }
1015 
1016 static
catalog_open(IsoStream * stream)1017 int catalog_open(IsoStream *stream)
1018 {
1019     int i, j, k, num_entries, ret;
1020     struct catalog_stream *data;
1021     uint8_t *wpt;
1022     struct el_torito_boot_catalog *cat;
1023     struct el_torito_boot_image **boots;
1024 
1025     if (stream == NULL) {
1026         return ISO_NULL_POINTER;
1027     }
1028     data = stream->data;
1029     cat = data->target->catalog;
1030     boots = cat->bootimages;
1031 
1032     if (data->offset != -1) {
1033         return ISO_FILE_ALREADY_OPENED;
1034     }
1035 
1036     memset(data->buffer, 0, BLOCK_SIZE);
1037 
1038     /* fill the buffer with the catalog contents */
1039     write_validation_entry(data->buffer,
1040                            boots[0]->platform_id, boots[0]->id_string);
1041 
1042     /* write default entry = first boot image */
1043     ret = write_section_entry(data->buffer + 32, data->target, 0);
1044     if (ret < 0)
1045         return ret;
1046 
1047     /* IMPORTANT: The maximum number of boot images must fit into BLOCK_SIZE */
1048     wpt = data->buffer + 64;
1049     for (i = 1; i < cat->num_bootimages; ) {
1050         /* Look ahead and put images of same platform_id and id_string
1051            into the same section */
1052         for (j = i + 1; j < cat->num_bootimages; j++) {
1053              if (boots[i]->platform_id != boots[j]->platform_id)
1054         break;
1055              for (k = 0; k < (int) sizeof(boots[i]->id_string); k++)
1056                  if (boots[i]->id_string[k] != boots[j]->id_string[k])
1057              break;
1058              if (k < (int) sizeof(boots[i]->id_string))
1059         break;
1060         }
1061         num_entries = j - i;
1062 
1063         write_section_header(wpt, data->target, i, num_entries);
1064         wpt += 32;
1065         for (j = 0; j < num_entries; j++) {
1066             ret = write_section_entry(wpt,  data->target, i);
1067             if (ret < 0)
1068                 return ret;
1069             wpt += 32;
1070             i++;
1071         }
1072     }
1073     data->offset = 0;
1074     return ISO_SUCCESS;
1075 }
1076 
1077 static
catalog_close(IsoStream * stream)1078 int catalog_close(IsoStream *stream)
1079 {
1080     struct catalog_stream *data;
1081     if (stream == NULL) {
1082         return ISO_NULL_POINTER;
1083     }
1084     data = stream->data;
1085 
1086     if (data->offset == -1) {
1087         return ISO_FILE_NOT_OPENED;
1088     }
1089     data->offset = -1;
1090     return ISO_SUCCESS;
1091 }
1092 
1093 static
catalog_get_size(IsoStream * stream)1094 off_t catalog_get_size(IsoStream *stream)
1095 {
1096     return BLOCK_SIZE;
1097 }
1098 
1099 static
catalog_read(IsoStream * stream,void * buf,size_t count)1100 int catalog_read(IsoStream *stream, void *buf, size_t count)
1101 {
1102     size_t len;
1103     struct catalog_stream *data;
1104     if (stream == NULL || buf == NULL) {
1105         return ISO_NULL_POINTER;
1106     }
1107     if (count == 0) {
1108         return ISO_WRONG_ARG_VALUE;
1109     }
1110     data = stream->data;
1111 
1112     if (data->offset == -1) {
1113         return ISO_FILE_NOT_OPENED;
1114     }
1115 
1116     len = MIN(count, (size_t) (BLOCK_SIZE - data->offset));
1117     memcpy(buf, data->buffer + data->offset, len);
1118     return len;
1119 }
1120 
1121 static
catalog_is_repeatable(IsoStream * stream)1122 int catalog_is_repeatable(IsoStream *stream)
1123 {
1124     return 1;
1125 }
1126 
1127 /**
1128  * fs_id will be the id reserved for El-Torito
1129  * dev_id will be 0 for catalog, 1 for boot image (if needed)
1130  * ino_id 0 is supposed to be unique. At write time it will get assigned
1131  * an automatic file serial number in the ISO, if needed.
1132  */
1133 static
catalog_get_id(IsoStream * stream,unsigned int * fs_id,dev_t * dev_id,ino_t * ino_id)1134 void catalog_get_id(IsoStream *stream, unsigned int *fs_id, dev_t *dev_id,
1135                    ino_t *ino_id)
1136 {
1137     *fs_id = ISO_ELTORITO_FS_ID;
1138     *dev_id = 0;
1139     *ino_id = 0;
1140 }
1141 
1142 static
catalog_free(IsoStream * stream)1143 void catalog_free(IsoStream *stream)
1144 {
1145     free(stream->data);
1146 }
1147 
1148 IsoStreamIface catalog_stream_class = {
1149     0,
1150     "boot",
1151     catalog_open,
1152     catalog_close,
1153     catalog_get_size,
1154     catalog_read,
1155     catalog_is_repeatable,
1156     catalog_get_id,
1157     catalog_free,
1158     NULL,
1159     NULL,
1160     NULL,
1161     NULL
1162 };
1163 
1164 /**
1165  * Create an IsoStream for writing El-Torito catalog for a given target.
1166  */
1167 static
catalog_stream_new(Ecma119Image * target,IsoStream ** stream)1168 int catalog_stream_new(Ecma119Image *target, IsoStream **stream)
1169 {
1170     IsoStream *str;
1171     struct catalog_stream *data;
1172 
1173     if (target == NULL || stream == NULL || target->catalog == NULL) {
1174         return ISO_NULL_POINTER;
1175     }
1176 
1177     str = calloc(1, sizeof(IsoStream));
1178     if (str == NULL) {
1179         return ISO_OUT_OF_MEM;
1180     }
1181     data = calloc(1, sizeof(struct catalog_stream));
1182     if (data == NULL) {
1183         free(str);
1184         return ISO_OUT_OF_MEM;
1185     }
1186 
1187     /* fill data */
1188     data->target = target;
1189     data->offset = -1;
1190 
1191     str->refcount = 1;
1192     str->data = data;
1193     str->class = &catalog_stream_class;
1194 
1195     *stream = str;
1196     return ISO_SUCCESS;
1197 }
1198 
el_torito_catalog_file_src_create(Ecma119Image * target,IsoFileSrc ** src)1199 int el_torito_catalog_file_src_create(Ecma119Image *target, IsoFileSrc **src)
1200 {
1201     int ret;
1202     IsoFileSrc *file;
1203     IsoStream *stream;
1204 
1205     if (target == NULL || src == NULL || target->catalog == NULL) {
1206         return ISO_OUT_OF_MEM;
1207     }
1208 
1209     if (target->cat != NULL) {
1210         /* catalog file src already created */
1211         *src = target->cat;
1212         return ISO_SUCCESS;
1213     }
1214 
1215     file = calloc(1, sizeof(IsoFileSrc));
1216     if (file == NULL) {
1217         return ISO_OUT_OF_MEM;
1218     }
1219 
1220     ret = catalog_stream_new(target, &stream);
1221     if (ret < 0) {
1222         free(file);
1223         return ret;
1224     }
1225 
1226     /* fill fields */
1227     file->no_write = 0; /* TODO allow copy of old img catalog???? */
1228     file->checksum_index = 0;
1229     file->nsections = 1;
1230     file->sections = calloc(1, sizeof(struct iso_file_section));
1231     file->sort_weight = target->catalog->sort_weight;
1232     file->stream = stream;
1233 
1234     ret = iso_file_src_add(target, file, src);
1235     if (ret <= 0) {
1236         iso_stream_unref(stream);
1237         free(file);
1238     } else {
1239         target->cat = *src;
1240     }
1241     return ret;
1242 }
1243 
1244 /******************* EL-TORITO WRITER *******************************/
1245 
1246 /**
1247  * Insert boot info table content into buf.
1248  *
1249  * @return
1250  *      1 on success, 0 error (but continue), < 0 error
1251  */
make_boot_info_table(uint8_t * buf,uint32_t pvd_lba,uint32_t boot_lba,uint32_t imgsize)1252 int make_boot_info_table(uint8_t *buf, uint32_t pvd_lba,
1253                          uint32_t boot_lba, uint32_t imgsize)
1254 {
1255     struct boot_info_table *info;
1256     uint32_t checksum;
1257     uint32_t offset;
1258 
1259     info = (struct boot_info_table *) (buf + 8);
1260     if (imgsize < 64)
1261         return ISO_ISOLINUX_CANT_PATCH;
1262 
1263     /* compute checksum, as the the sum of all 32 bit words in boot image
1264      * from offset 64 */
1265     checksum = 0;
1266     offset = 64;
1267 
1268     while (offset <= imgsize - 4) {
1269         checksum += iso_read_lsb(buf + offset, 4);
1270         offset += 4;
1271     }
1272     if (offset != imgsize) {
1273         /*
1274          * file length not multiple of 4
1275          * empty space in isofs is padded with zero;
1276          * assume same for last dword
1277          */
1278         checksum += iso_read_lsb(buf + offset, imgsize - offset);
1279     }
1280 
1281     /*memset(info, 0, sizeof(struct boot_info_table));*/
1282     iso_lsb(info->bi_pvd, pvd_lba, 4);
1283     iso_lsb(info->bi_file, boot_lba, 4);
1284     iso_lsb(info->bi_length, imgsize, 4);
1285     iso_lsb(info->bi_csum, checksum, 4);
1286     memset(buf + 24, 0, 40);
1287     return ISO_SUCCESS;
1288 }
1289 
1290 /**
1291  * Patch an El Torito boot image by a boot info table.
1292  *
1293  * @return
1294  *      1 on success, 0 error (but continue), < 0 error
1295  */
1296 static
patch_boot_info_table(uint8_t * buf,Ecma119Image * t,size_t imgsize,int idx)1297 int patch_boot_info_table(uint8_t *buf, Ecma119Image *t,
1298                                size_t imgsize, int idx)
1299 {
1300     int ret;
1301 
1302     if (imgsize < 64) {
1303         return iso_msg_submit(t->image->id, ISO_ISOLINUX_CANT_PATCH, 0,
1304             "Isolinux image too small. We won't patch it.");
1305     }
1306     if (t->bootsrc[idx] == NULL)
1307         return iso_msg_submit(t->image->id, ISO_ISOLINUX_CANT_PATCH, 0,
1308             "Cannot apply ISOLINUX patching outside of ISO 9660 filesystem.");
1309     ret = make_boot_info_table(buf, t->opts->ms_block + (uint32_t) 16,
1310                                t->bootsrc[idx]->sections[0].block,
1311                                (uint32_t) imgsize);
1312     return ret;
1313 }
1314 
1315 
1316 /**
1317  * Patch a GRUB2 El Torito boot image.
1318  */
1319 static
patch_grub2_boot_image(uint8_t * buf,Ecma119Image * t,size_t imgsize,int idx,size_t pos,int offst)1320 int patch_grub2_boot_image(uint8_t *buf, Ecma119Image *t,
1321                            size_t imgsize, int idx,
1322                            size_t pos, int offst)
1323 {
1324     uint64_t blk;
1325 
1326     if (imgsize < pos + 8)
1327         return iso_msg_submit(t->image->id, ISO_ISOLINUX_CANT_PATCH, 0,
1328                      "Boot image too small for GRUB2. Will not patch it.");
1329     if (t->bootsrc[idx] == NULL)
1330         return iso_msg_submit(t->image->id, ISO_ISOLINUX_CANT_PATCH, 0,
1331             "Cannot apply GRUB2 patching outside of ISO 9660 filesystem.");
1332     blk = ((uint64_t) t->bootsrc[idx]->sections[0].block) * 4 + offst;
1333     iso_lsb((buf + pos), blk & 0xffffffff, 4);
1334     iso_lsb((buf + pos + 4), blk >> 32, 4);
1335     return ISO_SUCCESS;
1336 }
1337 
1338 
1339 /* Patch the boot images if indicated */
iso_patch_eltoritos(Ecma119Image * t)1340 int iso_patch_eltoritos(Ecma119Image *t)
1341 {
1342     int ret, idx;
1343     size_t size;
1344     uint8_t *buf;
1345     IsoStream *new = NULL;
1346     IsoStream *original = NULL;
1347 
1348     if (t->catalog == NULL)
1349         return ISO_SUCCESS;
1350 
1351     for (idx = 0; idx < t->catalog->num_bootimages; idx++) {
1352         if (!(t->catalog->bootimages[idx]->isolinux_options & 0x201))
1353     continue;
1354         if (t->bootsrc[idx] == NULL)
1355             return iso_msg_submit(t->image->id, ISO_ISOLINUX_CANT_PATCH, 0,
1356             "Cannot apply boot image patching outside of ISO 9660 filesystem");
1357 
1358         original = t->bootsrc[idx]->stream;
1359         size = (size_t) iso_stream_get_size(original);
1360         if (size > Libisofs_elto_max_patchablE)
1361             return ISO_PATCH_OVERSIZED_BOOT;
1362         if (iso_stream_get_input_stream(original, 0) != NULL)
1363             return ISO_PATCH_FILTERED_BOOT;
1364         buf = calloc(1, size);
1365         if (buf == NULL) {
1366             return ISO_OUT_OF_MEM;
1367         }
1368         ret = iso_stream_open(original);
1369         if (ret < 0) {
1370             free(buf);
1371             return ret;
1372         }
1373         ret = iso_stream_read(original, buf, size);
1374         iso_stream_close(original);
1375         if (ret != (int) size) {
1376             if (ret >= 0)
1377                iso_msg_submit(t->image->id, ISO_FILE_READ_ERROR, 0,
1378         "Cannot read all bytes from El Torito boot image for boot info table");
1379             return (ret < 0) ? ret : (int) ISO_FILE_READ_ERROR;
1380         }
1381 
1382         /* ok, patch the read buffer */
1383         if (t->catalog->bootimages[idx]->isolinux_options & 0x200) {
1384             /* GRUB2 boot provisions */
1385             ret = patch_grub2_boot_image(buf, t, size, idx,
1386                                          Libisofs_grub2_elto_patch_poS,
1387                                          Libisofs_grub2_elto_patch_offsT);
1388             if (ret < 0)
1389                 return ret;
1390 	}
1391         /* Must be done as last patching */
1392         if (t->catalog->bootimages[idx]->isolinux_options & 0x01) {
1393             /* Boot Info Table */
1394             ret = patch_boot_info_table(buf, t, size, idx);
1395             if (ret < 0)
1396                 return ret;
1397         }
1398 
1399         /* replace the original stream with a memory stream that reads from
1400          * the patched buffer */
1401         ret = iso_memory_stream_new(buf, size, &new);
1402         if (ret < 0) {
1403             return ret;
1404         }
1405         t->bootsrc[idx]->stream = new;
1406         iso_stream_unref(original);
1407     }
1408     return ISO_SUCCESS;
1409 }
1410 
1411 static
eltorito_writer_compute_data_blocks(IsoImageWriter * writer)1412 int eltorito_writer_compute_data_blocks(IsoImageWriter *writer)
1413 {
1414     /*
1415      * We have nothing to write.
1416      */
1417     return ISO_SUCCESS;
1418 }
1419 
1420 
1421 /**
1422  * Write the Boot Record Volume Descriptor (ECMA-119, 8.2)
1423  */
1424 static
eltorito_writer_write_vol_desc(IsoImageWriter * writer)1425 int eltorito_writer_write_vol_desc(IsoImageWriter *writer)
1426 {
1427     Ecma119Image *t;
1428     struct ecma119_boot_rec_vol_desc vol;
1429 
1430     if (writer == NULL) {
1431         return ISO_NULL_POINTER;
1432     }
1433 
1434     t = writer->target;
1435     iso_msg_debug(t->image->id, "Write El-Torito boot record");
1436 
1437     memset(&vol, 0, sizeof(struct ecma119_boot_rec_vol_desc));
1438     vol.vol_desc_type[0] = 0;
1439     memcpy(vol.std_identifier, "CD001", 5);
1440     vol.vol_desc_version[0] = 1;
1441     memcpy(vol.boot_sys_id, "EL TORITO SPECIFICATION", 23);
1442     iso_lsb(vol.boot_catalog,
1443             t->cat->sections[0].block - t->eff_partition_offset, 4);
1444     return iso_write(t, &vol, sizeof(struct ecma119_boot_rec_vol_desc));
1445 }
1446 
1447 static
eltorito_writer_write_data(IsoImageWriter * writer)1448 int eltorito_writer_write_data(IsoImageWriter *writer)
1449 {
1450     /* nothing to do, the files are written by the file writer */
1451     return ISO_SUCCESS;
1452 }
1453 
1454 static
eltorito_writer_free_data(IsoImageWriter * writer)1455 int eltorito_writer_free_data(IsoImageWriter *writer)
1456 {
1457     /* nothing to do */
1458     return ISO_SUCCESS;
1459 }
1460 
eltorito_writer_create(Ecma119Image * target)1461 int eltorito_writer_create(Ecma119Image *target)
1462 {
1463     int ret, idx, outsource_efi = 0;
1464     IsoImageWriter *writer;
1465     IsoFile *bootimg = NULL;
1466     IsoFileSrc *src = NULL;
1467 
1468     writer = calloc(1, sizeof(IsoImageWriter));
1469     if (writer == NULL) {
1470         return ISO_OUT_OF_MEM;
1471     }
1472 
1473     writer->compute_data_blocks = eltorito_writer_compute_data_blocks;
1474     writer->write_vol_desc = eltorito_writer_write_vol_desc;
1475     writer->write_data = eltorito_writer_write_data;
1476     writer->free_data = eltorito_writer_free_data;
1477     writer->data = NULL;
1478     writer->target = target;
1479 
1480     /* add this writer to image */
1481     target->writers[target->nwriters++] = writer;
1482 
1483     /*
1484      * get catalog and image file sources.
1485      * Note that the catalog may be already added, when creating the low
1486      * level ECMA-119 tree.
1487      */
1488     if (target->cat == NULL) {
1489         ret = el_torito_catalog_file_src_create(target, &src);
1490         if (ret < 0) {
1491             return ret;
1492         }
1493     }
1494 
1495     if (target->opts->efi_boot_partition != NULL)
1496         if (strcmp(target->opts->efi_boot_partition, "--efi-boot-image") == 0)
1497             outsource_efi = 1;
1498     for (idx = 0; idx < target->catalog->num_bootimages; idx++) {
1499         target->bootsrc[idx] = NULL;
1500         if (target->catalog->bootimages[idx]->appended_idx >= 0) {
1501             /* Use an appended partition as boot image rather than IsoFile */
1502             target->boot_appended_idx[idx] =
1503                                 target->catalog->bootimages[idx]->appended_idx;
1504             target->boot_intvl_start[idx] =
1505                               target->catalog->bootimages[idx]->appended_start;
1506             target->boot_intvl_size[idx] =
1507                                target->catalog->bootimages[idx]->appended_size;
1508     continue;
1509         }
1510 
1511         bootimg = target->catalog->bootimages[idx]->image;
1512         ret = iso_file_src_create(target, bootimg, &src);
1513         if (ret < 0) {
1514             return ret;
1515         }
1516         target->bootsrc[idx] = src;
1517 
1518         /* For patching an image, it needs to be copied always */
1519         if (target->catalog->bootimages[idx]->isolinux_options & 0x01) {
1520             src->no_write = 0;
1521         }
1522 
1523         /* If desired: Recognize first EFI boot image that will be newly
1524            written, and mark it as claimed for being a partition.
1525         */
1526         if (outsource_efi &&
1527             target->catalog->bootimages[idx]->platform_id == 0xef &&
1528             src->no_write == 0) {
1529            target->efi_boot_part_filesrc = src;
1530            src->sections[0].block = 0xfffffffe;
1531            ((IsoNode *) bootimg)->hidden |=
1532                                    LIBISO_HIDE_ON_HFSPLUS | LIBISO_HIDE_ON_FAT;
1533            outsource_efi = 0;
1534         }
1535     }
1536 
1537     /* we need the bootable volume descriptor */
1538     target->curblock++;
1539 
1540     if (outsource_efi) {
1541         /* Disable EFI Boot partition and complain */
1542         free(target->opts->efi_boot_partition);
1543         target->opts->efi_boot_partition = NULL;
1544         iso_msg_submit(target->image->id, ISO_BOOT_NO_EFI_ELTO, 0,
1545 "No newly added El Torito EFI boot image found for exposure as GPT partition");
1546         return ISO_BOOT_NO_EFI_ELTO;
1547     }
1548 
1549     return ISO_SUCCESS;
1550 }
1551 
1552