summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChip Salzenberg <chip@pobox.com>1999-04-06 19:32:40 +0000
committerTodd Rinaldo <toddr@cpanel.net>2019-10-19 07:03:08 -0500
commit8393453d7039ab6d0d3a6abce4de9f9d1532211e (patch)
treec394b14a1a73400598a89caf35a48c5f1c3dd337
parentecd2912d7ea6d6a6d18794059cd75e9fc0c0736f (diff)
downloadperl-8393453d7039ab6d0d3a6abce4de9f9d1532211e.tar.gz
Disable setuid execution if 'nosuid' mount option specified.
(Original fix from Jarkko; hand-hackery of Configure by Chip.) p4raw-id: //depot/maint-5.004/perl@3222
-rwxr-xr-xConfigure77
-rw-r--r--config_h.SH49
-rw-r--r--perl.c92
3 files changed, 218 insertions, 0 deletions
diff --git a/Configure b/Configure
index 9f462b5673..caa66cb4fd 100755
--- a/Configure
+++ b/Configure
@@ -408,6 +408,13 @@ d_sockpair=''
sockethdr=''
socketlib=''
d_statblks=''
+d_fstatfs=''
+d_statfs=''
+d_statfsflags=''
+d_fstatvfs=''
+d_statvfs=''
+d_getmntent=''
+d_hasmntopt=''
d_stdio_cnt_lval=''
d_stdio_ptr_lval=''
d_stdiobase=''
@@ -483,6 +490,7 @@ i_locale=''
i_malloc=''
i_math=''
i_memory=''
+i_mntent=''
i_ndbm=''
i_neterrno=''
i_niin=''
@@ -507,11 +515,13 @@ i_bsdioctl=''
i_sysfilio=''
i_sysioctl=''
i_syssockio=''
+i_sysmount=''
i_sysndir=''
i_sysparam=''
i_sysresrc=''
i_sysselct=''
i_sysstat=''
+i_sysstatvfs=''
i_systimes=''
i_systypes=''
i_sysun=''
@@ -6069,6 +6079,23 @@ eval $inlibc
set chsize d_chsize
eval $inlibc
+hasfield='varname=$1; struct=$2; field=$3; shift; shift; shift;
+while $test $# -ge 2; do
+ case "$1" in
+ $define) echo "#include <$2>";;
+ esac ;
+ shift 2;
+done > try.c;
+echo "int main () { struct $struct foo; foo.$field = 0; }" >> try.c;
+if eval $cc $optimize $ccflags -c try.c >/dev/null 2>&1; then
+ val="$define";
+else
+ val="$undef";
+fi;
+set $varname;
+eval $setvar;
+$rm -f try.c try.o'
+
: check for const keyword
echo " "
echo 'Checking to see if your C compiler knows about "const"...' >&4
@@ -9533,6 +9560,10 @@ eval $inhdr
set math.h i_math
eval $inhdr
+: see if this is a mntent.h system
+set mntent.h i_mntent
+eval $inhdr
+
: see if ndbm.h is available
set ndbm.h t_ndbm
eval $inhdr
@@ -9871,6 +9902,38 @@ eval $setvar
set sys/param.h i_sysparam
eval $inhdr
+: see if this is a sys/mount.h system
+set sys/mount.h i_sysmount
+eval $inhdr
+
+: see if statfs exists
+set statfs d_statfs
+eval $inlibc
+
+: see if fstatfs exists
+set fstatfs d_fstatfs
+eval $inlibc
+
+: see if statfs knows about mount flags
+set d_statfsflags statfs f_flags $i_sysparam sys/param.h $i_sysmount sys/mount.h
+eval $hasfield
+
+: see if statvfs exists
+set statvfs d_statvfs
+eval $inlibc
+
+: see if fstatvfs exists
+set fstatvfs d_fstatvfs
+eval $inlibc
+
+: see if getmntent exists
+set getmntent d_getmntent
+eval $inlibc
+
+: see if hasmntopt exists
+set hasmntopt d_hasmntopt
+eval $inlibc
+
: see if sys/resource.h has to be included
set sys/resource.h i_sysresrc
eval $inhdr
@@ -9883,6 +9946,10 @@ eval $inhdr
set sys/types.h i_systypes
eval $inhdr
+: see if this is a sys/statvfs.h system
+set sys/statvfs.h i_sysstatvfs
+eval $inhdr
+
: see if this is a sys/un.h system
set sys/un.h i_sysun
eval $inhdr
@@ -10248,12 +10315,16 @@ d_flock='$d_flock'
d_fork='$d_fork'
d_fpathconf='$d_fpathconf'
d_fsetpos='$d_fsetpos'
+d_fstatfs='$d_fstatfs'
+d_fstatvfs='$d_fstatvfs'
d_ftime='$d_ftime'
d_getgrps='$d_getgrps'
d_setgrps='$d_setgrps'
d_gethent='$d_gethent'
d_gethname='$d_gethname'
d_getlogin='$d_getlogin'
+d_getmntent='$d_getmntent'
+d_hasmntopt='$d_hasmntopt'
d_getpgid='$d_getpgid'
d_getpgrp2='$d_getpgrp2'
d_getpgrp='$d_getpgrp'
@@ -10347,6 +10418,9 @@ d_sigsetjmp='$d_sigsetjmp'
d_socket='$d_socket'
d_sockpair='$d_sockpair'
d_statblks='$d_statblks'
+d_statfs='$d_statfs'
+d_statfsflags='$d_statfsflags'
+d_statvfs='$d_statvfs'
d_stdio_cnt_lval='$d_stdio_cnt_lval'
d_stdio_ptr_lval='$d_stdio_ptr_lval'
d_stdiobase='$d_stdiobase'
@@ -10438,6 +10512,7 @@ i_locale='$i_locale'
i_malloc='$i_malloc'
i_math='$i_math'
i_memory='$i_memory'
+i_mntent='$i_mntent'
i_ndbm='$i_ndbm'
i_neterrno='$i_neterrno'
i_niin='$i_niin'
@@ -10454,12 +10529,14 @@ i_sysfile='$i_sysfile'
i_sysfilio='$i_sysfilio'
i_sysin='$i_sysin'
i_sysioctl='$i_sysioctl'
+i_sysmount='$i_sysmount'
i_sysndir='$i_sysndir'
i_sysparam='$i_sysparam'
i_sysresrc='$i_sysresrc'
i_sysselct='$i_sysselct'
i_syssockio='$i_syssockio'
i_sysstat='$i_sysstat'
+i_sysstatvfs='$i_sysstatvfs'
i_systime='$i_systime'
i_systimek='$i_systimek'
i_systimes='$i_systimes'
diff --git a/config_h.SH b/config_h.SH
index f8963a9638..c2486f638e 100644
--- a/config_h.SH
+++ b/config_h.SH
@@ -1260,6 +1260,24 @@ sed <<!GROK!THIS! >config.h -e 's!^#undef\(.*/\)\*!/\*#define\1 \*!' -e 's!^#un-
*/
#$i_systypes I_SYS_TYPES /**/
+/* I_MNTENT:
+ * This symbol, if defined, indicates that <mntent.h> exists and
+ * should be included.
+ */
+#$i_mntent I_MNTENT /**/
+
+/* I_SYS_MOUNT:
+ * This symbol, if defined, indicates that <sys/mount.h> exists and
+ * should be included.
+ */
+#$i_sysmount I_SYS_MOUNT /**/
+
+/* I_SYS_STATVFS:
+ * This symbol, if defined, indicates that <sys/statvfs.h> exists and
+ * should be included.
+ */
+#$i_sysstatvfs I_SYS_STATVFS /**/
+
/* I_SYS_UN:
* This symbol, if defined, indicates to the C program that it should
* include <sys/un.h> to get UNIX domain socket definitions.
@@ -1623,6 +1641,37 @@ sed <<!GROK!THIS! >config.h -e 's!^#undef\(.*/\)\*!/\*#define\1 \*!' -e 's!^#un-
*/
#$d_sfio USE_SFIO /**/
+/* HAS_FSTATFS:
+ * This symbol, if defined, indicates that the fstatfs routine is
+ * available to do stat filesystems of file descriptors.
+ */
+/* HAS_STRUCT_STATFS_FLAGS:
+ * This symbol, if defined, indicates that the struct statfs
+ * does have the f_flags member containing the mount flags of
+ * the filesystem holding the file.
+ * This kind of struct statfs is coming from sys/mount.h (BSD)
+ * and not from sys/statfs.h (SYSV).
+ */
+#$d_fstatfs HAS_FSTATFS /**/
+#$d_statfsflags HAS_STRUCT_STATFS_FLAGS /**/
+
+/* HAS_FSTATVFS:
+ * This symbol, if defined, indicates that the fstatvfs routine is
+ * available to do stat filesystems of file descriptors.
+ */
+#$d_fstatvfs HAS_FSTATVFS /**/
+
+/* HAS_GETMNTENT:
+ * This symbol, if defined, indicates that the getmntent routine is
+ * available to enumerate mounted filesystems.
+ */
+/* HAS_HASMNTOPT:
+ * This symbol, if defined, indicates that the hasmntopt routine is
+ * available to check options on mounted filesystems.
+ */
+#$d_getmntent HAS_GETMNTENT /**/
+#$d_hasmntopt HAS_HASMNTOPT /**/
+
/* Sigjmp_buf:
* This is the buffer type to be used with Sigsetjmp and Siglongjmp.
*/
diff --git a/perl.c b/perl.c
index 7fccf4da9d..4d982fb9a6 100644
--- a/perl.c
+++ b/perl.c
@@ -20,6 +20,20 @@
#include <unistd.h>
#endif
+#ifdef IAMSUID
+
+#ifdef I_SYS_STATVFS
+# include <sys/statvfs.h> /* for f?statvfs() */
+#endif
+#ifdef I_SYS_MOUNT
+# include <sys/mount.h> /* for *BSD f?statfs() */
+#endif
+#ifdef I_MNTENT
+# include <mntent.h> /* for getmntent() */
+#endif
+
+#endif /* IAMSUID */
+
#if !defined(STANDARD_C) && !defined(HAS_GETENV_PROTOTYPE)
char *getenv _((char *)); /* Usually in <stdlib.h> */
#endif
@@ -79,6 +93,9 @@ static void open_script _((char *, bool, SV *));
static void perldoc_ref _((void));
static void usage _((char *));
static void validate_suid _((char *, char*));
+#ifdef IAMSUID
+static int fd_on_nosuid_fs _((int));
+#endif
static I32 read_e_script _((int idx, SV *buf_sv, int maxlen));
static int fdscript = -1;
@@ -1889,6 +1906,10 @@ char *scriptname;
croak("Can't swap uid and euid"); /* really paranoid */
if (Stat(SvPVX(GvSV(curcop->cop_filegv)),&tmpstatbuf) < 0)
croak("Permission denied"); /* testing full pathname here */
+#if defined(IAMSUID) && !defined(NO_NOSUID_CHECK)
+ if (fd_on_nosuid_fs(PerlIO_fileno(rsfp)))
+ croak("Permission denied");
+#endif
#if defined(IAMSUID) && defined(__NetBSD__)
/* XXX Other BSD 4.4-derived BSDs?
FreeBSD, OpenBSD, BSDI, MachTen? */
@@ -2688,3 +2709,74 @@ my_exit_jump()
JMPENV_JUMP(2);
}
+
+#ifdef IAMSUID
+static int
+fd_on_nosuid_fs(int fd)
+{
+ int on_nosuid = 0;
+ int check_okay = 0;
+/*
+ * Preferred order: fstatvfs(), fstatfs(), getmntent().
+ * fstatvfs() is UNIX98.
+ * fstatfs() is BSD.
+ * getmntent() is O(number-of-mounted-filesystems) and can hang.
+ */
+
+# ifdef HAS_FSTATVFS
+ struct statvfs stfs;
+ check_okay = fstatvfs(fd, &stfs) == 0;
+ on_nosuid = check_okay && (stfs.f_flag & ST_NOSUID);
+# else
+# if defined(HAS_FSTATFS) && defined(HAS_STRUCT_STATFS_FLAGS)
+ struct statfs stfs;
+ check_okay = fstatfs(fd, &stfs) == 0;
+# undef PERL_MOUNT_NOSUID
+# if !defined(PERL_MOUNT_NOSUID) && defined(MNT_NOSUID)
+# define PERL_MOUNT_NOSUID MNT_NOSUID
+# endif
+# if !defined(PERL_MOUNT_NOSUID) && defined(MS_NOSUID)
+# define PERL_MOUNT_NOSUID MS_NOSUID
+# endif
+# if !defined(PERL_MOUNT_NOSUID) && defined(M_NOSUID)
+# define PERL_MOUNT_NOSUID M_NOSUID
+# endif
+# ifdef PERL_MOUNT_NOSUID
+ on_nosuid = check_okay && (stfs.f_flags & PERL_MOUNT_NOSUID);
+# endif
+# else
+# if defined(HAS_GETMNTENT) && defined(HAS_HASMNTOPT) && defined(MNTOPT_NOSUID)
+
+ /* perlsdio.h might have disabled these */
+# undef fopen
+# undef fclose
+
+ void *mtab = fopen("/etc/mtab", "r");
+ struct mntent *entry;
+ struct stat 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;
+ break;
+ } /* A single fs may well fail its stat(). */
+ }
+ }
+ if (mtab)
+ fclose(mtab);
+
+# endif /* mntent */
+# endif /* statfs */
+# endif /* statvfs */
+
+ if (!check_okay)
+ croak("Can't check filesystem of script \"%s\"", origfilename);
+ return on_nosuid;
+}
+#endif /* IAMSUID */