WISH: support tex fonts
TODO: document transient_for, vt and the grab etc. functionality
-TODO: add warning about perl interpreter and setuid/setgid
- perl: implement additional hook: line_update, add_lines.
- perl: urxvt::line now can set via ->t and ->r.
- perl: much increased functionality, better overlays, popup support
and much much more.
- perl: anyevent support.
+ - perl: run tainted and ignore perl-eval/perl-lib if installed
+ setuid/setgid.
- free the resource database: this plugs a massive memory hole. as a
side effect, it also gets rid of XGetDefault calls.
- free one of the cursors, fixes a small memory leaks.
=item B<perl-eval>: I<string>
-Perl code to be evaluated when all extensions have been registered. See the
-@@RXVT_NAME@@perl(3) manpage.
+Perl code to be evaluated when all extensions have been registered. See
+the @@RXVT_NAME@@perl(3) manpage. Due to security reasons, this resource
+will be ignored when running setuid/setgid.
=item B<perl-lib>: I<path>
Colon-separated list of additional directories that hold extension
scripts. When looking for extensions specified by the C<perl> resource,
@@RXVT_NAME@@ will first look in these directories and then in
-F<@@RXVT_LIBDIR@@/urxvt/perl/>.
+F<@@RXVT_LIBDIR@@/urxvt/perl/>. Due to security reasons, this resource
+will be ignored when running setuid/setgid.
See the @@RXVT_NAME@@perl(3) manpage.
# include <termios.h>
#endif
+#if (defined(HAVE_SETEUID) || defined(HAVE_SETREUID)) && !defined(__CYGWIN32__)
+static uid_t saved_euid;
+static gid_t saved_egid;
+#endif
+
vector<rxvt_term *> rxvt_term::termlist;
static char curlocale[128], savelocale[128];
|| (rs[Rs_perl_ext_2] && *rs[Rs_perl_ext_2])
|| (rs[Rs_perl_eval] && *rs[Rs_perl_eval]))
{
- rxvt_perl.init ();
+ bool tainted = false;
+
+#if (defined(HAVE_SETEUID) || defined(HAVE_SETREUID)) && !defined(__CYGWIN32__)
+ // ignore some perl-related arguments if some bozo installed us set[ug]id
+ if (getuid () != saved_euid || getgid () != saved_egid)
+ {
+ tainted = true;
+
+ if ((rs[Rs_perl_lib] && *rs[Rs_perl_lib])
+ || (rs[Rs_perl_eval] && *rs[Rs_perl_eval]))
+ {
+ rxvt_warn ("running with elevated privileges: ignoring perl-lib and perl-eval.\n");
+ rs[Rs_perl_lib] = 0;
+ rs[Rs_perl_eval] = "our $tainted = 1";
+ }
+ }
+#endif
+ rxvt_perl.init (tainted);
HOOK_INVOKE ((this, HOOK_INIT, DT_END));
}
#endif
void
rxvt_privileges (rxvt_privaction action)
{
-#if (defined(HAVE_SETEUID) || defined(HAVE_SETREUID)) && !defined(__CYGWIN32__)
- static uid_t euid;
- static gid_t egid;
-#endif
-
#if ! defined(__CYGWIN32__)
# if !defined(HAVE_SETEUID) && defined(HAVE_SETREUID)
/* setreuid () is the poor man's setuid (), seteuid () */
setegid (getgid ());
break;
case SAVE:
- euid = geteuid ();
- egid = getegid ();
+ saved_euid = geteuid ();
+ saved_egid = getegid ();
break;
case RESTORE:
- seteuid (euid);
- setegid (egid);
+ seteuid (saved_euid);
+ setegid (saved_egid);
break;
}
# else
bool should_invoke[HOOK_NUM];
- void init ();
+ void init (bool tainted);
bool invoke (rxvt_term *term, hook_type htype, ...);
void line_update (rxvt_term *term);
};
/////////////////////////////////////////////////////////////////////////////
+static SV *
+taint (SV *sv)
+{
+ SvTAINT (sv);
+ return sv;
+}
+
+static SV *
+taint_if (SV *sv, SV *src)
+{
+ if (SvTAINTED (src))
+ SvTAINT (sv);
+
+ return sv;
+}
+
static wchar_t *
sv2wcs (SV *sv)
{
}
void
-rxvt_perl_interp::init ()
+rxvt_perl_interp::init (bool tainted)
{
if (!perl)
{
char *argv[] = {
"",
"-edo '" LIBDIR "/urxvt.pm' or ($@ and die $@) or exit 1",
+ "-T",
};
perl = perl_alloc ();
perl_construct (perl);
- if (perl_parse (perl, xs_init, 2, argv, (char **)NULL)
+ if (perl_parse (perl, xs_init, 2 + !!tainted, argv, (char **)NULL)
|| perl_run (perl))
{
rxvt_warn ("unable to initialize perl-interpreter, continuing without.\n");
break;
case DT_STR:
- XPUSHs (sv_2mortal (newSVpv (va_arg (ap, char *), 0)));
+ XPUSHs (taint (sv_2mortal (newSVpv (va_arg (ap, char *), 0))));
break;
case DT_STR_LEN:
char *str = va_arg (ap, char *);
int len = va_arg (ap, int);
- XPUSHs (sv_2mortal (newSVpvn (str, len)));
+ XPUSHs (taint (sv_2mortal (newSVpvn (str, len))));
}
break;
wchar_t *wstr = va_arg (ap, wchar_t *);
int wlen = va_arg (ap, int);
- XPUSHs (sv_2mortal (wcs2sv (wstr, wlen)));
+ XPUSHs (taint (sv_2mortal (wcs2sv (wstr, wlen))));
}
break;
free (wstr);
- RETVAL = newSVpv (mbstr, 0);
+ RETVAL = taint_if (newSVpv (mbstr, 0), str);
free (mbstr);
}
OUTPUT:
wchar_t *wstr = rxvt_mbstowcs (data, len);
rxvt_pop_locale ();
- RETVAL = wcs2sv (wstr);
+ RETVAL = taint_if (wcs2sv (wstr), octets);
free (wstr);
}
OUTPUT:
for (int col = 0; col < THIS->ncol; col++)
wstr [col] = l.t [col];
- XPUSHs (sv_2mortal (wcs2sv (wstr, THIS->ncol)));
+ XPUSHs (taint (sv_2mortal (wcs2sv (wstr, THIS->ncol))));
delete [] wstr;
}
rxvt_pop_locale ();
- RETVAL = wcs2sv (rstr, r - rstr);
+ RETVAL = taint_if (wcs2sv (rstr, r - rstr), string);
delete [] rstr;
}
else
*r++ = *s;
- RETVAL = wcs2sv (rstr, r - rstr);
+ RETVAL = taint_if (wcs2sv (rstr, r - rstr), text);
delete [] rstr;
}
croak ("requested out-of-bound resource %s+%d,", name, index - rs->value);
if (GIMME_V != G_VOID)
- XPUSHs (THIS->rs [index] ? sv_2mortal (newSVpv (THIS->rs [index], 0)) : &PL_sv_undef);
+ XPUSHs (THIS->rs [index] ? sv_2mortal (taint (newSVpv (THIS->rs [index], 0))) : &PL_sv_undef);
if (newval)
{
PPCODE:
{
if (GIMME_V != G_VOID)
- XPUSHs (sv_2mortal (wcs2sv (THIS->selection.text, THIS->selection.len)));
+ XPUSHs (taint (sv_2mortal (wcs2sv (THIS->selection.text, THIS->selection.len))));
if (newtext)
{
. (do { local $/; <$fh> })
. "\n};\n1";
+ $source =~ /(.*)/s and $source = $1; # untaint
+
eval $source or die "$path: $@";
$pkg