Skip to content

Commit fdfbc95

Browse files
authored
Merge branch 'main' into non-issue/add-basic-kmeans
2 parents fe9e86e + 49a9137 commit fdfbc95

File tree

19 files changed

+824
-199
lines changed

19 files changed

+824
-199
lines changed

modules/ingest-attachment/src/main/java/org/elasticsearch/ingest/attachment/TikaImpl.java

Lines changed: 1 addition & 111 deletions
Original file line numberDiff line numberDiff line change
@@ -16,33 +16,11 @@
1616
import org.apache.tika.parser.AutoDetectParser;
1717
import org.apache.tika.parser.Parser;
1818
import org.apache.tika.parser.ParserDecorator;
19-
import org.elasticsearch.SpecialPermission;
20-
import org.elasticsearch.bootstrap.FilePermissionUtils;
21-
import org.elasticsearch.core.PathUtils;
22-
import org.elasticsearch.core.SuppressForbidden;
23-
import org.elasticsearch.jdk.JarHell;
2419

2520
import java.io.ByteArrayInputStream;
2621
import java.io.IOException;
27-
import java.io.UncheckedIOException;
28-
import java.lang.reflect.ReflectPermission;
29-
import java.net.URISyntaxException;
30-
import java.net.URL;
31-
import java.net.URLClassLoader;
32-
import java.nio.file.Files;
33-
import java.nio.file.Path;
34-
import java.security.AccessControlContext;
35-
import java.security.AccessController;
36-
import java.security.PermissionCollection;
37-
import java.security.Permissions;
38-
import java.security.PrivilegedActionException;
39-
import java.security.PrivilegedExceptionAction;
40-
import java.security.ProtectionDomain;
41-
import java.security.SecurityPermission;
4222
import java.util.Arrays;
4323
import java.util.HashSet;
44-
import java.util.LinkedHashSet;
45-
import java.util.PropertyPermission;
4624
import java.util.Set;
4725

