summaryrefslogtreecommitdiff
path: root/process.c
diff options
context:
space:
mode:
authorakr <akr@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2014-09-04 14:56:03 +0000
committerakr <akr@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2014-09-04 14:56:03 +0000
commitf20d51b0adb640c9351b3025e6dda7843c3342aa (patch)
treedd5586bf5ac5f1177bba913e00b58acbaee17d48 /process.c
parentd80282eecce4d2b6a7c3f419659d6e4d8eecb536 (diff)
* 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. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@47386 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
Diffstat (limited to 'process.c')
-rw-r--r--process.c71
1 files changed, 70 insertions, 1 deletions
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