*--tend = '\0';
if (num_svs) {
+ const char *p;
+ STRLEN nlen = 0;
/* New style explicit name, type is just mode and layer info */
#ifdef USE_STDIO
if (SvROK(*svp) && !strchr(oname,'&')) {
goto say_false;
}
#endif /* USE_STDIO */
- if (!IS_SAFE_PATHNAME(*svp, "open"))
+ p = (SvOK(*svp) || SvGMAGICAL(*svp)) ? SvPV(*svp, nlen) : NULL;
+
+ if (p && !IS_SAFE_PATHNAME(p, nlen, "open"))
goto say_false;
- name = (SvOK(*svp) || SvGMAGICAL(*svp)) ?
- savesvpv (*svp) : savepvs ("");
+ name = p ? savepvn(p, nlen) : savepvs("");
+
SAVEFREEPV(name);
}
else {
}
}
else {
- const char *name = SvPV_nomg_const_nolen(*mark);
+ const char *name = SvPV_nomg_const(*mark, len);
APPLY_TAINT_PROPER();
- if (!IS_SAFE_PATHNAME(*mark, "chmod") ||
+ if (!IS_SAFE_PATHNAME(name, len, "chmod") ||
PerlLIO_chmod(name, val)) {
tot--;
}
}
}
else {
- const char *name = SvPV_nomg_const_nolen(*mark);
+ const char *name = SvPV_nomg_const(*mark, len);
APPLY_TAINT_PROPER();
- if (!IS_SAFE_PATHNAME(*mark, "chown") ||
+ if (!IS_SAFE_PATHNAME(name, len, "chown") ||
PerlLIO_chown(name, val, val2)) {
tot--;
}
APPLY_TAINT_PROPER();
tot = sp - mark;
while (++mark <= sp) {
- s = SvPV_nolen_const(*mark);
+ s = SvPV_const(*mark, len);
APPLY_TAINT_PROPER();
- if (!IS_SAFE_PATHNAME(*mark, "unlink")) {
+ if (!IS_SAFE_PATHNAME(s, len, "unlink")) {
tot--;
}
else if (PerlProc_geteuid() || PL_unsafe) {
}
}
else {
- const char * const name = SvPV_nomg_const_nolen(*mark);
+ const char * const name = SvPV_nomg_const(*mark, len);
APPLY_TAINT_PROPER();
- if (!IS_SAFE_PATHNAME(*mark, "utime")) {
+ if (!IS_SAFE_PATHNAME(name, len, "utime")) {
tot--;
}
else
dVAR;
SV * const tmpcmd = newSV(0);
PerlIO *fp;
+ STRLEN len;
+ const char *s = SvPV(tmpglob, len);
PERL_ARGS_ASSERT_START_GLOB;
- if (!IS_SAFE_SYSCALL(tmpglob, "pattern", "glob"))
+ if (!IS_SAFE_SYSCALL(s, len, "pattern", "glob"))
return NULL;
ENTER;
Ap |I32 |whichsig_pv |NN const char* sig
Ap |I32 |whichsig_pvn |NN const char* sig|STRLEN len
: used to check for NULs in pathnames and other names
-AiR |bool |is_safe_syscall|NN SV *pv|NN const char *what|NN const char *op_name
+AiR |bool |is_safe_syscall|NN const char *pv|STRLEN len|NN const char *what|NN const char *op_name
: Used in pp_ctl.c
p |void |write_to_stderr|NN SV* msv
: Used in op.c
#define instr Perl_instr
#define is_ascii_string Perl_is_ascii_string
#define is_lvalue_sub() Perl_is_lvalue_sub(aTHX)
-#define is_safe_syscall(a,b,c) S_is_safe_syscall(aTHX_ a,b,c)
+#define is_safe_syscall(a,b,c,d) S_is_safe_syscall(aTHX_ a,b,c,d)
#define is_uni_alnum(a) Perl_is_uni_alnum(aTHX_ a)
#define is_uni_alnum_lc(a) Perl_is_uni_alnum_lc(aTHX_ a)
#define is_uni_alnumc(a) Perl_is_uni_alnumc(aTHX_ a)
else pat = SvPV_nomg(patsv,len), is_utf8 = !!SvUTF8(patsv);
patend = pat + len;
+ assert(SvTYPE(entries) != SVt_PVAV);
+ sv_upgrade((SV *)entries, SVt_PVAV);
+
+ if (!IS_SAFE_SYSCALL(pat, len, "pattern", "glob"))
+ return FALSE;
+
/* extract patterns */
s = pat-1;
while (++s < patend) {
}
end_of_parsing:
- assert(SvTYPE(entries) != SVt_PVAV);
- sv_upgrade((SV *)entries, SVt_PVAV);
- if (!IS_SAFE_SYSCALL(patsv, "pattern", "glob"))
- return FALSE;
-
if (patav) {
I32 items = AvFILLp(patav) + 1;
SV **svp = AvARRAY(patav);
/* ------------------------------- perl.h ----------------------------- */
/*
-=for apidoc AiR|bool|is_safe_syscall|SV *pv|const char *what|const char *op_name
+=for apidoc AiR|bool|is_safe_syscall|const char *pv|STRLEN len|const char *what|const char *op_name
Test that the given C<pv> doesn't contain any internal NUL characters.
If it does, set C<errno> to ENOENT, optionally warn, and return FALSE.
*/
PERL_STATIC_INLINE bool
-S_is_safe_syscall(pTHX_ SV *pv, const char *what, const char *op_name) {
+S_is_safe_syscall(pTHX_ const char *pv, STRLEN len, const char *what, const char *op_name) {
/* While the Windows CE API provides only UCS-16 (or UTF-16) APIs
* perl itself uses xce*() functions which accept 8-bit strings.
*/
PERL_ARGS_ASSERT_IS_SAFE_SYSCALL;
- if (SvPOK(pv) && SvCUR(pv) >= 1) {
- char *p = SvPVX(pv);
+ if (pv && len > 1) {
char *null_at;
- if (UNLIKELY((null_at = (char *)memchr(p, 0, SvCUR(pv)-1)) != NULL)) {
+ if (UNLIKELY((null_at = (char *)memchr(pv, 0, len-1)) != NULL)) {
SETERRNO(ENOENT, LIB_INVARG);
Perl_ck_warner(aTHX_ packWARN(WARN_SYSCALLS),
"Invalid \\0 character in %s for %s: %s\\0%s",
- what, op_name, p, null_at+1);
+ what, op_name, pv, null_at+1);
return FALSE;
}
}
/* check embedded \0 characters in pathnames passed to syscalls,
but allow one ending \0 */
-#define IS_SAFE_SYSCALL(pv, what, op_name) (S_is_safe_syscall(aTHX_ (pv), (what), (op_name)))
+#define IS_SAFE_SYSCALL(p, len, what, op_name) (S_is_safe_syscall(aTHX_ (p), (len), (what), (op_name)))
-#define IS_SAFE_PATHNAME(pv, op_name) IS_SAFE_SYSCALL((pv), "pathname", (op_name))
+#define IS_SAFE_PATHNAME(p, len, op_name) IS_SAFE_SYSCALL((p), (len), "pathname", (op_name))
#if defined(OEMVS)
#define NO_ENV_ARRAY_IN_MAIN
if (*args == &PL_sv_undef)
return PerlIO_tmpfile();
else {
- const char *name = SvPV_nolen_const(*args);
- if (!IS_SAFE_PATHNAME(*args, "open"))
+ STRLEN len;
+ const char *name = SvPV_nolen_const(*args, len);
+ if (!IS_SAFE_PATHNAME(name, len, "open"))
return NULL;
if (*mode == IoTYPE_NUMERIC) {
#endif
}
if (imode != -1) {
- const char *path = SvPV_nolen_const(*args);
- if (!IS_SAFE_PATHNAME(*args, "open"))
+ STRLEN len;
+ const char *path = SvPV_const(*args, len);
+ if (!IS_SAFE_PATHNAME(path, len, "open"))
return NULL;
fd = PerlLIO_open3(path, imode, perm);
}
{
char tmode[8];
if (PerlIOValid(f)) {
- const char * const path = SvPV_nolen_const(*args);
+ STRLEN len;
+ const char * const path = SvPV_const(*args, len);
PerlIOStdio * const s = PerlIOSelf(f, PerlIOStdio);
FILE *stdio;
- if (!IS_SAFE_PATHNAME(*args, "open"))
+ if (!IS_SAFE_PATHNAME(path, len, "open"))
return NULL;
PerlIOUnix_refcnt_dec(fileno(s->stdio));
stdio = PerlSIO_freopen(path, (mode = PerlIOStdio_mode(mode, tmode)),
}
else {
if (narg > 0) {
- const char * const path = SvPV_nolen_const(*args);
- if (!IS_SAFE_PATHNAME(*args, "open"))
+ STRLEN len;
+ const char * const path = SvPV_const(*args, len);
+ if (!IS_SAFE_PATHNAME(path, len, "open"))
return NULL;
if (*mode == IoTYPE_NUMERIC) {
mode++;
S_check_type_and_open(pTHX_ SV *name)
{
Stat_t st;
- const char *p = SvPV_nolen_const(name);
+ STRLEN len;
+ const char *p = SvPV_const(name, len);
int st_rc;
PERL_ARGS_ASSERT_CHECK_TYPE_AND_OPEN;
* rather than for the .pm file.
* This check prevents a \0 in @INC causing problems.
*/
- if (!IS_SAFE_PATHNAME(name, "require"))
+ if (!IS_SAFE_PATHNAME(p, len, "require"))
return NULL;
st_rc = PerlLIO_stat(p, &st);
* warning referring to the .pmc which the user probably doesn't
* know or care about
*/
- if (!IS_SAFE_PATHNAME(name, "require"))
+ if (!IS_SAFE_PATHNAME(p, namelen, "require"))
return NULL;
if (namelen > 3 && memEQs(p + namelen - 3, 3, ".pm")) {
name = SvPV_const(sv, len);
if (!(name && len > 0 && *name))
DIE(aTHX_ "Null filename used");
- if (!IS_SAFE_PATHNAME(sv, "require")) {
+ if (!IS_SAFE_PATHNAME(name, len, "require")) {
DIE(aTHX_ "Can't locate %s: %s",
pv_escape(newSVpvs_flags("",SVs_TEMP),SvPVX(sv),SvCUR(sv),
SvCUR(sv)*2,NULL, SvUTF8(sv)?PERL_PV_ESCAPE_UNI:0),
PERL_CALLCONV I32 Perl_is_lvalue_sub(pTHX)
__attribute__warn_unused_result__;
-PERL_STATIC_INLINE bool S_is_safe_syscall(pTHX_ SV *pv, const char *what, const char *op_name)
+PERL_STATIC_INLINE bool S_is_safe_syscall(pTHX_ const char *pv, STRLEN len, const char *what, const char *op_name)
__attribute__warn_unused_result__
__attribute__nonnull__(pTHX_1)
- __attribute__nonnull__(pTHX_2)
- __attribute__nonnull__(pTHX_3);
+ __attribute__nonnull__(pTHX_3)
+ __attribute__nonnull__(pTHX_4);
#define PERL_ARGS_ASSERT_IS_SAFE_SYSCALL \
assert(pv); assert(what); assert(op_name)
like($WARN, qr/^Invalid \\0 character in pathname for chmod: $temp_match\\0\.invalid/,
"also on chmod"); $WARN = '';
- $TODO = "broken for overloading";
is(chmod(0444, $fno), 0, "chmod fails with \\0 in name (overload)");
like($WARN, qr/^Invalid \\0 character in pathname for chmod: $temp_match\\0\.overload/,
"also on chmod"); $WARN = '';
- undef $TODO;
is (glob($fn), undef, "glob fails with \\0 in name");
like($WARN, qr/^Invalid \\0 character in pattern for glob: $temp_match\\0\.invalid/,
"also on glob"); $WARN = '';
- $TODO = "broken for overloading";
is (glob($fno), undef, "glob fails with \\0 in name (overload)");
like($WARN, qr/^Invalid \\0 character in pattern for glob: $temp_match\\0\.overload/,
"also on glob"); $WARN = '';
- undef $TODO;
{
no warnings 'syscalls';
like($WARN, qr/^Invalid \\0 character in pathname for unlink: $temp_match\\0\.invalid/,
"also on unlink"); $WARN = '';
- $TODO = "broken for overloading";
is (unlink($fno), 0, "unlink fails with \\0 in name (overload)");
like($WARN, qr/^Invalid \\0 character in pathname for unlink: $temp_match\\0\.overload/,
"also on unlink"); $WARN = '';
- local $TODO = "this is broken for overloading";
ok(-f $temp, "nothing removed the temp file");
is((stat $temp)[2], $final_mode, "nothing changed its mode");
is((stat $temp)[9], $final_mtime, "nothing changes its mtime");