-
Notifications
You must be signed in to change notification settings - Fork 25.6k
Avoid SecurityException in repository-S3 on DefaultS3OutputStream.flush() #25254
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Avoid SecurityException in repository-S3 on DefaultS3OutputStream.flush() #25254
Conversation
… in repository-S3 plugin to avoid SecurityException by Streams.copy(). A plugin is only allowed to use its own jars when performing privileged operations. The S3 client might open a new Socket on close(). elastic#25192
|
Since this is a community submitted pull request, a Jenkins build has not been kicked off automatically. Can an Elastic organization member please verify the contents of this patch and then kick off a build manually? |
|
Thanks @joachimdraeger. I'll take a look at this. Is this the only place where this occurs? I see that we close those Maybe we should also override |
|
@elasticmachine please test this |
| }); | ||
| } | ||
|
|
||
| private void flushPriveleged(byte[] bytes, int off, int len, boolean closing) throws IOException { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Spelling: flushPrivileged
Hmm. Now that I look at the source for So I think your change will be sufficient. |
|
@tbrooks8 See #25206 for why we came to the approach here. |
|
I added poc code for testing socket permissions. Test fails without the fix. |
|
|
||
| private void openSocket() { | ||
| try { | ||
| Socket socket = new Socket("localhost", 9200); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Are there any guidelines which ports could be used in unit/integration tests? I think I wasn't able to use any other port than 9200 without changing further permissions.
|
Just found out about MockSocket, I can probably make this work nicely now. |
|
@jasontedor, I added the Socket tests and changed it to use MockSocket and a random port. I think this is in-line with similar tests now. |
|
Yes, mock socket is the way to go. I'll look closely soon. |
|
test this please |
|
Did you forget to tag elasticmachine, @jasontedor? |
|
@elasticmachine test this please |
|
@joachimdraeger No, that's not necessary. In fact, I had checked on the status of the build previously and it was green. What happened here is that the cleanup of the PR builds is quite aggressive, they only stay outstanding for a few days (to be precise, I think that it's three). Thus, the build was cleaned up sometime over the weekend and that leads to the PR status no longer showing up on the PR. Thankfully, @s1monw kicked off another build and we see here that we are still green. |
jasontedor
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks @joachimdraeger, this generally looks good but I left some more thorough comments.
| this.mockSocketPort = mockSocketPort; | ||
| } | ||
|
|
||
| // simulate a socket connection to check that SocketAccess is used correctly |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you elaborate a bit more why this necessary, exactly what we are simulating here?
| // simulate a socket connection to check that SocketAccess is used correctly | ||
| private void simulateS3SocketConnection() { | ||
| try { | ||
| Socket socket = new Socket(InetAddress.getByName("127.0.0.1"), mockSocketPort); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe wrap this in a try-with-resources instead?
| Socket socket = new Socket(InetAddress.getByName("127.0.0.1"), mockSocketPort); | ||
| socket.close(); | ||
| } catch (IOException e) { | ||
| throw new RuntimeException(e); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How about throwing UncheckedIOException instead?
| public static void openMockSocket() throws IOException { | ||
| socket = new MockServerSocket(0, 50, InetAddress.getByName("127.0.0.1")); | ||
| new Thread(() -> { | ||
| while (!socket.isClosed()) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's not obvious to me what is going on here, can you please explain?
| try { | ||
| socket.accept(); | ||
| } catch (IOException e) { | ||
| logger.log(Level.ERROR, e); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't understand this?
| @BeforeClass | ||
| public static void openMockSocket() throws IOException { | ||
| socket = new MockServerSocket(0, 50, InetAddress.getByName("127.0.0.1")); | ||
| new Thread(() -> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This thread can leak and fail the test, I think that you need to clean it up (join on it in tear down).
…bStoreContainerTests and further improvements.
|
Thanks for the review @jasontedor, I implemented the suggested changes and hope that the additional documentation makes it clearer. |
jasontedor
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM, I left one more request though. Did you want to take another look @tbrooks8?
| Socket socket = new Socket(InetAddress.getByName("127.0.0.1"), mockSocketPort); | ||
| socket.close(); | ||
| try (Socket socket = new Socket(InetAddress.getByName("127.0.0.1"), mockSocketPort)) { | ||
| Assert.assertTrue(socket.isConnected()); // NOOP to keep static analysis happy |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We tend to static import these assert methods; would you mind doing the same here so this can only be assertTrue without the class qualifier?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sure, no problem
Tim-Brooks
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I mean this all looks alright to me. I just kind of have a question about how we handle the server socket that we must open for this test.
| // Accept connections from MockAmazonS3. | ||
| mockS3ServerSocket.accept(); | ||
| } catch (IOException e) { | ||
| logger.log(Level.ERROR, e); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think that this will generate an error in the logs most of the time when this test ends. As we will call close and I think accept throws an exception when the socket is closed. @jasontedor - is this alright?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's a good point @tbrooks8, we should not do this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'll remove it
|
Thanks for the review @tbrooks8. Could you have another look? |
Tim-Brooks
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
|
Ready to merge @jasontedor ? |
* master: Remove deprecated created and found from index, delete and bulk (elastic#25516) fix testEnsureVersionCompatibility for 5.5.0 release fix Version.v6_0_0 min compatibility version to 5.5.0 Add bwc indices for 5.5.0 Add v5_5_1 constant [DOCS] revise high level client Search Scroll API docs (elastic#25599) Improve REST error handling when endpoint does not support HTTP verb, add OPTIONS support (elastic#24437) Avoid SecurityException in repository-S3 on DefaultS3OutputStream.flush() (elastic#25254) [Tests] Add tests for CompletionSuggestionBuilder#build() (elastic#25575)
* master: (42 commits) Harden global checkpoint tracker Remove deprecated created and found from index, delete and bulk (elastic#25516) fix testEnsureVersionCompatibility for 5.5.0 release fix Version.v6_0_0 min compatibility version to 5.5.0 Add bwc indices for 5.5.0 Add v5_5_1 constant [DOCS] revise high level client Search Scroll API docs (elastic#25599) Improve REST error handling when endpoint does not support HTTP verb, add OPTIONS support (elastic#24437) Avoid SecurityException in repository-S3 on DefaultS3OutputStream.flush() (elastic#25254) [Tests] Add tests for CompletionSuggestionBuilder#build() (elastic#25575) Enable cross-setting validation [Docs] Fix typo in bootstrap-checks.asciidoc (elastic#25597) Index ids in binary form. (elastic#25352) bwc checkout should fetch from all remotes IndexingIT should check for global checkpoints regardless of master version [Tests] Add tests for PhraseSuggestionBuilder#build() (elastic#25571) Remove unused class MinimalMap (elastic#25590) [Docs] Document Scroll API for Java High Level REST Client (elastic#25554) Disable date field mapping changing (elastic#25285) Allow BWC Testing against a specific branch (elastic#25510) ...
|
Thanks for merging @tbrooks8. |
Moved SocketAccess.doPrivileged up the stack to DefaultS3OutputStream in repository-S3 plugin to avoid SecurityException by Streams.copy(). A plugin is only allowed to use its own jars when performing privileged operations. The S3 client might open a new Socket on close(). #25192