New option -drive_class for safety management of pseudo-drive access

This commit is contained in:
Thomas Schmitt 2008-12-16 13:02:11 +00:00
parent b0f6179233
commit d76129e3be
6 changed files with 325 additions and 34 deletions

View File

@ -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

View File

@ -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);

View File

@ -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);

View File

@ -1 +1 @@
#define Xorriso_timestamP "2008.12.14.231145"
#define Xorriso_timestamP "2008.12.16.130139"

View File

@ -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);
}

View File

@ -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.
*/