YARN-5121. fix some container-executor portability issues. Contributed by Allen Wittenauer.
This commit is contained in:
parent
ce93595d7a
commit
ef501b1a0b
32
LICENSE.txt
32
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:
|
||||
|
@ -273,6 +273,18 @@
|
||||
</configuration>
|
||||
</plugin>
|
||||
|
||||
<plugin>
|
||||
<groupId>org.apache.rat</groupId>
|
||||
<artifactId>apache-rat-plugin</artifactId>
|
||||
<configuration>
|
||||
<excludes>
|
||||
<exclude>src/main/native/container-executor/impl/compat/fstatat.h</exclude>
|
||||
<exclude>src/main/native/container-executor/impl/compat/openat.h</exclude>
|
||||
<exclude>src/main/native/container-executor/impl/compat/unlinkat.h</exclude>
|
||||
</excludes>
|
||||
</configuration>
|
||||
</plugin>
|
||||
|
||||
<plugin>
|
||||
<groupId>org.apache.hadoop</groupId>
|
||||
<artifactId>hadoop-maven-plugins</artifactId>
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
@ -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 <sys/stat.h>
|
||||
|
||||
#include <unistd.h>
|
||||
|
||||
#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_ */
|
@ -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 <fcntl.h>
|
||||
#include <stdarg.h>
|
||||
#include <unistd.h>
|
||||
|
||||
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_ */
|
||||
|
@ -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 <sys/stat.h>
|
||||
|
||||
#include <unistd.h>
|
||||
|
||||
#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_ */
|
@ -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 <fcntl.h>
|
||||
#include <stdarg.h>
|
||||
#include <unistd.h>
|
||||
|
||||
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_ */
|
||||
|
@ -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 <fcntl.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#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_ */
|
||||
|
@ -17,7 +17,7 @@
|
||||
*/
|
||||
|
||||
// ensure we get the posix version of dirname by including this first
|
||||
#include <libgen.h>
|
||||
#include <libgen.h>
|
||||
|
||||
#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);
|
||||
|
||||
|
@ -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.
|
||||
|
@ -40,6 +40,28 @@
|
||||
#include <sys/mount.h>
|
||||
#include <sys/wait.h>
|
||||
|
||||
#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));
|
||||
|
@ -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,
|
||||
|
@ -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 <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#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 <libproc.h>
|
||||
|
||||
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
|
@ -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);
|
||||
|
@ -29,7 +29,19 @@
|
||||
#include <sys/stat.h>
|
||||
#include <sys/wait.h>
|
||||
|
||||
#define TEST_ROOT "/tmp/test-container-executor"
|
||||
#ifdef __APPLE__
|
||||
#include <CoreFoundation/CFString.h>
|
||||
#include <CoreFoundation/CFPreferences.h>
|
||||
|
||||
#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");
|
||||
|
Loading…
Reference in New Issue
Block a user