]> git.ipfire.org Git - thirdparty/open-vm-tools.git/commitdiff
Interpose dlopen() to only allow root-owned library
authorOliver Kurth <okurth@vmware.com>
Fri, 15 Sep 2017 18:23:35 +0000 (11:23 -0700)
committerOliver Kurth <okurth@vmware.com>
Fri, 15 Sep 2017 18:23:35 +0000 (11:23 -0700)
Only allow dlopen() on library that meets the following:
- the library file is root-owened
- the directory is root-owned, and not others-writable.

open-vm-tools/lib/misc/posixDlopen.c

index fca6a18fbdb66cae5413f80e45525c5d42ccc03d..489abfa45d4a112b6bffb4288a36d041ba7eda26 100644 (file)
@@ -1,5 +1,5 @@
 /*********************************************************
- * Copyright (C) 2008-2016 VMware, Inc. All rights reserved.
+ * Copyright (C) 2008-2017 VMware, Inc. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU Lesser General Public License as published
@@ -16,6 +16,7 @@
  *
  *********************************************************/
 
+#define _GNU_SOURCE
 #define UNICODE_BUILDING_POSIX_WRAPPERS
 #include <stdio.h>
 #include <stdlib.h>
 
 #if !defined(_WIN32)
 #include <dlfcn.h>
+#include <sys/stat.h>
 #endif
 
 #include "vmware.h"
 #include "posixInt.h"
 
 
+#if defined(__linux__) && !defined(VMX86_SERVER) && !defined(VMX86_DEVEL)
+
+void *dlopen(const char *pathName, int flag) __attribute__((alias("Root_Dlopen")));
+
+static void *(*realDlopen)(const char *filename, int flag);
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * Root_Dlopen --
+ *
+ *      PR 1817345: only allow dlopen a library that meets the following:
+ *         - file is owned by the root
+ *         - directory is owned by the root, and not others-writable
+ *
+ * Results:
+ *      NULL    doesn't meet the above constraints or dlopen failure
+ *      !NULL   Success
+ *
+ * Side effects:
+ *      errno is set on error
+ *
+ *----------------------------------------------------------------------
+ */
+
+void *
+Root_Dlopen(const char *pathName,  // IN:
+            int flag)              // IN:
+
+{
+   struct stat sb;
+   char *realName, *p;
+   void *handle = NULL;
+   char savec;
+
+   if (UNLIKELY(realDlopen == NULL)) {
+      realDlopen = dlsym(RTLD_NEXT, "dlopen");
+      VERIFY(realDlopen != NULL);
+   }
+
+   if (pathName == NULL || strchr(pathName, '/') == NULL) {
+      return realDlopen(pathName, flag);
+   }
+
+   realName = Posix_RealPath(pathName);
+   if (!realName) {
+      Log("Fail to realpath: %s, errno=%d\n", pathName, errno);
+      goto out;
+   }
+
+   /* verify the file */
+   if (Posix_Stat(realName, &sb) != 0) {
+      Log("Fail to stat file: %s, errno=%d\n", realName, errno);
+      goto err;
+   }
+   if (sb.st_uid != 0) {
+      Log("File not root-owned: %s, id=%d\n", realName, sb.st_uid);
+      goto err;
+   }
+
+   /* verify the directory */
+   if ((p = strrchr(realName, '/')) == NULL) {
+      Log("Fail to find dir: %s\n", realName);
+      goto err;
+   }
+   savec = *(p + 1);
+   *(p + 1) = '\0';
+
+   if (Posix_Stat(realName, &sb) != 0) {
+      Log("Fail to stat dir: %s, errno=%d\n", realName, errno);
+      goto err;
+   }
+
+   if (sb.st_uid != 0 || (sb.st_mode & S_IWOTH)) {
+      Log("Dir not root-owned or others-writable: %s, id=%d mode=0x%x\n",
+          realName, sb.st_uid, sb.st_mode);
+      goto err;
+   }
+
+   *(p + 1) = savec;  /* restore file realName */
+   handle = (*realDlopen)(realName, flag);
+   free(realName);
+   return handle;
+err:
+   free(realName);
+out:
+   Log("Denied library: %s\n", pathName);
+   return realDlopen("/dev/null/dlopen/denied", 0);
+}
+#endif
+
+
 #if !defined(_WIN32)
 /*
  *----------------------------------------------------------------------