Przeglądaj źródła

YARN-9884. Make container-executor mount logic modular
Contributed by Eric Badger

Eric Yang 5 lat temu
rodzic
commit
72b1bed998
10 zmienionych plików z 929 dodań i 455 usunięć
  1. 1 0
      hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/CMakeLists.txt
  2. 2 2
      hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/native/container-executor/impl/container-executor.c
  3. 5 0
      hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/native/container-executor/impl/main.c
  4. 137 0
      hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/native/container-executor/impl/util.c
  5. 39 7
      hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/native/container-executor/impl/util.h
  6. 298 365
      hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/native/container-executor/impl/utils/docker-util.c
  7. 0 31
      hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/native/container-executor/impl/utils/docker-util.h
  8. 356 0
      hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/native/container-executor/impl/utils/mount-utils.c
  9. 40 0
      hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/native/container-executor/impl/utils/mount-utils.h
  10. 51 50
      hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/native/container-executor/test/utils/test_docker_util.cc

+ 1 - 0
hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/CMakeLists.txt

@@ -137,6 +137,7 @@ add_library(container
     main/native/container-executor/impl/modules/fpga/fpga-module.c
     main/native/container-executor/impl/modules/devices/devices-module.c
     main/native/container-executor/impl/utils/docker-util.c
+    main/native/container-executor/impl/utils/mount-utils.c
 )
 
 add_executable(container-executor

+ 2 - 2
hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/native/container-executor/impl/container-executor.c

@@ -1367,7 +1367,7 @@ char **construct_docker_command(const char *command_file) {
   ret = get_docker_command(command_file, &CFG, &buffer);
   if (ret != 0) {
     fprintf(ERRORFILE, "Error constructing docker command, docker error code=%d, error message='%s'\n", ret,
-            get_docker_error_message(ret));
+            get_error_message(ret));
     exit(DOCKER_RUN_FAILED);
   }
 
@@ -1414,7 +1414,7 @@ int exec_container(const char *command_file) {
   if (ret != 0) {
     free_configuration(&command_config);
     free(docker_binary);
-    return INVALID_COMMAND_FILE;
+    return INVALID_DOCKER_COMMAND_FILE;
   }
 
   char *value = get_configuration_value("docker-command", DOCKER_COMMAND_FILE_SECTION, &command_config);

+ 5 - 0
hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/native/container-executor/impl/main.c

@@ -788,6 +788,11 @@ int main(int argc, char **argv) {
     break;
   }
 
+  if (exit_code) {
+    fprintf(ERRORFILE, "Nonzero exit code=%d, error message='%s'\n", exit_code,
+            get_error_message(exit_code));
+  }
+
   flush_and_close_log_files();
   return exit_code;
 }

+ 137 - 0
hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/native/container-executor/impl/util.c

@@ -195,3 +195,140 @@ void quote_and_append_arg(char **str, size_t *size, const char* param, const cha
   sprintf(cur_ptr, append_format, param, tmp);
   free(tmp);
 }
+
+
+const char *get_error_message(const int error_code) {
+    switch (error_code) {
+      case INVALID_ARGUMENT_NUMBER:
+        return "Invalid argument number";
+      case INVALID_COMMAND_PROVIDED:
+        return "Invalid command provided";
+      case INVALID_NM_ROOT_DIRS:
+        return "Invalid NM root dirs";
+      case SETUID_OPER_FAILED:
+        return "setuid operation failed";
+      case UNABLE_TO_EXECUTE_CONTAINER_SCRIPT:
+        return "Unable to execute container script";
+      case UNABLE_TO_SIGNAL_CONTAINER:
+        return "Unable to signal container";
+      case INVALID_CONTAINER_PID:
+        return "Invalid container PID";
+      case OUT_OF_MEMORY:
+        return "Out of memory";
+      case INITIALIZE_USER_FAILED:
+        return "Initialize user failed";
+      case PATH_TO_DELETE_IS_NULL:
+        return "Path to delete is null";
+      case INVALID_CONTAINER_EXEC_PERMISSIONS:
+        return "Invalid container-executor permissions";
+      case INVALID_CONFIG_FILE:
+        return "Invalid config file";
+      case SETSID_OPER_FAILED:
+        return "setsid operation failed";
+      case WRITE_PIDFILE_FAILED:
+        return "Write to pidfile failed";
+      case WRITE_CGROUP_FAILED:
+        return "Write to cgroup failed";
+      case TRAFFIC_CONTROL_EXECUTION_FAILED:
+        return "Traffic control execution failed";
+      case DOCKER_RUN_FAILED:
+        return "Docker run failed";
+      case ERROR_OPENING_DOCKER_FILE:
+        return "Error opening Docker file";
+      case ERROR_READING_DOCKER_FILE:
+        return "Error reading Docker file";
+      case FEATURE_DISABLED:
+        return "Feature disabled";
+      case COULD_NOT_CREATE_SCRIPT_COPY:
+        return "Could not create script copy";
+      case COULD_NOT_CREATE_CREDENTIALS_COPY:
+        return "Could not create credentials copy";
+      case COULD_NOT_CREATE_WORK_DIRECTORIES:
+        return "Could not create work dirs";
+      case COULD_NOT_CREATE_APP_LOG_DIRECTORIES:
+        return "Could not create app log dirs";
+      case COULD_NOT_CREATE_TMP_DIRECTORIES:
+        return "Could not create tmp dirs";
+      case ERROR_CREATE_CONTAINER_DIRECTORIES_ARGUMENTS:
+        return "Error in create container directories arguments";
+      case ERROR_SANITIZING_DOCKER_COMMAND:
+        return "Error sanitizing Docker command";
+      case DOCKER_IMAGE_INVALID:
+        return "Docker image invalid";
+      case ERROR_COMPILING_REGEX:
+        return "Error compiling regex";
+      case INVALID_CONTAINER_ID:
+        return "Invalid container id";
+      case DOCKER_EXEC_FAILED:
+        return "Docker exec failed";
+      case COULD_NOT_CREATE_KEYSTORE_COPY:
+        return "Could not create keystore copy";
+      case COULD_NOT_CREATE_TRUSTSTORE_COPY:
+        return "Could not create truststore copy";
+      case ERROR_CALLING_SETVBUF:
+        return "Error calling setvbuf";
+      case BUFFER_TOO_SMALL:
+        return "Buffer too small";
+      case INVALID_MOUNT:
+        return "Invalid mount";
+      case INVALID_RO_MOUNT:
+        return "Invalid read-only mount";
+      case INVALID_RW_MOUNT:
+        return "Invalid read-write mount";
+      case MOUNT_ACCESS_ERROR:
+        return "Mount access error";
+      case INVALID_DOCKER_COMMAND_FILE:
+        return "Invalid docker command file passed";
+      case INCORRECT_DOCKER_COMMAND:
+        return "Incorrect command";
+      case INVALID_DOCKER_CONTAINER_NAME:
+        return "Invalid docker container name";
+      case INVALID_DOCKER_IMAGE_NAME:
+        return "Invalid docker image name";
+      case INVALID_DOCKER_USER_NAME:
+        return "Invalid docker user name";
+      case INVALID_DOCKER_INSPECT_FORMAT:
+        return "Invalid docker inspect format";
+      case UNKNOWN_DOCKER_COMMAND:
+        return "Unknown docker command";
+      case INVALID_DOCKER_NETWORK:
+        return "Invalid docker network";
+      case INVALID_DOCKER_PORTS_MAPPING:
+        return "Invalid docker ports mapping";
+      case INVALID_DOCKER_CAPABILITY:
+        return "Invalid docker capability";
+      case PRIVILEGED_DOCKER_CONTAINERS_DISABLED:
+        return "Privileged docker containers are disabled";
+      case INVALID_DOCKER_DEVICE:
+        return "Invalid docker device";
+      case INVALID_DOCKER_STOP_COMMAND:
+        return "Invalid docker stop command";
+      case INVALID_DOCKER_KILL_COMMAND:
+        return "Invalid docker kill command";
+      case INVALID_DOCKER_VOLUME_DRIVER:
+        return "Invalid docker volume-driver";
+      case INVALID_DOCKER_VOLUME_NAME:
+        return "Invalid docker volume name";
+      case INVALID_DOCKER_VOLUME_COMMAND:
+        return "Invalid docker volume command";
+      case DOCKER_PID_HOST_DISABLED:
+        return "Docker host pid namespace is disabled";
+      case INVALID_DOCKER_PID_NAMESPACE:
+        return "Invalid docker pid namespace";
+      case INVALID_DOCKER_IMAGE_TRUST:
+        return "Docker image is not trusted";
+      case INVALID_DOCKER_TMPFS_MOUNT:
+        return "Invalid docker tmpfs mount";
+      case INVALID_DOCKER_RUNTIME:
+        return "Invalid docker runtime";
+      case DOCKER_SERVICE_MODE_DISABLED:
+        return "Docker service mode disabled";
+      default:
+        return "Unknown error code";
+    }
+}
+
+int is_regex(const char *str) {
+    // regex should begin with prefix "regex:"
+    return (strncmp(str, "regex:", 6) == 0);
+}

+ 39 - 7
hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/native/container-executor/impl/util.h

@@ -31,10 +31,10 @@ enum errorcodes {
   INVALID_COMMAND_PROVIDED = 3,
   // SUPER_USER_NOT_ALLOWED_TO_RUN_TASKS (NOT USED) 4
   INVALID_NM_ROOT_DIRS = 5,
-  SETUID_OPER_FAILED, //6
-  UNABLE_TO_EXECUTE_CONTAINER_SCRIPT, //7
-  UNABLE_TO_SIGNAL_CONTAINER, //8
-  INVALID_CONTAINER_PID, //9
+  SETUID_OPER_FAILED = 6,
+  UNABLE_TO_EXECUTE_CONTAINER_SCRIPT = 7,
+  UNABLE_TO_SIGNAL_CONTAINER = 8,
+  INVALID_CONTAINER_PID = 9,
   // ERROR_RESOLVING_FILE_PATH (NOT_USED) 10
   // RELATIVE_PATH_COMPONENTS_IN_FILE_PATH (NOT USED) 11
   // UNABLE_TO_STAT_FILE (NOT USED) 12
@@ -46,8 +46,8 @@ enum errorcodes {
   OUT_OF_MEMORY = 18,
   // INITIALIZE_DISTCACHEFILE_FAILED (NOT USED) 19
   INITIALIZE_USER_FAILED = 20,
-  PATH_TO_DELETE_IS_NULL, //21
-  INVALID_CONTAINER_EXEC_PERMISSIONS, //22
+  PATH_TO_DELETE_IS_NULL = 21,
+  INVALID_CONTAINER_EXEC_PERMISSIONS = 22,
   // PREPARE_JOB_LOGS_FAILED (NOT USED) 23
   INVALID_CONFIG_FILE = 24,
   SETSID_OPER_FAILED = 25,
@@ -72,7 +72,35 @@ enum errorcodes {
   DOCKER_EXEC_FAILED = 44,
   COULD_NOT_CREATE_KEYSTORE_COPY = 45,
   COULD_NOT_CREATE_TRUSTSTORE_COPY = 46,
-  ERROR_CALLING_SETVBUF = 47
+  ERROR_CALLING_SETVBUF = 47,
+  BUFFER_TOO_SMALL = 48,
+  INVALID_MOUNT = 49,
+  INVALID_RO_MOUNT = 50,
+  INVALID_RW_MOUNT = 51,
+  MOUNT_ACCESS_ERROR = 52,
+  INVALID_DOCKER_COMMAND_FILE = 53,
+  INCORRECT_DOCKER_COMMAND = 54,
+  INVALID_DOCKER_CONTAINER_NAME = 55,
+  INVALID_DOCKER_IMAGE_NAME = 56,
+  INVALID_DOCKER_USER_NAME = 57,
+  INVALID_DOCKER_INSPECT_FORMAT = 58,
+  UNKNOWN_DOCKER_COMMAND = 59,
+  INVALID_DOCKER_NETWORK = 60,
+  INVALID_DOCKER_PORTS_MAPPING = 61,
+  INVALID_DOCKER_CAPABILITY = 62,
+  PRIVILEGED_DOCKER_CONTAINERS_DISABLED = 63,
+  INVALID_DOCKER_DEVICE = 64,
+  INVALID_DOCKER_STOP_COMMAND = 65,
+  INVALID_DOCKER_KILL_COMMAND = 66,
+  INVALID_DOCKER_VOLUME_DRIVER = 67,
+  INVALID_DOCKER_VOLUME_NAME = 68,
+  INVALID_DOCKER_VOLUME_COMMAND = 69,
+  DOCKER_PID_HOST_DISABLED = 70,
+  INVALID_DOCKER_PID_NAMESPACE = 71,
+  INVALID_DOCKER_IMAGE_TRUST = 72,
+  INVALID_DOCKER_TMPFS_MOUNT = 73,
+  INVALID_DOCKER_RUNTIME = 74,
+  DOCKER_SERVICE_MODE_DISABLED = 75
 };
 
 /* Macros for min/max. */
@@ -169,4 +197,8 @@ inline void* alloc_and_clear_memory(size_t num, size_t size) {
   return ret;
 }
 
+const char *get_error_message(const int error_code);
+
+int is_regex(const char *str);
+
 #endif

+ 298 - 365
hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/native/container-executor/impl/utils/docker-util.c

@@ -32,6 +32,7 @@
 #include <grp.h>
 #include <pwd.h>
 #include <errno.h>
+#include "mount-utils.h"
 
 int entry_point = 0;
 
@@ -40,11 +41,11 @@ static int read_and_verify_command_file(const char *command_file, const char *do
   int ret = 0;
   ret = read_config(command_file, command_config);
   if (ret != 0) {
-    return INVALID_COMMAND_FILE;
+    return INVALID_DOCKER_COMMAND_FILE;
   }
   char *command = get_configuration_value("docker-command", DOCKER_COMMAND_FILE_SECTION, command_config);
   if (command == NULL || (strcmp(command, docker_command) != 0)) {
-    ret = INCORRECT_COMMAND;
+    ret = INCORRECT_DOCKER_COMMAND;
   }
   free(command);
   return ret;
@@ -173,23 +174,12 @@ free_and_exit:
   return ret;
 }
 
-static int is_regex(const char *str) {
-  // regex should begin with prefix "regex:"
-  return (strncmp(str, "regex:", 6) == 0);
-}
-
 static int is_valid_tmpfs_mount(const char *mount) {
   const char *regex_str = "^/[^:]+$";
   // execute_regex_match return 0 is matched success
   return execute_regex_match(regex_str, mount) == 0;
 }
 
-static int is_volume_name(const char *volume_name) {
-  const char *regex_str = "^[a-zA-Z0-9]([a-zA-Z0-9_.-]*)$";
-  // execute_regex_match return 0 is matched success
-  return execute_regex_match(regex_str, volume_name) == 0;
-}
-
 static int is_valid_ports_mapping(const char *ports_mapping) {
   const char *regex_str = "^:[0-9]+|^[0-9]+:[0-9]+|^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\\.)"
                           "{3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5]):[0-9]+:[0-9]+$";
@@ -197,11 +187,6 @@ static int is_valid_ports_mapping(const char *ports_mapping) {
   return execute_regex_match(regex_str, ports_mapping) == 0;
 }
 
-static int is_volume_name_matched_by_regex(const char* requested, const char* pattern) {
-  // execute_regex_match return 0 is matched success
-  return is_volume_name(requested) && (execute_regex_match(pattern + sizeof("regex:"), requested) == 0);
-}
-
 static int add_param_to_command_if_allowed(const struct configuration *command_config,
                                            const struct configuration *executor_cfg,
                                            const char *key, const char *allowed_key, const char *param,
@@ -322,66 +307,6 @@ static int validate_container_name(const char *container_name) {
   return INVALID_DOCKER_CONTAINER_NAME;
 }
 
-const char *get_docker_error_message(const int error_code) {
-
-  switch (error_code) {
-    case INVALID_COMMAND_FILE:
-      return "Invalid command file passed";
-    case INCORRECT_COMMAND:
-      return "Incorrect command";
-    case BUFFER_TOO_SMALL:
-      return "Command buffer too small";
-    case INVALID_DOCKER_CONTAINER_NAME:
-      return "Invalid docker container name";
-    case INVALID_DOCKER_IMAGE_NAME:
-      return "Invalid docker image name";
-    case INVALID_DOCKER_USER_NAME:
-      return "Invalid docker user name";
-    case INVALID_DOCKER_INSPECT_FORMAT:
-      return "Invalid docker inspect format";
-    case UNKNOWN_DOCKER_COMMAND:
-      return "Unknown docker command";
-    case INVALID_DOCKER_NETWORK:
-      return "Invalid docker network";
-    case INVALID_DOCKER_PORTS_MAPPING:
-      return "Invalid docker ports mapping";
-    case INVALID_DOCKER_CAPABILITY:
-      return "Invalid docker capability";
-    case PRIVILEGED_CONTAINERS_DISABLED:
-      return "Privileged containers are disabled";
-    case INVALID_DOCKER_MOUNT:
-      return "Invalid docker mount";
-    case INVALID_DOCKER_RO_MOUNT:
-      return "Invalid docker read-only mount";
-    case INVALID_DOCKER_RW_MOUNT:
-      return "Invalid docker read-write mount";
-    case MOUNT_ACCESS_ERROR:
-      return "Mount access error";
-    case INVALID_DOCKER_DEVICE:
-      return "Invalid docker device";
-    case INVALID_DOCKER_VOLUME_DRIVER:
-      return "Invalid docker volume-driver";
-    case INVALID_DOCKER_VOLUME_NAME:
-      return "Invalid docker volume name";
-    case INVALID_DOCKER_VOLUME_COMMAND:
-      return "Invalid docker volume command";
-    case PID_HOST_DISABLED:
-      return "Host pid namespace is disabled";
-    case INVALID_PID_NAMESPACE:
-      return "Invalid pid namespace";
-    case INVALID_DOCKER_IMAGE_TRUST:
-      return "Docker image is not trusted";
-    case INVALID_DOCKER_TMPFS_MOUNT:
-      return "Invalid docker tmpfs mount";
-    case INVALID_DOCKER_RUNTIME:
-      return "Invalid docker runtime";
-    case SERVICE_MODE_DISABLED:
-      return "Service mode disabled";
-    default:
-      return "Unknown error";
-  }
-}
-
 int get_max_retries(const struct configuration *conf) {
   int retries = 10;
   char *max_retries = get_configuration_value(DOCKER_INSPECT_MAX_RETRIES_KEY,
@@ -424,7 +349,7 @@ int get_docker_command(const char *command_file, const struct configuration *con
   ret = read_config(command_file, &command_config);
   if (ret != 0) {
     free_configuration(&command_config);
-    return INVALID_COMMAND_FILE;
+    return INVALID_DOCKER_COMMAND_FILE;
   }
 
   char *docker = get_docker_binary(conf);
@@ -905,7 +830,7 @@ int get_docker_exec_command(const char *command_file, const struct configuration
       }
     }
   } else {
-    ret = INVALID_COMMAND_FILE;
+    ret = INVALID_DOCKER_COMMAND_FILE;
   }
 free_and_exit:
   free(container_name);
@@ -999,7 +924,7 @@ int is_service_mode_enabled(const struct configuration *command_config,
       if (is_feature_enabled(DOCKER_SERVICE_MODE_ENABLED_KEY, ret, section)) {
         ret = 1;
       } else {
-        ret = SERVICE_MODE_DISABLED;
+        ret = DOCKER_SERVICE_MODE_DISABLED;
       }
      }
     free(value);
@@ -1083,17 +1008,17 @@ static int set_pid_namespace(const struct configuration *command_config,
           }
         } else {
           fprintf(ERRORFILE, "Host pid namespace is disabled\n");
-          ret = PID_HOST_DISABLED;
+          ret = DOCKER_PID_HOST_DISABLED;
           goto free_and_exit;
         }
       } else {
         fprintf(ERRORFILE, "Host pid namespace is disabled\n");
-        ret = PID_HOST_DISABLED;
+        ret = DOCKER_PID_HOST_DISABLED;
         goto free_and_exit;
       }
     } else {
       fprintf(ERRORFILE, "Invalid pid namespace\n");
-      ret = INVALID_PID_NAMESPACE;
+      ret = INVALID_DOCKER_PID_NAMESPACE;
     }
   }
 
@@ -1161,164 +1086,6 @@ static int set_env(const struct configuration *command_config, struct args *args
   return ret;
 }
 
-/**
- * Helper function to help normalize mounts for checking if mounts are
- * permitted. The function does the following -
- * 1. Find the canonical path for mount using realpath
- * 2. If the path is a directory, add a '/' at the end (if not present)
- * 3. Return a copy of the canonicalised path(to be freed by the caller)
- * @param mount path to be canonicalised
- * @param isRegexAllowed whether regex matching is allowed for normalize mount
- * @return pointer to canonicalised path, NULL on error
- */
-static char* normalize_mount(const char* mount, int isRegexAllowed) {
-  int ret = 0;
-  struct stat buff;
-  char *ret_ptr = NULL, *real_mount = NULL;
-  if (mount == NULL) {
-    return NULL;
-  }
-  real_mount = realpath(mount, NULL);
-  if (real_mount == NULL) {
-    // If mount is a valid named volume, just return it and let docker decide
-    if (is_volume_name(mount)) {
-      return strdup(mount);
-    }
-    // we only allow permitted mount to be REGEX, for permitted mount, we check
-    // if it's a valid REGEX return; for user mount, we need to strictly check
-    if (isRegexAllowed) {
-      if (is_regex(mount)) {
-        return strdup(mount);
-      }
-    }
-    fprintf(ERRORFILE, "Could not determine real path of mount '%s'\n", mount);
-    return NULL;
-  }
-  ret = stat(real_mount, &buff);
-  if (ret == 0) {
-    if (S_ISDIR(buff.st_mode)) {
-      size_t len = strlen(real_mount);
-      if (len <= 0) {
-        free(real_mount);
-        return NULL;
-      }
-      if (real_mount[len - 1] != '/') {
-        ret_ptr = (char *) alloc_and_clear_memory(len + 2, sizeof(char));
-        strncpy(ret_ptr, real_mount, len);
-        ret_ptr[len] = '/';
-        ret_ptr[len + 1] = '\0';
-      } else {
-        ret_ptr = strdup(real_mount);
-      }
-    } else {
-      ret_ptr = strdup(real_mount);
-    }
-  } else {
-    fprintf(ERRORFILE, "Could not stat path '%s'\n", real_mount);
-    ret_ptr = NULL;
-  }
-  free(real_mount);
-  return ret_ptr;
-}
-
-static int normalize_mounts(char **mounts, int isRegexAllowed) {
-  int i = 0;
-  char *tmp = NULL;
-  if (mounts == NULL) {
-    return 0;
-  }
-  for (i = 0; mounts[i] != NULL; ++i) {
-    tmp = normalize_mount(mounts[i], isRegexAllowed);
-    if (tmp == NULL) {
-      return -1;
-    }
-    free(mounts[i]);
-    mounts[i] = tmp;
-  }
-  return 0;
-}
-
-static int check_mount_permitted(const char **permitted_mounts, const char *requested) {
-  int i = 0, ret = 0;
-  size_t permitted_mount_len = 0;
-  if (permitted_mounts == NULL) {
-    return 0;
-  }
-  char *normalized_path = normalize_mount(requested, 0);
-  if (normalized_path == NULL) {
-    return -1;
-  }
-  for (i = 0; permitted_mounts[i] != NULL; ++i) {
-    if (strcmp(normalized_path, permitted_mounts[i]) == 0) {
-      ret = 1;
-      break;
-    }
-    // if (permitted_mounts[i] is a REGEX): use REGEX to compare; return
-    if (is_regex(permitted_mounts[i]) &&
-    is_volume_name_matched_by_regex(normalized_path, permitted_mounts[i])) {
-      ret = 1;
-      break;
-    }
-
-    // directory check
-    permitted_mount_len = strlen(permitted_mounts[i]);
-    struct stat path_stat;
-    stat(permitted_mounts[i], &path_stat);
-    if(S_ISDIR(path_stat.st_mode)) {
-      if (strncmp(normalized_path, permitted_mounts[i], permitted_mount_len) == 0) {
-        ret = 1;
-        break;
-      }
-    }
-  }
-  free(normalized_path);
-  return ret;
-}
-
-static char* get_mount_source(const char *mount) {
-  const char *tmp = strchr(mount, ':');
-  if (tmp == NULL) {
-    fprintf(ERRORFILE, "Invalid docker mount '%s'\n", mount);
-    return NULL;
-  }
-  size_t len = tmp - mount;
-  return strndup(mount, len);
-}
-
-static char* get_mount_type(const char *mount) {
-  const char *tmp = strrchr(mount, ':');
-  if (tmp == NULL) {
-    fprintf(ERRORFILE, "Invalid docker mount '%s'\n", mount);
-    return NULL;
-  }
-  if (strlen(tmp) < 2) {
-    fprintf(ERRORFILE, "Invalid docker mount '%s'\n", mount);
-    return NULL;
-  }
-  char *mount_type = strdup(&tmp[1]);
-  if (strncmp("ro", mount_type, 2) != 0 &&
-      strncmp("rw", mount_type, 2) != 0) {
-    fprintf(ERRORFILE, "Invalid docker mount type '%s'\n", mount_type);
-    free(mount_type);
-    return NULL;
-  }
-  if (strlen(mount_type) > 2) {
-    if (strlen(mount_type) < 8 ||
-        (strcmp("shared", mount_type + 3) != 0 &&
-        strcmp("rshared", mount_type + 3) != 0 &&
-        strcmp("slave", mount_type + 3) != 0 &&
-        strcmp("rslave", mount_type + 3) != 0 &&
-        strcmp("private", mount_type + 3) != 0 &&
-        strcmp("rprivate", mount_type + 3) != 0)) {
-      fprintf(ERRORFILE, "Invalid docker mount type '%s'\n", mount_type);
-      free(mount_type);
-      return NULL;
-    }
-    mount_type[2] = ',';
-  }
-  return mount_type;
-}
-
 static int add_tmpfs_mounts(const struct configuration *command_config, args *args) {
   char **values = get_configuration_values_delimiter("tmpfs", DOCKER_COMMAND_FILE_SECTION, command_config, ",");
   int i = 0, ret = 0;
@@ -1348,122 +1115,7 @@ free_and_exit:
   return ret;
 }
 
-static int add_mounts(const struct configuration *command_config, const struct configuration *conf, args *args) {
-  const char *tmp_path_buffer[2] = {NULL, NULL};
-  char *mount_src = NULL;
-  char *mount_type = NULL;
-  char **permitted_ro_mounts = get_configuration_values_delimiter("docker.allowed.ro-mounts",
-                                                                  CONTAINER_EXECUTOR_CFG_DOCKER_SECTION, conf, ",");
-  char **permitted_rw_mounts = get_configuration_values_delimiter("docker.allowed.rw-mounts",
-                                                                  CONTAINER_EXECUTOR_CFG_DOCKER_SECTION, conf, ",");
-  char **values = get_configuration_values_delimiter("mounts", DOCKER_COMMAND_FILE_SECTION, command_config, ",");
-  char *config_path = get_config_path("");
-  const char *container_executor_cfg_path = normalize_mount(config_path, 0);
-  free(config_path);
-  int i = 0, permitted_rw = 0, permitted_ro = 0, ret = 0;
-  if (values == NULL) {
-    goto free_and_exit;
-  }
-  // Disable mount volumes if image is not trusted.
-  if (check_trusted_image(command_config, conf) != 0) {
-    fprintf(ERRORFILE, "Disable mount volume for untrusted image\n");
-    // YARN will implicitly bind node manager local directory to
-    // docker image.  This can create file system security holes,
-    // if docker container has binary to escalate privileges.
-    // For untrusted image, we drop mounting without reporting
-    // INVALID_DOCKER_MOUNT messages to allow running untrusted
-    // image in a sandbox.
-    ret = 0;
-    goto free_and_exit;
-  }
-  ret = normalize_mounts(permitted_ro_mounts, 1);
-  ret |= normalize_mounts(permitted_rw_mounts, 1);
-  if (ret != 0) {
-    fprintf(ERRORFILE, "Unable to find permitted docker mounts on disk\n");
-    ret = MOUNT_ACCESS_ERROR;
-    goto free_and_exit;
-  }
-  for (i = 0; values[i] != NULL; i++) {
-    mount_src = get_mount_source(values[i]);
-    if (mount_src == NULL) {
-      fprintf(ERRORFILE, "Invalid docker mount '%s'\n", values[i]);
-      ret = INVALID_DOCKER_MOUNT;
-      goto free_and_exit;
-    }
-    mount_type = get_mount_type(values[i]);
-    if (mount_type == NULL) {
-      fprintf(ERRORFILE, "Invalid docker mount '%s'\n", values[i]);
-      ret = INVALID_DOCKER_MOUNT;
-      goto free_and_exit;
-    }
-    permitted_rw = check_mount_permitted((const char **) permitted_rw_mounts, mount_src);
-    permitted_ro = check_mount_permitted((const char **) permitted_ro_mounts, mount_src);
-    if (permitted_ro == -1 || permitted_rw == -1) {
-      fprintf(ERRORFILE, "Invalid docker mount '%s', realpath=%s\n", values[i], mount_src);
-      ret = INVALID_DOCKER_MOUNT;
-      goto free_and_exit;
-    }
-    if (strncmp("rw", mount_type, 2) == 0) {
-      // rw mount
-      if (permitted_rw == 0) {
-        fprintf(ERRORFILE, "Configuration does not allow docker mount '%s', realpath=%s\n", values[i], mount_src);
-        ret = INVALID_DOCKER_RW_MOUNT;
-        goto free_and_exit;
-      } else {
-        // determine if the user can modify the container-executor.cfg file
-        tmp_path_buffer[0] = normalize_mount(mount_src, 0);
-        // just re-use the function, flip the args to check if the container-executor path is in the requested
-        // mount point
-        ret = check_mount_permitted(tmp_path_buffer, container_executor_cfg_path);
-        free((void *) tmp_path_buffer[0]);
-        if (ret == 1) {
-          fprintf(ERRORFILE, "Attempting to mount a parent directory '%s' of container-executor.cfg as read-write\n",
-                  values[i]);
-          ret = INVALID_DOCKER_RW_MOUNT;
-          goto free_and_exit;
-        }
-      }
-    } else {
-      // ro mount
-      if (permitted_ro == 0 && permitted_rw == 0) {
-        fprintf(ERRORFILE, "Configuration does not allow docker mount '%s', realpath=%s\n", values[i], mount_src);
-        ret = INVALID_DOCKER_RO_MOUNT;
-        goto free_and_exit;
-      }
-    }
-
-    if (strlen(mount_type) > 2) {
-      // overwrite separator between read mode and propagation option with ','
-      int mount_type_index = strlen(values[i]) - strlen(mount_type);
-      values[i][mount_type_index + 2] = ',';
-    }
 
-    ret = add_to_args(args, "-v");
-    if (ret != 0) {
-      ret = BUFFER_TOO_SMALL;
-      goto free_and_exit;
-    }
-
-    ret = add_to_args(args, values[i]);
-    if (ret != 0) {
-      ret = BUFFER_TOO_SMALL;
-      goto free_and_exit;
-    }
-    free(mount_src);
-    free(mount_type);
-    mount_src = NULL;
-    mount_type = NULL;
-  }
-
-free_and_exit:
-  free(mount_src);
-  free(mount_type);
-  free_values(permitted_ro_mounts);
-  free_values(permitted_rw_mounts);
-  free_values(values);
-  free((void *) container_executor_cfg_path);
-  return ret;
-}
 
 static int check_privileges(const char *user) {
   int ngroups = 0;
@@ -1567,13 +1219,13 @@ static int set_privileged(const struct configuration *command_config, const stru
         // Disable set privileged if entry point mode is disabled
         if (get_use_entry_point_flag() != 1) {
           fprintf(ERRORFILE, "Privileged containers are disabled for non-entry-point mode\n");
-          ret = PRIVILEGED_CONTAINERS_DISABLED;
+          ret = PRIVILEGED_DOCKER_CONTAINERS_DISABLED;
           goto free_and_exit;
         }
         // Disable set privileged if image is not trusted.
         if (check_trusted_image(command_config, conf) != 0) {
           fprintf(ERRORFILE, "Privileged containers are disabled from untrusted source\n");
-          ret = PRIVILEGED_CONTAINERS_DISABLED;
+          ret = PRIVILEGED_DOCKER_CONTAINERS_DISABLED;
           goto free_and_exit;
         }
         allowed = check_privileges(user);
@@ -1584,17 +1236,17 @@ static int set_privileged(const struct configuration *command_config, const stru
           }
         } else {
           fprintf(ERRORFILE, "Privileged containers are disabled for user: %s\n", user);
-          ret = PRIVILEGED_CONTAINERS_DISABLED;
+          ret = PRIVILEGED_DOCKER_CONTAINERS_DISABLED;
           goto free_and_exit;
         }
       } else {
         fprintf(ERRORFILE, "Privileged containers are disabled\n");
-        ret = PRIVILEGED_CONTAINERS_DISABLED;
+        ret = PRIVILEGED_DOCKER_CONTAINERS_DISABLED;
         goto free_and_exit;
       }
     } else {
       fprintf(ERRORFILE, "Privileged containers are disabled\n");
-      ret = PRIVILEGED_CONTAINERS_DISABLED;
+      ret = PRIVILEGED_DOCKER_CONTAINERS_DISABLED;
       goto free_and_exit;
     }
   }
