From ef501b1a0b4c34a2cc43eb082d1c2364684cd7f1 Mon Sep 17 00:00:00 2001 From: Chris Nauroth Date: Sat, 30 Jul 2016 08:26:00 -0700 Subject: [PATCH] YARN-5121. fix some container-executor portability issues. Contributed by Allen Wittenauer. --- LICENSE.txt | 32 +++++ .../hadoop-yarn-server-nodemanager/pom.xml | 12 ++ .../src/CMakeLists.txt | 16 ++- .../src/config.h.cmake | 8 +- .../container-executor/impl/compat/fchmodat.h | 56 ++++++++ .../impl/compat/fdopendir.h | 52 +++++++ .../container-executor/impl/compat/fstatat.h | 67 +++++++++ .../container-executor/impl/compat/openat.h | 74 ++++++++++ .../container-executor/impl/compat/unlinkat.h | 67 +++++++++ .../container-executor/impl/configuration.c | 15 ++- .../container-executor/impl/configuration.h | 6 +- .../impl/container-executor.c | 112 ++++++++------- .../impl/container-executor.h | 2 +- .../container-executor/impl/get_executable.c | 127 ++++++++++++++++++ .../native/container-executor/impl/main.c | 38 ++++-- .../test/test-container-executor.c | 103 ++++++++++---- 16 files changed, 691 insertions(+), 96 deletions(-) create mode 100644 hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/native/container-executor/impl/compat/fchmodat.h create mode 100644 hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/native/container-executor/impl/compat/fdopendir.h create mode 100644 hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/native/container-executor/impl/compat/fstatat.h create mode 100644 hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/native/container-executor/impl/compat/openat.h create mode 100644 hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/native/container-executor/impl/compat/unlinkat.h create mode 100644 hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/native/container-executor/impl/get_executable.c diff --git a/LICENSE.txt b/LICENSE.txt index f4d869d1bd0..6910a098b0a 100644 --- a/LICENSE.txt +++ b/LICENSE.txt @@ -414,6 +414,38 @@ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +For hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/native/container-executor/impl/compat/{fstatat|openat|unlinkat}.h: + +Copyright (c) 2012 The FreeBSD Foundation +All rights reserved. + +This software was developed by Pawel Jakub Dawidek under sponsorship from +the FreeBSD Foundation. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + +1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +SUCH DAMAGE. + +============= + The binary distribution of this product bundles binaries of leveldb (http://code.google.com/p/leveldb/), which is available under the following license: diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/pom.xml b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/pom.xml index a2f81d1b65b..f10fa08c325 100644 --- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/pom.xml +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/pom.xml @@ -273,6 +273,18 @@ + + org.apache.rat + apache-rat-plugin + + + src/main/native/container-executor/impl/compat/fstatat.h + src/main/native/container-executor/impl/compat/openat.h + src/main/native/container-executor/impl/compat/unlinkat.h + + + + org.apache.hadoop hadoop-maven-plugins diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/CMakeLists.txt b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/CMakeLists.txt index d4d6ae14f65..204b3cad1d5 100644 --- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/CMakeLists.txt +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/CMakeLists.txt @@ -24,7 +24,20 @@ string(REPLACE "-D_FILE_OFFSET_BITS=64" "" CMAKE_C_FLAGS "${CMAKE_C_FLAGS}") string(REPLACE "-D_FILE_OFFSET_BITS=64" "" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}") include(CheckFunctionExists) +check_function_exists(canonicalize_file_name HAVE_CANONICALIZE_FILE_NAME) check_function_exists(fcloseall HAVE_FCLOSEALL) +check_function_exists(fchmodat HAVE_FCHMODAT) +check_function_exists(fdopendir HAVE_FDOPENDIR) +check_function_exists(fstatat HAVE_FSTATAT) +check_function_exists(openat HAVE_OPENAT) +check_function_exists(unlinkat HAVE_UNLINKAT) + +if(APPLE) + include_directories( /System/Library/Frameworks ) + find_library(COCOA_LIBRARY Cocoa) + mark_as_advanced(COCOA_LIBRARY) + set(EXTRA_LIBS ${COCOA_LIBRARY}) +endif(APPLE) function(output_directory TGT DIR) set_target_properties(${TGT} PROPERTIES @@ -46,6 +59,7 @@ configure_file(${CMAKE_SOURCE_DIR}/config.h.cmake ${CMAKE_BINARY_DIR}/config.h) add_library(container main/native/container-executor/impl/configuration.c main/native/container-executor/impl/container-executor.c + main/native/container-executor/impl/get_executable.c ) add_executable(container-executor @@ -60,6 +74,6 @@ add_executable(test-container-executor main/native/container-executor/test/test-container-executor.c ) target_link_libraries(test-container-executor - container + container ${EXTRA_LIBS} ) output_directory(test-container-executor target/usr/local/bin) diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/config.h.cmake b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/config.h.cmake index 0f7a490c376..0ab7bbdfb3c 100644 --- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/config.h.cmake +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/config.h.cmake @@ -20,6 +20,12 @@ #cmakedefine HADOOP_CONF_DIR "@HADOOP_CONF_DIR@" -#cmakedefine HAVE_FCLOSEALL "@HAVE_FCLOSEALL@" +#cmakedefine HAVE_CANONICALIZE_FILE_NAME @HAVE_CANONICALIZE_FILE_NAME@ +#cmakedefine HAVE_FCHMODAT @HAVE_FCHMODAT@ +#cmakedefine HAVE_FCLOSEALL @HAVE_FCLOSEALL@ +#cmakedefine HAVE_FDOPENDIR @HAVE_FDOPENDIR@ +#cmakedefine HAVE_FSTATAT @HAVE_FSTATAT@ +#cmakedefine HAVE_OPENAT @HAVE_OPENAT@ +#cmakedefine HAVE_UNLINKAT @HAVE_UNLINKAT@ #endif diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/native/container-executor/impl/compat/fchmodat.h b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/native/container-executor/impl/compat/fchmodat.h new file mode 100644 index 00000000000..7812b5d3dd6 --- /dev/null +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/native/container-executor/impl/compat/fchmodat.h @@ -0,0 +1,56 @@ +/** + * 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 _FCHMODAT_H_ +#define _FCHMODAT_H_ + +#include + +#include + +#define AT_SYMLINK_NOFOLLOW 0x01 + +static int +fchmodat(int fd, const char *path, mode_t mode, int flag) +{ + int cfd, error, ret; + + cfd = open(".", O_RDONLY | O_DIRECTORY); + if (cfd == -1) + return (-1); + + if (fchdir(fd) == -1) { + error = errno; + (void)close(cfd); + errno = error; + return (-1); + } + + if (flag == AT_SYMLINK_NOFOLLOW) + ret = lchmod(path, mode); + else + ret = chmod(path, mode); + + error = errno; + (void)fchdir(cfd); + (void)close(cfd); + errno = error; + return (ret); +} + +#endif /* !_FCHMODAT_H_ */ diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/native/container-executor/impl/compat/fdopendir.h b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/native/container-executor/impl/compat/fdopendir.h new file mode 100644 index 00000000000..1f9bdc34824 --- /dev/null +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/native/container-executor/impl/compat/fdopendir.h @@ -0,0 +1,52 @@ +/** + * 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 _FDOPENDIR_H_ +#define _FDOPENDIR_H_ + +#include +#include +#include + +DIR * +fdopendir(int fd) +{ + int cfd, error; + DIR *dfd; + + cfd = open(".", O_RDONLY | O_DIRECTORY); + if (cfd == -1) + return (NULL); + + if (fchdir(fd) == -1) { + error = errno; + (void)close(cfd); + errno = error; + return (NULL); + } + + dfd=opendir("."); + error = errno; + (void)fchdir(cfd); + (void)close(cfd); + errno = error; + return (dfd); +} + +#endif /* !_FDOPENDIR_H_ */ + diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/native/container-executor/impl/compat/fstatat.h b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/native/container-executor/impl/compat/fstatat.h new file mode 100644 index 00000000000..e1b1658ec12 --- /dev/null +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/native/container-executor/impl/compat/fstatat.h @@ -0,0 +1,67 @@ +/*- + * Copyright (c) 2012 The FreeBSD Foundation + * All rights reserved. + * + * This software was developed by Pawel Jakub Dawidek under sponsorship from + * the FreeBSD Foundation. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _FSTATAT_H_ +#define _FSTATAT_H_ + +#include + +#include + +#define AT_SYMLINK_NOFOLLOW 0x01 + +static int +fstatat(int fd, const char *path, struct stat *buf, int flag) +{ + int cfd, error, ret; + + cfd = open(".", O_RDONLY | O_DIRECTORY); + if (cfd == -1) + return (-1); + + if (fchdir(fd) == -1) { + error = errno; + (void)close(cfd); + errno = error; + return (-1); + } + + if (flag == AT_SYMLINK_NOFOLLOW) + ret = lstat(path, buf); + else + ret = stat(path, buf); + + error = errno; + (void)fchdir(cfd); + (void)close(cfd); + errno = error; + return (ret); +} + +#endif /* !_FSTATAT_H_ */ diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/native/container-executor/impl/compat/openat.h b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/native/container-executor/impl/compat/openat.h new file mode 100644 index 00000000000..005be374756 --- /dev/null +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/native/container-executor/impl/compat/openat.h @@ -0,0 +1,74 @@ +/*- + * Copyright (c) 2012 The FreeBSD Foundation + * All rights reserved. + * + * This software was developed by Pawel Jakub Dawidek under sponsorship from + * the FreeBSD Foundation. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _OPENAT_H_ +#define _OPENAT_H_ + +#include +#include +#include + +static int +openat(int fd, const char *path, int flags, ...) +{ + int cfd, ffd, error; + + cfd = open(".", O_RDONLY | O_DIRECTORY); + if (cfd == -1) + return (-1); + + if (fchdir(fd) == -1) { + error = errno; + (void)close(cfd); + errno = error; + return (-1); + } + + if ((flags & O_CREAT) != 0) { + va_list ap; + int mode; + + va_start(ap, flags); + mode = va_arg(ap, int); + va_end(ap); + + ffd = open(path, flags, mode); + } else { + ffd = open(path, flags); + } + + error = errno; + (void)fchdir(cfd); + (void)close(cfd); + errno = error; + return (ffd); +} + +#endif /* !_OPENAT_H_ */ + diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/native/container-executor/impl/compat/unlinkat.h b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/native/container-executor/impl/compat/unlinkat.h new file mode 100644 index 00000000000..a4977a1a2d4 --- /dev/null +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/native/container-executor/impl/compat/unlinkat.h @@ -0,0 +1,67 @@ +/*- + * Copyright (c) 2012 The FreeBSD Foundation + * All rights reserved. + * + * This software was developed by Pawel Jakub Dawidek under sponsorship from + * the FreeBSD Foundation. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _UNLINKAT_H_ +#define _UNLINKAT_H_ + +#include +#include + +#define AT_REMOVEDIR 0x01 + +static int +unlinkat(int fd, const char *path, int flag) +{ + int cfd, error, ret; + + cfd = open(".", O_RDONLY | O_DIRECTORY); + if (cfd == -1) + return (-1); + + if (fchdir(fd) == -1) { + error = errno; + (void)close(cfd); + errno = error; + return (-1); + } + + if (flag == AT_REMOVEDIR) + ret = rmdir(path); + else + ret = unlink(path); + + error = errno; + (void)fchdir(cfd); + (void)close(cfd); + errno = error; + return (ret); +} + +#endif /* !_UNLINKAT_H_ */ + diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/native/container-executor/impl/configuration.c b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/native/container-executor/impl/configuration.c index 3447524dd36..69ceaf6d4c0 100644 --- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/native/container-executor/impl/configuration.c +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/native/container-executor/impl/configuration.c @@ -17,7 +17,7 @@ */ // ensure we get the posix version of dirname by including this first -#include +#include #include "configuration.h" #include "container-executor.h" @@ -68,7 +68,7 @@ static int is_only_root_writable(const char *file) { return 0; } if ((file_stat.st_mode & (S_IWGRP | S_IWOTH)) != 0) { - fprintf(ERRORFILE, + fprintf(ERRORFILE, "File %s must not be world or group writable, but is %03lo\n", file, (unsigned long)file_stat.st_mode & (~S_IFMT)); return 0; @@ -92,8 +92,13 @@ char *resolve_config_path(const char* file_name, const char *root) { real_fname = buffer; } +#ifdef HAVE_CANONICALIZE_FILE_NAME + char * ret = (real_fname == NULL) ? NULL : canonicalize_file_name(real_fname); +#else char * ret = (real_fname == NULL) ? NULL : realpath(real_fname, NULL); +#endif #ifdef DEBUG + fprintf(stderr,"ret = %s\n", ret); fprintf(stderr, "resolve_config_path(file_name=%s,root=%s)=%s\n", file_name, root ? root : "null", ret ? ret : "null"); #endif @@ -102,7 +107,7 @@ char *resolve_config_path(const char* file_name, const char *root) { /** * Ensure that the configuration file and all of the containing directories - * are only writable by root. Otherwise, an attacker can change the + * are only writable by root. Otherwise, an attacker can change the * configuration and potentially cause damage. * returns 0 if permissions are ok */ @@ -155,7 +160,7 @@ void read_config(const char* file_name, struct configuration *cfg) { exit(OUT_OF_MEMORY); } size_read = getline(&line,&linesize,conf_file); - + //feof returns true only after we read past EOF. //so a file with no new line, at last can reach this place //if size_read returns negative check for eof condition @@ -235,7 +240,7 @@ void read_config(const char* file_name, struct configuration *cfg) { free(line); } - + //close the file fclose(conf_file); diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/native/container-executor/impl/configuration.h b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/native/container-executor/impl/configuration.h index 8f87cb28582..e7e5710a2b2 100644 --- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/native/container-executor/impl/configuration.h +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/native/container-executor/impl/configuration.h @@ -24,7 +24,7 @@ /** * Ensure that the configuration file and all of the containing directories - * are only writable by root. Otherwise, an attacker can change the + * are only writable by root. Otherwise, an attacker can change the * configuration and potentially cause damage. * returns 0 if permissions are ok */ @@ -78,7 +78,7 @@ void free_configurations(struct configuration *cfg); /** * If str is a string of the form key=val, find 'key' - * + * * @param input The input string * @param out Where to put the output string. * @param out_len The length of the output buffer. @@ -91,7 +91,7 @@ int get_kv_key(const char *input, char *out, size_t out_len); /** * If str is a string of the form key=val, find 'val' - * + * * @param input The input string * @param out Where to put the output string. * @param out_len The length of the output buffer. diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/native/container-executor/impl/container-executor.c b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/native/container-executor/impl/container-executor.c index e40101cc0d5..fef71731056 100644 --- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/native/container-executor/impl/container-executor.c +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/native/container-executor/impl/container-executor.c @@ -40,6 +40,28 @@ #include #include +#include "config.h" + +#ifndef HAVE_FCHMODAT +#include "compat/fchmodat.h" +#endif + +#ifndef HAVE_FDOPENDIR +#include "compat/fdopendir.h" +#endif + +#ifndef HAVE_FSTATAT +#include "compat/fstatat.h" +#endif + +#ifndef HAVE_OPENAT +#include "compat/openat.h" +#endif + +#ifndef HAVE_UNLINKAT +#include "compat/unlinkat.h" +#endif + static const int DEFAULT_MIN_USERID = 1000; static const char* DEFAULT_BANNED_USERS[] = {"yarn", "mapred", "hdfs", "bin", 0}; @@ -84,31 +106,14 @@ char *get_nodemanager_group() { return get_value(NM_GROUP_KEY, &executor_cfg); } -/** - * get the executable filename. - */ -char* get_executable() { - char buffer[EXECUTOR_PATH_MAX]; - snprintf(buffer, EXECUTOR_PATH_MAX, "/proc/%" PRId64 "/exe", (int64_t)getpid()); - char *filename = malloc(EXECUTOR_PATH_MAX); - ssize_t len = readlink(buffer, filename, EXECUTOR_PATH_MAX); - if (len == -1) { - fprintf(ERRORFILE, "Can't get executable name from %s - %s\n", buffer, - strerror(errno)); - exit(-1); - } else if (len >= EXECUTOR_PATH_MAX) { - fprintf(ERRORFILE, "Executable name %.*s is longer than %d characters.\n", - EXECUTOR_PATH_MAX, filename, EXECUTOR_PATH_MAX); - exit(-1); - } - filename[len] = '\0'; - return filename; -} - int check_executor_permissions(char *executable_file) { errno = 0; +#ifdef HAVE_CANONICALIZE_FILE_NAME + char * resolved_path = canonicalize_file_name(executable_file); +#else char * resolved_path = realpath(executable_file, NULL); +#endif if (resolved_path == NULL) { fprintf(ERRORFILE, "Error resolving the canonical name for the executable : %s!", @@ -119,7 +124,7 @@ int check_executor_permissions(char *executable_file) { struct stat filestat; errno = 0; if (stat(resolved_path, &filestat) != 0) { - fprintf(ERRORFILE, + fprintf(ERRORFILE, "Could not stat the executable : %s!.\n", strerror(errno)); return -1; } @@ -181,6 +186,7 @@ static int change_effective_user(uid_t user, gid_t group) { return 0; } +#ifdef __linux /** * Write the pid of the current process to the cgroup file. * cgroup_file: Path to cgroup file where pid needs to be written to. @@ -218,6 +224,7 @@ static int write_pid_to_cgroup_as_root(const char* cgroup_file, pid_t pid) { return 0; } +#endif /** * Write the pid of the current process into the pid file. @@ -384,7 +391,7 @@ static int wait_and_write_exit_code(pid_t pid, const char* exit_code_file) { * priviledges. */ int change_user(uid_t user, gid_t group) { - if (user == getuid() && user == geteuid() && + if (user == getuid() && user == geteuid() && group == getgid() && group == getegid()) { return 0; } @@ -396,7 +403,7 @@ int change_user(uid_t user, gid_t group) { return SETUID_OPER_FAILED; } if (setgid(group) != 0) { - fprintf(LOGFILE, "unable to set group to %d - %s\n", group, + fprintf(LOGFILE, "unable to set group to %d - %s\n", group, strerror(errno)); fprintf(LOGFILE, "Real: %d:%d; Effective: %d:%d\n", getuid(), getgid(), geteuid(), getegid()); @@ -415,7 +422,7 @@ int change_user(uid_t user, gid_t group) { /** * Utility function to concatenate argB to argA using the concat_pattern. */ -char *concatenate(char *concat_pattern, char *return_path_name, +char *concatenate(char *concat_pattern, char *return_path_name, int numArgs, ...) { va_list ap; va_start(ap, numArgs); @@ -592,12 +599,12 @@ int check_dir(const char* npath, mode_t st_mode, mode_t desired, int finalCompon * Function to prepare the container directories. * It creates the container work and log directories. */ -static int create_container_directories(const char* user, const char *app_id, +static int create_container_directories(const char* user, const char *app_id, const char *container_id, char* const* local_dir, char* const* log_dir, const char *work_dir) { // create dirs as 0750 const mode_t perms = S_IRWXU | S_IRGRP | S_IXGRP; if (app_id == NULL || container_id == NULL || user == NULL || user_detail == NULL || user_detail->pw_name == NULL) { - fprintf(LOGFILE, + fprintf(LOGFILE, "Either app_id, container_id or the user passed is null.\n"); return -1; } @@ -605,7 +612,7 @@ static int create_container_directories(const char* user, const char *app_id, int result = -1; char* const* local_dir_ptr; for(local_dir_ptr = local_dir; *local_dir_ptr != NULL; ++local_dir_ptr) { - char *container_dir = get_container_work_directory(*local_dir_ptr, user, app_id, + char *container_dir = get_container_work_directory(*local_dir_ptr, user, app_id, container_id); if (container_dir == NULL) { return -1; @@ -720,7 +727,7 @@ struct passwd* check_user(const char *user) { char *end_ptr = NULL; min_uid = strtol(min_uid_str, &end_ptr, 10); if (min_uid_str == end_ptr || *end_ptr != '\0') { - fprintf(LOGFILE, "Illegal value of %s for %s in configuration\n", + fprintf(LOGFILE, "Illegal value of %s for %s in configuration\n", min_uid_str, MIN_USERID_KEY); fflush(LOGFILE); free(min_uid_str); @@ -848,7 +855,7 @@ int create_directory_for_user(const char* path) { } if (change_effective_user(user, group) != 0) { fprintf(LOGFILE, "Failed to change user to %i - %i\n", user, group); - + ret = -1; } return ret; @@ -881,14 +888,14 @@ static int open_file_as_nm(const char* filename) { * The input stream is closed. * Return 0 if everything is ok. */ -static int copy_file(int input, const char* in_filename, +static int copy_file(int input, const char* in_filename, const char* out_filename, mode_t perm) { const int buffer_size = 128*1024; char buffer[buffer_size]; int out_fd = open(out_filename, O_WRONLY|O_CREAT|O_EXCL|O_NOFOLLOW, perm); if (out_fd == -1) { - fprintf(LOGFILE, "Can't open %s for output - %s\n", out_filename, + fprintf(LOGFILE, "Can't open %s for output - %s\n", out_filename, strerror(errno)); fflush(LOGFILE); return -1; @@ -910,13 +917,13 @@ static int copy_file(int input, const char* in_filename, len = read(input, buffer, buffer_size); } if (len < 0) { - fprintf(LOGFILE, "Failed to read file %s - %s\n", in_filename, + fprintf(LOGFILE, "Failed to read file %s - %s\n", in_filename, strerror(errno)); close(out_fd); return -1; } if (close(out_fd) != 0) { - fprintf(LOGFILE, "Failed to close file %s - %s\n", out_filename, + fprintf(LOGFILE, "Failed to close file %s - %s\n", out_filename, strerror(errno)); return -1; } @@ -1328,20 +1335,22 @@ int launch_docker_container_as_user(const char * user, const char *app_id, } if (pid != 0) { +#ifdef __linux fprintf(LOGFILE, "Writing to cgroup task files...\n"); // cgroups-based resource enforcement if (resources_key != NULL && ! strcmp(resources_key, "cgroups")) { - // write pid to cgroups - char* const* cgroup_ptr; - for (cgroup_ptr = resources_values; cgroup_ptr != NULL && + // write pid to cgroups + char* const* cgroup_ptr; + for (cgroup_ptr = resources_values; cgroup_ptr != NULL && *cgroup_ptr != NULL; ++cgroup_ptr) { - if (strcmp(*cgroup_ptr, "none") != 0 && + if (strcmp(*cgroup_ptr, "none") != 0 && write_pid_to_cgroup_as_root(*cgroup_ptr, pid) != 0) { - exit_code = WRITE_CGROUP_FAILED; - goto cleanup; - } - } + exit_code = WRITE_CGROUP_FAILED; + goto cleanup; + } + } } +#endif // write pid to pidfile fprintf(LOGFILE, "Writing pid file...\n"); @@ -1481,7 +1490,7 @@ int launch_container_as_user(const char *user, const char *app_id, goto cleanup; } - // setsid + // setsid pid_t pid = setsid(); if (pid == -1) { exit_code = SETSID_OPER_FAILED; @@ -1496,12 +1505,13 @@ int launch_container_as_user(const char *user, const char *app_id, goto cleanup; } +#ifdef __linux fprintf(LOGFILE, "Writing to cgroup task files...\n"); // cgroups-based resource enforcement if (resources_key != NULL && ! strcmp(resources_key, "cgroups")) { // write pid to cgroups char* const* cgroup_ptr; - for (cgroup_ptr = resources_values; cgroup_ptr != NULL && + for (cgroup_ptr = resources_values; cgroup_ptr != NULL && *cgroup_ptr != NULL; ++cgroup_ptr) { if (strcmp(*cgroup_ptr, "none") != 0 && write_pid_to_cgroup_as_root(*cgroup_ptr, pid) != 0) { @@ -1510,6 +1520,7 @@ int launch_container_as_user(const char *user, const char *app_id, } } } +#endif fprintf(LOGFILE, "Creating local dirs...\n"); exit_code = create_local_dirs(user, app_id, container_id, @@ -1569,11 +1580,8 @@ int signal_container_as_user(const char *user, int pid, int sig) { if (kill(-pid, sig) < 0) { if(errno != ESRCH) { - fprintf(LOGFILE, - "Error signalling process group %d with signal %d - %s\n", - -pid, sig, strerror(errno)); - fprintf(stderr, - "Error signalling process group %d with signal %d - %s\n", + fprintf(LOGFILE, + "Error signalling process group %d with signal %d - %s\n", -pid, sig, strerror(errno)); fflush(LOGFILE); return UNABLE_TO_SIGNAL_CONTAINER; @@ -1794,7 +1802,7 @@ int recursive_unlink_children(const char *name) * full_path : the path to delete * needs_tt_user: the top level directory must be deleted by the tt user. */ -static int delete_path(const char *full_path, +static int delete_path(const char *full_path, int needs_tt_user) { int ret; @@ -1900,7 +1908,7 @@ void chown_dir_contents(const char *dir_path, uid_t uid, gid_t gid) { char *buf = stpncpy(path_tmp, dir_path, strlen(dir_path)); *buf++ = '/'; - + dp = opendir(dir_path); if (dp != NULL) { while ((ep = readdir(dp)) != NULL) { @@ -1934,7 +1942,7 @@ int mount_cgroup(const char *pair, const char *hierarchy) { get_kv_value(pair, mount_path, strlen(pair)) < 0) { fprintf(LOGFILE, "Failed to mount cgroup controller; invalid option: %s\n", pair); - result = -1; + result = -1; } else { if (mount("none", mount_path, "cgroup", 0, controller) == 0) { char *buf = stpncpy(hier_path, mount_path, strlen(mount_path)); diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/native/container-executor/impl/container-executor.h b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/native/container-executor/impl/container-executor.h index df5b7d86d3a..1bfa3a52167 100644 --- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/native/container-executor/impl/container-executor.h +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/native/container-executor/impl/container-executor.h @@ -177,7 +177,7 @@ int signal_container_as_user(const char *user, int pid, int sig); // delete a directory (or file) recursively as the user. The directory // could optionally be relative to the baseDir set of directories (if the same // directory appears on multiple disk volumes, the disk volumes should be passed -// as the baseDirs). If baseDirs is not specified, then dir_to_be_deleted is +// as the baseDirs). If baseDirs is not specified, then dir_to_be_deleted is // assumed as the absolute path int delete_as_user(const char *user, const char *dir_to_be_deleted, diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/native/container-executor/impl/get_executable.c b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/native/container-executor/impl/get_executable.c new file mode 100644 index 00000000000..cd897354cf1 --- /dev/null +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/native/container-executor/impl/get_executable.c @@ -0,0 +1,127 @@ +/** + * 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. + */ + +/* + * This code implements OS-specific ways to get the absolute + * filename of the executable. Typically, one would use + * realpath(argv[0]) (or equivalent), however, because this + * code runs as setuid and will be used later on to determine + * relative paths, we want something a big more secure + * since argv[0] is replaceable by malicious code. + * + * NOTE! The value returned will be free()'d later on! + * + */ + +#include +#include +#include +#include +#include +#include "config.h" +#include "configuration.h" +#include "container-executor.h" + +/* + * A generic function to read a link and return + * the value for use with System V procfs. + * With much thanks to Tom Killian, Roger Faulkner, + * and Ron Gomes, this is pretty generic code. + * + * The various BSDs do not have (reliably) + * have /proc. Custom implementations follow. + */ + +char *__get_exec_readproc(char *procfn) { + char *filename; + ssize_t len; + + filename = malloc(EXECUTOR_PATH_MAX); + if (!filename) { + fprintf(ERRORFILE,"cannot allocate memory for filename: %s\n",strerror(errno)); + exit(-1); + } + len = readlink(procfn, filename, EXECUTOR_PATH_MAX); + if (len == -1) { + fprintf(ERRORFILE,"Can't get executable name from %s - %s\n", procfn, + strerror(errno)); + exit(-1); + } else if (len >= EXECUTOR_PATH_MAX) { + fprintf(ERRORFILE,"Executable name %.*s is longer than %d characters.\n", + EXECUTOR_PATH_MAX, filename, EXECUTOR_PATH_MAX); + exit(-1); + } + filename[len] = '\0'; + return filename; +} + +#ifdef __APPLE__ + +/* + * Mac OS X doesn't have a procfs, but there is + * libproc which we can use instead. It is available + * in most modern versions of OS X as of this writing (2016). + */ + +#include + +char* get_executable() { + char *filename; + pid_t pid; + + filename = malloc(PROC_PIDPATHINFO_MAXSIZE); + if (!filename) { + fprintf(ERRORFILE,"cannot allocate memory for filename: %s\n",strerror(errno)); + exit(-1); + } + pid = getpid(); + if (proc_pidpath(pid,filename,PROC_PIDPATHINFO_MAXSIZE) <= 0) { + fprintf(ERRORFILE,"Can't get executable name from pid %u - %s\n", pid, + strerror(errno)); + exit(-1); + } + return filename; +} + +#elif defined(__linux) + + +char* get_executable() { + return __get_exec_readproc("/proc/self/exe"); +} + +#elif defined(__sun) + +/* + * It's tempting to use getexecname(), but there is no guarantee + * we will get a full path and worse, we'd be reliant on getcwd() + * being where our exec is at. Instead, we'll use the /proc + * method, using the "invisible" /proc/self link that only the + * process itself can see. (Anyone that tells you /proc/self + * doesn't exist on Solaris hasn't read the proc(4) man page.) + */ + +char* get_executable() { + return __get_exec_readproc("/proc/self/path/a.out"); +} + +#else + +#error Cannot safely determine executable path on this operating system. + +#endif diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/native/container-executor/impl/main.c b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/native/container-executor/impl/main.c index 222467a9597..6fade5cae3c 100644 --- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/native/container-executor/impl/main.c +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/native/container-executor/impl/main.c @@ -83,7 +83,7 @@ static void flush_and_close_log_files() { fclose(LOGFILE); LOGFILE = NULL; } - + if (ERRORFILE != NULL) { fflush(ERRORFILE); fclose(ERRORFILE); @@ -96,19 +96,27 @@ in case of validation failures. Also sets up configuration / group information e This function is to be called in every invocation of container-executor, irrespective of whether an explicit checksetup operation is requested. */ -static void assert_valid_setup(char *current_executable) { +static void assert_valid_setup() { + int ret; char *executable_file = get_executable(); + if (!executable_file) { + fprintf(ERRORFILE,"realpath of executable: %s\n",strerror(errno)); + flush_and_close_log_files(); + exit(-1); + } char *orig_conf_file = HADOOP_CONF_DIR "/" CONF_FILENAME; - char *conf_file = resolve_config_path(orig_conf_file, current_executable); + char *conf_file = resolve_config_path(orig_conf_file, executable_file); if (conf_file == NULL) { + free(executable_file); fprintf(ERRORFILE, "Configuration file %s not found.\n", orig_conf_file); flush_and_close_log_files(); exit(INVALID_CONFIG_FILE); } if (check_configuration_permissions(conf_file) != 0) { + free(executable_file); flush_and_close_log_files(); exit(INVALID_CONFIG_FILE); } @@ -118,28 +126,42 @@ static void assert_valid_setup(char *current_executable) { // look up the node manager group in the config file char *nm_group = get_nodemanager_group(); if (nm_group == NULL) { + free(executable_file); fprintf(ERRORFILE, "Can't get configured value for %s.\n", NM_GROUP_KEY); flush_and_close_log_files(); exit(INVALID_CONFIG_FILE); } struct group *group_info = getgrnam(nm_group); if (group_info == NULL) { + free(executable_file); fprintf(ERRORFILE, "Can't get group information for %s - %s.\n", nm_group, strerror(errno)); flush_and_close_log_files(); exit(INVALID_CONFIG_FILE); } set_nm_uid(getuid(), group_info->gr_gid); - // if we are running from a setuid executable, make the real uid root - setuid(0); - // set the real and effective group id to the node manager group - setgid(group_info->gr_gid); + /* + * if we are running from a setuid executable, make the real uid root + * we're going to ignore this result just in case we aren't. + */ + ret=setuid(0); + + /* + * set the real and effective group id to the node manager group + * we're going to ignore this result just in case we aren't + */ + ret=setgid(group_info->gr_gid); + + /* make the unused var warning to away */ + ret++; if (check_executor_permissions(executable_file) != 0) { + free(executable_file); fprintf(ERRORFILE, "Invalid permissions on container-executor binary.\n"); flush_and_close_log_files(); exit(INVALID_CONTAINER_EXEC_PERMISSIONS); } + free(executable_file); } @@ -407,7 +429,7 @@ static int validate_run_as_user_commands(int argc, char **argv, int *operation) int main(int argc, char **argv) { open_log_files(); - assert_valid_setup(argv[0]); + assert_valid_setup(); int operation; int ret = validate_arguments(argc, argv, &operation); diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/native/container-executor/test/test-container-executor.c b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/native/container-executor/test/test-container-executor.c index e9ad370c4ea..a2dead235fa 100644 --- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/native/container-executor/test/test-container-executor.c +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/native/container-executor/test/test-container-executor.c @@ -29,7 +29,19 @@ #include #include -#define TEST_ROOT "/tmp/test-container-executor" +#ifdef __APPLE__ +#include +#include + +#define TMPDIR "/private/tmp" +#define RELTMPDIR "../.." +#else +#define RELTMPDIR ".." +#define TMPDIR "/tmp" +#endif + +#define TEST_ROOT TMPDIR "/test-container-executor" + #define DONT_TOUCH_FILE "dont-touch-me" #define NM_LOCAL_DIRS TEST_ROOT "/local-1%" TEST_ROOT "/local-2%" \ TEST_ROOT "/local-3%" TEST_ROOT "/local-4%" TEST_ROOT "/local-5" @@ -155,8 +167,8 @@ void check_pid_file(const char* pid_file, pid_t mypid) { } void test_get_user_directory() { - char *user_dir = get_user_directory("/tmp", "user"); - char *expected = "/tmp/usercache/user"; + char *user_dir = get_user_directory(TMPDIR, "user"); + char *expected = TMPDIR "/usercache/user"; if (strcmp(user_dir, expected) != 0) { printf("test_get_user_directory expected %s got %s\n", expected, user_dir); exit(1); @@ -165,8 +177,8 @@ void test_get_user_directory() { } void test_get_app_directory() { - char *expected = "/tmp/usercache/user/appcache/app_200906101234_0001"; - char *app_dir = (char *) get_app_directory("/tmp", "user", + char *expected = TMPDIR "/usercache/user/appcache/app_200906101234_0001"; + char *app_dir = (char *) get_app_directory(TMPDIR, "user", "app_200906101234_0001"); if (strcmp(app_dir, expected) != 0) { printf("test_get_app_directory expected %s got %s\n", expected, app_dir); @@ -176,9 +188,9 @@ void test_get_app_directory() { } void test_get_container_directory() { - char *container_dir = get_container_work_directory("/tmp", "owen", "app_1", + char *container_dir = get_container_work_directory(TMPDIR, "owen", "app_1", "container_1"); - char *expected = "/tmp/usercache/owen/appcache/app_1/container_1"; + char *expected = TMPDIR"/usercache/owen/appcache/app_1/container_1"; if (strcmp(container_dir, expected) != 0) { printf("Fail get_container_work_directory got %s expected %s\n", container_dir, expected); @@ -188,9 +200,9 @@ void test_get_container_directory() { } void test_get_container_launcher_file() { - char *expected_file = ("/tmp/usercache/user/appcache/app_200906101234_0001" + char *expected_file = (TMPDIR"/usercache/user/appcache/app_200906101234_0001" "/launch_container.sh"); - char *app_dir = get_app_directory("/tmp", "user", + char *app_dir = get_app_directory(TMPDIR, "user", "app_200906101234_0001"); char *container_file = get_container_launcher_file(app_dir); if (strcmp(container_file, expected_file) != 0) { @@ -241,9 +253,9 @@ void test_resolve_config_path() { TEST_ROOT "\n"); exit(1); } - if (strcmp(resolve_config_path(".." TEST_ROOT, TEST_ROOT), TEST_ROOT) != 0) { + if (strcmp(resolve_config_path(RELTMPDIR TEST_ROOT, TEST_ROOT), TEST_ROOT) != 0) { printf("FAIL: failed to resolve config_name on a relative path name: " - ".." TEST_ROOT " (relative to " TEST_ROOT ")"); + RELTMPDIR TEST_ROOT " (relative to " TEST_ROOT ")"); exit(1); } } @@ -266,9 +278,9 @@ void test_delete_container() { exit(1); } char* app_dir = get_app_directory(TEST_ROOT "/local-2", yarn_username, "app_1"); - char* dont_touch = get_app_directory(TEST_ROOT "/local-2", yarn_username, + char* dont_touch = get_app_directory(TEST_ROOT "/local-2", yarn_username, DONT_TOUCH_FILE); - char* container_dir = get_container_work_directory(TEST_ROOT "/local-2", + char* container_dir = get_container_work_directory(TEST_ROOT "/local-2", yarn_username, "app_1", "container_1"); char buffer[100000]; sprintf(buffer, "mkdir -p %s/who/let/the/dogs/out/who/who", container_dir); @@ -328,9 +340,9 @@ void test_delete_container() { void test_delete_app() { char* app_dir = get_app_directory(TEST_ROOT "/local-2", yarn_username, "app_2"); - char* dont_touch = get_app_directory(TEST_ROOT "/local-2", yarn_username, + char* dont_touch = get_app_directory(TEST_ROOT "/local-2", yarn_username, DONT_TOUCH_FILE); - char* container_dir = get_container_work_directory(TEST_ROOT "/local-2", + char* container_dir = get_container_work_directory(TEST_ROOT "/local-2", yarn_username, "app_2", "container_1"); char buffer[100000]; sprintf(buffer, "mkdir -p %s/who/let/the/dogs/out/who/who", container_dir); @@ -488,7 +500,7 @@ void test_signal_container_group() { exit(0); } printf("Child container launched as %" PRId64 "\n", (int64_t)child); - // there's a race condition for child calling change_user and us + // there's a race condition for child calling change_user and us // calling signal_container_as_user, hence sleeping sleep(3); if (signal_container_as_user(yarn_username, child, SIGKILL) != 0) { @@ -504,7 +516,7 @@ void test_signal_container_group() { exit(1); } if (WTERMSIG(status) != SIGKILL) { - printf("FAIL: child was killed with %d instead of %d\n", + printf("FAIL: child was killed with %d instead of %d\n", WTERMSIG(status), SIGKILL); exit(1); } @@ -550,7 +562,7 @@ void test_init_app() { fflush(stderr); pid_t child = fork(); if (child == -1) { - printf("FAIL: failed to fork process for init_app - %s\n", + printf("FAIL: failed to fork process for init_app - %s\n", strerror(errno)); exit(1); } else if (child == 0) { @@ -632,7 +644,7 @@ void test_run_container() { printf("FAIL: failed to seteuid back to user - %s\n", strerror(errno)); exit(1); } - if (fprintf(script, "#!/bin/bash\n" + if (fprintf(script, "#!/usr/bin/env bash\n" "touch foobar\n" "exit 0") < 0) { printf("FAIL: fprintf failed - %s\n", strerror(errno)); @@ -644,17 +656,17 @@ void test_run_container() { } fflush(stdout); fflush(stderr); - char* container_dir = get_container_work_directory(TEST_ROOT "/local-1", + char* container_dir = get_container_work_directory(TEST_ROOT "/local-1", yarn_username, "app_4", "container_1"); const char * pid_file = TEST_ROOT "/pid.txt"; pid_t child = fork(); if (child == -1) { - printf("FAIL: failed to fork process for init_app - %s\n", + printf("FAIL: failed to fork process for init_app - %s\n", strerror(errno)); exit(1); } else if (child == 0) { - if (launch_container_as_user(yarn_username, "app_4", "container_1", + if (launch_container_as_user(yarn_username, "app_4", "container_1", container_dir, script_name, TEST_ROOT "/creds.txt", pid_file, local_dirs, log_dirs, "cgroups", cgroups_pids) != 0) { @@ -802,7 +814,7 @@ void test_recursive_unlink_children() { // effective user id. If executed by a super-user everything // gets tested. Here are different ways of execing the test binary: // 1. regular user assuming user == yarn user -// $ test-container-executor +// $ test-container-executor // 2. regular user with a given yarn user // $ test-container-executor yarn_user // 3. super user with a given user and assuming user == yarn user @@ -810,6 +822,7 @@ void test_recursive_unlink_children() { // 4. super user with a given user and a given yarn user // # test-container-executor user yarn_user int main(int argc, char **argv) { + int ret; LOGFILE = stdout; ERRORFILE = stderr; @@ -817,7 +830,7 @@ int main(int argc, char **argv) { if (system("chmod -R u=rwx " TEST_ROOT "; rm -fr " TEST_ROOT)) { exit(1); } - + if (mkdirs(TEST_ROOT "/logs/userlogs", 0755) != 0) { exit(1); } @@ -881,10 +894,36 @@ int main(int argc, char **argv) { test_check_user(0); +#ifdef __APPLE__ + printf("OS X: disabling CrashReporter\n"); + /* + * disable the "unexpectedly quit" dialog box + * because we know we're going to make our container + * do exactly that. + */ + CFStringRef crashType = CFSTR("DialogType"); + CFStringRef crashModeNone = CFSTR("None"); + CFStringRef crashAppID = CFSTR("com.apple.CrashReporter"); + CFStringRef crashOldMode = CFPreferencesCopyAppValue(CFSTR("DialogType"), CFSTR("com.apple.CrashReporter")); + + CFPreferencesSetAppValue(crashType, crashModeNone, crashAppID); + CFPreferencesAppSynchronize(crashAppID); +#endif + // the tests that change user need to be run in a subshell, so that // when they change user they don't give up our privs run_test_in_child("test_signal_container_group", test_signal_container_group); +#ifdef __APPLE__ + /* + * put the "unexpectedly quit" dialog back + */ + + CFPreferencesSetAppValue(crashType, crashOldMode, crashAppID); + CFPreferencesAppSynchronize(crashAppID); + printf("OS X: CrashReporter re-enabled\n"); +#endif + // init app and run container can't be run if you aren't testing as root if (getuid() == 0) { // these tests do internal forks so that the change_owner and execs @@ -893,7 +932,13 @@ int main(int argc, char **argv) { test_run_container(); } - seteuid(0); + /* + * try to seteuid(0). if it doesn't work, carry on anyway. + * we're going to capture the return value to get rid of a + * compiler warning. + */ + ret=seteuid(0); + ret++; // test_delete_user must run as root since that's how we use the delete_as_user test_delete_user(); free_executor_configurations(); @@ -904,11 +949,19 @@ int main(int argc, char **argv) { } read_executor_config(TEST_ROOT "/test.cfg"); +#ifdef __APPLE__ + username = "_uucp"; + test_check_user(1); + + username = "_networkd"; + test_check_user(1); +#else username = "bin"; test_check_user(1); username = "sys"; test_check_user(1); +#endif run("rm -fr " TEST_ROOT); printf("\nFinished tests\n");