CVE-2014-2209: Permissions, Privileges, and Access Controls (CWE-264)
value: Facebook HipHop Virtual Machine (HHVM) before 3.1.0 does not drop supplemental group memberships within hphp/util/capability.cpp and hphp/util/light-process.cpp, which allows remote attackers to bypass intended access restrictions by leveraging group permissions for a file or directory.
CWE description: Weaknesses in this category are related to the management of permissions, privileges, and other security features that are used to perform access control.
Published: 2014-12-28T15:59Z
Repository: https://github.com/facebook/hhvm
Language: C++
Files changed: hphp/util/capability.cpp, hphp/util/light-process.cpp
Commit date: 2014-05-02 09:56:06 -0700
Commit message: Drop supplementary groups when changing to non-root

Summary: When running HHVM as a non-root user, UID and GID are updated correctly but supplementary groups are not dropped properly. This runs initgroups inside main thread and lightprocess threads to reset groups to those of the specified non-root user.

Reviewed By: @markw65

Differential Revision: D1193229

Diff: diff --git a/hphp/util/capability.cpp b/hphp/util/capability.cpp
index 56133790c4..e4c9df2070 100644
--- a/hphp/util/capability.cpp
+++ b/hphp/util/capability.cpp
@@ -22,10 +22,11 @@
 #include <linux/types.h>
 #include <sys/capability.h>
 #include <sys/prctl.h>
 #include <sys/types.h>
 #include <pwd.h>
+#include <grp.h>
 
 namespace HPHP {
 ///////////////////////////////////////////////////////////////////////////////
 
 static bool setInitialCapabilities() {
@@ -100,10 +101,16 @@ bool Capability::ChangeUnixUser(uid_t uid) {
       Logger::Error("unable to getpwuid(%d): %s", uid,
                     folly::errnoStr(errno).c_str());
       return false;
     }
 
+    if (initgroups(pw->pw_name, pw->pw_gid) < 0) {
+      Logger::Error("unable to drop supplementary group privs: %s",
+                    folly::errnoStr(errno).c_str());
+      return false;
+    }
+
     if (pw->pw_gid == 0 || setgid(pw->pw_gid) < 0) {
       Logger::Error("unable to drop gid privs: %s",
                     folly::errnoStr(errno).c_str());
       return false;
     }
diff --git a/hphp/util/light-process.cpp b/hphp/util/light-process.cpp
index 02d2c84260..3c67c32e66 100644
--- a/hphp/util/light-process.cpp
+++ b/hphp/util/light-process.cpp
@@ -23,10 +23,11 @@
 #include <sys/types.h>
 #include <sys/wait.h>
 #include <sys/socket.h>
 
 #include <afdt.h>
+#include <grp.h>
 #include <stdlib.h>
 #include <unistd.h>
 #include <poll.h>
 #include <pwd.h>
 #include <signal.h>
@@ -297,10 +298,11 @@ static void do_change_user(FILE *fin, FILE *fout) {
   lwp_read(fin, uname);
   if (uname.length() > 0) {
     struct passwd *pw = getpwnam(uname.c_str());
     if (pw) {
       if (pw->pw_gid) {
+        initgroups(pw->pw_name, pw->pw_gid);
         setgid(pw->pw_gid);
       }
       if (pw->pw_uid) {
         setuid(pw->pw_uid);
       }

Fixed code: #include <grp.h>
    if (initgroups(pw->pw_name, pw->pw_gid) < 0) {
      Logger::Error("unable to drop supplementary group privs: %s",
                    folly::errnoStr(errno).c_str());
      return false;
    }

#include <grp.h>
        initgroups(pw->pw_name, pw->pw_gid);