X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=blobdiff_plain;f=perl.c;h=f6c3931d39b202f2eb2629013bcdc6f5a81550ad;hb=1f29050e2eb08bf295614d688f7af7d12afe73f6;hp=57f2938a77319cf9242d4e457d3bf8feba679d3b;hpb=d17ea59705db215628334e7846dd1056ff795f97;p=p5sagit%2Fp5-mst-13.2.git diff --git a/perl.c b/perl.c index 57f2938..f6c3931 100644 --- a/perl.c +++ b/perl.c @@ -1,7 +1,7 @@ /* perl.c * - * Copyright (C) 1993, 1994, 1995, 1996, 1997, 1998, 1999, - * 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007 by Larry Wall and others + * Copyright (C) 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001 + * 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 by Larry Wall and others * * You may distribute under the terms of either the GNU General Public * License or the Artistic License, as specified in the README file. @@ -9,7 +9,11 @@ */ /* - * "A ship then new they built for him/of mithril and of elven glass" --Bilbo + * A ship then new they built for him + * of mithril and of elven-glass + * --from Bilbo's song of EƤrendil + * + * [p.236 of _The Lord of the Rings_, II/i: "Many Meetings"] */ /* This file contains the top-level functions that are used to create, use @@ -18,65 +22,6 @@ * function of the interpreter; that can be found in perlmain.c */ -/* PSz 12 Nov 03 - * - * Be proud that perl(1) may proclaim: - * Setuid Perl scripts are safer than C programs ... - * Do not abandon (deprecate) suidperl. Do not advocate C wrappers. - * - * The flow was: perl starts, notices script is suid, execs suidperl with same - * arguments; suidperl opens script, checks many things, sets itself with - * right UID, execs perl with similar arguments but with script pre-opened on - * /dev/fd/xxx; perl checks script is as should be and does work. This was - * insecure: see perlsec(1) for many problems with this approach. - * - * The "correct" flow should be: perl starts, opens script and notices it is - * suid, checks many things, execs suidperl with similar arguments but with - * script on /dev/fd/xxx; suidperl checks script and /dev/fd/xxx object are - * same, checks arguments match #! line, sets itself with right UID, execs - * perl with same arguments; perl checks many things and does work. - * - * (Opening the script in perl instead of suidperl, we "lose" scripts that - * are readable to the target UID but not to the invoker. Where did - * unreadable scripts work anyway?) - * - * For now, suidperl and perl are pretty much the same large and cumbersome - * program, so suidperl can check its argument list (see comments elsewhere). - * - * References: - * Original bug report: - * http://bugs.perl.org/index.html?req=bug_id&bug_id=20010322.218 - * http://rt.perl.org/rt2/Ticket/Display.html?id=6511 - * Comments and discussion with Debian: - * http://bugs.debian.org/203426 - * http://bugs.debian.org/220486 - * Debian Security Advisory DSA 431-1 (does not fully fix problem): - * http://www.debian.org/security/2004/dsa-431 - * CVE candidate: - * http://cve.mitre.org/cgi-bin/cvename.cgi?name=CAN-2003-0618 - * Previous versions of this patch sent to perl5-porters: - * http://www.mail-archive.com/perl5-porters@perl.org/msg71953.html - * http://www.mail-archive.com/perl5-porters@perl.org/msg75245.html - * http://www.mail-archive.com/perl5-porters@perl.org/msg75563.html - * http://www.mail-archive.com/perl5-porters@perl.org/msg75635.html - * -Paul Szabo - psz@maths.usyd.edu.au http://www.maths.usyd.edu.au:8000/u/psz/ -School of Mathematics and Statistics University of Sydney 2006 Australia - * - */ -/* PSz 13 Nov 03 - * Use truthful, neat, specific error messages. - * Cannot always hide the truth; security must not depend on doing so. - */ - -/* PSz 18 Feb 04 - * Use global(?), thread-local fdscript for easier checks. - * (I do not understand how we could possibly get a thread race: - * do not all threads go through the same initialization? Or in - * fact, are not threads started only after we get the script and - * so know what to do? Oh well, make things super-safe...) - */ - #include "EXTERN.h" #define PERL_IN_PERL_C #include "perl.h" @@ -125,39 +70,29 @@ char *getenv (char *); /* Usually in */ static I32 read_e_script(pTHX_ int idx, SV *buf_sv, int maxlen); -#ifdef DOSUID -# ifdef IAMSUID -/* Drop scriptname */ -# define validate_suid(validarg, scriptname, fdscript, suidscript, linestr_sv, rsfp) S_validate_suid(aTHX_ validarg, fdscript, suidscript, linestr_sv, rsfp) -# else -/* Drop suidscript */ -# define validate_suid(validarg, scriptname, fdscript, suidscript, linestr_sv, rsfp) S_validate_suid(aTHX_ validarg, scriptname, fdscript, linestr_sv, rsfp) -# endif -#else -# ifdef SETUID_SCRIPTS_ARE_SECURE_NOW +#ifdef SETUID_SCRIPTS_ARE_SECURE_NOW /* Drop everything. Heck, don't even try to call it */ -# define validate_suid(validarg, scriptname, fdscript, suidscript, linestr_sv, rsfp) NOOP -# else +# define validate_suid(validarg, scriptname, fdscript, suidscript, linestr_sv, rsfp) NOOP +#else /* Drop almost everything */ -# define validate_suid(validarg, scriptname, fdscript, suidscript, linestr_sv, rsfp) S_validate_suid(aTHX_ rsfp) -# endif +# define validate_suid(validarg, scriptname, fdscript, suidscript, linestr_sv, rsfp) S_validate_suid(aTHX_ rsfp) #endif #define CALL_BODY_EVAL(myop) \ if (PL_op == (myop)) \ - PL_op = Perl_pp_entereval(aTHX); \ + PL_op = PL_ppaddr[OP_ENTEREVAL](aTHX); \ if (PL_op) \ CALLRUNOPS(aTHX); #define CALL_BODY_SUB(myop) \ if (PL_op == (myop)) \ - PL_op = Perl_pp_entersub(aTHX); \ + PL_op = PL_ppaddr[OP_ENTERSUB](aTHX); \ if (PL_op) \ CALLRUNOPS(aTHX); #define CALL_LIST_BODY(cv) \ PUSHMARK(PL_stack_sp); \ - call_sv((SV*)(cv), G_EVAL|G_DISCARD); + call_sv(MUTABLE_SV((cv)), G_EVAL|G_DISCARD); static void S_init_tls_and_interp(PerlInterpreter *my_perl) @@ -367,9 +302,9 @@ perl_construct(pTHXx) PL_fdpid = newAV(); /* for remembering popen pids by fd */ PL_modglobal = newHV(); /* pointers to per-interpreter module globals */ PL_errors = newSVpvs(""); - sv_setpvn(PERL_DEBUG_PAD(0), "", 0); /* For regex debugging. */ - sv_setpvn(PERL_DEBUG_PAD(1), "", 0); /* ext/re needs these */ - sv_setpvn(PERL_DEBUG_PAD(2), "", 0); /* even without DEBUGGING. */ + sv_setpvs(PERL_DEBUG_PAD(0), ""); /* For regex debugging. */ + sv_setpvs(PERL_DEBUG_PAD(1), ""); /* ext/re needs these */ + sv_setpvs(PERL_DEBUG_PAD(2), ""); /* even without DEBUGGING. */ #ifdef USE_ITHREADS /* First entry is a list of empty elements. It needs to be initialised else all hell breaks loose in S_find_uninit_var(). */ @@ -457,6 +392,10 @@ perl_construct(pTHXx) PL_timesbase.tms_cstime = 0; #endif + PL_registered_mros = newHV(); + /* Start with 1 bucket, for DFS. It's unlikely we'll need more. */ + HvMAX(PL_registered_mros) = 0; + ENTER; } @@ -662,7 +601,7 @@ perl_destruct(pTHXx) int f; const char *where; /* Our success message is an integer 0, and a char 0 */ - static const char success[sizeof(int) + 1]; + static const char success[sizeof(int) + 1] = {0}; close(fd[0]); @@ -845,6 +784,8 @@ perl_destruct(pTHXx) PL_exitlist = NULL; PL_exitlistlen = 0; + SvREFCNT_dec(PL_registered_mros); + /* jettison our possibly duplicated environment */ /* if PERL_USE_SAFE_PUTENV is defined environ will not have been copied * so we certainly shouldn't free it here @@ -901,7 +842,7 @@ perl_destruct(pTHXx) PL_regex_pad = NULL; #endif - SvREFCNT_dec((SV*) PL_stashcache); + SvREFCNT_dec(MUTABLE_SV(PL_stashcache)); PL_stashcache = NULL; /* loosen bonds of global variables */ @@ -942,8 +883,8 @@ perl_destruct(pTHXx) /* magical thingies */ - SvREFCNT_dec(PL_ofs_sv); /* $, */ - PL_ofs_sv = NULL; + SvREFCNT_dec(PL_ofsgv); /* *, */ + PL_ofsgv = NULL; SvREFCNT_dec(PL_ors_sv); /* $\ */ PL_ors_sv = NULL; @@ -1213,7 +1154,7 @@ perl_destruct(pTHXx) SV* sv; register SV* svend; - for (sva = PL_sv_arenaroot; sva; sva = (SV*)SvANY(sva)) { + for (sva = PL_sv_arenaroot; sva; sva = MUTABLE_SV(SvANY(sva))) { svend = &sva[SvREFCNT(sva)]; for (sv = sva + 1; sv < svend; ++sv) { if (SvTYPE(sv) != SVTYPEMASK) { @@ -1514,11 +1455,6 @@ perl_parse(pTHXx_ XSINIT_t xsinit, int argc, char **argv, char **env) PERL_UNUSED_ARG(my_perl); #endif -#ifdef SETUID_SCRIPTS_ARE_SECURE_NOW_AND_IAMSUID - Perl_croak(aTHX_ "suidperl is no longer needed since the kernel can now " - "execute\nsetuid perl scripts securely.\n"); -#endif - #if defined(USE_HASH_SEED) || defined(USE_HASH_SEED_EXPLICIT) /* [perl #22371] Algorimic Complexity Attack on Perl 5.6.1, 5.8.0 * This MUST be done before any hash stores or fetches take place. @@ -1699,9 +1635,6 @@ S_parse_body(pTHX_ char **env, XSINIT_t xsinit) char **argv = PL_origargv; const char *scriptname = NULL; VOL bool dosearch = FALSE; -#ifdef DOSUID - const char *validarg = ""; -#endif register SV *sv; register char c; const char *cddir = NULL; @@ -1712,7 +1645,7 @@ S_parse_body(pTHX_ char **env, XSINIT_t xsinit) bool add_read_e_script = FALSE; SvGROW(linestr_sv, 80); - sv_setpvn(linestr_sv,"",0); + sv_setpvs(linestr_sv,""); sv = newSVpvs(""); /* first used for -I flags */ SAVEFREESV(sv); @@ -1723,18 +1656,6 @@ S_parse_body(pTHX_ char **env, XSINIT_t xsinit) for (argc--,argv++; argc > 0; argc--,argv++) { if (argv[0][0] != '-' || !argv[0][1]) break; -#ifdef DOSUID - if (*validarg) - validarg = " PHOOEY "; - else - validarg = argv[0]; - /* - * Can we rely on the kernel to start scripts with argv[1] set to - * contain all #! line switches (the whole line)? (argv[0] is set to - * the interpreter name, argv[2] to the script name; argv[3] and - * above may contain other arguments.) - */ -#endif s = argv[0]+1; reswitch: switch ((c = *s)) { @@ -1822,7 +1743,7 @@ S_parse_body(pTHX_ char **env, XSINIT_t xsinit) if (s && *s) { STRLEN len = strlen(s); const char * const p = savepvn(s, len); - incpush(p, TRUE, TRUE, FALSE, FALSE); + incpush(p, TRUE, TRUE, FALSE, FALSE, FALSE); sv_catpvs(sv, "-I"); sv_catpvn(sv, p, len); sv_catpvs(sv, " "); @@ -1872,12 +1793,18 @@ S_parse_body(pTHX_ char **env, XSINIT_t xsinit) # ifdef PERL_MEM_LOG_TIMESTAMP " PERL_MEM_LOG_TIMESTAMP" # endif +# ifdef PERL_USE_DEVEL + " PERL_USE_DEVEL" +# endif # ifdef PERL_USE_SAFE_PUTENV " PERL_USE_SAFE_PUTENV" # endif # ifdef USE_SITECUSTOMIZE " USE_SITECUSTOMIZE" # endif +# ifdef USE_FAST_STDIO + " USE_FAST_STDIO" +# endif , 0); sv_catpv(opts_prog, PL_bincompat_options); @@ -1888,7 +1815,6 @@ S_parse_body(pTHX_ char **env, XSINIT_t xsinit) #else sv_catpvs(opts_prog,"\"\\nCharacteristics of this binary (from libperl): \\n"); #endif - sv_catpvs(opts_prog," Compile-time options: $_\\n\","); #if defined(LOCAL_PATCH_COUNT) @@ -1899,7 +1825,7 @@ S_parse_body(pTHX_ char **env, XSINIT_t xsinit) for (i = 1; i <= LOCAL_PATCH_COUNT; i++) { if (PL_localpatches[i]) Perl_sv_catpvf(aTHX_ opts_prog,"q%c\t%s\n%c,", - 0, PL_localpatches[i], 0); + 0, PL_localpatches[i], 0); } } #endif @@ -1977,7 +1903,6 @@ S_parse_body(pTHX_ char **env, XSINIT_t xsinit) #endif (s = PerlEnv_getenv("PERL5OPT"))) { - const char *popt = s; while (isSPACE(*s)) s++; if (*s == '-' && *(s+1) == 'T') { @@ -1988,7 +1913,7 @@ S_parse_body(pTHX_ char **env, XSINIT_t xsinit) else { char *popt_copy = NULL; while (s && *s) { - char *d; + const char *d; while (isSPACE(*s)) s++; if (*s == '-') { @@ -2004,9 +1929,9 @@ S_parse_body(pTHX_ char **env, XSINIT_t xsinit) while (++s && *s) { if (isSPACE(*s)) { if (!popt_copy) { - popt_copy = SvPVX(sv_2mortal(newSVpv(popt,0))); - s = popt_copy + (s - popt); - d = popt_copy + (d - popt); + popt_copy = SvPVX(sv_2mortal(newSVpv(d,0))); + s = popt_copy + (s - d); + d = popt_copy; } *s++ = '\0'; break; @@ -2056,13 +1981,10 @@ S_parse_body(pTHX_ char **env, XSINIT_t xsinit) { bool suidscript = FALSE; -#ifdef DOSUID - const int fdscript = -#endif - open_script(scriptname, dosearch, &suidscript, &rsfp); + open_script(scriptname, dosearch, &suidscript, &rsfp); validate_suid(validarg, scriptname, fdscript, suidscript, - linestr_sv, rsfp); + linestr_sv, rsfp); #ifndef PERL_MICRO # if defined(SIGCHLD) || defined(SIGCLD) @@ -2098,7 +2020,7 @@ S_parse_body(pTHX_ char **env, XSINIT_t xsinit) } } - PL_main_cv = PL_compcv = (CV*)newSV_type(SVt_PVCV); + PL_main_cv = PL_compcv = MUTABLE_CV(newSV_type(SVt_PVCV)); CvUNIQUE_on(PL_compcv); CvPADLIST(PL_compcv) = pad_new(0); @@ -2168,12 +2090,12 @@ S_parse_body(pTHX_ char **env, XSINIT_t xsinit) U32 out = PL_unicode & PERL_UNICODE_OUT_FLAG; if (in) { if (out) - sv_setpvn(sv, ":utf8\0:utf8", 11); + sv_setpvs(sv, ":utf8\0:utf8"); else - sv_setpvn(sv, ":utf8\0", 6); + sv_setpvs(sv, ":utf8\0"); } else if (out) - sv_setpvn(sv, "\0:utf8", 6); + sv_setpvs(sv, "\0:utf8"); SvSETMAGIC(sv); } } @@ -2401,21 +2323,22 @@ S_run_body(pTHX_ I32 oldscope) =for apidoc p||get_sv -Returns the SV of the specified Perl scalar. If C is set and the -Perl variable does not exist then it will be created. If C is not -set and the variable does not exist then NULL is returned. +Returns the SV of the specified Perl scalar. C are passed to +C. If C is set and the +Perl variable does not exist then it will be created. If C is zero +and the variable does not exist then NULL is returned. =cut */ SV* -Perl_get_sv(pTHX_ const char *name, I32 create) +Perl_get_sv(pTHX_ const char *name, I32 flags) { GV *gv; PERL_ARGS_ASSERT_GET_SV; - gv = gv_fetchpv(name, create, SVt_PV); + gv = gv_fetchpv(name, flags, SVt_PV); if (gv) return GvSV(gv); return NULL; @@ -2426,21 +2349,22 @@ Perl_get_sv(pTHX_ const char *name, I32 create) =for apidoc p||get_av -Returns the AV of the specified Perl array. If C is set and the -Perl variable does not exist then it will be created. If C is not -set and the variable does not exist then NULL is returned. +Returns the AV of the specified Perl array. C are passed to +C. If C is set and the +Perl variable does not exist then it will be created. If C is zero +and the variable does not exist then NULL is returned. =cut */ AV* -Perl_get_av(pTHX_ const char *name, I32 create) +Perl_get_av(pTHX_ const char *name, I32 flags) { - GV* const gv = gv_fetchpv(name, create, SVt_PVAV); + GV* const gv = gv_fetchpv(name, flags, SVt_PVAV); PERL_ARGS_ASSERT_GET_AV; - if (create) + if (flags) return GvAVn(gv); if (gv) return GvAV(gv); @@ -2452,21 +2376,22 @@ Perl_get_av(pTHX_ const char *name, I32 create) =for apidoc p||get_hv -Returns the HV of the specified Perl hash. If C is set and the -Perl variable does not exist then it will be created. If C is not -set and the variable does not exist then NULL is returned. +Returns the HV of the specified Perl hash. C are passed to +C. If C is set and the +Perl variable does not exist then it will be created. If C is zero +and the variable does not exist then NULL is returned. =cut */ HV* -Perl_get_hv(pTHX_ const char *name, I32 create) +Perl_get_hv(pTHX_ const char *name, I32 flags) { - GV* const gv = gv_fetchpv(name, create, SVt_PVHV); + GV* const gv = gv_fetchpv(name, flags, SVt_PVHV); PERL_ARGS_ASSERT_GET_HV; - if (create) + if (flags) return GvHVn(gv); if (gv) return GvHV(gv); @@ -2512,6 +2437,8 @@ Perl_get_cvn_flags(pTHX_ const char *name, STRLEN len, I32 flags) return NULL; } +/* Nothing in core calls this now, but we can't replace it with a macro and + move it to mathoms.c as a macro would evaluate name twice. */ CV* Perl_get_cv(pTHX_ const char *name, I32 flags) { @@ -2570,7 +2497,7 @@ Perl_call_pv(pTHX_ const char *sub_name, I32 flags) { PERL_ARGS_ASSERT_CALL_PV; - return call_sv((SV*)get_cv(sub_name, TRUE), flags); + return call_sv(MUTABLE_SV(get_cv(sub_name, GV_ADD)), flags); } /* @@ -2647,7 +2574,7 @@ Perl_call_sv(pTHX_ SV *sv, VOL I32 flags) && (PL_DBcv || (PL_DBcv = GvCV(PL_DBsub))) /* Try harder, since this may have been a sighandler, thus * curstash may be meaningless. */ - && (SvTYPE(sv) != SVt_PVCV || CvSTASH((CV*)sv) != PL_debstash) + && (SvTYPE(sv) != SVt_PVCV || CvSTASH((const CV *)sv) != PL_debstash) && !(flags & G_NODEBUG)) PL_op->op_private |= OPpENTERSUB_DB; @@ -2680,8 +2607,9 @@ Perl_call_sv(pTHX_ SV *sv, VOL I32 flags) redo_body: CALL_BODY_SUB((OP*)&myop); retval = PL_stack_sp - (PL_stack_base + oldmark); - if (!(flags & G_KEEPERR)) - sv_setpvn(ERRSV,"",0); + if (!(flags & G_KEEPERR)) { + CLEAR_ERRSV(); + } break; case 1: STATUS_ALL_FAILURE; @@ -2781,8 +2709,9 @@ Perl_eval_sv(pTHX_ SV *sv, I32 flags) redo_body: CALL_BODY_EVAL((OP*)&myop); retval = PL_stack_sp - (PL_stack_base + oldmark); - if (!(flags & G_KEEPERR)) - sv_setpvn(ERRSV,"",0); + if (!(flags & G_KEEPERR)) { + CLEAR_ERRSV(); + } break; case 1: STATUS_ALL_FAILURE; @@ -2848,7 +2777,7 @@ Perl_eval_pv(pTHX_ const char *p, I32 croak_on_error) PUTBACK; if (croak_on_error && SvTRUE(ERRSV)) { - Perl_croak(aTHX_ SvPVx_nolen_const(ERRSV)); + Perl_croak(aTHX_ "%s", SvPVx_nolen_const(ERRSV)); } return sv; @@ -2884,17 +2813,6 @@ Perl_require_pv(pTHX_ const char *pv) POPSTACK; } -void -Perl_magicname(pTHX_ const char *sym, const char *name, I32 namlen) -{ - register GV * const gv = gv_fetchpv(sym, GV_ADD, SVt_PV); - - PERL_ARGS_ASSERT_MAGICNAME; - - if (gv) - sv_magic(GvSV(gv), (SV*)gv, PERL_MAGIC_sv, name, namlen); -} - STATIC void S_usage(pTHX_ const char *name) /* XXX move this out into a module ? */ { @@ -2960,7 +2878,7 @@ Perl_get_debug_opts(pTHX_ const char **s, bool givehelp) " o Method and overloading resolution", " c String/numeric conversions", " P Print profiling info, source file input state", - " m Memory allocation", + " m Memory and SV allocation", " f Format processing", " r Regular expression parsing and execution", " x Syntax tree dump", @@ -3062,7 +2980,7 @@ Perl_moreswitches(pTHX_ const char *s) PL_rs = newSVpvn(&ch, 1); } } - sv_setsv(get_sv("/", TRUE), PL_rs); + sv_setsv(get_sv("/", GV_ADD), PL_rs); return s + numlen; } case 'C': @@ -3175,7 +3093,7 @@ Perl_moreswitches(pTHX_ const char *s) p++; } while (*p && *p != '-'); e = savepvn(s, e-s); - incpush(e, TRUE, TRUE, FALSE, FALSE); + incpush(e, TRUE, TRUE, FALSE, FALSE, TRUE); Safefree(e); s = p; if (*s == '-') @@ -3240,7 +3158,7 @@ Perl_moreswitches(pTHX_ const char *s) if (colon) Perl_croak(aTHX_ "Invalid module name %.*s with -%c option: " "contains single ':'", - s - start, start, option); + (int)(s - start), start, option); end = s + strlen(s); if (*s != '=') { sv_catpvn(sv, start, end - start); @@ -3301,14 +3219,30 @@ Perl_moreswitches(pTHX_ const char *s) if (!sv_derived_from(PL_patchlevel, "version")) upg_version(PL_patchlevel, TRUE); #if !defined(DGUX) - PerlIO_printf(PerlIO_stdout(), - Perl_form(aTHX_ "\nThis is perl, %"SVf + { + SV* level= vstringify(PL_patchlevel); #ifdef PERL_PATCHNUM - " DEVEL" STRINGIFY(PERL_PATCHNUM) -#endif - " built for %s", - SVfARG(vstringify(PL_patchlevel)), - ARCHNAME)); +# ifdef PERL_GIT_UNCOMMITTED_CHANGES + SV *num = newSVpvs(PERL_PATCHNUM "*"); +# else + SV *num = newSVpvs(PERL_PATCHNUM); +# endif + + if (sv_len(num)>=sv_len(level) && strnEQ(SvPV_nolen(num),SvPV_nolen(level),sv_len(level))) { + SvREFCNT_dec(level); + level= num; + } else { + Perl_sv_catpvf(aTHX_ level, " (%"SVf")", num); + SvREFCNT_dec(num); + } + #endif + PerlIO_printf(PerlIO_stdout(), + "\nThis is perl, %"SVf + " built for %s", + level, + ARCHNAME); + SvREFCNT_dec(level); + } #else /* DGUX */ /* Adjust verbose output as in the perl that ships with the DG/UX OS from EMC */ PerlIO_printf(PerlIO_stdout(), @@ -3321,7 +3255,6 @@ Perl_moreswitches(pTHX_ const char *s) Perl_form(aTHX_ " OS Specific Release: %s\n", OSVERS)); #endif /* !DGUX */ - #if defined(LOCAL_PATCH_COUNT) if (LOCAL_PATCH_COUNT > 0) PerlIO_printf(PerlIO_stdout(), @@ -3332,7 +3265,7 @@ Perl_moreswitches(pTHX_ const char *s) #endif PerlIO_printf(PerlIO_stdout(), - "\n\nCopyright 1987-2007, Larry Wall\n"); + "\n\nCopyright 1987-2009, Larry Wall\n"); #ifdef MACOS_TRADITIONAL PerlIO_printf(PerlIO_stdout(), "\nMac OS port Copyright 1991-2002, Matthias Neeracher;\n" @@ -3430,8 +3363,10 @@ Internet, point your browser at http://www.perl.org/, the Perl Home Page.\n\n"); return s; case '*': case ' ': - if (s[1] == '-') /* Additional switches on #! line. */ - return s+2; + while( *s == ' ' ) + ++s; + if (s[0] == '-') /* Additional switches on #! line. */ + return s+1; break; case '-': case 0: @@ -3540,7 +3475,7 @@ S_init_main_stash(pTHX) of the SvREFCNT_dec, only to add it again with hv_name_set */ SvREFCNT_dec(GvHV(gv)); hv_name_set(PL_defstash, "main", 4, 0); - GvHV(gv) = (HV*)SvREFCNT_inc_simple(PL_defstash); + GvHV(gv) = MUTABLE_HV(SvREFCNT_inc_simple(PL_defstash)); SvREADONLY_on(gv); PL_incgv = gv_HVadd(gv_AVadd(gv_fetchpvs("INC", GV_ADD|GV_NOTQUAL, SVt_PVAV))); @@ -3560,14 +3495,14 @@ S_init_main_stash(pTHX) gv_SVadd(PL_errgv); #endif sv_grow(ERRSV, 240); /* Preallocate - for immediate signals. */ - sv_setpvn(ERRSV, "", 0); + CLEAR_ERRSV(); PL_curstash = PL_defstash; CopSTASH_set(&PL_compiling, PL_defstash); PL_debstash = GvHV(gv_fetchpvs("DB::", GV_ADDMULTI, SVt_PVHV)); PL_globalstash = GvHV(gv_fetchpvs("CORE::GLOBAL::", GV_ADDMULTI, SVt_PVHV)); /* We must init $/ before switches are processed. */ - sv_setpvn(get_sv("/", TRUE), "\n", 1); + sv_setpvs(get_sv("/", GV_ADD), "\n"); } STATIC int @@ -3631,23 +3566,6 @@ S_open_script(pTHX_ const char *scriptname, bool dosearch, fcntl(PerlIO_fileno(*rsfpp),F_SETFD,1); # endif } -#ifdef IAMSUID - else { - Perl_croak(aTHX_ "sperl needs fd script\n" - "You should not call sperl directly; do you need to " - "change a #! line\nfrom sperl to perl?\n"); - -/* PSz 11 Nov 03 - * Do not open (or do other fancy stuff) while setuid. - * Perl does the open, and hands script to suidperl on a fd; - * suidperl only does some checks, sets up UIDs and re-execs - * perl with that fd as it has always done. - */ - } - if (*suidscript) { - Perl_croak(aTHX_ "suidperl needs (suid) fd script\n"); - } -#else /* IAMSUID */ else if (!*scriptname) { forbid_setid(0, *suidscript); *rsfpp = PerlIO_stdin(); @@ -3700,7 +3618,6 @@ S_open_script(pTHX_ const char *scriptname, bool dosearch, fcntl(PerlIO_fileno(*rsfpp),F_SETFD,1); # endif } -#endif /* IAMSUID */ if (!*rsfpp) { /* PSz 16 Sep 03 Keep neat error message */ if (PL_e_script) @@ -3719,532 +3636,18 @@ S_open_script(pTHX_ const char *scriptname, bool dosearch, * I_MNTENT HAS_GETMNTENT HAS_HASMNTOPT * here so that metaconfig picks them up. */ -#ifdef IAMSUID -STATIC int -S_fd_on_nosuid_fs(pTHX_ int fd) -{ -/* PSz 27 Feb 04 - * We used to do this as "plain" user (after swapping UIDs with setreuid); - * but is needed also on machines without setreuid. - * Seems safe enough to run as root. - */ - int check_okay = 0; /* able to do all the required sys/libcalls */ - int on_nosuid = 0; /* the fd is on a nosuid fs */ - /* PSz 12 Nov 03 - * Need to check noexec also: nosuid might not be set, the average - * sysadmin would say that nosuid is irrelevant once he sets noexec. - */ - int on_noexec = 0; /* the fd is on a noexec fs */ - -/* - * Preferred order: fstatvfs(), fstatfs(), ustat()+getmnt(), getmntent(). - * fstatvfs() is UNIX98. - * fstatfs() is 4.3 BSD. - * ustat()+getmnt() is pre-4.3 BSD. - * getmntent() is O(number-of-mounted-filesystems) and can hang on - * an irrelevant filesystem while trying to reach the right one. - */ - -#undef FD_ON_NOSUID_CHECK_OKAY /* found the syscalls to do the check? */ - -# if !defined(FD_ON_NOSUID_CHECK_OKAY) && \ - defined(HAS_FSTATVFS) -# define FD_ON_NOSUID_CHECK_OKAY - struct statvfs stfs; - - check_okay = fstatvfs(fd, &stfs) == 0; - on_nosuid = check_okay && (stfs.f_flag & ST_NOSUID); -#ifdef ST_NOEXEC - /* ST_NOEXEC certainly absent on AIX 5.1, and doesn't seem to be documented - on platforms where it is present. */ - on_noexec = check_okay && (stfs.f_flag & ST_NOEXEC); -#endif -# endif /* fstatvfs */ - -# if !defined(FD_ON_NOSUID_CHECK_OKAY) && \ - defined(PERL_MOUNT_NOSUID) && \ - defined(PERL_MOUNT_NOEXEC) && \ - defined(HAS_FSTATFS) && \ - defined(HAS_STRUCT_STATFS) && \ - defined(HAS_STRUCT_STATFS_F_FLAGS) -# define FD_ON_NOSUID_CHECK_OKAY - struct statfs stfs; - - check_okay = fstatfs(fd, &stfs) == 0; - on_nosuid = check_okay && (stfs.f_flags & PERL_MOUNT_NOSUID); - on_noexec = check_okay && (stfs.f_flags & PERL_MOUNT_NOEXEC); -# endif /* fstatfs */ - -# if !defined(FD_ON_NOSUID_CHECK_OKAY) && \ - defined(PERL_MOUNT_NOSUID) && \ - defined(PERL_MOUNT_NOEXEC) && \ - defined(HAS_FSTAT) && \ - defined(HAS_USTAT) && \ - defined(HAS_GETMNT) && \ - defined(HAS_STRUCT_FS_DATA) && \ - defined(NOSTAT_ONE) -# define FD_ON_NOSUID_CHECK_OKAY - Stat_t fdst; - - if (fstat(fd, &fdst) == 0) { - struct ustat us; - if (ustat(fdst.st_dev, &us) == 0) { - struct fs_data fsd; - /* NOSTAT_ONE here because we're not examining fields which - * vary between that case and STAT_ONE. */ - if (getmnt((int*)0, &fsd, (int)0, NOSTAT_ONE, us.f_fname) == 0) { - size_t cmplen = sizeof(us.f_fname); - if (sizeof(fsd.fd_req.path) < cmplen) - cmplen = sizeof(fsd.fd_req.path); - if (strnEQ(fsd.fd_req.path, us.f_fname, cmplen) && - fdst.st_dev == fsd.fd_req.dev) { - check_okay = 1; - on_nosuid = fsd.fd_req.flags & PERL_MOUNT_NOSUID; - on_noexec = fsd.fd_req.flags & PERL_MOUNT_NOEXEC; - } - } - } - } -# endif /* fstat+ustat+getmnt */ - -# if !defined(FD_ON_NOSUID_CHECK_OKAY) && \ - defined(HAS_GETMNTENT) && \ - defined(HAS_HASMNTOPT) && \ - defined(MNTOPT_NOSUID) && \ - defined(MNTOPT_NOEXEC) -# define FD_ON_NOSUID_CHECK_OKAY - FILE *mtab = fopen("/etc/mtab", "r"); - struct mntent *entry; - Stat_t stb, fsb; - - if (mtab && (fstat(fd, &stb) == 0)) { - while (entry = getmntent(mtab)) { - if (stat(entry->mnt_dir, &fsb) == 0 - && fsb.st_dev == stb.st_dev) - { - /* found the filesystem */ - check_okay = 1; - if (hasmntopt(entry, MNTOPT_NOSUID)) - on_nosuid = 1; - if (hasmntopt(entry, MNTOPT_NOEXEC)) - on_noexec = 1; - break; - } /* A single fs may well fail its stat(). */ - } - } - if (mtab) - fclose(mtab); -# endif /* getmntent+hasmntopt */ - - if (!check_okay) - Perl_croak(aTHX_ "Can't check filesystem of script \"%s\" for nosuid/noexec", PL_origfilename); - if (on_nosuid) - Perl_croak(aTHX_ "Setuid script \"%s\" on nosuid filesystem", PL_origfilename); - if (on_noexec) - Perl_croak(aTHX_ "Setuid script \"%s\" on noexec filesystem", PL_origfilename); - return ((!check_okay) || on_nosuid || on_noexec); -} -#endif /* IAMSUID */ - -#ifdef DOSUID -STATIC void -S_validate_suid(pTHX_ const char *validarg, -# ifndef IAMSUID - const char *scriptname, -# endif - int fdscript, -# ifdef IAMSUID - bool suidscript, -# endif - SV *linestr_sv, PerlIO *rsfp) -{ - dVAR; - const char *s, *s2; - - PERL_ARGS_ASSERT_VALIDATE_SUID; - - /* do we need to emulate setuid on scripts? */ - - /* This code is for those BSD systems that have setuid #! scripts disabled - * in the kernel because of a security problem. Merely defining DOSUID - * in perl will not fix that problem, but if you have disabled setuid - * scripts in the kernel, this will attempt to emulate setuid and setgid - * on scripts that have those now-otherwise-useless bits set. The setuid - * root version must be called suidperl or sperlN.NNN. If regular perl - * discovers that it has opened a setuid script, it calls suidperl with - * the same argv that it had. If suidperl finds that the script it has - * just opened is NOT setuid root, it sets the effective uid back to the - * uid. We don't just make perl setuid root because that loses the - * effective uid we had before invoking perl, if it was different from the - * uid. - * PSz 27 Feb 04 - * Description/comments above do not match current workings: - * suidperl must be hardlinked to sperlN.NNN (that is what we exec); - * suidperl called with script open and name changed to /dev/fd/N/X; - * suidperl croaks if script is not setuid; - * making perl setuid would be a huge security risk (and yes, that - * would lose any euid we might have had). - * - * DOSUID must be defined in both perl and suidperl, and IAMSUID must - * be defined in suidperl only. suidperl must be setuid root. The - * Configure script will set this up for you if you want it. - */ - - if (PerlLIO_fstat(PerlIO_fileno(rsfp),&PL_statbuf) < 0) /* normal stat is insecure */ - Perl_croak(aTHX_ "Can't stat script \"%s\"",PL_origfilename); - if (PL_statbuf.st_mode & (S_ISUID|S_ISGID)) { - I32 len; - const char *linestr; - const char *s_end; - -# ifdef IAMSUID - if (fdscript < 0 || !suidscript) - Perl_croak(aTHX_ "Need (suid) fdscript in suidperl\n"); /* We already checked this */ - /* PSz 11 Nov 03 - * Since the script is opened by perl, not suidperl, some of these - * checks are superfluous. Leaving them in probably does not lower - * security(?!). - */ - /* PSz 27 Feb 04 - * Do checks even for systems with no HAS_SETREUID. - * We used to swap, then re-swap UIDs with -# ifdef HAS_SETREUID - if (setreuid(PL_euid,PL_uid) < 0 - || PerlProc_getuid() != PL_euid || PerlProc_geteuid() != PL_uid) - Perl_croak(aTHX_ "Can't swap uid and euid"); -# endif -# ifdef HAS_SETREUID - if (setreuid(PL_uid,PL_euid) < 0 - || PerlProc_getuid() != PL_uid || PerlProc_geteuid() != PL_euid) - Perl_croak(aTHX_ "Can't reswap uid and euid"); -# endif - */ - /* On this access check to make sure the directories are readable, - * there is actually a small window that the user could use to make - * filename point to an accessible directory. So there is a faint - * chance that someone could execute a setuid script down in a - * non-accessible directory. I don't know what to do about that. - * But I don't think it's too important. The manual lies when - * it says access() is useful in setuid programs. - * - * So, access() is pretty useless... but not harmful... do anyway. - */ - if (PerlLIO_access(CopFILE(PL_curcop),1)) { /*double check*/ - Perl_croak(aTHX_ "Can't access() script\n"); - } - - /* If we can swap euid and uid, then we can determine access rights - * with a simple stat of the file, and then compare device and - * inode to make sure we did stat() on the same file we opened. - * Then we just have to make sure he or she can execute it. - * - * PSz 24 Feb 04 - * As the script is opened by perl, not suidperl, we do not need to - * care much about access rights. - * - * The 'script changed' check is needed, or we can get lied to - * about $0 with e.g. - * suidperl /dev/fd/4//bin/x 4 4000) - Perl_croak(aTHX_ "Very long #! line"); - /* Allow more than a single space after #! */ - while (isSPACE(*s)) s++; - /* Sanity check on buffer end */ - while ((*s) && !isSPACE(*s)) s++; - for (s2 = s; (s2 > linestr && - (isDIGIT(s2[-1]) || s2[-1] == '.' || s2[-1] == '_' - || s2[-1] == '-')); s2--) ; - /* Sanity check on buffer start */ - if ( (s2-4 < linestr || strnNE(s2-4,"perl",4)) && - (s-9 < linestr || strnNE(s-9,"perl",4)) ) - Perl_croak(aTHX_ "Not a perl script"); - while (*s == ' ' || *s == '\t') s++; - /* - * #! arg must be what we saw above. They can invoke it by - * mentioning suidperl explicitly, but they may not add any strange - * arguments beyond what #! says if they do invoke suidperl that way. - */ - /* - * The way validarg was set up, we rely on the kernel to start - * scripts with argv[1] set to contain all #! line switches (the - * whole line). - */ - /* - * Check that we got all the arguments listed in the #! line (not - * just that there are no extraneous arguments). Might not matter - * much, as switches from #! line seem to be acted upon (also), and - * so may be checked and trapped in perl. But, security checks must - * be done in suidperl and not deferred to perl. Note that suidperl - * does not get around to parsing (and checking) the switches on - * the #! line (but execs perl sooner). - * Allow (require) a trailing newline (which may be of two - * characters on some architectures?) (but no other trailing - * whitespace). - */ - len = strlen(validarg); - if (strEQ(validarg," PHOOEY ") || - strnNE(s,validarg,len) || !isSPACE(s[len]) || - !((s_end - s) == len+1 - || ((s_end - s) == len+2 && isSPACE(s[len+1])))) - Perl_croak(aTHX_ "Args must match #! line"); - -# ifndef IAMSUID - if (fdscript < 0 && - PL_euid != PL_uid && (PL_statbuf.st_mode & S_ISUID) && - PL_euid == PL_statbuf.st_uid) - if (!PL_do_undump) - Perl_croak(aTHX_ "YOU HAVEN'T DISABLED SET-ID SCRIPTS IN THE KERNEL YET!\n\ -FIX YOUR KERNEL, OR PUT A C WRAPPER AROUND THIS SCRIPT!\n"); -# endif /* IAMSUID */ - - if (fdscript < 0 && - PL_euid) { /* oops, we're not the setuid root perl */ - /* PSz 18 Feb 04 - * When root runs a setuid script, we do not go through the same - * steps of execing sperl and then perl with fd scripts, but - * simply set up UIDs within the same perl invocation; so do - * not have the same checks (on options, whatever) that we have - * for plain users. No problem really: would have to be a script - * that does not actually work for plain users; and if root is - * foolish and can be persuaded to run such an unsafe script, he - * might run also non-setuid ones, and deserves what he gets. - * - * Or, we might drop the PL_euid check above (and rely just on - * fdscript to avoid loops), and do the execs - * even for root. - */ -# ifndef IAMSUID - int which; - /* PSz 11 Nov 03 - * Pass fd script to suidperl. - * Exec suidperl, substituting fd script for scriptname. - * Pass script name as "subdir" of fd, which perl will grok; - * in fact will use that to distinguish this from "normal" - * usage, see comments above. - */ - PerlIO_rewind(rsfp); - PerlLIO_lseek(PerlIO_fileno(rsfp),(Off_t)0,0); /* just in case rewind didn't */ - /* PSz 27 Feb 04 Sanity checks on scriptname */ - if ((!scriptname) || (!*scriptname) ) { - Perl_croak(aTHX_ "No setuid script name\n"); - } - if (*scriptname == '-') { - Perl_croak(aTHX_ "Setuid script name may not begin with dash\n"); - /* Or we might confuse it with an option when replacing - * name in argument list, below (though we do pointer, not - * string, comparisons). - */ - } - for (which = 1; PL_origargv[which] && PL_origargv[which] != scriptname; which++) ; - if (!PL_origargv[which]) { - Perl_croak(aTHX_ "Can't change argv to have fd script\n"); - } - PL_origargv[which] = savepv(Perl_form(aTHX_ "/dev/fd/%d/%s", - PerlIO_fileno(rsfp), PL_origargv[which])); -# if defined(HAS_FCNTL) && defined(F_SETFD) - fcntl(PerlIO_fileno(rsfp),F_SETFD,0); /* ensure no close-on-exec */ -# endif - PERL_FPU_PRE_EXEC - PerlProc_execv(Perl_form(aTHX_ "%s/sperl"PERL_FS_VER_FMT, BIN_EXP, - (int)PERL_REVISION, (int)PERL_VERSION, - (int)PERL_SUBVERSION), PL_origargv); - PERL_FPU_POST_EXEC -# endif /* IAMSUID */ - Perl_croak(aTHX_ "Can't do setuid (cannot exec sperl)\n"); - } - - if (PL_statbuf.st_mode & S_ISGID && PL_statbuf.st_gid != PL_egid) { -/* PSz 26 Feb 04 - * This seems back to front: we try HAS_SETEGID first; if not available - * then try HAS_SETREGID; as a last chance we try HAS_SETRESGID. May be OK - * in the sense that we only want to set EGID; but are there any machines - * with either of the latter, but not the former? Same with UID, later. - */ -# ifdef HAS_SETEGID - (void)setegid(PL_statbuf.st_gid); -# else -# ifdef HAS_SETREGID - (void)setregid((Gid_t)-1,PL_statbuf.st_gid); -# else -# ifdef HAS_SETRESGID - (void)setresgid((Gid_t)-1,PL_statbuf.st_gid,(Gid_t)-1); -# else - PerlProc_setgid(PL_statbuf.st_gid); -# endif -# endif -# endif - if (PerlProc_getegid() != PL_statbuf.st_gid) - Perl_croak(aTHX_ "Can't do setegid!\n"); - } - if (PL_statbuf.st_mode & S_ISUID) { - if (PL_statbuf.st_uid != PL_euid) -# ifdef HAS_SETEUID - (void)seteuid(PL_statbuf.st_uid); /* all that for this */ -# else -# ifdef HAS_SETREUID - (void)setreuid((Uid_t)-1,PL_statbuf.st_uid); -# else -# ifdef HAS_SETRESUID - (void)setresuid((Uid_t)-1,PL_statbuf.st_uid,(Uid_t)-1); -# else - PerlProc_setuid(PL_statbuf.st_uid); -# endif -# endif -# endif - if (PerlProc_geteuid() != PL_statbuf.st_uid) - Perl_croak(aTHX_ "Can't do seteuid!\n"); - } - else if (PL_uid) { /* oops, mustn't run as root */ -# ifdef HAS_SETEUID - (void)seteuid((Uid_t)PL_uid); -# else -# ifdef HAS_SETREUID - (void)setreuid((Uid_t)-1,(Uid_t)PL_uid); -# else -# ifdef HAS_SETRESUID - (void)setresuid((Uid_t)-1,(Uid_t)PL_uid,(Uid_t)-1); -# else - PerlProc_setuid((Uid_t)PL_uid); -# endif -# endif -# endif - if (PerlProc_geteuid() != PL_uid) - Perl_croak(aTHX_ "Can't do seteuid!\n"); - } - init_ids(); - if (!cando(S_IXUSR,TRUE,&PL_statbuf)) - Perl_croak(aTHX_ "Effective UID cannot exec script\n"); /* they can't do this */ - } -# ifdef IAMSUID - else if (fdscript < 0 || !suidscript) - /* PSz 13 Nov 03 Caught elsewhere, useless(?!) here */ - Perl_croak(aTHX_ "(suid) fdscript needed in suidperl\n"); - else { -/* PSz 16 Sep 03 Keep neat error message */ - Perl_croak(aTHX_ "Script is not setuid/setgid in suidperl\n"); - } - - /* We absolutely must clear out any saved ids here, so we */ - /* exec the real perl, substituting fd script for scriptname. */ - /* (We pass script name as "subdir" of fd, which perl will grok.) */ - /* - * It might be thought that using setresgid and/or setresuid (changed to - * set the saved IDs) above might obviate the need to exec, and we could - * go on to "do the perl thing". - * - * Is there such a thing as "saved GID", and is that set for setuid (but - * not setgid) execution like suidperl? Without exec, it would not be - * cleared for setuid (but not setgid) scripts (or might need a dummy - * setresgid). - * - * We need suidperl to do the exact same argument checking that perl - * does. Thus it cannot be very small; while it could be significantly - * smaller, it is safer (simpler?) to make it essentially the same - * binary as perl (but they are not identical). - Maybe could defer that - * check to the invoked perl, and suidperl be a tiny wrapper instead; - * but prefer to do thorough checks in suidperl itself. Such deferral - * would make suidperl security rely on perl, a design no-no. - * - * Setuid things should be short and simple, thus easy to understand and - * verify. They should do their "own thing", without influence by - * attackers. It may help if their internal execution flow is fixed, - * regardless of platform: it may be best to exec anyway. - * - * Suidperl should at least be conceptually simple: a wrapper only, - * never to do any real perl. Maybe we should put - * #ifdef IAMSUID - * Perl_croak(aTHX_ "Suidperl should never do real perl\n"); - * #endif - * into the perly bits. - */ - PerlIO_rewind(rsfp); - PerlLIO_lseek(PerlIO_fileno(rsfp),(Off_t)0,0); /* just in case rewind didn't */ - /* PSz 11 Nov 03 - * Keep original arguments: suidperl already has fd script. - */ -# if defined(HAS_FCNTL) && defined(F_SETFD) - fcntl(PerlIO_fileno(rsfp),F_SETFD,0); /* ensure no close-on-exec */ -# endif - PERL_FPU_PRE_EXEC - PerlProc_execv(Perl_form(aTHX_ "%s/perl"PERL_FS_VER_FMT, BIN_EXP, - (int)PERL_REVISION, (int)PERL_VERSION, - (int)PERL_SUBVERSION), PL_origargv);/* try again */ - PERL_FPU_POST_EXEC - Perl_croak(aTHX_ "Can't do setuid (suidperl cannot exec perl)\n"); -# endif /* IAMSUID */ -} - -#else /* !DOSUID */ - -# ifdef SETUID_SCRIPTS_ARE_SECURE_NOW +#ifdef SETUID_SCRIPTS_ARE_SECURE_NOW /* Don't even need this function. */ -# else +#else STATIC void S_validate_suid(pTHX_ PerlIO *rsfp) { PERL_ARGS_ASSERT_VALIDATE_SUID; if (PL_euid != PL_uid || PL_egid != PL_gid) { /* (suidperl doesn't exist, in fact) */ -# ifndef SETUID_SCRIPTS_ARE_SECURE_NOW + dVAR; + PerlLIO_fstat(PerlIO_fileno(rsfp),&PL_statbuf); /* may be either wrapped or real suid */ if ((PL_euid != PL_uid && PL_euid == PL_statbuf.st_uid && PL_statbuf.st_mode & S_ISUID) || @@ -4253,12 +3656,10 @@ S_validate_suid(pTHX_ PerlIO *rsfp) if (!PL_do_undump) Perl_croak(aTHX_ "YOU HAVEN'T DISABLED SET-ID SCRIPTS IN THE KERNEL YET!\n\ FIX YOUR KERNEL, PUT A C WRAPPER AROUND THIS SCRIPT, OR USE -u AND UNDUMP!\n"); -# endif /* SETUID_SCRIPTS_ARE_SECURE_NOW */ /* not set-id, must be wrapped */ } } -# endif /* SETUID_SCRIPTS_ARE_SECURE_NOW */ -#endif /* DOSUID */ +#endif /* SETUID_SCRIPTS_ARE_SECURE_NOW */ STATIC void S_find_beginning(pTHX_ SV* linestr_sv, PerlIO *rsfp) @@ -4416,34 +3817,8 @@ S_forbid_setid(pTHX_ const char flag, const bool suidscript) /* g */ if (PL_egid != PL_gid) Perl_croak(aTHX_ "No %s allowed while running setgid", message); #endif /* SETUID_SCRIPTS_ARE_SECURE_NOW */ - /* PSz 29 Feb 04 - * Checks for UID/GID above "wrong": why disallow - * perl -e 'print "Hello\n"' - * from within setuid things?? Simply drop them: replaced by - * fdscript/suidscript and #ifdef IAMSUID checks below. - * - * This may be too late for command-line switches. Will catch those on - * the #! line, after finding the script name and setting up - * fdscript/suidscript. Note that suidperl does not get around to - * parsing (and checking) the switches on the #! line, but checks that - * the two sets are identical. - * - * With SETUID_SCRIPTS_ARE_SECURE_NOW, could we use fdscript, also or - * instead, or would that be "too late"? (We never have suidscript, can - * we be sure to have fdscript?) - * - * Catch things with suidscript (in descendant of suidperl), even with - * right UID/GID. Was already checked in suidperl, with #ifdef IAMSUID, - * below; but I am paranoid. - * - * Also see comments about root running a setuid script, elsewhere. - */ if (suidscript) Perl_croak(aTHX_ "No %s allowed with (suid) fdscript", message); -#ifdef IAMSUID - /* PSz 11 Nov 03 Catch it in suidperl, always! */ - Perl_croak(aTHX_ "No %s allowed in suidperl", message); -#endif /* IAMSUID */ } void @@ -4538,7 +3913,9 @@ S_init_predump_symbols(pTHX) GV *tmpgv; IO *io; - sv_setpvn(get_sv("\"", TRUE), " ", 1); + sv_setpvs(get_sv("\"", GV_ADD), " "); + PL_ofsgv = (GV*)SvREFCNT_inc(gv_fetchpvs(",", GV_ADD|GV_NOTQUAL, SVt_PV)); + PL_stdingv = gv_fetchpvs("STDIN", GV_ADD|GV_NOTQUAL, SVt_PVIO); GvMULTI_on(PL_stdingv); io = GvIOp(PL_stdingv); @@ -4546,7 +3923,7 @@ S_init_predump_symbols(pTHX) IoIFP(io) = PerlIO_stdin(); tmpgv = gv_fetchpvs("stdin", GV_ADD|GV_NOTQUAL, SVt_PV); GvMULTI_on(tmpgv); - GvIOp(tmpgv) = (IO*)SvREFCNT_inc_simple(io); + GvIOp(tmpgv) = MUTABLE_IO(SvREFCNT_inc_simple(io)); tmpgv = gv_fetchpvs("STDOUT", GV_ADD|GV_NOTQUAL, SVt_PVIO); GvMULTI_on(tmpgv); @@ -4556,7 +3933,7 @@ S_init_predump_symbols(pTHX) setdefout(tmpgv); tmpgv = gv_fetchpvs("stdout", GV_ADD|GV_NOTQUAL, SVt_PV); GvMULTI_on(tmpgv); - GvIOp(tmpgv) = (IO*)SvREFCNT_inc_simple(io); + GvIOp(tmpgv) = MUTABLE_IO(SvREFCNT_inc_simple(io)); PL_stderrgv = gv_fetchpvs("STDERR", GV_ADD|GV_NOTQUAL, SVt_PVIO); GvMULTI_on(PL_stderrgv); @@ -4565,7 +3942,7 @@ S_init_predump_symbols(pTHX) IoOFP(io) = IoIFP(io) = PerlIO_stderr(); tmpgv = gv_fetchpvs("stderr", GV_ADD|GV_NOTQUAL, SVt_PV); GvMULTI_on(tmpgv); - GvIOp(tmpgv) = (IO*)SvREFCNT_inc_simple(io); + GvIOp(tmpgv) = MUTABLE_IO(SvREFCNT_inc_simple(io)); PL_statname = newSV(0); /* last filename we did stat on */ @@ -4625,9 +4002,9 @@ S_init_postdump_symbols(pTHX_ register int argc, register char **argv, register PERL_ARGS_ASSERT_INIT_POSTDUMP_SYMBOLS; PL_toptarget = newSV_type(SVt_PVFM); - sv_setpvn(PL_toptarget, "", 0); + sv_setpvs(PL_toptarget, ""); PL_bodytarget = newSV_type(SVt_PVFM); - sv_setpvn(PL_bodytarget, "", 0); + sv_setpvs(PL_bodytarget, ""); PL_formtarget = PL_bodytarget; TAINT; @@ -4640,7 +4017,11 @@ S_init_postdump_symbols(pTHX_ register int argc, register char **argv, register sv_setpv(GvSV(tmpgv),MacPerl_MPWFileName(PL_origfilename)); #else sv_setpv(GvSV(tmpgv),PL_origfilename); - magicname("0", "0", 1); + { + GV * const gv = gv_fetchpv("0", GV_ADD, SVt_PV); + if (gv) + sv_magic(GvSV(gv), MUTABLE_SV(gv), PERL_MAGIC_sv, "0", 1); + } #endif } if ((PL_envgv = gv_fetchpvs("ENV", GV_ADD|GV_NOTQUAL, SVt_PVHV))) { @@ -4668,18 +4049,21 @@ S_init_postdump_symbols(pTHX_ register int argc, register char **argv, register environ[0] = NULL; } if (env) { - char *s; + char *s, *old_var; SV *sv; for (; *env; env++) { - if (!(s = strchr(*env,'=')) || s == *env) + old_var = *env; + + if (!(s = strchr(old_var,'=')) || s == old_var) continue; + #if defined(MSDOS) && !defined(DJGPP) *s = '\0'; - (void)strupr(*env); + (void)strupr(old_var); *s = '='; #endif sv = newSVpv(s+1, 0); - (void)hv_store(hv, *env, s - *env, sv, 0); + (void)hv_store(hv, old_var, s - old_var, sv, 0); if (env_is_not_environ) mg_set(sv); } @@ -4699,7 +4083,7 @@ S_init_postdump_symbols(pTHX_ register int argc, register char **argv, register /* touch @F array to prevent spurious warnings 20020415 MJD */ if (PL_minus_a) { - (void) get_av("main::F", TRUE | GV_ADDMULTI); + (void) get_av("main::F", GV_ADD | GV_ADDMULTI); } } @@ -4721,9 +4105,9 @@ S_init_perllib(pTHX) #else if (s) #endif - incpush(s, TRUE, TRUE, TRUE, FALSE); + incpush(s, TRUE, TRUE, TRUE, FALSE, FALSE); else - incpush(PerlEnv_getenv("PERLLIB"), FALSE, FALSE, TRUE, FALSE); + incpush(PerlEnv_getenv("PERLLIB"), FALSE, FALSE, TRUE, FALSE, FALSE); #else /* VMS */ /* Treat PERL5?LIB as a possible search list logical name -- the * "natural" VMS idiom for a Unix path string. We allow each @@ -4732,9 +4116,9 @@ S_init_perllib(pTHX) char buf[256]; int idx = 0; if (my_trnlnm("PERL5LIB",buf,0)) - do { incpush(buf,TRUE,TRUE,TRUE,FALSE); } while (my_trnlnm("PERL5LIB",buf,++idx)); + do { incpush(buf,TRUE,TRUE,TRUE,FALSE, FALSE); } while (my_trnlnm("PERL5LIB",buf,++idx)); else - while (my_trnlnm("PERLLIB",buf,idx++)) incpush(buf,FALSE,FALSE,TRUE,FALSE); + while (my_trnlnm("PERLLIB",buf,idx++)) incpush(buf,FALSE,FALSE,TRUE,FALSE, FALSE); #endif /* VMS */ } @@ -4742,11 +4126,11 @@ S_init_perllib(pTHX) ARCHLIB PRIVLIB SITEARCH SITELIB VENDORARCH and VENDORLIB */ #ifdef APPLLIB_EXP - incpush(APPLLIB_EXP, TRUE, TRUE, TRUE, TRUE); + incpush(APPLLIB_EXP, TRUE, TRUE, TRUE, TRUE, FALSE); #endif #ifdef ARCHLIB_EXP - incpush(ARCHLIB_EXP, FALSE, FALSE, TRUE, TRUE); + incpush(ARCHLIB_EXP, FALSE, FALSE, TRUE, TRUE, FALSE); #endif #ifdef MACOS_TRADITIONAL { @@ -4759,73 +4143,74 @@ S_init_perllib(pTHX) Perl_sv_setpvf(aTHX_ privdir, "%slib:", macperl); if (PerlLIO_stat(SvPVX(privdir), &tmpstatbuf) >= 0 && S_ISDIR(tmpstatbuf.st_mode)) - incpush(SvPVX(privdir), TRUE, FALSE, TRUE, FALSE); + incpush(SvPVX(privdir), TRUE, FALSE, TRUE, FALSE, FALSE); Perl_sv_setpvf(aTHX_ privdir, "%ssite_perl:", macperl); if (PerlLIO_stat(SvPVX(privdir), &tmpstatbuf) >= 0 && S_ISDIR(tmpstatbuf.st_mode)) - incpush(SvPVX(privdir), TRUE, FALSE, TRUE, FALSE); + incpush(SvPVX(privdir), TRUE, FALSE, TRUE, FALSE, FALSE); SvREFCNT_dec(privdir); } if (!PL_tainting) - incpush(":", FALSE, FALSE, TRUE, FALSE); + incpush(":", FALSE, FALSE, FALSE, FALSE, FALSE); #else #ifndef PRIVLIB_EXP # define PRIVLIB_EXP "/usr/local/lib/perl5:/usr/local/lib/perl" #endif #if defined(WIN32) - incpush(PRIVLIB_EXP, TRUE, FALSE, TRUE, TRUE); + incpush(PRIVLIB_EXP, TRUE, FALSE, TRUE, TRUE, FALSE); #else - incpush(PRIVLIB_EXP, FALSE, FALSE, TRUE, TRUE); + incpush(PRIVLIB_EXP, FALSE, FALSE, TRUE, TRUE, FALSE); #endif #ifdef SITEARCH_EXP /* sitearch is always relative to sitelib on Windows for * DLL-based path intuition to work correctly */ # if !defined(WIN32) - incpush(SITEARCH_EXP, FALSE, FALSE, TRUE, TRUE); + incpush(SITEARCH_EXP, FALSE, FALSE, TRUE, TRUE, FALSE); # endif #endif #ifdef SITELIB_EXP # if defined(WIN32) /* this picks up sitearch as well */ - incpush(SITELIB_EXP, TRUE, FALSE, TRUE, TRUE); + incpush(SITELIB_EXP, TRUE, FALSE, TRUE, TRUE, FALSE); # else - incpush(SITELIB_EXP, FALSE, FALSE, TRUE, TRUE); + incpush(SITELIB_EXP, FALSE, FALSE, TRUE, TRUE, FALSE); # endif #endif #if defined(SITELIB_STEM) && defined(PERL_INC_VERSION_LIST) /* Search for version-specific dirs below here */ - incpush(SITELIB_STEM, FALSE, TRUE, TRUE, TRUE); + incpush(SITELIB_STEM, FALSE, TRUE, TRUE, TRUE, FALSE); #endif #ifdef PERL_VENDORARCH_EXP /* vendorarch is always relative to vendorlib on Windows for * DLL-based path intuition to work correctly */ # if !defined(WIN32) - incpush(PERL_VENDORARCH_EXP, FALSE, FALSE, TRUE, TRUE); + incpush(PERL_VENDORARCH_EXP, FALSE, FALSE, TRUE, TRUE, FALSE); # endif #endif #ifdef PERL_VENDORLIB_EXP # if defined(WIN32) - incpush(PERL_VENDORLIB_EXP, TRUE, FALSE, TRUE, TRUE); /* this picks up vendorarch as well */ + incpush(PERL_VENDORLIB_EXP, TRUE, FALSE, TRUE, TRUE, FALSE); /* this picks up vendorarch as well */ # else - incpush(PERL_VENDORLIB_EXP, FALSE, FALSE, TRUE, TRUE); + incpush(PERL_VENDORLIB_EXP, FALSE, FALSE, TRUE, TRUE, FALSE); # endif #endif -#ifdef PERL_VENDORLIB_STEM /* Search for version-specific dirs below here */ - incpush(PERL_VENDORLIB_STEM, FALSE, TRUE, TRUE, TRUE); +#if defined(PERL_VENDORLIB_STEM) && defined(PERL_INC_VERSION_LIST) + /* Search for version-specific dirs below here */ + incpush(PERL_VENDORLIB_STEM, FALSE, TRUE, TRUE, TRUE, FALSE); #endif #ifdef PERL_OTHERLIBDIRS - incpush(PERL_OTHERLIBDIRS, TRUE, TRUE, TRUE, TRUE); + incpush(PERL_OTHERLIBDIRS, TRUE, TRUE, TRUE, TRUE, FALSE); #endif if (!PL_tainting) - incpush(".", FALSE, FALSE, TRUE, FALSE); + incpush(".", FALSE, FALSE, FALSE, FALSE, FALSE); #endif /* MACOS_TRADITIONAL */ } @@ -4867,7 +4252,7 @@ S_incpush_if_exists(pTHX_ SV *dir) STATIC void S_incpush(pTHX_ const char *dir, bool addsubdirs, bool addoldvers, bool usesep, - bool canrelocate) + bool canrelocate, bool unshift) { dVAR; SV *subdir = NULL; @@ -5079,8 +4464,14 @@ S_incpush(pTHX_ const char *dir, bool addsubdirs, bool addoldvers, bool usesep, #endif } - /* finally push this lib directory on the end of @INC */ - av_push(GvAVn(PL_incgv), libdir); + /* finally add this lib directory at the end of @INC */ + if (unshift) { + av_unshift( GvAVn( PL_incgv ), 1 ); + av_store( GvAVn( PL_incgv ), 0, libdir ); + } + else { + av_push(GvAVn(PL_incgv), libdir); + } } if (subdir) { assert (SvREFCNT(subdir) == 1); @@ -5103,19 +4494,19 @@ Perl_call_list(pTHX_ I32 oldscope, AV *paramList) PERL_ARGS_ASSERT_CALL_LIST; while (av_len(paramList) >= 0) { - cv = (CV*)av_shift(paramList); + cv = MUTABLE_CV(av_shift(paramList)); if (PL_savebegin) { if (paramList == PL_beginav) { /* save PL_beginav for compiler */ - Perl_av_create_and_push(aTHX_ &PL_beginav_save, (SV*)cv); + Perl_av_create_and_push(aTHX_ &PL_beginav_save, MUTABLE_SV(cv)); } else if (paramList == PL_checkav) { /* save PL_checkav for compiler */ - Perl_av_create_and_push(aTHX_ &PL_checkav_save, (SV*)cv); + Perl_av_create_and_push(aTHX_ &PL_checkav_save, MUTABLE_SV(cv)); } else if (paramList == PL_unitcheckav) { /* save PL_unitcheckav for compiler */ - Perl_av_create_and_push(aTHX_ &PL_unitcheckav_save, (SV*)cv); + Perl_av_create_and_push(aTHX_ &PL_unitcheckav_save, MUTABLE_SV(cv)); } } else { if (!PL_madskills) @@ -5223,22 +4614,34 @@ Perl_my_failure_exit(pTHX) */ if (MY_POSIX_EXIT) { - /* In POSIX_EXIT mode follow Perl documentations and use 255 for - * the exit code when there isn't an error. - */ + /* According to the die_exit.t tests, if errno is non-zero */ + /* It should be used for the error status. */ - if (STATUS_UNIX == 0) - STATUS_UNIX_EXIT_SET(255); - else { - STATUS_UNIX_EXIT_SET(STATUS_UNIX); + if (errno == EVMSERR) { + STATUS_NATIVE = vaxc$errno; + } else { - /* The exit code could have been set by $? or vmsish which - * means that it may not be fatal. So convert - * success/warning codes to fatal. - */ - if ((STATUS_NATIVE & (STS$K_SEVERE|STS$K_ERROR)) == 0) + /* According to die_exit.t tests, if the child_exit code is */ + /* also zero, then we need to exit with a code of 255 */ + if ((errno != 0) && (errno < 256)) + STATUS_UNIX_EXIT_SET(errno); + else if (STATUS_UNIX < 255) { STATUS_UNIX_EXIT_SET(255); + } + } + + /* The exit code could have been set by $? or vmsish which + * means that it may not have fatal set. So convert + * success/warning codes to fatal with out changing + * the POSIX status code. The severity makes VMS native + * status handling work, while UNIX mode programs use the + * the POSIX exit codes. + */ + if ((STATUS_NATIVE & (STS$K_SEVERE|STS$K_ERROR)) == 0) { + STATUS_NATIVE &= STS$M_COND_ID; + STATUS_NATIVE |= STS$K_ERROR | STS$M_INHIB_MSG; + } } else { /* Traditionally Perl on VMS always expects a Fatal Error. */