blob: cd897354cf134a54cfa6616f31bb5f285c8d2233 [file] [log] [blame]
/**
* 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