Mailing List Archive

Re: [PERL] Assorted comments on the Safe module
Chip Salzenberg writes:
>
> According to Tim Bunce:
> > Note that you can't really rely on 'number of operators' as a way to
> > tell if any of the operators have changed. It's quite possible that one
> > operator could be deleted and another added in the same release.
> >
> > Requiring an exact version match would avoid this issue at no cost.
>
> What if Perl were modified to make the opcode name list a Perl
> variable? Something like @CORE::OPCODES. Then the Safe build process
> could embed the current value of the array into the installed Safe
> module, and at runtime Safe could check to be sure that the running
> Perl had an identical OPCODES array. Then we wouldn't have any
> trouble from version changes independent of opcode mask changes.
> (What if a user installs a patch that adds a new opcode (like
> "tied"))?
>
> As a bonus, opcode masks would become much easier to modify.
>
> In fact, you could create a tied package for them:
>
> Tie %mask, 'Safe::OpcodeMask', $Safe::DefaultMask;
> $mask{open} = 0;
> # etc.

The opname() and opcode() functions in Safe already give guaranteed
reliable access to the underlying op_name[] array (and now the size
of that array is guaranteed to be MAXO() too). A tied hash similar to
the sort you mention can be set up which has (untested)
use Safe qw(opname opcode);
sub FETCH {
return opcode($_[1]);
}
The values of the hash are the opcode rather than the mask. Similarly,
a real hash can be initialised with
use Safe qw(opname opcode MAXO);
@ops{opname(0..MAXO - 1)} = (0..MAXO-1);
You could easily deliver them as masks instead if desired.
I think what Tim's worried about (and I partially agree) is people
hard-coding opcodes as numbers or making bad assumptions about them.
I'd hoped that people using Safe would realise that they shouldn't
make such assumptions (just as people should use
use Socket;
foo(AF_INET);
instead of hard coding "2"). Since I'm off away for Christmas soon,
I've done the other patches, although I've left out the version
checking since at least some appears to happen automagically. Using
perl 5.001m together with Safe.so from 5.002 gives:
% perl -I../../lib -le 'use Safe'
Perl lib version (5.002) doesn't match executable version (5.001)
BEGIN failed--compilation aborted at -e line 1.

If considered desirable, I can clean up the mask interface in the
new year. Here's a patch to go on top of the original one. It should
be applied from the perl5.002beta1 directory but only affects
ext/Safe/Safe.xs and ext/Safe/Safe.pm. It turns out that
I<print>, I<sysread> and I<E<lt>HANDLEE<gt>>. Those file operators
is correct--the extra E is part of the podese for > (E<gt>).

Happy Christmas, everyone.

--Malcolm

----------------------------- cut here -----------------------------
*** 1.7 1995/12/20 12:29:36
--- ext/Safe/Safe.pm 1995/12/20 17:47:17
***************
*** 27,36 ****
variables with) the compartment's namespace and only that
data will be visible to code evaluated in the compartment.

! By default, the only variables shared with
! compartments are $_ and @_. This is because otherwise perl
! operators which default to $_ will not work and neither will
! the assignment of arguments to @_ on subroutine entry.

=item an operator mask

--- 27,37 ----
variables with) the compartment's namespace and only that
data will be visible to code evaluated in the compartment.

! By default, the only variables shared with compartments are the
! "underscore" variables $_ and @_ (and, technically, the much less
! frequently used %_, the _ filehandle and so on). This is because
! otherwise perl operators which default to $_ will not work and neither
! will the assignment of arguments to @_ on subroutine entry.

=item an operator mask

***************
*** 48,54 ****
out all operations which give "access to the system" in some sense.
This includes masking off operators such as I<system>, I<open>,
I<chown>, and I<shmget> but does not mask off operators such as
! I<print>, I<sysread> and I<E<lt>HANDLEE<gt>>. Those file operators
are allowed since for the code in the compartment to have access
to a filehandle, the code outside the compartment must have explicitly
placed the filehandle variable inside the compartment.
--- 49,55 ----
out all operations which give "access to the system" in some sense.
This includes masking off operators such as I<system>, I<open>,
I<chown>, and I<shmget> but does not mask off operators such as
! I<print>, I<sysread> and I<E<lt>HANDLE<gt>>. Those file operators
are allowed since for the code in the compartment to have access
to a filehandle, the code outside the compartment must have explicitly
placed the filehandle variable inside the compartment.
***************
*** 72,87 ****
MAXO, each of which is either 0x00 or 0x01. Here, MAXO is the number
of operators in the current version of perl. The subroutine MAXO()
(available for export by package Safe) returns the number of operators
! in the version of perl at the time the Safe extension was B<built>.

- If the Safe module is used as a dynamic extension then it should not
- be used with a future version of perl which has a different number
- of operators. The presence of a 0x01 byte at offset B<n> of the string
- indicates that operator number B<n> should be masked (i.e. disallowed).
- The Safe extension makes available routines for converting from operator
- names to operator numbers (and I<vice versa>) and for converting from a
- list of operator names to the corresponding mask (and I<vice versa>).
-
=head2 Methods in class Safe

To create a new compartment, use
--- 73,87 ----
MAXO, each of which is either 0x00 or 0x01. Here, MAXO is the number
of operators in the current version of perl. The subroutine MAXO()
(available for export by package Safe) returns the number of operators
! in the current version of perl. Note that, unlike the beta versions of
! the Safe extension, this is a reliable count of the number of
! operators in the currently running perl executable. The presence of a
! 0x01 byte at offset B<n> of the string indicates that operator number
! B<n> should be masked (i.e. disallowed). The Safe extension makes
! available routines for converting from operator names to operator
! numbers (and I<vice versa>) and for converting from a list of operator
! names to the corresponding mask (and I<vice versa>).

=head2 Methods in class Safe

To create a new compartment, use
*** 1.6 1995/12/20 12:31:17
--- ext/Safe/Safe.xs 1995/12/20 12:51:42
***************
*** 22,28 ****
Newz(666, op_mask, maxo, char);
SAVEFREEPV(op_mask);
str = SvPV(mask, len);
! for (i = 0; i < maxo && i < len; i++)
op_mask[i] = str[i];
defstash = gv_stashpv(package, TRUE);
endav = (AV*)sv_2mortal((SV*)newAV()); /* Ignore END blocks for now */
--- 22,30 ----
Newz(666, op_mask, maxo, char);
SAVEFREEPV(op_mask);
str = SvPV(mask, len);
! if (maxo != len)
! croak("Bad mask length");
! for (i = 0; i < maxo; i++)
op_mask[i] = str[i];
defstash = gv_stashpv(package, TRUE);
endav = (AV*)sv_2mortal((SV*)newAV()); /* Ignore END blocks for now */
***************
*** 50,56 ****
STRLEN len;
char *maskstr = SvPV(mask, len);
int i;
! for (i = 0; i < len && i < maxo; i++)
if (maskstr[i])
XPUSHs(sv_2mortal(newSVpv(op_name[i], 0)));

--- 52,60 ----
STRLEN len;
char *maskstr = SvPV(mask, len);
int i;
! if (maxo != len)
! croak("Bad mask length");
! for (i = 0; i < maxo; i++)
if (maskstr[i])
XPUSHs(sv_2mortal(newSVpv(op_name[i], 0)));

----------------------------- cut here -----------------------------

--
Malcolm Beattie <mbeattie@sable.ox.ac.uk>
Unix Systems Programmer
Oxford University Computing Services