Skip to content

Commit cf3e92a

Browse files
committed
Merge branch 'master' into feature/search-request-refactoring
2 parents ef5fc72 + c375180 commit cf3e92a

File tree

7 files changed

+124
-19
lines changed

7 files changed

+124
-19
lines changed

core/src/main/java/org/elasticsearch/Version.java

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -253,7 +253,9 @@ public class Version {
253253
public static final int V_1_7_2_ID = 1070299;
254254
public static final Version V_1_7_2 = new Version(V_1_7_2_ID, false, org.apache.lucene.util.Version.LUCENE_4_10_4);
255255
public static final int V_1_7_3_ID = 1070399;
256-
public static final Version V_1_7_3 = new Version(V_1_7_3_ID, true, org.apache.lucene.util.Version.LUCENE_4_10_4);
256+
public static final Version V_1_7_3 = new Version(V_1_7_3_ID, false, org.apache.lucene.util.Version.LUCENE_4_10_4);
257+
public static final int V_1_7_4_ID = 1070499;
258+
public static final Version V_1_7_4 = new Version(V_1_7_4_ID, true, org.apache.lucene.util.Version.LUCENE_4_10_4);
257259

258260
public static final int V_2_0_0_beta1_ID = 2000001;
259261
public static final Version V_2_0_0_beta1 = new Version(V_2_0_0_beta1_ID, false, org.apache.lucene.util.Version.LUCENE_5_2_1);
@@ -295,6 +297,8 @@ public static Version fromId(int id) {
295297
return V_2_0_0_beta2;
296298
case V_2_0_0_beta1_ID:
297299
return V_2_0_0_beta1;
300+
case V_1_7_4_ID:
301+
return V_1_7_4;
298302
case V_1_7_3_ID:
299303
return V_1_7_3;
300304
case V_1_7_2_ID:

core/src/main/java/org/elasticsearch/bootstrap/JNANatives.java

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,9 @@ private JNANatives() {}
4646
static boolean LOCAL_MLOCKALL = false;
4747
// Set to true, in case native seccomp call was successful
4848
static boolean LOCAL_SECCOMP = false;
49+
// Set to true, in case policy can be applied to all threads of the process (even existing ones)
50+
// otherwise they are only inherited for new threads (ES app threads)
51+
static boolean LOCAL_SECCOMP_ALL = false;
4952

5053
static void tryMlockall() {
5154
int errno = Integer.MIN_VALUE;
@@ -177,8 +180,11 @@ static void addConsoleCtrlHandler(ConsoleCtrlHandler handler) {
177180

178181
static void trySeccomp(Path tmpFile) {
179182
try {
180-
Seccomp.init(tmpFile);
183+
int ret = Seccomp.init(tmpFile);
181184
LOCAL_SECCOMP = true;
185+
if (ret == 1) {
186+
LOCAL_SECCOMP_ALL = true;
187+
}
182188
} catch (Throwable t) {
183189
// this is likely to happen unless the kernel is newish, its a best effort at the moment
184190
// so we log stacktrace at debug for now...

core/src/main/java/org/elasticsearch/bootstrap/Seccomp.java

Lines changed: 89 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,7 @@ static interface LinuxLibrary extends Library {
120120
static final int PR_SET_NO_NEW_PRIVS = 38; // since Linux 3.5
121121
static final int PR_GET_SECCOMP = 21; // since Linux 2.6.23
122122
static final int PR_SET_SECCOMP = 22; // since Linux 2.6.23
123-
static final int SECCOMP_MODE_FILTER = 2; // since Linux Linux 3.5
123+
static final long SECCOMP_MODE_FILTER = 2; // since Linux Linux 3.5
124124

125125
/** corresponds to struct sock_filter */
126126
static final class SockFilter {
@@ -209,9 +209,10 @@ static SockFilter BPF_JUMP(int code, int k, int jt, int jf) {
209209
static final int NR_SYSCALL_FORK = 57;
210210
static final int NR_SYSCALL_EXECVE = 59;
211211
static final int NR_SYSCALL_EXECVEAT = 322; // since Linux 3.19
212+
static final int NR_SYSCALL_TUXCALL = 184; // should return ENOSYS
212213

213214
/** try to install our BPF filters via seccomp() or prctl() to block execution */
214-
private static void linuxImpl() {
215+
private static int linuxImpl() {
215216
// first be defensive: we can give nice errors this way, at the very least.
216217
// also, some of these security features get backported to old versions, checking kernel version here is a big no-no!
217218
boolean supported = Constants.LINUX && "amd64".equals(Constants.OS_ARCH);
@@ -224,24 +225,85 @@ private static void linuxImpl() {
224225
throw new UnsupportedOperationException("seccomp unavailable: could not link methods. requires kernel 3.5+ with CONFIG_SECCOMP and CONFIG_SECCOMP_FILTER compiled in");
225226
}
226227

227-
// check for kernel version
228-
if (linux_libc.prctl(PR_GET_NO_NEW_PRIVS, 0, 0, 0, 0) < 0) {
228+
// pure paranoia:
229+
230+
// check that unimplemented syscalls actually return ENOSYS
231+
// you never know (e.g. https://code.google.com/p/chromium/issues/detail?id=439795)
232+
if (linux_libc.syscall(NR_SYSCALL_TUXCALL) >= 0 || Native.getLastError() != ENOSYS) {
233+
throw new UnsupportedOperationException("seccomp unavailable: your kernel is buggy and you should upgrade");
234+
}
235+
236+
// try to check system calls really are who they claim
237+
// you never know (e.g. https://chromium.googlesource.com/chromium/src.git/+/master/sandbox/linux/seccomp-bpf/sandbox_bpf.cc#57)
238+
final int bogusArg = 0xf7a46a5c;
239+
240+
// test seccomp(BOGUS)
241+
long ret = linux_libc.syscall(SECCOMP_SYSCALL_NR, bogusArg);
242+
if (ret != -1) {
243+
throw new UnsupportedOperationException("seccomp unavailable: seccomp(BOGUS_OPERATION) returned " + ret);
244+
} else {
229245
int errno = Native.getLastError();
230246
switch (errno) {
231-
case ENOSYS: throw new UnsupportedOperationException("seccomp unavailable: requires kernel 3.5+ with CONFIG_SECCOMP and CONFIG_SECCOMP_FILTER compiled in");
232-
default: throw new UnsupportedOperationException("prctl(PR_GET_NO_NEW_PRIVS): " + JNACLibrary.strerror(errno));
247+
case ENOSYS: break; // ok
248+
case EINVAL: break; // ok
249+
default: throw new UnsupportedOperationException("seccomp(BOGUS_OPERATION): " + JNACLibrary.strerror(errno));
233250
}
234251
}
235-
// check for SECCOMP
236-
if (linux_libc.prctl(PR_GET_SECCOMP, 0, 0, 0, 0) < 0) {
252+
253+
// test seccomp(VALID, BOGUS)
254+
ret = linux_libc.syscall(SECCOMP_SYSCALL_NR, SECCOMP_SET_MODE_FILTER, bogusArg);
255+
if (ret != -1) {
256+
throw new UnsupportedOperationException("seccomp unavailable: seccomp(SECCOMP_SET_MODE_FILTER, BOGUS_FLAG) returned " + ret);
257+
} else {
237258
int errno = Native.getLastError();
238259
switch (errno) {
239-
case EINVAL: throw new UnsupportedOperationException("seccomp unavailable: CONFIG_SECCOMP not compiled into kernel, CONFIG_SECCOMP and CONFIG_SECCOMP_FILTER are needed");
240-
default: throw new UnsupportedOperationException("prctl(PR_GET_SECCOMP): " + JNACLibrary.strerror(errno));
260+
case ENOSYS: break; // ok
261+
case EINVAL: break; // ok
262+
default: throw new UnsupportedOperationException("seccomp(SECCOMP_SET_MODE_FILTER, BOGUS_FLAG): " + JNACLibrary.strerror(errno));
241263
}
242264
}
265+
266+
// test prctl(BOGUS)
267+
ret = linux_libc.prctl(bogusArg, 0, 0, 0, 0);
268+
if (ret != -1) {
269+
throw new UnsupportedOperationException("seccomp unavailable: prctl(BOGUS_OPTION) returned " + ret);
270+
} else {
271+
int errno = Native.getLastError();
272+
switch (errno) {
273+
case ENOSYS: break; // ok
274+
case EINVAL: break; // ok
275+
default: throw new UnsupportedOperationException("prctl(BOGUS_OPTION): " + JNACLibrary.strerror(errno));
276+
}
277+
}
278+
279+
// now just normal defensive checks
280+
281+
// check for GET_NO_NEW_PRIVS
282+
switch (linux_libc.prctl(PR_GET_NO_NEW_PRIVS, 0, 0, 0, 0)) {
283+
case 0: break; // not yet set
284+
case 1: break; // already set by caller
285+
default:
286+
int errno = Native.getLastError();
287+
if (errno == ENOSYS) {
288+
throw new UnsupportedOperationException("seccomp unavailable: requires kernel 3.5+ with CONFIG_SECCOMP and CONFIG_SECCOMP_FILTER compiled in");
289+
} else {
290+
throw new UnsupportedOperationException("prctl(PR_GET_NO_NEW_PRIVS): " + JNACLibrary.strerror(errno));
291+
}
292+
}
293+
// check for SECCOMP
294+
switch (linux_libc.prctl(PR_GET_SECCOMP, 0, 0, 0, 0)) {
295+
case 0: break; // not yet set
296+
case 2: break; // already in filter mode by caller
297+
default:
298+
int errno = Native.getLastError();
299+
if (errno == EINVAL) {
300+
throw new UnsupportedOperationException("seccomp unavailable: CONFIG_SECCOMP not compiled into kernel, CONFIG_SECCOMP and CONFIG_SECCOMP_FILTER are needed");
301+
} else {
302+
throw new UnsupportedOperationException("prctl(PR_GET_SECCOMP): " + JNACLibrary.strerror(errno));
303+
}
304+
}
243305
// check for SECCOMP_MODE_FILTER
244-
if (linux_libc.prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, 0, 0, 0) < 0) {
306+
if (linux_libc.prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, 0, 0, 0) != 0) {
245307
int errno = Native.getLastError();
246308
switch (errno) {
247309
case EFAULT: break; // available
@@ -251,10 +313,15 @@ private static void linuxImpl() {
251313
}
252314

253315
// ok, now set PR_SET_NO_NEW_PRIVS, needed to be able to set a seccomp filter as ordinary user
254-
if (linux_libc.prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0) < 0) {
316+
if (linux_libc.prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0) != 0) {
255317
throw new UnsupportedOperationException("prctl(PR_SET_NO_NEW_PRIVS): " + JNACLibrary.strerror(Native.getLastError()));
256318
}
257319

320+
// check it worked
321+
if (linux_libc.prctl(PR_GET_NO_NEW_PRIVS, 0, 0, 0, 0) != 1) {
322+
throw new UnsupportedOperationException("seccomp filter did not really succeed: prctl(PR_GET_NO_NEW_PRIVS): " + JNACLibrary.strerror(Native.getLastError()));
323+
}
324+
258325
// BPF installed to check arch, then syscall range. See https://www.kernel.org/doc/Documentation/prctl/seccomp_filter.txt for details.
259326
SockFilter insns[] = {
260327
/* 1 */ BPF_STMT(BPF_LD + BPF_W + BPF_ABS, SECCOMP_DATA_ARCH_OFFSET), //
@@ -272,14 +339,16 @@ private static void linuxImpl() {
272339
prog.write();
273340
long pointer = Pointer.nativeValue(prog.getPointer());
274341

342+
int method = 1;
275343
// install filter, if this works, after this there is no going back!
276344
// first try it with seccomp(SECCOMP_SET_MODE_FILTER), falling back to prctl()
277345
if (linux_libc.syscall(SECCOMP_SYSCALL_NR, SECCOMP_SET_MODE_FILTER, SECCOMP_FILTER_FLAG_TSYNC, pointer) != 0) {
346+
method = 0;
278347
int errno1 = Native.getLastError();
279348
if (logger.isDebugEnabled()) {
280349
logger.debug("seccomp(SECCOMP_SET_MODE_FILTER): " + JNACLibrary.strerror(errno1) + ", falling back to prctl(PR_SET_SECCOMP)...");
281350
}
282-
if (linux_libc.prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, pointer, 0, 0) < 0) {
351+
if (linux_libc.prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, pointer, 0, 0) != 0) {
283352
int errno2 = Native.getLastError();
284353
throw new UnsupportedOperationException("seccomp(SECCOMP_SET_MODE_FILTER): " + JNACLibrary.strerror(errno1) +
285354
", prctl(PR_SET_SECCOMP): " + JNACLibrary.strerror(errno2));
@@ -291,7 +360,8 @@ private static void linuxImpl() {
291360
throw new UnsupportedOperationException("seccomp filter installation did not really succeed. seccomp(PR_GET_SECCOMP): " + JNACLibrary.strerror(Native.getLastError()));
292361
}
293362

294-
logger.debug("Linux seccomp filter installation successful");
363+
logger.debug("Linux seccomp filter installation successful, threads: [{}]", method == 1 ? "all" : "app" );
364+
return method;
295365
}
296366

297367
// OS X implementation via sandbox(7)
@@ -334,7 +404,7 @@ private static void macImpl(Path tmpFile) throws IOException {
334404
// first be defensive: we can give nice errors this way, at the very least.
335405
boolean supported = Constants.MAC_OS_X;
336406
if (supported == false) {
337-
throw new IllegalStateException("bug: should not be trying to initialize seccomp for an unsupported OS");
407+
throw new IllegalStateException("bug: should not be trying to initialize seatbelt for an unsupported OS");
338408
}
339409

340410
// we couldn't link methods, could be some really ancient OS X (< Leopard) or some bug
@@ -372,12 +442,14 @@ private static void macImpl(Path tmpFile) throws IOException {
372442
* Attempt to drop the capability to execute for the process.
373443
* <p>
374444
* This is best effort and OS and architecture dependent. It may throw any Throwable.
445+
* @return 0 if we can do this for application threads, 1 for the entire process
375446
*/
376-
static void init(Path tmpFile) throws Throwable {
447+
static int init(Path tmpFile) throws Throwable {
377448
if (Constants.LINUX) {
378-
linuxImpl();
449+
return linuxImpl();
379450
} else if (Constants.MAC_OS_X) {
380451
macImpl(tmpFile);
452+
return 1;
381453
} else {
382454
throw new UnsupportedOperationException("syscall filtering not supported for OS: '" + Constants.OS_NAME + "'");
383455
}

core/src/test/java/org/elasticsearch/bootstrap/SeccompTests.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,16 @@ public void setUp() throws Exception {
3030
assumeTrue("requires seccomp filter installation", Natives.isSeccompInstalled());
3131
// otherwise security manager will block the execution, no fun
3232
assumeTrue("cannot test with security manager enabled", System.getSecurityManager() == null);
33+
// otherwise, since we don't have TSYNC support, rules are not applied to the test thread
34+
// (randomizedrunner class initialization happens in its own thread, after the test thread is created)
35+
// instead we just forcefully run it for the test thread here.
36+
if (!JNANatives.LOCAL_SECCOMP_ALL) {
37+
try {
38+
Seccomp.init(createTempDir());
39+
} catch (Throwable e) {
40+
throw new RuntimeException("unable to forcefully apply seccomp to test thread", e);
41+
}
42+
}
3343
}
3444

3545
public void testNoExecution() throws Exception {

core/src/test/java/org/elasticsearch/common/lucene/LuceneTests.java

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
import org.apache.lucene.search.MatchAllDocsQuery;
2929
import org.apache.lucene.search.TermQuery;
3030
import org.apache.lucene.store.Directory;
31+
import org.apache.lucene.store.MMapDirectory;
3132
import org.apache.lucene.store.MockDirectoryWrapper;
3233
import org.apache.lucene.util.Version;
3334
import org.elasticsearch.test.ESTestCase;
@@ -359,4 +360,16 @@ public void testCount() throws Exception {
359360
w.close();
360361
dir.close();
361362
}
363+
364+
/**
365+
* Test that the "unmap hack" is detected as supported by lucene.
366+
* This works around the following bug: https://bugs.openjdk.java.net/browse/JDK-4724038
367+
* <p>
368+
* While not guaranteed, current status is "Critical Internal API": http://openjdk.java.net/jeps/260
369+
* Additionally this checks we did not screw up the security logic around the hack.
370+
*/
371+
public void testMMapHackSupported() throws Exception {
372+
// add assume's here if needed for certain platforms, but we should know if it does not work.
373+
assertTrue(MMapDirectory.UNMAP_SUPPORTED);
374+
}
362375
}
Binary file not shown.
Binary file not shown.

0 commit comments

Comments
 (0)