@@ -1606,6 +1258,287 @@ free_and_exit:
   return ret;
 }
 
+
+
+static char* get_docker_mount_source(const char *mount) {
+    const char *tmp = strchr(mount, ':');
+    if (tmp == NULL) {
+        fprintf(ERRORFILE, "Invalid docker mount '%s'\n", mount);
+        return NULL;
+    }
+    size_t len = tmp - mount;
+    return strndup(mount, len);
+}
+
+static char* get_docker_mount_dest(const char *mount) {
+    size_t len;
+    const char *start = strchr(mount, ':') + 1;
+    if (start == NULL) {
+        fprintf(ERRORFILE, "Invalid docker mount '%s'\n", mount);
+        return NULL;
+    }
+
+    const char *end = strchr(start, ':');
+    if (end == NULL) {
+        len = strlen(mount) - (start - mount);
+    } else {
+        len = end - start;
+    }
+    return strndup(start, len);
+}
+
+static mount_options* get_docker_mount_options(const char *mount_string) {
+    char **opts = NULL;
+    mount_options *options = NULL;
+    unsigned int num_opts = 0;
+    char *option = NULL;
+    int len = 0;
+
+    //+1 because we don't care about the ':'
+    const char *option_string = strrchr(mount_string, ':') + 1;
+    if (option_string == NULL) {
+        fprintf(ERRORFILE, "Invalid docker mount '%s'\n", mount_string);
+        return NULL;
+    }
+
+    options = (mount_options *) calloc(1, sizeof(*options));
+    if (options == NULL) {
+        fprintf(ERRORFILE, "Unable to allocate %ld bytes\n", sizeof(*options));
+        return NULL;
+    }
+
+    len = strlen(option_string);
+
+    if (len == 2) {
+        opts = (char **) calloc(1, sizeof(*opts));
+        if (opts == NULL) {
+            fprintf(ERRORFILE, "Unable to allocate %ld bytes\n", sizeof(*opts));
+            free(options);
+            return NULL;
+        }
+        num_opts = 1;
+    } else if (len < 8) {
+        fprintf(ERRORFILE, "Invalid docker mount. Too many options. '%s'\n", mount_string);
+        free(options);
+        return NULL;
+    } else {
+        opts = (char **) calloc(2, sizeof(*opts));
+        if (opts == NULL) {
+          fprintf(ERRORFILE, "Unable to allocate %ld bytes\n", 2 * sizeof(*opts));
+          free(options);
+          return NULL;
+        }
+        num_opts = 2;
+    }
+
+    options->opts = opts;
+    options->num_opts = num_opts;
+
+    char *option_string_token = strdup(option_string);
+    option = strtok(option_string_token, "+");
+    for (unsigned int i = 0; i < options->num_opts; i++) {
+        if (option == NULL) {
+            fprintf(ERRORFILE, "Invalid docker mount options '%s'\n", mount_string);
+            free(option_string_token);
+            free_mount_options(options);
+            return NULL;
+        }
+
+        if (strcmp("rw", option) == 0) {
+            options->rw = 1;
+        } else if (strcmp("ro", option) == 0) {
+            options->rw = 0;
+        } else if (strcmp("shared", option) != 0 &&
+          (strcmp("rshared", option) != 0) &&
+          (strcmp("slave", option) != 0) &&
+          (strcmp("rslave", option) != 0) &&
+          (strcmp("private", option) != 0) &&
+          (strcmp("rprivate", option) != 0)) {
+            fprintf(ERRORFILE, "Invalid docker mount options '%s'\n", mount_string);
+            free(option_string_token);
+            free_mount_options(options);
+            return NULL;
+        }
+        options->opts[i] = strdup(option);
+        option = strtok(NULL, "+");
+    }
+
+    free(option_string_token);
+    return options;
+}
+
+static char* get_docker_mount_options_string(mount_options *options) {
+    char *options_string = NULL;
+    int len = 0;
+    int idx = 0;
+    unsigned int i;
+
+    for (i = 0; i < options->num_opts; i++) {
+        len += strlen(options->opts[i]);
+    }
+    len += i; // i-1 commas plus 1 for NUL termination
+
+    options_string = (char *) calloc(len, sizeof(*options_string));
+    if (options_string == NULL) {
+      fputs("Unable to allocate memory\n", ERRORFILE);
+      return NULL;
+    }
+
+    idx += sprintf(options_string, "%s", options->opts[0]);
+    for (i = 1; i < options->num_opts; i++) {
+        idx += sprintf(options_string + idx, ",%s", options->opts[i]);
+    }
+
+  return options_string;
+}
+
+static int add_mounts_to_docker_args(mount *mounts, unsigned int num_mounts, args *args) {
+    int ret = 0, len;
+    unsigned int i;
+    char *mount_string = NULL;
+    char *options_string = NULL;
+
+    if (mounts == NULL) {
+        return ret;
+    }
+
+    for (i = 0; i < num_mounts; i++) {
+        ret = add_to_args(args, "-v");
+        if (ret != 0) {
+            ret = BUFFER_TOO_SMALL;
+            return ret;
+        }
+        options_string = get_docker_mount_options_string(mounts[i].options);
+
+        //magic number '+3': +1 for both ':', and +1 for NULL termination
+        len = strlen(mounts[i].src) + strlen(mounts[i].dest) + strlen(options_string) + 3;
+        mount_string = (char *) calloc(len, sizeof(*mount_string));
+
+        snprintf(mount_string, len, "%s:%s:%s", mounts[i].src, mounts[i].dest, options_string);
+
+        ret = add_to_args(args, mount_string);
+        if (ret != 0) {
+            ret = BUFFER_TOO_SMALL;
+            goto free_and_exit;
+        }
+        free(mount_string);
+        free(options_string);
+    }
+    return ret;
+
+free_and_exit:
+    free(mount_string);
+    free(options_string);
+    return ret;
+}
+
+static int get_docker_mounts(mount *mounts, char **mounts_string, unsigned int num_mounts) {
+    unsigned int i;
+    int ret = 0;
+    char *src, *dest;
+    mount_options *options = NULL;
+
+    if (mounts_string == NULL) {
+        fprintf(ERRORFILE, "Unable to normalize container-executor.cfg path\n");
+        ret = MOUNT_ACCESS_ERROR;
+        goto free_and_exit;
+    }
+
+    for (i = 0; i < num_mounts; i++) {
+        src = get_docker_mount_source(mounts_string[i]);
+        if (src == NULL) {
+            fprintf(ERRORFILE, "Invalid mount '%s'\n", mounts_string[i]);
+            ret = INVALID_MOUNT;
+            goto free_and_exit;
+        }
+        mounts[i].src = src;
+
+        dest = get_docker_mount_dest(mounts_string[i]);
+        if (dest == NULL) {
+            fprintf(ERRORFILE, "Invalid mount '%s'\n", mounts_string[i]);
+            ret = INVALID_MOUNT;
+            goto free_and_exit;
+        }
+        mounts[i].dest = dest;
+
+        options = get_docker_mount_options(mounts_string[i]);
+        if (options == NULL) {
+            fprintf(ERRORFILE, "Invalid mount '%s'\n", mounts_string[i]);
+            ret = INVALID_MOUNT;
+            goto free_and_exit;
+        }
+        mounts[i].options = options;
+    }
+
+free_and_exit:
+    return ret;
+}
+
+static int add_docker_mounts(const struct configuration *command_config, const struct configuration *conf, args *args) {
+    mount *mounts = NULL;
+    unsigned int num_mounts = 0;
+    int ret;
+    char **permitted_ro_mounts = NULL;
+    char **permitted_rw_mounts = NULL;
+    char **mounts_string = NULL;
+    permitted_ro_mounts = get_configuration_values_delimiter("docker.allowed.ro-mounts",
+                                                             CONTAINER_EXECUTOR_CFG_DOCKER_SECTION, conf, ",");
+    permitted_rw_mounts = get_configuration_values_delimiter("docker.allowed.rw-mounts",
+                                                             CONTAINER_EXECUTOR_CFG_DOCKER_SECTION, conf, ",");
+    mounts_string = get_configuration_values_delimiter("mounts", DOCKER_COMMAND_FILE_SECTION, command_config, ",");
+
+    if (mounts_string == NULL) {
+        ret = 0;
+        goto free_and_exit;
+    }
+
+    while (mounts_string[num_mounts] != NULL) {
+        num_mounts++;
+    }
+
+    // Disable mount volumes if image is not trusted.
+    if (check_trusted_image(command_config, conf) != 0) {
+        fprintf(ERRORFILE, "Disable mount volume for untrusted image\n");
+        // YARN will implicitly bind node manager local directory to
+        // docker image.  This can create file system security holes,
+        // if docker container has binary to escalate privileges.
+        // For untrusted image, we drop mounting without reporting
+        // INVALID_MOUNT messages to allow running untrusted
+        // image in a sandbox.
+        ret = 0;
+        goto free_and_exit;
+    }
+
+    mounts = (mount *) calloc(num_mounts, sizeof(*mounts));
+    if (mounts == NULL) {
+        fprintf(ERRORFILE, "Unable to allocate %ld bytes\n", num_mounts * sizeof(*mounts));
+        ret = OUT_OF_MEMORY;
+        goto free_and_exit;
+    }
+
+    ret = get_docker_mounts(mounts, mounts_string, num_mounts);
+    if (ret != 0) {
+        goto free_and_exit;
+    }
+
+    ret = validate_mounts(permitted_ro_mounts, permitted_rw_mounts, mounts, num_mounts);
+    if (ret != 0) {
+        goto free_and_exit;
+    }
+
+    ret = add_mounts_to_docker_args(mounts, num_mounts, args);
+    if (ret != 0) {
+        goto free_and_exit;
+    }
+
+free_and_exit:
+    free_values(permitted_ro_mounts);
+    free_values(permitted_rw_mounts);
+    free_values(mounts_string);
+    free_mounts(mounts, num_mounts);
+    return ret;
+}
+
 int get_docker_run_command(const char *command_file, const struct configuration *conf, args *args) {
   int ret = 0, i = 0;
   char *container_name = NULL, *user = NULL, *image = NULL;
@@ -1622,8 +1555,8 @@ int get_docker_run_command(const char *command_file, const struct configuration
   }
 
   service_mode_enabled = is_service_mode_enabled(&command_config, conf, args);
-  if (service_mode_enabled == SERVICE_MODE_DISABLED) {
-    ret = SERVICE_MODE_DISABLED;
+  if (service_mode_enabled == DOCKER_SERVICE_MODE_DISABLED) {
+    ret = DOCKER_SERVICE_MODE_DISABLED;
     goto free_and_exit;
   }
 
@@ -1721,7 +1654,7 @@ int get_docker_run_command(const char *command_file, const struct configuration
     goto free_and_exit;
   }
 
-  ret = add_mounts(&command_config, conf, args);
+  ret = add_docker_mounts(&command_config, conf, args);
   if (ret != 0) {
     goto free_and_exit;
   }

+ 0 - 31
hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/native/container-executor/impl/utils/docker-util.h

@@ -45,37 +45,6 @@ typedef struct args {
     char *data[DOCKER_ARG_MAX];
 } args;
 
-enum docker_error_codes {
-    INVALID_COMMAND_FILE = 1,
-    INCORRECT_COMMAND,
-    BUFFER_TOO_SMALL,
-    INVALID_DOCKER_CONTAINER_NAME,
-    INVALID_DOCKER_IMAGE_NAME,
-    INVALID_DOCKER_USER_NAME,
-    INVALID_DOCKER_INSPECT_FORMAT,
-    UNKNOWN_DOCKER_COMMAND,
-    INVALID_DOCKER_NETWORK,
-    INVALID_DOCKER_PORTS_MAPPING,
-    INVALID_DOCKER_CAPABILITY,
-    PRIVILEGED_CONTAINERS_DISABLED,
-    INVALID_DOCKER_MOUNT,
-    INVALID_DOCKER_RO_MOUNT,
-    INVALID_DOCKER_RW_MOUNT,
-    MOUNT_ACCESS_ERROR,
-    INVALID_DOCKER_DEVICE,
-    INVALID_DOCKER_STOP_COMMAND,
-    INVALID_DOCKER_KILL_COMMAND,
-    INVALID_DOCKER_VOLUME_DRIVER,
-    INVALID_DOCKER_VOLUME_NAME,
-    INVALID_DOCKER_VOLUME_COMMAND,
-    PID_HOST_DISABLED,
-    INVALID_PID_NAMESPACE,
-    INVALID_DOCKER_IMAGE_TRUST,
-    INVALID_DOCKER_TMPFS_MOUNT,
-    INVALID_DOCKER_RUNTIME,
-    SERVICE_MODE_DISABLED
-};
-
 /**
  * Get the full path for the docker binary.
  * @param conf Configuration for the container-executor

+ 356 - 0
hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/native/container-executor/impl/utils/mount-utils.c

@@ -0,0 +1,356 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "util.h"
+#include "mount-utils.h"
+#include "configuration.h"
+
+/**
+ * Function to free an options struct.
+ * @param options - options struct to be freed.
+ * @return void.
+ */
+void free_mount_options(mount_options *options) {
+  if (options == NULL) {
+      return;
+  }
+
+  if (options->opts != NULL) {
+      for (unsigned int i = 0; i < options->num_opts; i++) {
+          free(options->opts[i]);
+      }
+      free(options->opts);
+  }
+
+  free(options);
+}
+
+/**
+ * Function to free an array of mounts.
+ * @param mounts - Array of mounts to be freed.
+ * @param num_mounts - Number of mounts to be freed.
+ * @return void.
+ */
+void free_mounts(mount *mounts, const unsigned int num_mounts) {
+    if (mounts == NULL) {
+        return;
+    }
+
+    for (unsigned int i = 0; i < num_mounts; i++) {
+       free(mounts[i].src);
+       free(mounts[i].dest);
+       free_mount_options(mounts[i].options);
+    }
+    free(mounts);
+}
+
+/**
+ * Function to determine whether a string is a volume name.
+ * @param volume_name - string to check.
+ * @return 1 on match, 0 on no match.
+ */
+static int is_volume_name(const char *volume_name) {
+    const char *regex_str = "^[a-zA-Z0-9]([a-zA-Z0-9_.-]*)$";
+    // execute_regex_match return 0 is matched success
+    return execute_regex_match(regex_str, volume_name) == 0;
+}
+
+/**
+ * Function to determine whether a string is a valid volume name and if
+ * it matches a passed in regex.
+ * @param requested - string to check.
+ * @param pattern - regular expression to check against.
+ * @return 1 on match, 0 on no match.
+ */
+static int is_volume_name_matched_by_regex(const char* requested, const char* pattern) {
+    // execute_regex_match return 0 is matched success
+    return is_volume_name(requested) && (execute_regex_match(pattern + sizeof("regex:"), requested) == 0);
+}
+
+/**
+ * Helper function to help normalize mounts for checking if mounts are
+ * permitted. The function does the following -
+ * 1. Find the canonical path for mount using realpath
+ * 2. If the path is a directory, add a '/' at the end (if not present)
+ * 3. Return a copy of the canonicalised path(to be freed by the caller)
+ * @param mount path to be canonicalised.
+ * @param isRegexAllowed whether regex matching is allowed for normalize mount.
+ * @return pointer to canonicalised path, NULL on error.
+ */
+static char* normalize_mount(const char* mount, const int isRegexAllowed) {
+    int ret = 0;
+    struct stat buff;
+    char *ret_ptr = NULL, *real_mount = NULL;
+    if (mount == NULL) {
+        return NULL;
+    }
+    real_mount = realpath(mount, NULL);
+    if (real_mount == NULL) {
+        // If mount is a valid named volume, just return it and let the container runtime decide
+        if (is_volume_name(mount)) {
+            ret_ptr = strdup(mount);
+            goto free_and_exit;
+        }
+        // we only allow permitted mount to be REGEX, for permitted mount, we check
+        // if it's a valid REGEX return; for user mount, we need to strictly check
+        if (isRegexAllowed) {
+            if (is_regex(mount)) {
+                ret_ptr = strdup(mount);
+                goto free_and_exit;
+            }
+        }
+        fprintf(ERRORFILE, "Could not determine real path of mount '%s'\n", mount);
+        ret_ptr = NULL;
+        goto free_and_exit;
+    }
+    ret = stat(real_mount, &buff);
+    if (ret == 0) {
+        if (S_ISDIR(buff.st_mode)) {
+            size_t len = strlen(real_mount);
+            if (len <= 0) {
+                ret_ptr = NULL;
+                goto free_and_exit;
+            }
+            if (real_mount[len - 1] != '/') {
+                ret_ptr = (char *) alloc_and_clear_memory(len + 2, sizeof(char));
+                strncpy(ret_ptr, real_mount, len);
+                ret_ptr[len] = '/';
+                ret_ptr[len + 1] = '\0';
+            } else {
+                ret_ptr = strdup(real_mount);
+            }
+        } else {
+            ret_ptr = strdup(real_mount);
+        }
+    } else {
+        fprintf(ERRORFILE, "Could not stat path '%s'\n", real_mount);
+        ret_ptr = NULL;
+    }
+
+free_and_exit:
+    free(real_mount);
+    return ret_ptr;
+}
+
+/**
+ * Function to normalize an array of strings. Each string in the array will
+ * be normalized to its real path in the file system.
+ * @param mounts - An array of strings to normalize. The contents of this
+ * string array will be modified and replaced with their normalized equivalents.
+ * If a string is replaced, the original string will be freed. The caller is responsible
+ * for freeing the mounts string array.
+ * @param isRegexAllowed - Integer to determine whether or not regex is allowed.
+ * for any of the strings. 1 for allowed, 0 for not allowed.
+ * @return 0 on success, -1 on failure.
+ */
+static int normalize_mounts(char **mounts, const int isRegexAllowed) {
+    unsigned int i = 0;
+    char *tmp = NULL;
+    if (mounts == NULL) {
+        return 0;
+    }
+    for (i = 0; mounts[i] != NULL; ++i) {
+        tmp = normalize_mount(mounts[i], isRegexAllowed);
+        if (tmp == NULL) {
+            return -1;
+        }
+        free(mounts[i]);
+        mounts[i] = tmp;
+    }
+    return 0;
+}
+
+/**
+ * Function to get the normalized path of the container-executor config file.
+ * @param container_executor_cfg_path - A pointer to a string. This pointer will
+ * point to an allocated string containing the normalized path to the container-executor
+ * config file. The caller is responsible for freeing this memory.
+ * @return 0 on success, MOUNT_ACCESS_ERROR on failure.
+ */
+static int get_normalized_config_path(const char **container_executor_cfg_path) {
+    char *config_path = NULL;
+    int ret = 0;
+
+    config_path = get_config_path("");
+    *container_executor_cfg_path = normalize_mount(config_path, 0);
+    if (*container_executor_cfg_path == NULL) {
+        ret = MOUNT_ACCESS_ERROR;
+        goto free_and_exit;
+    }
+
+free_and_exit:
+    free(config_path);
+    return ret;
+}
+
+/**
+ * Function to determine whether or not a requested string path is allowed as a mount.
+ * The requested string will be normalized and checked against the normalized paths in the
+ * permitted_mounts string array. Volumes that match a regex in the permitted_mounts list
+ * will also be allowed.
+ * @param permitted_mounts - An array of strings that define the permitted list of paths
+ * for the requested string.
+ * @param requested - A string that is requested to be mounted.
+ * @return 0 on not permitted, 1 on permitted, -1 on error.
+ */
+static int check_mount_permitted(const char **permitted_mounts, const char *requested) {
+    int ret = 0;
+    unsigned int i;
+    size_t permitted_mount_len = 0;
+    if (permitted_mounts == NULL) {
+        return 0;
+    }
+    char *normalized_path = normalize_mount(requested, 0);
+    if (normalized_path == NULL) {
+        return -1;
+    }
+    for (i = 0; permitted_mounts[i] != NULL; ++i) {
+        if (strcmp(normalized_path, permitted_mounts[i]) == 0) {
+            ret = 1;
+            break;
+        }
+        // if (permitted_mounts[i] is a REGEX): use REGEX to compare; return
+        if (is_regex(permitted_mounts[i]) &&
+            is_volume_name_matched_by_regex(normalized_path, permitted_mounts[i])) {
+            ret = 1;
+            break;
+        }
+
+        // directory check
+        permitted_mount_len = strlen(permitted_mounts[i]);
+        struct stat path_stat;
+        stat(permitted_mounts[i], &path_stat);
+        if (S_ISDIR(path_stat.st_mode)) {
+            if (strncmp(normalized_path, permitted_mounts[i], permitted_mount_len) == 0) {
+                ret = 1;
+                break;
+            }
+        }
+    }
+    free(normalized_path);
+    return ret;
+}
+
+/**
+ * Function to validate whether a requested mount path is permitted or not. The normalized mount path
+ * must be in the correct permitted list based on the type of mount (ro or rw) and must not be a
+ * parent of the container-executor config file.
+ * @param permitted_ro_mounts - Array of permitted read-only mounts.
+ * @param permitted_rw_mounts - Array of permitted read-write mounts.
+ * @param requested  - Mount path to be validated
+ * @return 0 on valid mount, INVALID_MOUNT, INVALID_RW_MOUNT, INVALID_RO_MOUNT,
+ * or MOUNT_ACCESS_ERROR on error.
+ */
+static int validate_mount(const char **permitted_ro_mounts, const char **permitted_rw_mounts, const mount *requested) {
+    const char *container_executor_cfg_path = NULL;
+    const char *tmp_path_buffer[2] = {NULL, NULL};
+    int permitted_rw, permitted_ro;
+    int ret = 0;
+
+    if (requested == NULL) {
+        goto free_and_exit;
+    }
+
+    ret = get_normalized_config_path(&container_executor_cfg_path);
+    if (ret != 0) {
+        goto free_and_exit;
+    }
+
+    permitted_rw = check_mount_permitted(permitted_rw_mounts, requested->src);
+    permitted_ro = check_mount_permitted(permitted_ro_mounts, requested->src);
+
+    if (permitted_ro == -1 || permitted_rw == -1) {
+        fprintf(ERRORFILE, "Invalid mount src='%s', dest='%s'\n",
+                requested->src, requested->dest);
+        ret = INVALID_MOUNT;
+        goto free_and_exit;
+    }
+
+    if (requested->options != NULL && requested->options->rw == 1) {
+        // rw mount
+        if (permitted_rw == 0) {
+            fprintf(ERRORFILE, "Configuration does not allow mount src='%s', dest='%s'\n",
+                    requested->src, requested->dest);
+            ret = INVALID_RW_MOUNT;
+            goto free_and_exit;
+        } else {
+            // determine if the user can modify the container-executor.cfg file
+            tmp_path_buffer[0] = normalize_mount(requested->src, 0);
+            // just re-use the function, flip the args to check if the container-executor path is in the requested
+            // mount point
+            ret = check_mount_permitted(tmp_path_buffer, container_executor_cfg_path);
+            free((void *) tmp_path_buffer[0]);
+            if (ret == 1) {
+                fprintf(ERRORFILE, "Attempting to mount a parent directory of container-executor.cfg as read-write. src='%s', dest='%s'\n",
+                        requested->src, requested->dest);
+                ret = INVALID_RW_MOUNT;
+                goto free_and_exit;
+            }
+        }
+    } else {
+        // ro mount
+        if (permitted_ro == 0 && permitted_rw == 0) {
+            fprintf(ERRORFILE, "Configuration does not allow mount src='%s', dest='%s'\n",
+                    requested->src, requested->dest);
+            ret = INVALID_RO_MOUNT;
+            goto free_and_exit;
+        }
+    }
+
+free_and_exit:
+    free((void *) container_executor_cfg_path);
+    return ret;
+}
+
+/**
+ * Function to validate an array of mounts.
+ * @param permitted_ro_mounts - Array of permitted read-only mounts.
+ * @param permitted_rw_mounts - Array of permitted read-write mounts.
+ * @param mounts - Array of mounts to be validated.
+ * @param num_mounts - Number of mounts to be valildated.
+ * @return 0 on valid mounts, INVALID_MOUNT, INVALID_RW_MOUNT, INVALID_RO_MOUNT,
+ * or MOUNT_ACCESS_ERROR on error.
+ */
+int validate_mounts(char **permitted_ro_mounts, char **permitted_rw_mounts, mount *mounts, const unsigned int num_mounts) {
+    int ret = 0;
+    unsigned int i;
+
+    ret = normalize_mounts(permitted_ro_mounts, 1);
+    ret |= normalize_mounts(permitted_rw_mounts, 1);
+    if (ret != 0) {
+        fprintf(ERRORFILE, "Unable to find permitted mounts on disk\n");
+        ret = MOUNT_ACCESS_ERROR;
+        goto free_and_exit;
+    }
+
+    for (i = 0; i < num_mounts; i++) {
+        ret = validate_mount((const char **) permitted_ro_mounts, (const char **) permitted_rw_mounts, &mounts[i]);
+        if (ret != 0) {
+            goto free_and_exit;
+        }
+    }
+
+free_and_exit:
+    return ret;
+}

+ 40 - 0
hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/native/container-executor/impl/utils/mount-utils.h

@@ -0,0 +1,40 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __YARN_POSIX_CONTAINER_EXECUTOR_MOUNT_UTIL_H__
+#define __YARN_POSIX_CONTAINER_EXECUTOR_MOUNT_UTIL_H__
+
+typedef struct mount_options_struct {
+  char **opts;
+  unsigned int num_opts;
+  unsigned int rw; // 0 for read, 1 for write
+} mount_options;
+
+typedef struct mount_struct {
+    char *src;
+    char *dest;
+    mount_options *options;
+} mount;
+
+void free_mount_options(mount_options *options);
+
+void free_mounts(mount *mounts, const unsigned int num_mounts);
+
+int validate_mounts(char **permitted_ro_mounts, char **permitted_rw_mounts, mount *mounts, unsigned int num_mounts);
+
+#endif

+ 51 - 50
hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/native/container-executor/test/utils/test_docker_util.cc

@@ -22,6 +22,7 @@
 
 extern "C" {
 #include "utils/docker-util.c"
+#include "utils/mount-utils.c"
 }
 
 namespace ContainerExecutor {
@@ -121,7 +122,7 @@ namespace ContainerExecutor {
       for (itr = file_cmd_vec.begin(); itr != file_cmd_vec.end(); ++itr) {
         write_command_file(itr->first);
         int ret = (*docker_func)(docker_command_file.c_str(), &container_executor_cfg, &tmp);
-        ASSERT_EQ(0, ret) << "error message: " << get_docker_error_message(ret) << " for input " << itr->first;
+        ASSERT_EQ(0, ret) << "error message: " << get_error_message(ret) << " for input " << itr->first;
         char *actual = flatten(&tmp);
         ASSERT_STREQ(itr->second.c_str(), actual);
         reset_args(&tmp);
@@ -136,7 +137,7 @@ namespace ContainerExecutor {
         reset_args(&tmp);
       }
       int ret = (*docker_func)("unknown-file", &container_executor_cfg, &tmp);
-      ASSERT_EQ(static_cast<int>(INVALID_COMMAND_FILE), ret);
+      ASSERT_EQ(static_cast<int>(INVALID_DOCKER_COMMAND_FILE), ret);
       reset_args(&tmp);
     }
 
@@ -181,10 +182,10 @@ namespace ContainerExecutor {
     std::vector<std::pair<std::string, int> > bad_file_cmd_vec;
     bad_file_cmd_vec.push_back(std::make_pair<std::string, int>(
         "[docker-command-execution]\n  docker-command=run\n  format='{{.State.Status}}'",
-        static_cast<int>(INCORRECT_COMMAND)));
+        static_cast<int>(INCORRECT_DOCKER_COMMAND)));
     bad_file_cmd_vec.push_back(std::make_pair<std::string, int>(
         "docker-command=inspect\n  format='{{.State.Status}}'",
-        static_cast<int>(INCORRECT_COMMAND)));
+        static_cast<int>(INCORRECT_DOCKER_COMMAND)));
     bad_file_cmd_vec.push_back(std::make_pair<std::string, int>(
         "[docker-command-execution]\n  docker-command=inspect\n  format={{.State.Status}}\n  name=",
         static_cast<int>(INVALID_DOCKER_CONTAINER_NAME)));
@@ -218,9 +219,9 @@ namespace ContainerExecutor {
 
     std::vector<std::pair<std::string, int> > bad_file_cmd_vec;
     bad_file_cmd_vec.push_back(std::make_pair<std::string, int>(
-        "[docker-command-execution]\n  docker-command=run\n  image=image-id", static_cast<int>(INCORRECT_COMMAND)));
+        "[docker-command-execution]\n  docker-command=run\n  image=image-id", static_cast<int>(INCORRECT_DOCKER_COMMAND)));
     bad_file_cmd_vec.push_back(std::make_pair<std::string, int>(
-        "docker-command=load\n  image=image-id", static_cast<int>(INCORRECT_COMMAND)));
+        "docker-command=load\n  image=image-id", static_cast<int>(INCORRECT_DOCKER_COMMAND)));
     bad_file_cmd_vec.push_back(std::make_pair<std::string, int>(
         "[docker-command-execution]\n  docker-command=load\n  image=", static_cast<int>(INVALID_DOCKER_IMAGE_NAME)));
     bad_file_cmd_vec.push_back(std::make_pair<std::string, int>("[docker-command-execution]\n  docker-command=load",
@@ -288,9 +289,9 @@ namespace ContainerExecutor {
 
     std::vector<std::pair<std::string, int> > bad_file_cmd_vec;
     bad_file_cmd_vec.push_back(std::make_pair<std::string, int>(
-        "[docker-command-execution]\n  docker-command=run\n  image=image-id", static_cast<int>(INCORRECT_COMMAND)));
+        "[docker-command-execution]\n  docker-command=run\n  image=image-id", static_cast<int>(INCORRECT_DOCKER_COMMAND)));
     bad_file_cmd_vec.push_back(std::make_pair<std::string, int>(
-        "docker-command=pull\n  image=image-id", static_cast<int>(INCORRECT_COMMAND)));
+        "docker-command=pull\n  image=image-id", static_cast<int>(INCORRECT_DOCKER_COMMAND)));
     bad_file_cmd_vec.push_back(std::make_pair<std::string, int>(
         "[docker-command-execution]\n  docker-command=pull\n  image=", static_cast<int>(INVALID_DOCKER_IMAGE_NAME)));
     bad_file_cmd_vec.push_back(std::make_pair<std::string, int>("[docker-command-execution]\n  docker-command=pull",
@@ -309,9 +310,9 @@ namespace ContainerExecutor {
     std::vector<std::pair<std::string, int> > bad_file_cmd_vec;
     bad_file_cmd_vec.push_back(std::make_pair<std::string, int>(
         "[docker-command-execution]\n  docker-command=run\n  name=container_e1_12312_11111_02_000001",
-        static_cast<int>(INCORRECT_COMMAND)));
+        static_cast<int>(INCORRECT_DOCKER_COMMAND)));
     bad_file_cmd_vec.push_back(std::make_pair<std::string, int>(
-        "docker-command=rm\n  name=ctr-id", static_cast<int>(INCORRECT_COMMAND)));
+        "docker-command=rm\n  name=ctr-id", static_cast<int>(INCORRECT_DOCKER_COMMAND)));
     bad_file_cmd_vec.push_back(std::make_pair<std::string, int>(
         "[docker-command-execution]\n  docker-command=rm\n  name=", static_cast<int>(INVALID_DOCKER_CONTAINER_NAME)));
     bad_file_cmd_vec.push_back(std::make_pair<std::string, int>(
@@ -332,9 +333,9 @@ namespace ContainerExecutor {
     std::vector<std::pair<std::string, int> > bad_file_cmd_vec;
     bad_file_cmd_vec.push_back(std::make_pair<std::string, int>(
         "[docker-command-execution]\n  docker-command=run\n  name=container_e1_12312_11111_02_000001",
-        static_cast<int>(INCORRECT_COMMAND)));
+        static_cast<int>(INCORRECT_DOCKER_COMMAND)));
     bad_file_cmd_vec.push_back(std::make_pair<std::string, int>(
-        "docker-command=stop\n  name=ctr-id", static_cast<int>(INCORRECT_COMMAND)));
+        "docker-command=stop\n  name=ctr-id", static_cast<int>(INCORRECT_DOCKER_COMMAND)));
     bad_file_cmd_vec.push_back(std::make_pair<std::string, int>(
         "[docker-command-execution]\n  docker-command=stop\n  name=", static_cast<int>(INVALID_DOCKER_CONTAINER_NAME)));
     bad_file_cmd_vec.push_back(std::make_pair<std::string, int>(
@@ -359,9 +360,9 @@ namespace ContainerExecutor {
     std::vector<std::pair<std::string, int> > bad_file_cmd_vec;
     bad_file_cmd_vec.push_back(std::make_pair<std::string, int>(
         "[docker-command-execution]\n  docker-command=run\n  name=container_e1_12312_11111_02_000001",
-        static_cast<int>(INCORRECT_COMMAND)));
+        static_cast<int>(INCORRECT_DOCKER_COMMAND)));
     bad_file_cmd_vec.push_back(std::make_pair<std::string, int>(
-        "docker-command=kill\n  name=ctr-id", static_cast<int>(INCORRECT_COMMAND)));
+        "docker-command=kill\n  name=ctr-id", static_cast<int>(INCORRECT_DOCKER_COMMAND)));
     bad_file_cmd_vec.push_back(std::make_pair<std::string, int>(
         "[docker-command-execution]\n  docker-command=kill\n  name=", static_cast<int>(INVALID_DOCKER_CONTAINER_NAME)));
     bad_file_cmd_vec.push_back(std::make_pair<std::string, int>(
@@ -382,9 +383,9 @@ namespace ContainerExecutor {
     std::vector<std::pair<std::string, int> > bad_file_cmd_vec;
     bad_file_cmd_vec.push_back(std::make_pair<std::string, int>(
         "[docker-command-execution]\n  docker-command=run\n  name=container_e1_12312_11111_02_000001",
-        static_cast<int>(INCORRECT_COMMAND)));
+        static_cast<int>(INCORRECT_DOCKER_COMMAND)));
     bad_file_cmd_vec.push_back(std::make_pair<std::string, int>(
-        "docker-command=start\n  name=ctr-id", static_cast<int>(INCORRECT_COMMAND)));
+        "docker-command=start\n  name=ctr-id", static_cast<int>(INCORRECT_DOCKER_COMMAND)));
     bad_file_cmd_vec.push_back(std::make_pair<std::string, int>(
         "[docker-command-execution]\n  docker-command=start\n  name=", static_cast<int>(INVALID_DOCKER_CONTAINER_NAME)));
     bad_file_cmd_vec.push_back(std::make_pair<std::string, int>(
@@ -474,7 +475,7 @@ namespace ContainerExecutor {
       }
       ret = set_runtime(&cmd_cfg, &container_cfg, &buff);
       char *actual = flatten(&buff);
-      ASSERT_EQ(0, ret) << "error message: " << get_docker_error_message(ret) << " for input " << itr->first;
+      ASSERT_EQ(0, ret) << "error message: " << get_error_message(ret) << " for input " << itr->first;
       ASSERT_STREQ(itr->second.c_str(), actual);
       reset_args(&buff);
       free(actual);
@@ -599,7 +600,7 @@ namespace ContainerExecutor {
       }
       ret = add_ports_mapping_to_command(&cmd_cfg, &buff);
       char *actual = flatten(&buff);
-      ASSERT_EQ(0, ret) << "error message: " << get_docker_error_message(ret) << " for input " << itr->first;
+      ASSERT_EQ(0, ret) << "error message: " << get_error_message(ret) << " for input " << itr->first;
       ASSERT_STREQ(itr->second.c_str(), actual);
       reset_args(&buff);
       free(actual);
@@ -655,7 +656,7 @@ namespace ContainerExecutor {
         "[docker-command-execution]\n  docker-command=run", ""));
     bad_file_cmd_vec.push_back(std::make_pair<std::string, int>(
         "[docker-command-execution]\n  docker-command=run\n pid=other",
-        static_cast<int>(INVALID_PID_NAMESPACE)));
+        static_cast<int>(INVALID_DOCKER_PID_NAMESPACE)));
 
     for (int i = 1; i < 3; ++i) {
       write_container_executor_cfg(container_executor_cfg_contents[0]);
@@ -719,10 +720,10 @@ namespace ContainerExecutor {
       bad_file_cmd_vec.clear();
       bad_file_cmd_vec.push_back(std::make_pair<std::string, int>(
         "[docker-command-execution]\n  docker-command=run\n pid=other",
-        static_cast<int>(INVALID_PID_NAMESPACE)));
+        static_cast<int>(INVALID_DOCKER_PID_NAMESPACE)));
       bad_file_cmd_vec.push_back(std::make_pair<std::string, int>(
         "[docker-command-execution]\n  docker-command=run\n pid=host",
-        static_cast<int>(PID_HOST_DISABLED)));
+        static_cast<int>(DOCKER_PID_HOST_DISABLED)));
       for (itr2 = bad_file_cmd_vec.begin(); itr2 != bad_file_cmd_vec.end(); ++itr2) {
         write_command_file(itr2->first);
         ret = read_config(docker_command_file.c_str(), &cmd_cfg);
@@ -816,7 +817,7 @@ namespace ContainerExecutor {
           FAIL();
         }
         ret = set_privileged(&cmd_cfg, &container_cfg, &buff);
-        ASSERT_EQ(6, ret);
+        ASSERT_EQ(INVALID_DOCKER_USER_NAME, ret);
         ASSERT_EQ(0, buff.length);
         reset_args(&buff);
         free_configuration(&cmd_cfg);
@@ -827,7 +828,7 @@ namespace ContainerExecutor {
         FAIL();
       }
       ret = set_privileged(&cmd_cfg, &container_cfg, &buff);
-      ASSERT_EQ(PRIVILEGED_CONTAINERS_DISABLED, ret);
+      ASSERT_EQ(PRIVILEGED_DOCKER_CONTAINERS_DISABLED, ret);
       ASSERT_EQ(0, buff.length);
       reset_args(&buff);
       free_configuration(&cmd_cfg);
@@ -864,7 +865,7 @@ namespace ContainerExecutor {
         FAIL();
       }
       ret = set_privileged(&cmd_cfg, &container_cfg, &buff);
-      ASSERT_EQ(PRIVILEGED_CONTAINERS_DISABLED, ret);
+      ASSERT_EQ(PRIVILEGED_DOCKER_CONTAINERS_DISABLED, ret);
       ASSERT_EQ(0, buff.length);
       reset_args(&buff);
       free_configuration(&cmd_cfg);
@@ -1069,7 +1070,7 @@ namespace ContainerExecutor {
   }
 
 
-  TEST_F(TestDockerUtil, test_add_mounts) {
+  TEST_F(TestDockerUtil, test_add_docker_mounts) {
     struct configuration container_cfg, cmd_cfg;
     struct args buff = ARGS_INITIAL_VALUE;
     int ret = 0;
@@ -1125,7 +1126,7 @@ namespace ContainerExecutor {
       if (ret != 0) {
         FAIL();
       }
-      ret = add_mounts(&cmd_cfg, &container_cfg, &buff);
+      ret = add_docker_mounts(&cmd_cfg, &container_cfg, &buff);
       char *actual = flatten(&buff);
       ASSERT_EQ(0, ret);
       ASSERT_STREQ(itr->second.c_str(), actual);
@@ -1137,22 +1138,22 @@ namespace ContainerExecutor {
     std::vector<std::pair<std::string, int> > bad_file_cmds_vec;
     bad_file_cmds_vec.push_back(std::make_pair<std::string, int>(
         "[docker-command-execution]\n  docker-command=run\n  image=hadoop/image\n  mounts=/lib:/lib:rw",
-        static_cast<int>(INVALID_DOCKER_RW_MOUNT)));
+        static_cast<int>(INVALID_RW_MOUNT)));
     bad_file_cmds_vec.push_back(std::make_pair<std::string, int>(
         "[docker-command-execution]\n  docker-command=run\n  image=hadoop/image\n  mounts=/usr/bin/:/usr/bin:rw",
-        static_cast<int>(INVALID_DOCKER_RW_MOUNT)));
+        static_cast<int>(INVALID_RW_MOUNT)));
     bad_file_cmds_vec.push_back(std::make_pair<std::string, int>(
         "[docker-command-execution]\n  docker-command=run\n  image=hadoop/image\n  mounts=/blah:/blah:rw",
-        static_cast<int>(INVALID_DOCKER_MOUNT)));
+        static_cast<int>(INVALID_MOUNT)));
     bad_file_cmds_vec.push_back(std::make_pair<std::string, int>(
         "[docker-command-execution]\n  docker-command=run\n image=hadoop/image\n mounts=/tmp:/tmp:shared",
-        static_cast<int>(INVALID_DOCKER_MOUNT)));
+        static_cast<int>(INVALID_MOUNT)));
     bad_file_cmds_vec.push_back(std::make_pair<std::string, int>(
         "[docker-command-execution]\n  docker-command=run\n image=hadoop/image\n mounts=/lib:/lib",
-        static_cast<int>(INVALID_DOCKER_MOUNT)));
+        static_cast<int>(INVALID_MOUNT)));
     bad_file_cmds_vec.push_back(std::make_pair<std::string, int>(
         "[docker-command-execution]\n  docker-command=run\n image=hadoop/image\n mounts=/lib:/lib:other",
-        static_cast<int>(INVALID_DOCKER_MOUNT)));
+        static_cast<int>(INVALID_MOUNT)));
 
     std::vector<std::pair<std::string, int> >::const_iterator itr2;
 
