diff options
-rw-r--r-- | ChangeLog | 9 | ||||
-rw-r--r-- | configure.in | 2 | ||||
-rw-r--r-- | process.c | 71 |
3 files changed, 81 insertions, 1 deletions
@@ -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 @@ -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 |