From e57400b1a8f3e20388fda0dfbfec3666380aa1b8 Mon Sep 17 00:00:00 2001 From: Brendan O'Dea Date: Fri, 12 Sep 2003 10:12:51 +1000 Subject: [PATCH] Security: suidperl path disclosure revisited From: "Brendan O'Dea" Message-ID: <20030911141251.GA26907@londo.c47.org> p4raw-id: //depot/perl@21186 --- perl.c | 35 ++++++++++++++++++++++++----------- 1 file changed, 24 insertions(+), 11 deletions(-) diff --git a/perl.c b/perl.c index 4f41bf1..acce020 100644 --- a/perl.c +++ b/perl.c @@ -3153,8 +3153,10 @@ S_validate_suid(pTHX_ char *validarg, char *scriptname, int fdscript) * But I don't think it's too important. The manual lies when * it says access() is useful in setuid programs. */ - if (PerlLIO_access(CopFILE(PL_curcop),1)) /*double check*/ - Perl_croak(aTHX_ "Permission denied"); + if (PerlLIO_access(CopFILE(PL_curcop),1)) { /*double check*/ + errno = EPERM; + Perl_croak(aTHX_ "Permission denied\n"); + } #else /* 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 @@ -3174,15 +3176,20 @@ S_validate_suid(pTHX_ char *validarg, char *scriptname, int fdscript) #endif || PerlProc_getuid() != PL_euid || PerlProc_geteuid() != PL_uid) Perl_croak(aTHX_ "Can't swap uid and euid"); /* really paranoid */ - if (PerlLIO_stat(CopFILE(PL_curcop),&tmpstatbuf) < 0) - Perl_croak(aTHX_ "Permission denied"); /* testing full pathname here */ + if (PerlLIO_stat(CopFILE(PL_curcop),&tmpstatbuf) < 0) { + errno = EPERM; + Perl_croak(aTHX_ "Permission denied\n"); /* testing full pathname here */ + } #if defined(IAMSUID) && !defined(NO_NOSUID_CHECK) - if (fd_on_nosuid_fs(PerlIO_fileno(PL_rsfp))) - Perl_croak(aTHX_ "Permission denied"); + if (fd_on_nosuid_fs(PerlIO_fileno(PL_rsfp))) { + errno = EPERM; + Perl_croak(aTHX_ "Permission denied\n"); + } #endif if (tmpstatbuf.st_dev != PL_statbuf.st_dev || tmpstatbuf.st_ino != PL_statbuf.st_ino) { (void)PerlIO_close(PL_rsfp); + errno = EPERM; Perl_croak(aTHX_ "Permission denied\n"); } if ( @@ -3201,8 +3208,10 @@ S_validate_suid(pTHX_ char *validarg, char *scriptname, int fdscript) #endif /* HAS_SETREUID */ #endif /* IAMSUID */ - if (!S_ISREG(PL_statbuf.st_mode)) - Perl_croak(aTHX_ "Permission denied"); + if (!S_ISREG(PL_statbuf.st_mode)) { + errno = EPERM; + Perl_croak(aTHX_ "Permission denied\n"); + } if (PL_statbuf.st_mode & S_IWOTH) Perl_croak(aTHX_ "Setuid/gid script is writable by world"); PL_doswitches = FALSE; /* -s is insecure in suid */ @@ -3310,8 +3319,10 @@ FIX YOUR KERNEL, PUT A C WRAPPER AROUND THIS SCRIPT, OR USE -u AND UNDUMP!\n"); Perl_croak(aTHX_ "-P not allowed for setuid/setgid script\n"); else if (fdscript >= 0) Perl_croak(aTHX_ "fd script not allowed in suidperl\n"); - else + else { + errno = EPERM; Perl_croak(aTHX_ "Permission denied\n"); + } /* We absolutely must clear out any saved ids here, so we */ /* exec the real perl, substituting fd script for scriptname. */ @@ -3319,8 +3330,10 @@ FIX YOUR KERNEL, PUT A C WRAPPER AROUND THIS SCRIPT, OR USE -u AND UNDUMP!\n"); PerlIO_rewind(PL_rsfp); PerlLIO_lseek(PerlIO_fileno(PL_rsfp),(Off_t)0,0); /* just in case rewind didn't */ for (which = 1; PL_origargv[which] && PL_origargv[which] != scriptname; which++) ; - if (!PL_origargv[which]) - Perl_croak(aTHX_ "Permission denied"); + if (!PL_origargv[which]) { + errno = EPERM; + Perl_croak(aTHX_ "Permission denied\n"); + } PL_origargv[which] = savepv(Perl_form(aTHX_ "/dev/fd/%d/%s", PerlIO_fileno(PL_rsfp), PL_origargv[which])); #if defined(HAS_FCNTL) && defined(F_SETFD) -- 2.7.4