From 1a5307c2e9ec9c3ef31e2ba27e713d01fedec401 Mon Sep 17 00:00:00 2001 From: Thomas Schmitt Date: Tue, 16 Dec 2008 13:02:11 +0000 Subject: [PATCH] New option -drive_class for safety management of pseudo-drive access --- xorriso/xorriso.1 | 71 ++++++++++++++-- xorriso/xorriso.c | 164 +++++++++++++++++++++++++++++++----- xorriso/xorriso_private.h | 10 +++ xorriso/xorriso_timestamp.h | 2 +- xorriso/xorrisoburn.c | 107 +++++++++++++++++++++-- xorriso/xorrisoburn.h | 5 ++ 6 files changed, 325 insertions(+), 34 deletions(-) diff --git a/xorriso/xorriso.1 b/xorriso/xorriso.1 index d2ed2864..7ac38ab6 100644 --- a/xorriso/xorriso.1 +++ b/xorriso/xorriso.1 @@ -2,7 +2,7 @@ .\" First parameter, NAME, should be all caps .\" Second parameter, SECTION, should be 1-8, maybe w/ subsection .\" other parameters are allowed: see man(7), man(1) -.TH XORRISO 1 "Dec 13, 2008" +.TH XORRISO 1 "Dec 16, 2008" .\" Please adjust this date whenever revising the manpage. .\" .\" Some roff macros, for reference: @@ -296,14 +296,19 @@ Consider to bundle the authorized users in a group like old "floppy". Filesystem objects of nearly any type can be addressed by prefix "stdio:" and their path in the filesystem. E.g.: .br - -dev stdio:/tmp/pseudo_drive + -dev stdio:/dev/sdc +.br +The default setting of -drive_class allows to address files outside the +/dev tree without that prefix. E.g.: +.br + -dev /tmp/pseudo_drive .br If path leads to a regular file or to a block device then the emulated drive is random access readable and can be used for the method of growing if it already contains a valid ISO 9660 image. Any other file type is not readable via "stdio:" and can only be used as target for the method of modifying or blind growing. -Non existing paths in existing directories are handled as empty regular files. +Non-existing paths in existing directories are handled as empty regular files. .PP A very special kind of pseudo drive are open file descriptors. They are depicted by "stdio:/dev/fd/" and descriptor number (see man 2 open). @@ -326,12 +331,18 @@ If stdout is used as drive, then -use_readline is permanently disabled. Use of backdoors will cause severe memory and/or tty corruption. .PP Be aware that especially the superuser can write into any accessible file or -device by using its path with the "stdio:" prefix. Addresses without prefix -"stdio:" will only work if they lead to a MMC drive. +device by using its path with the "stdio:" prefix. By default any address +in the /dev tree without prefix "stdio:" will work only if it leads to a MMC +drive. .br One may use option .B -ban_stdio_write to surely prevent this risk and to allow only MMC drives. +.br +One may prepend "mmc:" to a path to surely disallow any automatic "stdio:". +.br +By option -drive_class one may ban certain paths or allow access without +prefix "stdio:" to other paths. .SS .B Rock Ridge, POSIX, X/Open, and El Torito: .br @@ -518,6 +529,41 @@ apply. See above paragraph "Libburn drives". An empty address string "" gives up the current output drive without aquiring a new one. No writing is possible without an output drive. .TP +\fB\-drive_class\fR "harmless"|"banned"|"risky"|"clear_list" disk_pattern +Add a drive path pattern to one of the safety lists or make those lists empty. +There are three lists defined which get tested in the following sequence: +.br +If a drive address path matches the "harmless" list then the drive will be +accepted. If it is not a MMC device then the prefix "stdio:" will be prepended +automatically. This list is empty by default. +.br +Else if the path matches the "banned" list then the drive will not be +accepted by xorriso but rather lead to a FAILURE event. This list is empty by +default. +.br +Else if the path matches the "risky" list and if it is not a MMC device, +then its address must have the prefix "stdio:" or it will be rejected. +This list has by default one entry: "/dev". +.br +If a drive path matches no list then it is considered "harmless". By default +these are all paths which do not begin with directory "/dev". +.br +A path matches a list if one of its parent paths or itself matches a list +entry. An eventual address prefix "stdio:" or "mmc:" will be ignored when +testing for matches. +.br +By pseudo-class "clear_list" and pseudo-patterns "banned", "risky", "harmless", +or "all", the lists may be made empty. +.br +E.g.: -drive_class clear_list banned +.br +One will normally define the -drive_class lists in one of the xorriso +Startup Files. +.br +Note: This is not a security feature but rather a bumper for the superuser to +prevent inadverted mishaps. For reliably blocking access to a device file you +have to deny its rw-permissions in the filesystem. +.TP \fB\-grow_blindly\fR "off"|predicted_nwa If predicted_nwa is a non-negative number then perform blind growing rather than modifying if -indev and -outdev are set to different drives. @@ -2735,11 +2781,22 @@ will be made terminal-safe by option -backslash_codes. .B Operate on storage facilities other than optical drives Full read-write operation is possible with regular files and block devices: .br -\fB$\fR xorriso -dev stdio:/tmp/regular_file ... +\fB$\fR xorriso -dev /tmp/regular_file ... +.br +Paths underneath /dev normally need prefix "stdio:" +.br +\fB$\fR xorriso -dev stdio:/dev/sdb ... +.br +If /dev/sdb is to be used frequently and /dev/sda is the system disk, +then consider to place the following lines in a xorriso Startup File. +They allow to use /dev/sdb without prefix and protect your disk from xorriso: +.br + -drive_class banned /dev/sda* + -drive_class harmless /dev/sdb .br Other writeable file types are supported write-only: .br -\fB$\fR xorriso -outdev stdio:/tmp/named_pipe ... +\fB$\fR xorriso -outdev /tmp/named_pipe ... .br Among the write-only drives is standard output: .br diff --git a/xorriso/xorriso.c b/xorriso/xorriso.c index ca30d980..e3d6c09d 100644 --- a/xorriso/xorriso.c +++ b/xorriso/xorriso.c @@ -3846,6 +3846,9 @@ int Xorriso_new(struct XorrisO ** xorriso,char *progname, int flag) m->global_file_mode= 0444; m->do_overwrite= 2; m->do_reassure= 0; + m->drive_blacklist= NULL; + m->drive_greylist= NULL; + m->drive_whitelist= NULL; m->toc_emulation_flag= 0; m->image_start_mode= 0; m->image_start_value[0]= 0; @@ -3979,6 +3982,9 @@ int Xorriso_new(struct XorrisO ** xorriso,char *progname, int flag) if(ret<=0) goto failure; Xorriso_relax_compliance(m, "default", 0); + ret= Xorriso_lst_new(&(m->drive_greylist), "/dev", m->drive_greylist, 1); + if(ret <= 0) + goto failure; return(1); failure:; @@ -4029,6 +4035,9 @@ int Xorriso_destroy(struct XorrisO **xorriso, int flag) free(m->out_charset); Xorriso_destroy_re(m,0); Exclusions_destroy(&(m->disk_exclusions), 0); + Xorriso_lst_destroy_all(&(m->drive_blacklist), 0); + Xorriso_lst_destroy_all(&(m->drive_greylist), 0); + Xorriso_lst_destroy_all(&(m->drive_whitelist), 0); Xorriso_detach_libraries(m, flag&1); free((char *) m); @@ -5132,14 +5141,14 @@ cannot_compile:; } -/* @return 0=match , else no match +/* @param flag bit0= do not shortcut last component of to_match + bit1= consider match if regex matches parent of path + bit2= retry beginning at failed last component + + @return 0=match , else no match */ int Xorriso_regexec(struct XorrisO *xorriso, char *to_match, int *failed_at, int flag) -/* - bit0= do not shortcut last component of to_match - bit2= retry beginning at failed last component -*/ { int ret,i,re_start= 0,reg_nomatch= -1; char *cpt,*npt,adr_part[SfileadrL],*mpt; @@ -5199,10 +5208,51 @@ int Xorriso_regexec(struct XorrisO *xorriso, char *to_match, int *failed_at, cpt++; } *failed_at= xorriso->re_fill; + if(flag & 2) + return(0); /* MATCH */ return(reg_nomatch); } +int Xorriso_is_in_patternlist(struct XorrisO *xorriso, + struct Xorriso_lsT *patternlist, char *path, + int flag) +{ + int ret, failed_at, i= 0; + struct Xorriso_lsT *s; + + xorriso->search_mode= 3; + xorriso->structured_search= 1; + + for(s= patternlist; s != NULL; s= Xorriso_lst_get_next(s, 0)) { + ret= Xorriso_prepare_regex(xorriso, Xorriso_lst_get_text(s, 0), 0); + if(ret <= 0) + return(-1); + /* Match path or parent of path */ + ret= Xorriso_regexec(xorriso, path, &failed_at, 2); + if(ret == 0) + return(i + 1); + i++; + } + return(0); +} + + +char *Xorriso_get_pattern(struct XorrisO *xorriso, + struct Xorriso_lsT *patternlist, int index, int flag) +{ + int i= 0; + struct Xorriso_lsT *s; + + for(s= patternlist; s != NULL; s= Xorriso_lst_get_next(s, 0)) { + if(i == index) + return(Xorriso_lst_get_text(s, 0)); + i++; + } + return(NULL); +} + + /* @param flag bit0= simple readlink(): no normalization, no multi-hop */ int Xorriso_resolve_link(struct XorrisO *xorriso, @@ -5546,7 +5596,7 @@ int Xorriso_status(struct XorrisO *xorriso, char *filter, FILE *fp, int flag) static char channel_prefixes[4][4]= {".","R","I","M"}; static char load_names[][20]= {"auto", "session", "track", "lba", "volid"}; static int max_load_mode= 4; - struct Xorriso_lsT *paths, *leafs; + struct Xorriso_lsT *paths, *leafs, *s; no_defaults= flag&1; line= xorriso->result_line; @@ -6078,7 +6128,36 @@ int Xorriso_status(struct XorrisO *xorriso, char *filter, FILE *fp, int flag) strcat(line, "\n"); if(!(is_default && no_defaults)) Xorriso_status_result(xorriso,filter,fp,flag&2); - + + is_default= 1; + if(xorriso->drive_blacklist != NULL || xorriso->drive_whitelist != NULL || + xorriso->drive_greylist == NULL) + is_default= 0; + if(xorriso->drive_greylist != NULL) { + if(strcmp(Xorriso_get_pattern(xorriso, xorriso->drive_greylist, 0, 0), + "/dev") != 0) + is_default= 0; + if(Xorriso_get_pattern(xorriso, xorriso->drive_greylist, 1, 0) != NULL) + is_default= 0; + } + if(!(is_default && no_defaults)) { + for(s= xorriso->drive_blacklist; s != NULL; s= Xorriso_lst_get_next(s, 0)) { + sprintf(line, "-drive_class 'banned' %s\n", + Text_shellsafe(Xorriso_lst_get_text(s, 0), sfe, 0)); + Xorriso_status_result(xorriso,filter,fp,flag&2); + } + for(s= xorriso->drive_greylist; s != NULL; s= Xorriso_lst_get_next(s, 0)) { + sprintf(line, "-drive_class 'risky' %s\n", + Text_shellsafe(Xorriso_lst_get_text(s, 0), sfe, 0)); + Xorriso_status_result(xorriso,filter,fp,flag&2); + } + for(s= xorriso->drive_whitelist; s != NULL; s= Xorriso_lst_get_next(s, 0)) { + sprintf(line, "-drive_class 'harmless' %s\n", + Text_shellsafe(Xorriso_lst_get_text(s, 0), sfe, 0)); + Xorriso_status_result(xorriso,filter,fp,flag&2); + } + } + do_single= 0; if(filter != NULL) if(strncmp(filter, "-indev", 6) == 0 || @@ -10900,13 +10979,12 @@ int Xorriso_option_assert_volid(struct XorrisO *xorriso, char *pattern, } } if(severity[0] != 0 || pattern[0] != 0) { - if(severity[0] == 0) { - if(strcmp(xorriso->abort_on_text, "NEVER") == 0) - sev_text= "ABORT"; - else - sev_text= xorriso->abort_on_text; - } else + if(severity[0] == 0) + sev_text= xorriso->abort_on_text; + else sev_text= severity; + if(strcmp(sev_text, "NEVER") == 0) + sev_text= "ABORT"; ret= Xorriso__text_to_sev(sev_text, &sev, 0); if(ret<=0) { sprintf(xorriso->info_text, "-assert_volid: Not a known severity name : "); @@ -12114,12 +12192,6 @@ int Xorriso_option_dev(struct XorrisO *xorriso, char *in_adr, int flag) Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FAILURE", 0); return(0); } - if(xorriso->ban_stdio_write) { - sprintf(xorriso->info_text, - "Drive address banned by -ban_stdio_write : '%s'", adr); - Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FAILURE", 0); - return(0); - } } if(xorriso->volset_change_pending && (flag&1)) { @@ -12242,6 +12314,48 @@ int Xorriso_option_disk_pattern(struct XorrisO *xorriso, char *mode, int flag) } +/* Option -drive_class */ +int Xorriso_option_drive_class(struct XorrisO *xorriso, + char *class, char *pattern, int flag) +{ + int ret= 1; + + if(strcmp(class, "banned") == 0) { + ret= Xorriso_lst_new(&(xorriso->drive_blacklist), pattern, + xorriso->drive_blacklist, 1); + } else if(strcmp(class, "caution") == 0) { + ret= Xorriso_lst_new(&(xorriso->drive_greylist), pattern, + xorriso->drive_greylist, 1); + } else if (strcmp(class, "harmless") == 0) { + ret= Xorriso_lst_new(&(xorriso->drive_whitelist), pattern, + xorriso->drive_whitelist, 1); + } else if (strcmp(class, "clear_list") == 0) { + if(strcmp(pattern, "banned") == 0) + Xorriso_lst_destroy_all(&(xorriso->drive_blacklist), 0); + else if(strcmp(pattern, "caution") == 0) + Xorriso_lst_destroy_all(&(xorriso->drive_greylist), 0); + else if(strcmp(pattern, "harmless") == 0) + Xorriso_lst_destroy_all(&(xorriso->drive_whitelist), 0); + else if(strcmp(pattern, "all") == 0) { + Xorriso_lst_destroy_all(&(xorriso->drive_blacklist), 0); + Xorriso_lst_destroy_all(&(xorriso->drive_greylist), 0); + Xorriso_lst_destroy_all(&(xorriso->drive_whitelist), 0); + } else { + sprintf(xorriso->info_text, "-drive_class clear : unknown class '%s'", + pattern); + Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FAILURE", 0); + return(0); + } + ret= 1; + } else { + sprintf(xorriso->info_text, "-drive_class: unknown class '%s'", class); + Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FAILURE", 0); + return(0); + } + return(ret); +} + + /* Option -dummy "on"|"off" */ int Xorriso_option_dummy(struct XorrisO *xorriso, char *mode, int flag) { @@ -12919,13 +13033,17 @@ int Xorriso_option_help(struct XorrisO *xorriso, int flag) "", "Preparation options:", "Drive addresses are either /dev/... as listed with option -devices or", -"disk files with prefix \"stdio:\", e.g. stdio:/tmp/pseudo_drive .", +"disk files, eventually with prefix \"stdio:\" if non-CD-drive in /dev tree.", +"E.g. /dev/sr0 , /tmp/pseudo_drive , stdio:/dev/sdc", " -dev address Set input and output drive and load eventual ISO image.", " Set the image expansion method to growing.", " -indev address Set input drive and load eventual ISO image. Use expansion", " methods modifying or blind growing.", " -outdev address", " Set output drive and use modifying or blind growing.", +" -drive_class \"harmless\"|\"banned\"|\"risky\"|\"clear_list\" disk_pattern", +" Add a drive path pattern to one of the safety lists or make", +" those lists empty. Defaulty entry in \"risky\" is \"/dev\".", " -grow_blindly \"off\"|predicted_nwa", " Switch between modifying and blind growing.", " -load \"session\"|\"track\"|\"lba\"|\"sbsector\"|\"volid\"|\"auto\" id", @@ -15433,7 +15551,7 @@ int Xorriso_count_args(struct XorrisO *xorriso, int argc, char **argv, "" }; static char arg2_commands[][40]= { - "assert_volid","boot_image","compare","compare_r", + "assert_volid","boot_image","compare","compare_r","drive_class", "errfile_log","error_behavior","extract","extract_single", "load","logfile", "map","map_single","page","return_with","update","update_r", @@ -15709,6 +15827,10 @@ next_command:; } else if(strcmp(cmd,"devices")==0) { ret= Xorriso_option_devices(xorriso, 0); + } else if(strcmp(cmd,"drive_class")==0) { + (*idx)+= 2; + ret= Xorriso_option_drive_class(xorriso, arg1, arg2, 0); + } else if(strcmp(cmd,"dummy")==0) { (*idx)++; ret= Xorriso_option_dummy(xorriso, arg1, 0); diff --git a/xorriso/xorriso_private.h b/xorriso/xorriso_private.h index 1fac8f42..36984045 100644 --- a/xorriso/xorriso_private.h +++ b/xorriso/xorriso_private.h @@ -132,6 +132,10 @@ struct XorrisO { /* the global context of xorriso */ /* >>> put libburn/isoburn aspects here */ + struct Xorriso_lsT *drive_blacklist; + struct Xorriso_lsT *drive_greylist; + struct Xorriso_lsT *drive_whitelist; + int toc_emulation_flag; /* bit0= bit3 for isoburn_drive_aquire() scan -ROM profiles for ISO sessions bit1= bit4 for isoburn_drive_aquire() @@ -599,6 +603,12 @@ int Xorriso_make_mount_cmd(struct XorrisO *xorriso, char *cmd, int Xorriso_execv(struct XorrisO *xorriso, char *cmd, char *env_path, int *status, int flag); +int Xorriso_is_in_patternlist(struct XorrisO *xorriso, + struct Xorriso_lsT *patternlist, char *path, int flag); + +char *Xorriso_get_pattern(struct XorrisO *xorriso, + struct Xorriso_lsT *patternlist, int index, int flag); + int Sfile_str(char target[SfileadrL], char *source, int flag); diff --git a/xorriso/xorriso_timestamp.h b/xorriso/xorriso_timestamp.h index 1e4d22ed..9517fc12 100644 --- a/xorriso/xorriso_timestamp.h +++ b/xorriso/xorriso_timestamp.h @@ -1 +1 @@ -#define Xorriso_timestamP "2008.12.14.231145" +#define Xorriso_timestamP "2008.12.16.130139" diff --git a/xorriso/xorrisoburn.c b/xorriso/xorrisoburn.c index 4b6b62f9..1dd08f3d 100644 --- a/xorriso/xorrisoburn.c +++ b/xorriso/xorrisoburn.c @@ -526,7 +526,7 @@ int Xorriso_aquire_drive(struct XorrisO *xorriso, char *adr, int flag) enum burn_disc_status state; IsoImage *volset = NULL; struct isoburn_read_opts *ropts= NULL; - char adr_data[SfileadrL], *libburn_adr, *boot_fate, *sev; + char libburn_adr[SfileadrL], *boot_fate, *sev; static int no_rr_or_joliet= 0; @@ -540,16 +540,17 @@ int Xorriso_aquire_drive(struct XorrisO *xorriso, char *adr, int flag) if(ret<=0) return(ret); - libburn_adr= adr; - if(strcmp(adr,"stdio:/dev/fd/1")==0) { + ret= Xorriso_auto_driveadr(xorriso, adr, libburn_adr, 0); + if(ret <= 0) + return(ret); + if(strcmp(libburn_adr,"stdio:/dev/fd/1")==0) { if(xorriso->dev_fd_1<0) { sprintf(xorriso->info_text, "-*dev \"stdio:/dev/fd/1\" was not a start argument. Cannot use it now."); Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FAILURE", 0); {ret= 0; goto ex;} } else { - sprintf(adr_data, "stdio:/dev/fd/%d", xorriso->dev_fd_1); - libburn_adr= adr_data; + sprintf(libburn_adr, "stdio:/dev/fd/%d", xorriso->dev_fd_1); } } @@ -8624,3 +8625,99 @@ ex:; } return(ret); } + + +int Xorriso_auto_driveadr(struct XorrisO *xorriso, char *adr, char *result, + int flag) +{ + int ret, is_known_mmc= 0; + char *path_pt, libburn_adr[BURN_DRIVE_ADR_LEN + SfileadrL]; + char *abs_pt, abs_adr[SfileadrL]; + + path_pt= adr; + if(strncmp(adr, "stdio:", 6) == 0) + path_pt= adr + 6; + else if(strncmp(adr, "mmc:", 4) == 0) + path_pt= adr + 4; + + + /* <<< replace by Xorriso_normalize_img_path() ? */; + + if(path_pt[0] != '/') { + abs_pt= getcwd(abs_adr, SfileadrL - 1); + if(abs_pt == NULL) { + Xorriso_msgs_submit(xorriso, 0, + "Relative drive path given. Cannot determine working directory.", + errno, "FAILURE", 0); + return(-1); + } + ret= Sfile_add_to_path(abs_adr, path_pt, 0); + if(ret <= 0) + return(-1); + } + + + ret= Xorriso_is_in_patternlist(xorriso, xorriso->drive_whitelist, path_pt, 0); + if(ret > 0) + goto ok; + ret= Xorriso_is_in_patternlist(xorriso, xorriso->drive_blacklist, path_pt, 0); + if(ret < 0) + return(ret); + if(ret) { + strcpy(xorriso->info_text, "Drive address "); + Text_shellsafe(adr, xorriso->info_text, 1); + strcat(xorriso->info_text, + " rejected because: -drive_class 'banned' "); + Text_shellsafe(Xorriso_get_pattern(xorriso, xorriso->drive_blacklist, + ret - 1, 0), + xorriso->info_text, 1); + Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FAILURE", 0); + return(0); + } + /* if in greylist and not MMC and not stdio prefix: reject */ + is_known_mmc= burn_drive_convert_fs_adr(path_pt, libburn_adr); + Xorriso_process_msg_queues(xorriso,0); + if(is_known_mmc < 0) + return(ret); + if(adr == path_pt && !is_known_mmc) { /* no prefix, no MMC */ + ret= Xorriso_is_in_patternlist(xorriso, xorriso->drive_greylist, path_pt,0); + if(ret < 0) + return(ret); + if(ret) { + strcpy(xorriso->info_text, "Drive address "); + Text_shellsafe(adr, xorriso->info_text, 1); + strcat(xorriso->info_text, + " rejected because: not MMC and -drive_class 'risky' "); + Text_shellsafe(Xorriso_get_pattern(xorriso,xorriso->drive_greylist, + ret - 1, 0), + xorriso->info_text, 1); + Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FAILURE", 0); + Xorriso_msgs_submit(xorriso, 0, + "If the address is a legitimate target, prepend \"stdio:\"", + 0, "HINT", 0); + return(0); + } + } +ok:; + if(strncmp(adr, "mmc:", 4) == 0) { + if(Sfile_str(result, path_pt, 0) <= 0) + return(0); + } else if(adr == path_pt && !is_known_mmc) { + Sfile_str(result, "stdio:", 0); + if(Sfile_str(result, adr, 1) <= 0) + return(0); + } else { + if(Sfile_str(result, adr, 0) <= 0) + return(0); + } + if(strncmp(result, "stdio:", 6)==0) { + if(xorriso->ban_stdio_write) { + strcpy(xorriso->info_text, "Drive address banned by -ban_stdio_write : "); + Text_shellsafe(result, xorriso->info_text, 1); + Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FAILURE", 0); + return(0); + } + } + return(1); +} + diff --git a/xorriso/xorrisoburn.h b/xorriso/xorrisoburn.h index b54c2a05..f06111d2 100644 --- a/xorriso/xorrisoburn.h +++ b/xorriso/xorrisoburn.h @@ -377,6 +377,11 @@ int Xorriso_mount(struct XorrisO *xorriso, char *dev, int adr_mode, char *adr_value, char *cmd, int flag); + +int Xorriso_auto_driveadr(struct XorrisO *xorriso, char *adr, char *result, + int flag); + + /* A pseudo file type for El-Torito bootsectors as in man 2 stat : For now take the highest possible value. */