summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog9
-rw-r--r--configure.in2
-rw-r--r--process.c71
3 files changed, 81 insertions, 1 deletions
diff --git a/ChangeLog b/ChangeLog
index 099deb099c..f16f57eb01 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,12 @@
+Thu Sep 4 23:39:52 2014 Tanaka Akira <akr@fsij.org>
+
+ * process.c (has_privilege): New function.
+ (retry_fork_async_signal_safe): Don't use vfork() for privileged
+ process.
+
+ * configure.in (getresuid): Check function.
+ (getresgid): Ditto.
+
Thu Sep 4 20:22:14 2014 Laurent Arnoud <laurent@spkdev.net>
* test/pathname/test_pathname.rb: added testcase for Pathname#mountpoint.
diff --git a/configure.in b/configure.in
index 5bd006f865..9080ab7559 100644
--- a/configure.in
+++ b/configure.in
@@ -1996,6 +1996,8 @@ AC_CHECK_FUNCS(getpgid)
AC_CHECK_FUNCS(getpgrp)
AC_CHECK_FUNCS(getpriority)
AC_CHECK_FUNCS(getpwnam_r)
+AC_CHECK_FUNCS(getresgid)
+AC_CHECK_FUNCS(getresuid)
AC_CHECK_FUNCS(getrlimit)
AC_CHECK_FUNCS(getsid)
AC_CHECK_FUNCS(gettimeofday) # for making ac_cv_func_gettimeofday
diff --git a/process.c b/process.c
index 77f5c6ad52..ee112d4249 100644
--- a/process.c
+++ b/process.c
@@ -3277,6 +3277,72 @@ recv_child_error(int fd, int *errp, char *errmsg, size_t errmsg_buflen)
return size != 0;
}
+static int
+has_privilege(void)
+{
+ /*
+ * has_privilege() is used to choose vfork() or fork().
+ *
+ * If the process has privilege, the parent process or
+ * the child process can change UID/GID.
+ * If vfork() is used to create the child process and
+ * the parent or child process change effective UID/GID,
+ * different privileged processes shares memory.
+ * It is a bad situation.
+ * So, fork() should be used.
+ */
+
+ rb_uid_t ruid, euid;
+ rb_gid_t rgid, egid;
+
+#if defined HAVE_ISSETUGID
+ if (issetugid())
+ return 1;
+#endif
+
+#ifdef HAVE_GETRESUID
+ {
+ int ret;
+ rb_uid_t suid;
+ ret = getresuid(&ruid, &euid, &suid);
+ if (ret == -1)
+ rb_sys_fail("getresuid(2)");
+ if (ruid != suid)
+ return 1;
+ }
+#else
+ {
+ rb_uid_t ruid = getuid();
+ rb_uid_t euid = geteuid();
+ }
+#endif
+
+ if (ruid == 0 || ruid != euid)
+ return 1;
+
+#ifdef HAVE_GETRESGID
+ {
+ int ret;
+ rb_gid_t sgid;
+ ret = getresgid(&rgid, &egid, &sgid);
+ if (ret == -1)
+ rb_sys_fail("getresgid(2)");
+ if (rgid != sgid)
+ return 0;
+ }
+#else
+ {
+ rb_gid_t rgid = getgid();
+ rb_gid_t egid = getegid();
+ }
+#endif
+
+ if (rgid == 0 || rgid != egid)
+ return 1;
+
+ return 0;
+}
+
static rb_pid_t
retry_fork_async_signal_safe(int *status, int *ep,
int (*chfunc)(void*, char *, size_t), void *charg,
@@ -3289,7 +3355,10 @@ retry_fork_async_signal_safe(int *status, int *ep,
while (1) {
prefork();
#ifdef HAVE_WORKING_VFORK
- pid = vfork();
+ if (!has_privilege())
+ pid = vfork();
+ else
+ pid = fork();
#else
pid = fork();
#endif