4826
/**
@@ -90,24 +68,8 @@ final class TikaImpl {
9068
* parses with tika, throwing any exception hit while parsing the document
9169
*/
9270
static String parse(final byte content[], final Metadata metadata, final int limit) throws TikaException, IOException {
93-
// check that its not unprivileged code like a script
94-
SpecialPermission.check();
95-
9671
try {
97-
return AccessController.doPrivileged(
98-
(PrivilegedExceptionAction<String>) () -> TIKA_INSTANCE.parseToString(new ByteArrayInputStream(content), metadata, limit),
99-
RESTRICTED_CONTEXT
100-
);
101-
} catch (PrivilegedActionException e) {
102-
// checked exception from tika: unbox it
103-
Throwable cause = e.getCause();
104-
if (cause instanceof TikaException tikaException) {
105-
throw tikaException;
106-
} else if (cause instanceof IOException ioException) {
107-
throw ioException;
108-
} else {
109-
throw new AssertionError(cause);
110-
}
72+
return TIKA_INSTANCE.parseToString(new ByteArrayInputStream(content), metadata, limit);
11173
} catch (LinkageError e) {
11274
if (e.getMessage().contains("bouncycastle")) {
11375
/*
@@ -119,76 +81,4 @@ static String parse(final byte content[], final Metadata metadata, final int lim
11981
throw new RuntimeException(e);
12082
}
12183
}
122-
123-
// apply additional containment for parsers, this is intersected with the current permissions
124-
// its hairy, but worth it so we don't have some XML flaw reading random crap from the FS
125-
private static final AccessControlContext RESTRICTED_CONTEXT = isUsingSecurityManager()
126-
? new AccessControlContext(new ProtectionDomain[] { new ProtectionDomain(null, getRestrictedPermissions()) })
127-
: null;
128-
129-
private static boolean isUsingSecurityManager() {
130-
return false;
131-
}
132-
133-
// compute some minimal permissions for parsers. they only get r/w access to the java temp directory,
134-
// the ability to load some resources from JARs, and read sysprops
135-
@SuppressForbidden(reason = "adds access to tmp directory")
136-
static PermissionCollection getRestrictedPermissions() {
137-
Permissions perms = new Permissions();
138-
139-
// property/env access needed for parsing
140-
perms.add(new PropertyPermission("*", "read"));
141-
perms.add(new RuntimePermission("getenv.TIKA_CONFIG"));
142-
143-
try {
144-
// add permissions for resource access:
145-
// classpath
146-
addReadPermissions(perms, JarHell.parseClassPath());
147-
// plugin jars
148-
if (TikaImpl.class.getClassLoader() instanceof URLClassLoader urlClassLoader) {
149-
URL[] urls = urlClassLoader.getURLs();
150-
Set<URL> set = new LinkedHashSet<>(Arrays.asList(urls));
151-
if (set.size() != urls.length) {
152-
throw new AssertionError("duplicate jars: " + Arrays.toString(urls));
153-
}
154-
addReadPermissions(perms, set);
155-
}
156-
// jvm's java.io.tmpdir (needs read/write)
157-
FilePermissionUtils.addDirectoryPath(
158-
perms,
159-
"java.io.tmpdir",
160-
PathUtils.get(System.getProperty("java.io.tmpdir")),
161-
"read,readlink,write,delete",
162-
false
163-
);
164-
} catch (IOException e) {
165-
throw new UncheckedIOException(e);
166-
}
167-
// current hacks needed for POI/PDFbox issues:
168-
perms.add(new SecurityPermission("putProviderProperty.BC"));
169-
perms.add(new SecurityPermission("insertProvider"));
170-
perms.add(new ReflectPermission("suppressAccessChecks"));
171-
perms.add(new RuntimePermission("accessClassInPackage.sun.java2d.cmm.kcms"));
172-
// xmlbeans, use by POI, needs to get the context classloader
173-
perms.add(new RuntimePermission("getClassLoader"));
174-
perms.setReadOnly();
175-
return perms;
176-
}
177-
178-
// add resources to (what is typically) a jar, but might not be (e.g. in tests/IDE)
179-
@SuppressForbidden(reason = "adds access to jar resources")
180-
static void addReadPermissions(Permissions perms, Set<URL> resources) throws IOException {
181-
try {
182-
for (URL url : resources) {
183-
Path path = PathUtils.get(url.toURI());
184-
if (Files.isDirectory(path)) {
185-
FilePermissionUtils.addDirectoryPath(perms, "class.path", path, "read,readlink", false);
186-
} else {
187-
FilePermissionUtils.addSingleFilePath(perms, path, "read,readlink");
188-
}
189-
}
190-
} catch (URISyntaxException bogus) {
191-
throw new RuntimeException(bogus);
192-
}
193-
}
19484
}

modules/ingest-attachment/src/main/plugin-metadata/plugin-security.policy

Lines changed: 0 additions & 23 deletions
This file was deleted.

muted-tests.yml

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -432,6 +432,15 @@ tests:
432432
- class: org.elasticsearch.xpack.esql.qa.single_node.GenerativeIT
433433
method: test
434434
issue: https://github.com/elastic/elasticsearch/issues/127157
435+
- class: org.elasticsearch.xpack.esql.qa.single_node.EsqlSpecIT
436+
method: test {fork.ForkWithWhereSortDescAndLimit SYNC}
437+
issue: https://github.com/elastic/elasticsearch/issues/127326
438+
- class: org.elasticsearch.geometry.utils.SpatialEnvelopeVisitorTests
439+
method: testVisitGeoPointsWrapping
440+
issue: https://github.com/elastic/elasticsearch/issues/123425
441+
- class: org.elasticsearch.xpack.esql.action.CrossClusterQueryWithFiltersIT
442+
method: testTimestampFilterFromQuery
443+
issue: https://github.com/elastic/elasticsearch/issues/127332
435444

436445
# Examples:
437446
#

server/src/main/java/org/elasticsearch/TransportVersions.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -227,7 +227,7 @@ static TransportVersion def(int id) {
227227
public static final TransportVersion DOC_FIELDS_AS_LIST = def(9_061_0_00);
228228
public static final TransportVersion DENSE_VECTOR_OFF_HEAP_STATS = def(9_062_00_0);
229229
public static final TransportVersion RANDOM_SAMPLER_QUERY_BUILDER = def(9_063_0_00);
230-
public static final TransportVersion SETTINGS_IN_DATA_STREAMS = def(9_064_00_0);
230+
public static final TransportVersion SETTINGS_IN_DATA_STREAMS = def(9_064_0_00);
231231

232232
/*
233233
* STOP! READ THIS FIRST! No, really,

server/src/main/java/org/elasticsearch/action/search/SearchQueryThenFetchAsyncAction.java

Lines changed: 70 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,9 @@
2323
import org.elasticsearch.action.support.IndicesOptions;
2424
import org.elasticsearch.client.internal.Client;
2525
import org.elasticsearch.cluster.ClusterState;
26+
import org.elasticsearch.common.bytes.ReleasableBytesReference;
2627
import org.elasticsearch.common.io.stream.NamedWriteableRegistry;
28+
import org.elasticsearch.common.io.stream.RecyclerBytesStreamOutput;
2729
import org.elasticsearch.common.io.stream.StreamInput;
2830
import org.elasticsearch.common.io.stream.StreamOutput;
2931
import org.elasticsearch.common.io.stream.Writeable;
@@ -50,6 +52,7 @@
5052
import org.elasticsearch.tasks.TaskId;
5153
import org.elasticsearch.threadpool.ThreadPool;
5254
import org.elasticsearch.transport.AbstractTransportRequest;
55+
import org.elasticsearch.transport.BytesTransportResponse;
5356
import org.elasticsearch.transport.LeakTracker;
5457
import org.elasticsearch.transport.SendRequestTransportException;
5558
import org.elasticsearch.transport.Transport;
@@ -58,6 +61,7 @@
5861
import org.elasticsearch.transport.TransportException;
5962
import org.elasticsearch.transport.TransportResponse;
6063
import org.elasticsearch.transport.TransportResponseHandler;
64+
import org.elasticsearch.transport.TransportService;
6165

6266
import java.io.IOException;
6367
import java.util.ArrayList;
@@ -215,41 +219,22 @@ public static final class NodeQueryResponse extends TransportResponse {
215219
this.topDocsStats = SearchPhaseController.TopDocsStats.readFrom(in);
216220
}
217221

218-
NodeQueryResponse(
219-
QueryPhaseResultConsumer.MergeResult mergeResult,
220-
Object[] results,
221-
SearchPhaseController.TopDocsStats topDocsStats
222-
) {
223-
this.results = results;
224-
for (Object result : results) {
225-
if (result instanceof QuerySearchResult r) {
226-
r.incRef();
227-
}
228-
}
229-
this.mergeResult = mergeResult;
230-
this.topDocsStats = topDocsStats;
231-
assert Arrays.stream(results).noneMatch(Objects::isNull) : Arrays.toString(results);
232-
}
233-
234222
// public for tests
235223
public Object[] getResults() {
236224
return results;
237225
}
238226

239227
@Override
240228
public void writeTo(StreamOutput out) throws IOException {
241-
out.writeArray((o, v) -> {
242-
if (v instanceof Exception e) {
243-
o.writeBoolean(false);
244-
o.writeException(e);
229+
out.writeVInt(results.length);
230+
for (Object result : results) {
231+
if (result instanceof Exception e) {
232+
writePerShardException(out, e);
245233
} else {
246-
o.writeBoolean(true);
247-
assert v instanceof QuerySearchResult : v;
248-
((QuerySearchResult) v).writeTo(o);
234+
writePerShardResult(out, (QuerySearchResult) result);
249235
}
250-
}, results);
251-
mergeResult.writeTo(out);
252-
topDocsStats.writeTo(out);
236+
}
237+
writeMergeResult(out, mergeResult, topDocsStats);
253238
}
254239

255240
@Override
@@ -280,6 +265,25 @@ public boolean decRef() {
280265
}
281266
return false;
282267
}
268+
269+
private static void writeMergeResult(
270+
StreamOutput out,
271+
QueryPhaseResultConsumer.MergeResult mergeResult,
272+
SearchPhaseController.TopDocsStats topDocsStats
273+
) throws IOException {
274+
mergeResult.writeTo(out);
275+
topDocsStats.writeTo(out);
276+
}
277+
278+
private static void writePerShardException(StreamOutput o, Exception e) throws IOException {
279+
o.writeBoolean(false);
280+
o.writeException(e);
281+
}
282+
283+
private static void writePerShardResult(StreamOutput out, SearchPhaseResult result) throws IOException {
284+
out.writeBoolean(true);
285+
result.writeTo(out);
286+
}
283287
}
284288

285289
/**
@@ -552,7 +556,7 @@ static void registerNodeSearchAction(
552556
) {
553557
var transportService = searchTransportService.transportService();
554558
var threadPool = transportService.getThreadPool();
555-
final Dependencies dependencies = new Dependencies(searchService, threadPool.executor(ThreadPool.Names.SEARCH));
559+
final Dependencies dependencies = new Dependencies(searchService, transportService, threadPool.executor(ThreadPool.Names.SEARCH));
556560
// Even though not all searches run on the search pool, we use the search pool size as the upper limit of shards to execute in
557561
// parallel to keep the implementation simple instead of working out the exact pool(s) a query will use up-front.
558562
final int searchPoolMax = threadPool.info(ThreadPool.Names.SEARCH).getMax();
@@ -715,7 +719,7 @@ public void onFailure(Exception e) {
715719
}
716720
}
717721

718-
private record Dependencies(SearchService searchService, Executor executor) {}
722+
private record Dependencies(SearchService searchService, TransportService transportService, Executor executor) {}
719723

720724
private static final class QueryPerNodeState {
721725

@@ -760,6 +764,8 @@ void onShardDone() {
760764
if (countDown.countDown() == false) {
761765
return;
762766
}
767+
RecyclerBytesStreamOutput out = null;
768+
boolean success = false;
763769
var channelListener = new ChannelActionListener<>(channel);
764770
try (queryPhaseResultConsumer) {
765771
var failure = queryPhaseResultConsumer.failure.get();
@@ -788,33 +794,46 @@ void onShardDone() {
788794
relevantShardIndices.set(localIndex);
789795
}
790796
}
791-
final Object[] results = new Object[queryPhaseResultConsumer.getNumShards()];
792-
for (int i = 0; i < results.length; i++) {
793-
var result = queryPhaseResultConsumer.results.get(i);
794-
if (result == null) {
795-
results[i] = failures.get(i);
796-
} else {
797-
// free context id and remove it from the result right away in case we don't need it anymore
798-
if (result instanceof QuerySearchResult q
799-
&& q.getContextId() != null
800-
&& relevantShardIndices.get(q.getShardIndex()) == false
801-
&& q.hasSuggestHits() == false
802-
&& q.getRankShardResult() == null
803-
&& searchRequest.searchRequest.scroll() == null
804-
&& isPartOfPIT(searchRequest.searchRequest, q.getContextId()) == false) {
805-
if (dependencies.searchService.freeReaderContext(q.getContextId())) {
806-
q.clearContextId();
807-
}
797+
final int resultCount = queryPhaseResultConsumer.getNumShards();
798+
out = dependencies.transportService.newNetworkBytesStream();
799+
out.setTransportVersion(channel.getVersion());
800+
try {
801+
out.writeVInt(resultCount);
802+
for (int i = 0; i < resultCount; i++) {
803+
var result = queryPhaseResultConsumer.results.get(i);
804+
if (result == null) {
805+
NodeQueryResponse.writePerShardException(out, failures.remove(i));
806+
} else {
807+
// free context id and remove it from the result right away in case we don't need it anymore
808+
maybeFreeContext(result, relevantShardIndices);
809+
NodeQueryResponse.writePerShardResult(out, result);
808810
}
809-
results[i] = result;
810811
}
811-
assert results[i] != null;
812+
NodeQueryResponse.writeMergeResult(out, mergeResult, queryPhaseResultConsumer.topDocsStats);
813+
success = true;
814+
} catch (IOException e) {
815+
handleMergeFailure(e, channelListener);
816+
return;
812817
}
818+
} finally {
819+
if (success == false && out != null) {
820+
out.close();
821+
}
822+
}
823+
ActionListener.respondAndRelease(channelListener, new BytesTransportResponse(new ReleasableBytesReference(out.bytes(), out)));
824+
}
813825

814-
ActionListener.respondAndRelease(
815-
channelListener,
816-
new NodeQueryResponse(mergeResult, results, queryPhaseResultConsumer.topDocsStats)
817-
);
826+
private void maybeFreeContext(SearchPhaseResult result, BitSet relevantShardIndices) {
827+
if (result instanceof QuerySearchResult q
828+
&& q.getContextId() != null
829+
&& relevantShardIndices.get(q.getShardIndex()) == false
830+
&& q.hasSuggestHits() == false
831+
&& q.getRankShardResult() == null
832+
&& searchRequest.searchRequest.scroll() == null
833+
&& isPartOfPIT(searchRequest.searchRequest, q.getContextId()) == false) {
834+
if (dependencies.searchService.freeReaderContext(q.getContextId())) {
835+
q.clearContextId();
836+
}
818837
}
819838
}
820839

0 commit comments

Comments
 (0)