diff --git a/src/iso.c b/src/iso.c index f7d9c4f6..e2ed8a4e 100644 --- a/src/iso.c +++ b/src/iso.c @@ -1,7 +1,7 @@ /* * Rufus: The Reliable USB Formatting Utility * ISO file extraction - * Copyright © 2011-2022 Pete Batard + * Copyright © 2011-2023 Pete Batard * Based on libcdio's iso & udf samples: * Copyright © 2003-2014 Rocky Bernstein * @@ -607,8 +607,7 @@ static int udf_extract_files(udf_t *p_udf, udf_dirent_t *p_udf_dirent, const cha return 0; out: - if (p_udf_dirent != NULL) - udf_dirent_free(p_udf_dirent); + udf_dirent_free(p_udf_dirent); ISO_BLOCKING(safe_closehandle(file_handle)); safe_free(psz_sanpath); safe_free(psz_fullpath); @@ -677,7 +676,7 @@ static int iso_extract_files(iso9660_t* p_iso, const char *psz_path) HANDLE file_handle = NULL; DWORD buf_size, wr_size, err; EXTRACT_PROPS props; - BOOL is_symlink, is_identical; + BOOL is_symlink, is_identical, free_p_statbuf = FALSE; int length, r = 1; char tmp[128], psz_fullpath[MAX_PATH], *psz_basename = NULL, *psz_sanpath = NULL; const char *psz_iso_name = &psz_fullpath[strlen(psz_extract_dir)]; @@ -708,6 +707,7 @@ static int iso_extract_files(iso9660_t* p_iso, const char *psz_path) _CDIO_LIST_FOREACH(p_entnode, p_entlist) { if (FormatStatus) goto out; p_statbuf = (iso9660_stat_t*) _cdio_list_node_data(p_entnode); + free_p_statbuf = FALSE; if (scan_only && (p_statbuf->rr.b3_rock == yep) && enable_rockridge) { if (p_statbuf->rr.u_su_fields & ISO_ROCK_SUF_PL) { if (!img_report.has_deep_directories) @@ -738,13 +738,9 @@ static int iso_extract_files(iso9660_t* p_iso, const char *psz_path) safe_strcpy(psz_basename, sizeof(psz_fullpath) - length - 1, p_statbuf->filename); if (safe_strlen(p_statbuf->filename) > 64) img_report.has_long_filename = TRUE; - // libcdio has a memleak for Rock Ridge symlinks. It doesn't look like there's an easy fix there as - // a generic list that's unaware of RR extensions is being used, so we prevent that memleak ourselves is_symlink = (p_statbuf->rr.psz_symlink != NULL); if (is_symlink) img_report.has_symlinks = SYMLINKS_RR; - if (scan_only) - safe_free(p_statbuf->rr.psz_symlink); } else { iso9660_name_translate_ext(p_statbuf->filename, psz_basename, joliet_level); } @@ -768,7 +764,8 @@ static int iso_extract_files(iso9660_t* p_iso, const char *psz_path) if (check_iso_props(psz_path, file_length, psz_basename, psz_fullpath, &props)) { continue; } - print_extracted_file(psz_fullpath, file_length); + if (!is_symlink) + print_extracted_file(psz_fullpath, file_length); for (i = 0; i < NB_OLD_C32; i++) { if (props.is_old_c32[i] && use_own_c32[i]) { static_sprintf(tmp, "%s/syslinux-%s/%s", FILES_DIR, embedded_sl_version_str[0], old_c32_name[i]); @@ -786,15 +783,35 @@ static int iso_extract_files(iso9660_t* p_iso, const char *psz_path) uprintf(" File name sanitized to '%s'", psz_sanpath); if (is_symlink) { if (file_length == 0) { - // Special handling for ISOs that have a syslinux → isolinux symbolic link (e.g. Knoppix) if ((safe_stricmp(p_statbuf->filename, "syslinux") == 0) && + // Special handling for ISOs that have a syslinux → isolinux symbolic link (e.g. Knoppix) (safe_stricmp(p_statbuf->rr.psz_symlink, "isolinux") == 0)) { static_strcpy(symlinked_syslinux, psz_fullpath); + print_extracted_file(psz_fullpath, file_length); uprintf(" Found Rock Ridge symbolic link to '%s'", p_statbuf->rr.psz_symlink); - } else + } else if (strcmp(psz_path, "/firmware") == 0) { + // Special handling for ISOs that use symlinks for /firmware/ (e.g. Debian non-free) + // TODO: Do we want to do this for all file symlinks? + char target_path[256]; + static_sprintf(target_path, "%s/%s", psz_path, p_statbuf->rr.psz_symlink); + p_statbuf = iso9660_ifs_stat_translate(p_iso, target_path); + if (p_statbuf != NULL) { + // The original p_statbuf will be freed automatically, but not + // the new one so we need to force an explicit free. + free_p_statbuf = TRUE; + file_length = p_statbuf->total_size; + print_extracted_file(psz_fullpath, file_length); + uprintf(" Duplicated from '%s'", target_path); + } else { + uprintf("Could not resolve Rock Ridge Symlink - ABORTING!"); + goto out; + } + } else { + // TODO: Ideally, we'd want to create a text file that contains the target link + print_extracted_file(psz_fullpath, file_length); uprintf(" Ignoring Rock Ridge symbolic link to '%s'", p_statbuf->rr.psz_symlink); + } } - safe_free(p_statbuf->rr.psz_symlink); } file_handle = CreatePreallocatedFile(psz_sanpath, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, file_length); @@ -830,6 +847,8 @@ static int iso_extract_files(iso9660_t* p_iso, const char *psz_path) if (!SetFileTime(file_handle, ft, ft, ft)) uprintf(" Could not set timestamp: %s", WindowsErrorString()); } + if (free_p_statbuf) + iso9660_stat_free(p_statbuf); ISO_BLOCKING(safe_closehandle(file_handle)); if (props.is_cfg || props.is_conf) fix_config(psz_sanpath, psz_path, psz_basename, &props); @@ -1245,10 +1264,8 @@ out: bled_exit(); } } - if (p_iso != NULL) - iso9660_close(p_iso); - if (p_udf != NULL) - udf_close(p_udf); + iso9660_close(p_iso); + udf_close(p_udf); if ((r != 0) && (FormatStatus == 0)) FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|APPERR((scan_only?ERROR_ISO_SCAN:ERROR_ISO_EXTRACT)); return (r == 0); @@ -1342,17 +1359,11 @@ try_iso: out: safe_closehandle(file_handle); - if (p_statbuf != NULL) - safe_free(p_statbuf->rr.psz_symlink); - safe_free(p_statbuf); - if (p_udf_root != NULL) - udf_dirent_free(p_udf_root); - if (p_udf_file != NULL) - udf_dirent_free(p_udf_file); - if (p_iso != NULL) - iso9660_close(p_iso); - if (p_udf != NULL) - udf_close(p_udf); + iso9660_stat_free(p_statbuf); + udf_dirent_free(p_udf_root); + udf_dirent_free(p_udf_file); + iso9660_close(p_iso); + udf_close(p_udf); return r; } @@ -1412,17 +1423,11 @@ try_iso: r = wim_header[3]; out: - if (p_statbuf != NULL) - safe_free(p_statbuf->rr.psz_symlink); - safe_free(p_statbuf); - if (p_udf_root != NULL) - udf_dirent_free(p_udf_root); - if (p_udf_file != NULL) - udf_dirent_free(p_udf_file); - if (p_iso != NULL) - iso9660_close(p_iso); - if (p_udf != NULL) - udf_close(p_udf); + iso9660_stat_free(p_statbuf); + udf_dirent_free(p_udf_root); + udf_dirent_free(p_udf_file); + iso9660_close(p_iso); + udf_close(p_udf); safe_free(wim_path); return bswap_uint32(r); } @@ -1541,12 +1546,9 @@ BOOL HasEfiImgBootLoaders(void) out: if (lf_fs != NULL) libfat_close(lf_fs); - if (p_statbuf != NULL) - safe_free(p_statbuf->rr.psz_symlink); - safe_free(p_statbuf); + iso9660_stat_free(p_statbuf); + iso9660_close(p_iso); safe_free(p_private); - if (p_iso != NULL) - iso9660_close(p_iso); return ret; } @@ -1671,12 +1673,9 @@ out: libfat_close(lf_fs); lf_fs = NULL; } - if (p_statbuf != NULL) - safe_free(p_statbuf->rr.psz_symlink); - safe_free(p_statbuf); + iso9660_stat_free(p_statbuf);; + iso9660_close(p_iso); safe_free(p_private); - if (p_iso != NULL) - iso9660_close(p_iso); } safe_closehandle(handle); safe_free(name); diff --git a/src/libcdio/cdio/rock.h b/src/libcdio/cdio/rock.h index 33774c7a..548228bf 100644 --- a/src/libcdio/cdio/rock.h +++ b/src/libcdio/cdio/rock.h @@ -98,23 +98,23 @@ PRAGMA_BEGIN_PACKED /*! system-use-sharing protocol */ typedef struct iso_su_sp_s{ - unsigned char magic[2]; + uint8_t magic[2]; uint8_t skip; } GNUC_PACKED iso_su_sp_t; /*! system-use extension record */ typedef struct iso_su_er_s { iso711_t len_id; /**< Identifier length. Value 10?. */ - unsigned char len_des; - unsigned char len_src; + uint8_t len_des; + uint8_t len_src; iso711_t ext_ver; /**< Extension version. Value 1? */ - char data[EMPTY_ARRAY_SIZE]; + char data[EMPTY_ARRAY_SIZE]; } GNUC_PACKED iso_su_er_t; typedef struct iso_su_ce_s { - char extent[8]; - char offset[8]; - char size[8]; + uint8_t extent[8]; + uint8_t offset[8]; + uint8_t size[8]; } iso_su_ce_t; /*! POSIX file attributes, PX. See Rock Ridge Section 4.1.2 */ @@ -165,7 +165,7 @@ typedef struct iso_rock_sl_part_s { /*! Symbolic link. See Rock Ridge Section 4.1.3 */ typedef struct iso_rock_sl_s { - unsigned char flags; + uint8_t flags; iso_rock_sl_part_t link; } GNUC_PACKED iso_rock_sl_t ; @@ -184,7 +184,7 @@ typedef enum { typedef struct iso_rock_nm_s { - unsigned char flags; + uint8_t flags; char name[EMPTY_ARRAY_SIZE]; } GNUC_PACKED iso_rock_nm_t ; diff --git a/src/libcdio/iso9660/rock.c b/src/libcdio/iso9660/rock.c index a957d785..d2c01165 100644 --- a/src/libcdio/iso9660/rock.c +++ b/src/libcdio/iso9660/rock.c @@ -1,6 +1,6 @@ /* - Copyright (C) 2020 Pete Batard - Copyright (C) 2005, 2008, 2010-2011, 2014, 2017 Rocky Bernstein + Copyright (C) 2020, 2023 Pete Batard + Copyright (C) 2005, 2008, 2010-2011, 2014, 2017, 2022 Rocky Bernstein Adapted from GNU/Linux fs/isofs/rock.c (C) 1992, 1993 Eric Youngdale @@ -94,34 +94,36 @@ realloc_symlink(/*in/out*/ iso9660_stat_t *p_stat, uint8_t i_grow) /* This is a way of ensuring that we have something in the system use fields that is compatible with Rock Ridge */ -#define CHECK_SP(FAIL) \ - if(rr->u.SP.magic[0] != 0xbe) FAIL; \ - if(rr->u.SP.magic[1] != 0xef) FAIL; \ +#define CHECK_SP(FAIL) \ + if (rr->u.SP.magic[0] != 0xbe) FAIL; \ + if (rr->u.SP.magic[1] != 0xef) FAIL; \ p_stat->rr.s_rock_offset = rr->u.SP.skip; /* We define a series of macros because each function must do exactly the same thing in certain places. We use the macros to ensure that everything is done correctly */ #define CONTINUE_DECLS \ - int cont_extent = 0, cont_offset = 0, cont_size = 0; \ - void *buffer = NULL + uint32_t cont_extent = 0, cont_offset = 0, cont_size = 0; \ + uint8_t *buffer = NULL -#define CHECK_CE \ - { cont_extent = from_733(*rr->u.CE.extent); \ - cont_offset = from_733(*rr->u.CE.offset); \ - cont_size = from_733(*rr->u.CE.size); \ - (void)cont_extent; (void)cont_offset, (void)cont_size; } +#define CHECK_CE(FAIL) \ + { cont_extent = from_733(*rr->u.CE.extent); \ + cont_offset = from_733(*rr->u.CE.offset); \ + if (cont_offset >= ISO_BLOCKSIZE) FAIL; \ + cont_size = from_733(*rr->u.CE.size); \ + if (cont_size >= ISO_BLOCKSIZE) FAIL; \ + } -#define SETUP_ROCK_RIDGE(DE,CHR,LEN) \ +#define SETUP_ROCK_RIDGE(DE,CHR,LEN) \ { \ LEN= sizeof(iso9660_dir_t) + DE->filename.len; \ - if(LEN & 1) LEN++; \ + if (LEN & 1) LEN++; \ CHR = ((unsigned char *) DE) + LEN; \ LEN = *((unsigned char *) DE) - LEN; \ if (0xff != p_stat->rr.s_rock_offset) \ { \ - LEN -= p_stat->rr.s_rock_offset; \ - CHR += p_stat->rr.s_rock_offset; \ + LEN -= p_stat->rr.s_rock_offset; \ + CHR += p_stat->rr.s_rock_offset; \ if (LEN<0) LEN=0; \ } \ } @@ -130,22 +132,22 @@ realloc_symlink(/*in/out*/ iso9660_stat_t *p_stat, uint8_t i_grow) the specified field of a iso_rock_statbuf_t. non-paramater variables are p_stat, rr, and cnt. */ -#define add_time(FLAG, TIME_FIELD) \ - if (rr->u.TF.flags & FLAG) { \ - p_stat->rr.TIME_FIELD.b_used = true; \ - p_stat->rr.TIME_FIELD.b_longdate = \ - (0 != (rr->u.TF.flags & ISO_ROCK_TF_LONG_FORM)); \ - if (p_stat->rr.TIME_FIELD.b_longdate) { \ - memcpy(&(p_stat->rr.TIME_FIELD.t.ltime), \ - &(rr->u.TF.time_bytes[cnt]), \ - sizeof(iso9660_ltime_t)); \ - cnt += sizeof(iso9660_ltime_t); \ - } else { \ - memcpy(&(p_stat->rr.TIME_FIELD.t.dtime), \ - &(rr->u.TF.time_bytes[cnt]), \ - sizeof(iso9660_dtime_t)); \ - cnt += sizeof(iso9660_dtime_t); \ - } \ +#define add_time(FLAG, TIME_FIELD) \ + if (rr->u.TF.flags & FLAG) { \ + p_stat->rr.TIME_FIELD.b_used = true; \ + p_stat->rr.TIME_FIELD.b_longdate = \ + (0 != (rr->u.TF.flags & ISO_ROCK_TF_LONG_FORM)); \ + if (p_stat->rr.TIME_FIELD.b_longdate) { \ + memcpy(&(p_stat->rr.TIME_FIELD.t.ltime), \ + &(rr->u.TF.time_bytes[cnt]), \ + sizeof(iso9660_ltime_t)); \ + cnt += sizeof(iso9660_ltime_t); \ + } else { \ + memcpy(&(p_stat->rr.TIME_FIELD.t.dtime), \ + &(rr->u.TF.time_bytes[cnt]), \ + sizeof(iso9660_dtime_t)); \ + cnt += sizeof(iso9660_dtime_t); \ + } \ } /* Indicates if we should process deep directory entries */ @@ -202,7 +204,7 @@ get_rock_ridge_filename(iso9660_dir_t * p_iso9660_dir, switch(sig) { case SIG('S','P'): - CHECK_SP(goto out); + CHECK_SP({cdio_warn("Invalid Rock Ridge SP field"); goto out;}); p_stat->rr.u_su_fields |= ISO_ROCK_SUF_SP; break; case SIG('C','E'): @@ -213,8 +215,17 @@ get_rock_ridge_filename(iso9660_dir_t * p_iso9660_dir, if ('\1' == p_iso9660_dir->filename.str[1] && 1 == i_fname) break; } - CHECK_CE; + CHECK_CE({cdio_warn("Invalid Rock Ridge CE field"); goto out;}); p_stat->rr.u_su_fields |= ISO_ROCK_SUF_CE; + /* We may already be processing a continuation block so free it */ + free(buffer); + buffer = calloc(1, ISO_BLOCKSIZE); + if (!buffer) + goto out; + if (iso9660_iso_seek_read(p_image, buffer, cont_extent, 1) != ISO_BLOCKSIZE) + goto out; + chr = &buffer[cont_offset]; + len = cont_size; break; case SIG('E','R'): cdio_debug("ISO 9660 Extensions: "); @@ -471,7 +482,7 @@ iso9660_get_rock_attr_str(posix_mode_t st_mode) result[ 8] = (st_mode & ISO_ROCK_IWOTH) ? 'w' : '-'; result[ 9] = (st_mode & ISO_ROCK_IXOTH) ? 'x' : '-'; - result[11] = '\0'; + result[10] = '\0'; return result; } diff --git a/src/rufus.rc b/src/rufus.rc index d6a37770..0767a13e 100644 --- a/src/rufus.rc +++ b/src/rufus.rc @@ -33,7 +33,7 @@ LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL IDD_DIALOG DIALOGEX 12, 12, 232, 326 STYLE DS_SETFONT | DS_MODALFRAME | DS_CENTER | WS_MINIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU EXSTYLE WS_EX_ACCEPTFILES -CAPTION "Rufus 3.22.1983" +CAPTION "Rufus 3.22.1985" FONT 9, "Segoe UI Symbol", 400, 0, 0x0 BEGIN LTEXT "Drive Properties",IDS_DRIVE_PROPERTIES_TXT,8,6,53,12,NOT WS_GROUP @@ -392,8 +392,8 @@ END // VS_VERSION_INFO VERSIONINFO - FILEVERSION 3,22,1983,0 - PRODUCTVERSION 3,22,1983,0 + FILEVERSION 3,22,1985,0 + PRODUCTVERSION 3,22,1985,0 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -411,13 +411,13 @@ BEGIN VALUE "Comments", "https://rufus.ie" VALUE "CompanyName", "Akeo Consulting" VALUE "FileDescription", "Rufus" - VALUE "FileVersion", "3.22.1983" + VALUE "FileVersion", "3.22.1985" VALUE "InternalName", "Rufus" VALUE "LegalCopyright", "© 2011-2023 Pete Batard (GPL v3)" VALUE "LegalTrademarks", "https://www.gnu.org/licenses/gpl-3.0.html" VALUE "OriginalFilename", "rufus-3.22.exe" VALUE "ProductName", "Rufus" - VALUE "ProductVersion", "3.22.1983" + VALUE "ProductVersion", "3.22.1985" END END BLOCK "VarFileInfo"