@@ -1162,7 +1163,7 @@ namespace ContainerExecutor {
       if (ret != 0) {
         FAIL();
       }
-      ret = add_mounts(&cmd_cfg, &container_cfg, &buff);
+      ret = add_docker_mounts(&cmd_cfg, &container_cfg, &buff);
       char *actual = flatten(&buff);
       ASSERT_EQ(itr2->second, ret);
       ASSERT_STREQ("", actual);
@@ -1181,8 +1182,8 @@ namespace ContainerExecutor {
       if (ret != 0) {
         FAIL();
       }
-      ret = add_mounts(&cmd_cfg, &container_cfg, &buff);
-      ASSERT_EQ(INVALID_DOCKER_RW_MOUNT, ret) << " for input " << cmd_file_contents;
+      ret = add_docker_mounts(&cmd_cfg, &container_cfg, &buff);
+      ASSERT_EQ(INVALID_RW_MOUNT, ret) << " for input " << cmd_file_contents;
       char *actual = flatten(&buff);
       ASSERT_STREQ("", actual);
       reset_args(&buff);
@@ -1196,7 +1197,7 @@ namespace ContainerExecutor {
     free(ce_path);
     free_configuration(&container_cfg);
 
-    // For untrusted image, container add_mounts will pass through
+    // For untrusted image, container add_docker_mounts will pass through
     // without mounting or report error code.
     container_executor_cfg_contents = "[docker]\n";
     write_container_executor_cfg(container_executor_cfg_contents);
@@ -1204,7 +1205,7 @@ namespace ContainerExecutor {
     if (ret != 0) {
       FAIL();
     }
-    ret = add_mounts(&cmd_cfg, &container_cfg, &buff);
+    ret = add_docker_mounts(&cmd_cfg, &container_cfg, &buff);
     char *actual = flatten(&buff);
     ASSERT_EQ(0, ret);
     ASSERT_STREQ("", actual);
@@ -1266,7 +1267,7 @@ namespace ContainerExecutor {
       if (ret != 0) {
         FAIL();
       }
-      ret = add_mounts(&cmd_cfg, &container_cfg, &buff);
+      ret = add_docker_mounts(&cmd_cfg, &container_cfg, &buff);
       char *actual = flatten(&buff);
       ASSERT_EQ(0, ret);
       ASSERT_STREQ(itr->second.c_str(), actual);
@@ -1278,10 +1279,10 @@ namespace ContainerExecutor {
     std::vector<std::pair<std::string, int> > bad_file_cmds_vec;
     bad_file_cmds_vec.push_back(std::make_pair<std::string, int>(
         "[docker-command-execution]\n  docker-command=run\n  image=hadoop/image\n  mounts=/etc:/etc:ro",
-        static_cast<int>(INVALID_DOCKER_RO_MOUNT)));
+        static_cast<int>(INVALID_RO_MOUNT)));
     bad_file_cmds_vec.push_back(std::make_pair<std::string, int>(
         "[docker-command-execution]\n  docker-command=run\n  image=hadoop/image\n  mounts=/blah:/blah:ro",
-        static_cast<int>(INVALID_DOCKER_MOUNT)));
+        static_cast<int>(INVALID_MOUNT)));
 
     std::vector<std::pair<std::string, int> >::const_iterator itr2;
 
@@ -1291,7 +1292,7 @@ namespace ContainerExecutor {
       if (ret != 0) {
         FAIL();
       }
-      ret = add_mounts(&cmd_cfg, &container_cfg, &buff);
+      ret = add_docker_mounts(&cmd_cfg, &container_cfg, &buff);
       char *actual = flatten(&buff);
       ASSERT_EQ(itr2->second, ret);
       ASSERT_STREQ("", actual);
@@ -1312,8 +1313,8 @@ namespace ContainerExecutor {
     if (ret != 0) {
       FAIL();
     }
-    ret = add_mounts(&cmd_cfg, &container_cfg, &buff);
-    ASSERT_EQ(INVALID_DOCKER_RO_MOUNT, ret);
+    ret = add_docker_mounts(&cmd_cfg, &container_cfg, &buff);
+    ASSERT_EQ(INVALID_RO_MOUNT, ret);
     ASSERT_EQ(0, buff.length);
     reset_args(&buff);
     free_configuration(&cmd_cfg);
@@ -1508,7 +1509,7 @@ namespace ContainerExecutor {
             "  network=bridge\n  privileged=true\n"
             "  cap-add=CHOWN,SETUID\n  cgroup-parent=ctr-cgroup\n  detach=true\n  rm=true\n  group-add=1000,1001\n"
             "  launch-command=bash,test_script.sh,arg1,arg2",
-        PRIVILEGED_CONTAINERS_DISABLED));
+        PRIVILEGED_DOCKER_CONTAINERS_DISABLED));
 
     // invalid rw mount
     bad_file_cmd_vec.push_back(std::make_pair<std::string, int>(
@@ -1518,7 +1519,7 @@ namespace ContainerExecutor {
             "  network=bridge\n  devices=/dev/test:/dev/test\n"
             "  cap-add=CHOWN,SETUID\n  cgroup-parent=ctr-cgroup\n  detach=true\n  rm=true\n"
             "  launch-command=bash,test_script.sh,arg1,arg2",
-        static_cast<int>(INVALID_DOCKER_RW_MOUNT)));
+        static_cast<int>(INVALID_RW_MOUNT)));
 
     // invalid ro mount
     bad_file_cmd_vec.push_back(std::make_pair<std::string, int>(
@@ -1528,7 +1529,7 @@ namespace ContainerExecutor {
             "  network=bridge\n  devices=/dev/test:/dev/test\n"
             "  cap-add=CHOWN,SETUID\n  cgroup-parent=ctr-cgroup\n  detach=true\n  rm=true\n"
             "  launch-command=bash,test_script.sh,arg1,arg2",
-        static_cast<int>(INVALID_DOCKER_RO_MOUNT)));
+        static_cast<int>(INVALID_RO_MOUNT)));
 
     // invalid capability
     bad_file_cmd_vec.push_back(std::make_pair<std::string, int>(
@@ -1548,7 +1549,7 @@ namespace ContainerExecutor {
             "  network=bridge\n  devices=/dev/dev1:/dev/dev1\n  privileged=true\n"
             "  cap-add=CHOWN,SETUID\n  cgroup-parent=ctr-cgroup\n  detach=true\n  rm=true\n"
             "  launch-command=bash,test_script.sh,arg1,arg2",
-        static_cast<int>(PRIVILEGED_CONTAINERS_DISABLED)));
+        static_cast<int>(PRIVILEGED_DOCKER_CONTAINERS_DISABLED)));
 
     // invalid network
     bad_file_cmd_vec.push_back(std::make_pair<std::string, int>(
@@ -1690,7 +1691,7 @@ namespace ContainerExecutor {
               "  network=bridge\n  devices=/dev/test:/dev/test\n  privileged=true\n"
               "  cap-add=CHOWN,SETUID\n  cgroup-parent=ctr-cgroup\n  detach=true\n  rm=true\n"
               "  launch-command=bash,test_script.sh,arg1,arg2",
-          static_cast<int>(PRIVILEGED_CONTAINERS_DISABLED)));
+          static_cast<int>(PRIVILEGED_DOCKER_CONTAINERS_DISABLED)));
 
       run_docker_command_test(file_cmd_vec, bad_file_cmd_vec, get_docker_run_command);
       free_configuration(&container_executor_cfg);
@@ -1978,10 +1979,10 @@ namespace ContainerExecutor {
     std::vector<std::pair<std::string, int> > bad_file_cmd_vec;
     bad_file_cmd_vec.push_back(std::make_pair<std::string, int>(
         "[docker-command-execution]\n  docker-command=run\n  image=image-id",
-        static_cast<int>(INCORRECT_COMMAND)));
+        static_cast<int>(INCORRECT_DOCKER_COMMAND)));
     bad_file_cmd_vec.push_back(std::make_pair<std::string, int>(
         "docker-command=images\n  image=image-id",
-        static_cast<int>(INCORRECT_COMMAND)));
+        static_cast<int>(INCORRECT_DOCKER_COMMAND)));
 
     run_docker_command_test(file_cmd_vec, bad_file_cmd_vec,
       get_docker_images_command);