1 /*
2  * Copyright (c) 2007 Vreixo Formoso
3  * Copyright (c) 2009 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 /*
12  * This file contains functions related to the reading of SUSP,
13  * Rock Ridge and AAIP extensions on an ECMA-119 image.
14  */
15 
16 #ifdef HAVE_CONFIG_H
17 #include "../config.h"
18 #endif
19 
20 #include "libisofs.h"
21 #include "ecma119.h"
22 #include "util.h"
23 #include "rockridge.h"
24 #include "messages.h"
25 
26 #include <sys/stat.h>
27 #include <stdlib.h>
28 #include <string.h>
29 
30 struct susp_iterator
31 {
32     uint8_t* base;
33     int pos;
34     int size;
35     IsoDataSource *src;
36     int msgid;
37 
38     /* Number of blocks in the ISO 9660 filesystem */
39     uint32_t fs_blocks;
40 
41     /* block and offset for next continuation area */
42     uint32_t ce_block;
43     uint32_t ce_off;
44 
45     /** Length of the next continuation area, 0 if no more CA are specified */
46     uint32_t ce_len;
47 
48     uint8_t *buffer; /*< If there are continuation areas */
49 };
50 
51 SuspIterator*
susp_iter_new(IsoDataSource * src,struct ecma119_dir_record * record,uint32_t fs_blocks,uint8_t len_skp,int msgid)52 susp_iter_new(IsoDataSource *src, struct ecma119_dir_record *record,
53               uint32_t fs_blocks, uint8_t len_skp, int msgid)
54 {
55     int pad = (record->len_fi[0] + 1) % 2;
56     struct susp_iterator *iter = malloc(sizeof(struct susp_iterator));
57     if (iter == NULL) {
58         return NULL;
59     }
60 
61     iter->base = record->file_id + record->len_fi[0] + pad;
62     iter->pos = len_skp; /* 0 in most cases */
63     iter->size = record->len_dr[0] - record->len_fi[0] - 33 - pad;
64     iter->src = src;
65     iter->msgid = msgid;
66     iter->fs_blocks = fs_blocks;
67 
68     iter->ce_len = 0;
69     iter->buffer = NULL;
70 
71     return iter;
72 }
73 
74 /* More than 1 MiB in a single file's CE area is suspicious */
75 #define ISO_SUSP_MAX_CE_BYTES (1024 * 1024)
76 
77 
78 /* @param flag bit0 = First call on root:
79                       Not yet clear whether this is SUSP at all
80 */
susp_iter_next(SuspIterator * iter,struct susp_sys_user_entry ** sue,int flag)81 int susp_iter_next(SuspIterator *iter, struct susp_sys_user_entry **sue,
82                    int flag)
83 {
84     struct susp_sys_user_entry *entry;
85 
86     entry = (struct susp_sys_user_entry*)(iter->base + iter->pos);
87 
88     if (flag & 1) {
89         /* Yet unclear whether it is SUSP at all */
90         if (iter->size < 7)
91             return 0;
92         if (!SUSP_SIG(entry, 'S', 'P'))
93             return 0;
94         if (entry->len_sue[0] < 7)
95             return 0;
96         /* Looks like SUSP enough to pass the further processing here. */
97     }
98     if ( (iter->pos + 4 > iter->size) || (SUSP_SIG(entry, 'S', 'T'))) {
99 
100         /*
101          * End of the System Use Area or Continuation Area.
102          * Note that ST is not needed when the space left is less than 4.
103          * (IEEE 1281, SUSP. section 4)
104          */
105         if (iter->ce_len) {
106             uint32_t block, nblocks, skipped_blocks, skipped_bytes;
107 
108             /* A CE was found, there is another continuation area */
109             skipped_blocks = iter->ce_off / BLOCK_SIZE;
110             skipped_bytes = skipped_blocks * BLOCK_SIZE;
111             nblocks = DIV_UP(iter->ce_off - skipped_bytes + iter->ce_len,
112                              BLOCK_SIZE);
113             if (nblocks <= 0 || iter->ce_len > ISO_SUSP_MAX_CE_BYTES)
114                 return ISO_SUSP_WRONG_CE_SIZE;
115             if (((uint64_t) iter->ce_block) + skipped_blocks + nblocks >
116                 (uint64_t) iter->fs_blocks)
117                 return ISO_SUSP_WRONG_CE_SIZE;
118             iter->buffer = realloc(iter->buffer, nblocks * BLOCK_SIZE);
119 
120             /* Read blocks needed to cache the given CE area range */
121             for (block = 0; block < nblocks; ++block) {
122                 int ret;
123                 ret = iter->src->read_block(iter->src,
124                                        iter->ce_block + skipped_blocks + block,
125                                        iter->buffer + block * BLOCK_SIZE);
126                 if (ret < 0) {
127                     return ret;
128                 }
129             }
130             iter->base = iter->buffer + (iter->ce_off - skipped_bytes);
131             iter->pos = 0;
132             iter->size = iter->ce_len;
133             iter->ce_len = 0;
134             entry = (struct susp_sys_user_entry*)iter->base;
135         } else {
136             return 0;
137         }
138     }
139 
140     if (entry->len_sue[0] == 0) {
141         /* a wrong image with this lead us to a infinity loop */
142         iso_msg_submit(iter->msgid, ISO_WRONG_RR, 0,
143                       "Damaged RR/SUSP information.");
144         return ISO_WRONG_RR;
145     }
146 
147     iter->pos += entry->len_sue[0];
148 
149     if (SUSP_SIG(entry, 'C', 'E')) {
150         /* Continuation entry */
151         if (iter->ce_len) {
152             int ret;
153             ret = iso_msg_submit(iter->msgid, ISO_UNSUPPORTED_SUSP, 0,
154                 "More than one CE System user entry has found in a single "
155                 "System Use field or continuation area. This breaks SUSP "
156                 "standard and it's not supported. Ignoring last CE. Maybe "
157                 "the image is damaged.");
158             if (ret < 0) {
159                 return ret;
160             }
161         } else {
162             iter->ce_block = iso_read_bb(entry->data.CE.block, 4, NULL);
163             iter->ce_off = iso_read_bb(entry->data.CE.offset, 4, NULL);
164             iter->ce_len = iso_read_bb(entry->data.CE.len, 4, NULL);
165         }
166 
167         /* we don't want to return CE entry to the user */
168         return susp_iter_next(iter, sue, 0);
169     } else if (SUSP_SIG(entry, 'P', 'D')) {
170         /* skip padding */
171         return susp_iter_next(iter, sue, 0);
172     }
173 
174     *sue = entry;
175     return ISO_SUCCESS;
176 }
177 
susp_iter_free(SuspIterator * iter)178 void susp_iter_free(SuspIterator *iter)
179 {
180     free(iter->buffer);
181     free(iter);
182 }
183 
184 /**
185  * Fills a struct stat with the values of a Rock Ridge PX entry (RRIP, 4.1.1).
186  *
187  * @return
188  *      1 on success, < 0 on error
189  */
read_rr_PX(struct susp_sys_user_entry * px,struct stat * st)190 int read_rr_PX(struct susp_sys_user_entry *px, struct stat *st)
191 {
192     if (px == NULL || st == NULL) {
193         return ISO_NULL_POINTER;
194     }
195     if (px->sig[0] != 'P' || px->sig[1] != 'X') {
196         return ISO_WRONG_ARG_VALUE;
197     }
198 
199     if (px->len_sue[0] != 44 && px->len_sue[0] != 36) {
200         return ISO_WRONG_RR;
201     }
202 
203     st->st_mode = iso_read_bb(px->data.PX.mode, 4, NULL);
204     st->st_nlink = iso_read_bb(px->data.PX.links, 4, NULL);
205     st->st_uid = iso_read_bb(px->data.PX.uid, 4, NULL);
206     st->st_gid = iso_read_bb(px->data.PX.gid, 4, NULL);
207     st->st_ino = 0;
208     if (px->len_sue[0] == 44) {
209         /* this corresponds to RRIP 1.12, so we have inode serial number */
210         st->st_ino = iso_read_bb(px->data.PX.serial, 4, NULL);
211         /* Indicate that st_ino is valid */
212         return 2;
213     }
214     return 1;
215 }
216 
217 /**
218  * Fills a struct stat with the values of a Rock Ridge TF entry (RRIP, 4.1.6)
219  *
220  * @return
221  *      1 on success, < 0 on error
222  */
read_rr_TF(struct susp_sys_user_entry * tf,struct stat * st)223 int read_rr_TF(struct susp_sys_user_entry *tf, struct stat *st)
224 {
225     time_t time;
226     int s;
227     int nts = 0;
228 
229     if (tf == NULL || st == NULL) {
230         return ISO_NULL_POINTER;
231     }
232     if (tf->sig[0] != 'T' || tf->sig[1] != 'F') {
233         return ISO_WRONG_ARG_VALUE;
234     }
235 
236     if (tf->data.TF.flags[0] & (1 << 7)) {
237         /* long form */
238         s = 17;
239     } else {
240         s = 7;
241     }
242 
243     /* 1. Creation time */
244     if (tf->data.TF.flags[0] & (1 << 0)) {
245         /* Linux accepts ctime by Creation time and by Attributes time.
246          * If both are given, then Attribute time will win.
247          */
248         if (tf->len_sue[0] < 5 + (nts+1) * s) {
249             /* RR TF entry too short. */
250             return ISO_WRONG_RR;
251         }
252         if (s == 7) {
253             time = iso_datetime_read_7(&tf->data.TF.t_stamps[nts*7]);
254         } else {
255             time = iso_datetime_read_17(&tf->data.TF.t_stamps[nts*17]);
256         }
257         st->st_ctime = time;
258         ++nts;
259     }
260 
261     /* 2. modify time */
262     if (tf->data.TF.flags[0] & (1 << 1)) {
263         if (tf->len_sue[0] < 5 + (nts+1) * s) {
264             /* RR TF entry too short. */
265             return ISO_WRONG_RR;
266         }
267         if (s == 7) {
268             time = iso_datetime_read_7(&tf->data.TF.t_stamps[nts*7]);
269         } else {
270             time = iso_datetime_read_17(&tf->data.TF.t_stamps[nts*17]);
271         }
272         st->st_mtime = time;
273         ++nts;
274     }
275 
276     /* 3. access time */
277     if (tf->data.TF.flags[0] & (1 << 2)) {
278         if (tf->len_sue[0] < 5 + (nts+1) * s) {
279             /* RR TF entry too short. */
280             return ISO_WRONG_RR;
281         }
282         if (s == 7) {
283             time = iso_datetime_read_7(&tf->data.TF.t_stamps[nts*7]);
284         } else {
285             time = iso_datetime_read_17(&tf->data.TF.t_stamps[nts*17]);
286         }
287         st->st_atime = time;
288         ++nts;
289     }
290 
291     /* 4. attributes time */
292     if (tf->data.TF.flags[0] & (1 << 3)) {
293         if (tf->len_sue[0] < 5 + (nts+1) * s) {
294             /* RR TF entry too short. */
295             return ISO_WRONG_RR;
296         }
297         if (s == 7) {
298             time = iso_datetime_read_7(&tf->data.TF.t_stamps[nts*7]);
299         } else {
300             time = iso_datetime_read_17(&tf->data.TF.t_stamps[nts*17]);
301         }
302         st->st_ctime = time;
303         ++nts;
304     }
305 
306     /* we ignore backup, expire and effect times */
307 
308     return ISO_SUCCESS;
309 }
310 
311 /**
312  * Read a RR NM entry (RRIP, 4.1.4), and appends the name stored there to
313  * the given name. You can pass a pointer to NULL as name.
314  *
315  * @return
316  *      1 on success, < 0 on error
317  */
read_rr_NM(struct susp_sys_user_entry * nm,char ** name,int * cont)318 int read_rr_NM(struct susp_sys_user_entry *nm, char **name, int *cont)
319 {
320     if (nm == NULL || name == NULL) {
321         return ISO_NULL_POINTER;
322     }
323     if (nm->sig[0] != 'N' || nm->sig[1] != 'M') {
324         return ISO_WRONG_ARG_VALUE;
325     }
326 
327     if (nm->len_sue[0] == 5) {
328         if (nm->data.NM.flags[0] & 0x2) {
329             /* it is a "." entry */
330             if (*name == NULL) {
331                 return ISO_SUCCESS;
332             } else {
333                 /* we can't have a previous not-NULL name */
334                 return ISO_WRONG_RR;
335             }
336         }
337     }
338 
339     if (nm->len_sue[0] <= 5) {
340         /* ".." entry is an error, as we will never call it */
341         return ISO_WRONG_RR;
342     }
343 
344     /* concatenate the results */
345     if (*cont) {
346         *name = realloc(*name, strlen(*name) + nm->len_sue[0] - 5 + 1);
347         strncat(*name, (char*)nm->data.NM.name, nm->len_sue[0] - 5);
348     } else {
349         *name = iso_util_strcopy((char*)nm->data.NM.name, nm->len_sue[0] - 5);
350     }
351     if (*name == NULL) {
352         return ISO_OUT_OF_MEM;
353     }
354 
355     /* and set cond according to the value of CONTINUE flag */
356     *cont = nm->data.NM.flags[0] & 0x01;
357     return ISO_SUCCESS;
358 }
359 
360 /**
361  * Read a SL RR entry (RRIP, 4.1.3), checking if the destination continues.
362  *
363  * @param cont
364  *      0 not continue, 1 continue, 2 continue component
365  * @return
366  *      1 on success, < 0 on error
367  */
read_rr_SL(struct susp_sys_user_entry * sl,char ** dest,int * cont)368 int read_rr_SL(struct susp_sys_user_entry *sl, char **dest, int *cont)
369 {
370     int pos;
371 
372     if (sl == NULL || dest == NULL) {
373         return ISO_NULL_POINTER;
374     }
375     if (sl->sig[0] != 'S' || sl->sig[1] != 'L') {
376         return ISO_WRONG_ARG_VALUE;
377     }
378 
379     for (pos = 0; pos + 5 < sl->len_sue[0];
380         pos += 2 + sl->data.SL.comps[pos + 1]) {
381         char *comp;
382         uint8_t len;
383         uint8_t flags = sl->data.SL.comps[pos];
384 
385         if (flags & 0x2) {
386             /* current directory */
387             len = 1;
388             comp = ".";
389         } else if (flags & 0x4) {
390             /* parent directory */
391             len = 2;
392             comp = "..";
393         } else if (flags & 0x8) {
394             /* root directory */
395             len = 1;
396             comp = "/";
397         } else if (flags & ~0x01) {
398             /* unsupported flag component */
399             return ISO_UNSUPPORTED_RR;
400         } else {
401             len = sl->data.SL.comps[pos + 1];
402             comp = (char*)&sl->data.SL.comps[pos + 2];
403         }
404 
405         if (*cont == 1) {
406             /* new component */
407             size_t size = strlen(*dest);
408             int has_slash;
409 
410             *dest = realloc(*dest, strlen(*dest) + len + 2);
411             if (*dest == NULL) {
412                 return ISO_OUT_OF_MEM;
413             }
414             /* it is a new compoenent, add the '/' */
415             has_slash = 0;
416             if (size > 0)
417                 if ((*dest)[size - 1] == '/')
418                     has_slash = 1;
419             if (!has_slash) {
420                 (*dest)[size] = '/';
421                 (*dest)[size+1] = '\0';
422             }
423             strncat(*dest, comp, len);
424         } else if (*cont == 2) {
425             /* the component continues */
426             *dest = realloc(*dest, strlen(*dest) + len + 1);
427             if (*dest == NULL) {
428                 return ISO_OUT_OF_MEM;
429             }
430             /* we don't have to add the '/' */
431             strncat(*dest, comp, len);
432         } else {
433             *dest = iso_util_strcopy(comp, len);
434         }
435         if (*dest == NULL) {
436             return ISO_OUT_OF_MEM;
437         }
438         /* do the component continue or not? */
439         *cont = (flags & 0x01) ? 2 : 1;
440     }
441 
442     if (*cont == 2) {
443         /* TODO check that SL flag is set to continute too ?*/
444     } else {
445         *cont = sl->data.SL.flags[0] & 0x1 ? 1 : 0;
446     }
447 
448     return ISO_SUCCESS;
449 }
450 
451 /**
452  * Fills a struct stat with the values of a Rock Ridge PN entry (RRIP, 4.1.2).
453  *
454  * @return
455  *      1 on success, < 0 on error
456  */
read_rr_PN(struct susp_sys_user_entry * pn,struct stat * st)457 int read_rr_PN(struct susp_sys_user_entry *pn, struct stat *st)
458 {
459     int high_shift= 0;
460 
461     if (pn == NULL || st == NULL) {
462         return ISO_NULL_POINTER;
463     }
464     if (pn->sig[0] != 'P' || pn->sig[1] != 'N') {
465         return ISO_WRONG_ARG_VALUE;
466     }
467 
468     if (pn->len_sue[0] != 20) {
469         return ISO_WRONG_RR;
470     }
471 
472     /* (dev_t << 32) causes compiler warnings on FreeBSD
473         because sizeof(dev_t) is 4.
474     */
475     st->st_rdev = (dev_t)iso_read_bb(pn->data.PN.low, 4, NULL);
476     if (sizeof(st->st_rdev) > 4) {
477         high_shift = 32;
478         st->st_rdev |= (dev_t)((dev_t)iso_read_bb(pn->data.PN.high, 4, NULL) <<
479                                high_shift);
480     }
481 
482 /* was originally:
483     st->st_rdev = (dev_t)((dev_t)iso_read_bb(pn->data.PN.high, 4, NULL) << 32)
484                   | (dev_t)iso_read_bb(pn->data.PN.low, 4, NULL);
485 */
486 
487     return ISO_SUCCESS;
488 }
489 
490 
491 /* AA is the obsolete field signature of AAIP versions < 2.0
492 */
read_aaip_AA(struct susp_sys_user_entry * sue,unsigned char ** aa_string,size_t * aa_size,size_t * aa_len,size_t * prev_field,int * is_done,int flag)493 int read_aaip_AA(struct susp_sys_user_entry *sue,
494                  unsigned char **aa_string, size_t *aa_size, size_t *aa_len,
495                  size_t *prev_field, int *is_done, int flag)
496 {
497      unsigned char *aapt;
498 
499      if (*is_done) {
500 
501          /* To coexist with Apple ISO :
502             Gracefully react on possibly trailing Apple AA
503          */
504          if (sue->version[0] != 1 || sue->len_sue[0] == 7)
505              return ISO_SUCCESS;
506 
507          return ISO_WRONG_RR;
508      }
509      if (*aa_size == 0 || *aa_string == NULL) {
510          /* Gracefully react on possibly leading Apple AA
511          */
512          if (sue->version[0] != 1 || sue->len_sue[0] < 9)
513              return ISO_SUCCESS;
514      }
515 
516      /* A valid AAIP AA entry has 5 header bytes and at least 1 component byte
517       */
518      if (sue->len_sue[0] < 6)
519          return ISO_WRONG_RR;
520 
521      /* Possibly create or grow storage */
522      if (*aa_size == 0 || *aa_string == NULL) {
523          *aa_size = *aa_len + sue->len_sue[0];
524          *aa_string = calloc(*aa_size, 1);
525          *aa_len = 0;
526      } else if (*aa_len + sue->len_sue[0] > *aa_size) {
527 
528          if (sue->version[0] != 1) {
529              /* Apple ISO within the AAIP field group is not AAIP compliant
530              */
531              return ISO_WRONG_RR;
532          }
533 
534          *aa_size += *aa_len + sue->len_sue[0];
535          *aa_string = realloc(*aa_string, *aa_size);
536      }
537      if (*aa_string == NULL)
538          return ISO_OUT_OF_MEM;
539 
540      if (*aa_len > 0) {
541          /* Mark prev_field as being continued */
542          (*aa_string)[*prev_field + 4] = 1;
543      }
544 
545      *prev_field = *aa_len;
546 
547      /* Compose new SUSP header with signature aa[], cont == 0 */
548      aapt = *aa_string + *aa_len;
549 
550      aapt[0] = 'A';
551      aapt[1] = 'L';
552      aapt[2] = sue->len_sue[0];
553      aapt[3] = 1;
554      aapt[4] = 0;
555 
556      /* Append sue payload */
557      memcpy(aapt + 5, sue->data.AL.comps, sue->len_sue[0] - 5);
558      *is_done = !(sue->data.AL.flags[0] & 1);
559      *aa_len += sue->len_sue[0];
560 
561      return ISO_SUCCESS;
562 }
563 
564 
565 /* AL is the field signature of AAIP versions >= 2.0
566 */
read_aaip_AL(struct susp_sys_user_entry * sue,unsigned char ** aa_string,size_t * aa_size,size_t * aa_len,size_t * prev_field,int * is_done,int flag)567 int read_aaip_AL(struct susp_sys_user_entry *sue,
568                  unsigned char **aa_string, size_t *aa_size, size_t *aa_len,
569                  size_t *prev_field, int *is_done, int flag)
570 {
571      unsigned char *aapt;
572 
573      if (*is_done)
574          return ISO_WRONG_RR;
575      if (sue->version[0] != 1)
576          return ISO_WRONG_RR;
577 
578      /* A valid AL entry has 5 header bytes and at least 1 component byte
579       */
580      if (sue->len_sue[0] < 6)
581          return ISO_WRONG_RR;
582 
583      /* Possibly create or grow storage */
584      if (*aa_size == 0 || *aa_string == NULL) {
585          *aa_size = *aa_len + sue->len_sue[0];
586          *aa_string = calloc(*aa_size, 1);
587          *aa_len = 0;
588      } else if (*aa_len + sue->len_sue[0] > *aa_size) {
589          *aa_size += *aa_len + sue->len_sue[0];
590          *aa_string = realloc(*aa_string, *aa_size);
591      }
592      if (*aa_string == NULL)
593          return ISO_OUT_OF_MEM;
594 
595      if (*aa_len > 0) {
596          /* Mark prev_field as being continued */
597          (*aa_string)[*prev_field + 4] = 1;
598      }
599 
600      *prev_field = *aa_len;
601 
602      /* Compose new SUSP header with signature aa[], cont == 0 */
603      aapt = *aa_string + *aa_len;
604 
605      aapt[0] = 'A';
606      aapt[1] = 'L';
607      aapt[2] = sue->len_sue[0];
608      aapt[3] = 1;
609      aapt[4] = 0;
610 
611      /* Append sue payload */
612      memcpy(aapt + 5, sue->data.AL.comps, sue->len_sue[0] - 5);
613      *is_done = !(sue->data.AL.flags[0] & 1);
614      *aa_len += sue->len_sue[0];
615 
616      return ISO_SUCCESS;
617 }
618 
619 /**
620  * Reads the zisofs parameters from a ZF field (see doc/zisofs_format.txt
621  * and doc/zisofs2_format.txt).
622  *
623  * @return
624  *      1 on success, < 0 on error
625  */
read_zisofs_ZF(struct susp_sys_user_entry * zf,uint8_t algorithm[2],uint8_t * header_size_div4,uint8_t * block_size_log2,uint64_t * uncompressed_size,int flag)626 int read_zisofs_ZF(struct susp_sys_user_entry *zf, uint8_t algorithm[2],
627                    uint8_t *header_size_div4, uint8_t *block_size_log2,
628                    uint64_t *uncompressed_size, int flag)
629 {
630     if (zf == NULL) {
631         return ISO_NULL_POINTER;
632     }
633     if ((zf->sig[0] != 'Z' || zf->sig[1] != 'F') &&
634         (zf->sig[0] != 'Z' || zf->sig[1] != '2'))
635         return ISO_WRONG_ARG_VALUE;
636     if (zf->len_sue[0] != 16) {
637         return ISO_WRONG_RR;
638     }
639     if (zf->version[0] > 2)
640         return ISO_WRONG_RR;
641     algorithm[0] = zf->data.ZF.parameters[0];
642     algorithm[1] = zf->data.ZF.parameters[1];
643     *header_size_div4 = zf->data.ZF.parameters[2];
644     *block_size_log2 = zf->data.ZF.parameters[3];
645     if (zf->version[0] == 1)
646         *uncompressed_size = iso_read_bb(&(zf->data.ZF.parameters[4]), 4,
647                                          NULL);
648     else
649         *uncompressed_size = iso_read_lsb64(&(zf->data.ZF.parameters[4]));
650     return ISO_SUCCESS;
651 }
652 
653 
654