-
Notifications
You must be signed in to change notification settings - Fork 8.8k
/
get_executable.c
215 lines (178 loc) · 5.74 KB
/
get_executable.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
/**
* 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 "config.h"
#include "configuration.h"
#include "container-executor.h"
#include <errno.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#ifdef HAVE_SYS_SYSCTL_H
#include <sys/types.h>
#include <sys/param.h>
#include <sys/sysctl.h>
#endif
/*
* 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.
*/
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 before readlink: %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,"Resolved path for %s [%s] is longer than %d characters.\n",
procfn, filename, EXECUTOR_PATH_MAX);
exit(-1);
}
filename[len] = '\0';
return filename;
}
#ifdef HAVE_SYSCTL
/*
* A generic function to ask the kernel via sysctl.
* This is used by most of the open source BSDs, as
* many do not reliably have a /proc mounted.
*/
char *__get_exec_sysctl(int *mib)
{
char buffer[EXECUTOR_PATH_MAX];
char *filename;
size_t len;
len = sizeof(buffer);
if (sysctl(mib, 4, buffer, &len, NULL, 0) == -1) {
fprintf(ERRORFILE,"Can't get executable name from kernel: %s\n",
strerror(errno));
exit(-1);
}
filename=malloc(EXECUTOR_PATH_MAX);
if (!filename) {
fprintf(ERRORFILE,"cannot allocate memory for filename after sysctl: %s\n",strerror(errno));
exit(-1);
}
snprintf(filename,EXECUTOR_PATH_MAX,"%s",buffer);
return filename;
}
#endif /* HAVE_SYSCTL */
#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 *argv0) {
char *filename;
pid_t pid;
filename = malloc(PROC_PIDPATHINFO_MAXSIZE);
if (!filename) {
fprintf(ERRORFILE,"cannot allocate memory for filename before proc_pidpath: %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(__FreeBSD__)
char* get_executable(char *argv0) {
static int mib[] = {
CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, -1
};
return __get_exec_sysctl(mib);
}
#elif defined(__linux)
char* get_executable(char *argv0) {
return __get_exec_readproc("/proc/self/exe");
}
#elif defined(__NetBSD__) && defined(KERN_PROC_PATHNAME)
/* Only really new NetBSD kernels have KERN_PROC_PATHNAME */
char* get_executable(char *argv0) {
static int mib[] = {
CTL_KERN, KERN_PROC_ARGS, -1, KERN_PROC_PATHNAME,
};
return __get_exec_sysctl(mib);
}
#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(char *argv0) {
return __get_exec_readproc("/proc/self/path/a.out");
}
#elif defined(HADOOP_CONF_DIR_IS_ABS)
/*
* This is the fallback for operating systems where
* we don't know how to ask the kernel where the executable
* is located. It is only used if the maven property
* container-executor.conf.dir is set to an absolute path
* for security reasons.
*/
char* get_executable (char *argv0) {
char *filename;
#ifdef HAVE_CANONICALIZE_FILE_NAME
filename=canonicalize_file_name(argv0);
#else
filename=realpath(argv0,NULL);
#endif
if (!filename) {
fprintf(ERRORFILE,"realpath of executable: %s\n",strerror(errno));
exit(-1);
}
return filename;
}
#else
/*
* If we ended up here, we're on an operating system that doesn't
* match any of the above. This means either the OS needs to get a
* code added or the container-executor.conf.dir maven property
* should be set to an absolute path.
*/
#error Cannot safely determine executable path with a relative HADOOP_CONF_DIR on this operating system.
#endif /* platform checks */