Skip to content

Conversation

@joachimdraeger
Copy link
Contributor

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

… 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
@elasticmachine
Copy link
Collaborator

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?

@Tim-Brooks
Copy link
Contributor

Tim-Brooks commented Jun 20, 2017

Thanks @joachimdraeger. I'll take a look at this.

Is this the only place where this occurs? I see that we close those S3OutputStream without protection in other places without protection:

try (OutputStream stream = createOutput(blobName)) {
            Streams.copy(inputStream, stream);
}

Maybe we should also override close(). And wrap the super.close() call in a doPrivileged block?

@Tim-Brooks
Copy link
Contributor

@elasticmachine please test this

});
}

private void flushPriveleged(byte[] bytes, int off, int len, boolean closing) throws IOException {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Spelling: flushPrivileged

@Tim-Brooks
Copy link
Contributor

Maybe we should also override close(). And wrap the super.close() call in a doPrivileged block?

Hmm. Now that I look at the source for S3OutputStream, I see that all the calls route through the flush method.

public abstract void flush(byte[] bytes, int off, int len, boolean closing) throws IOException;

So I think your change will be sufficient.

@jasontedor
Copy link
Member

@tbrooks8 See #25206 for why we came to the approach here.

@joachimdraeger
Copy link
Contributor Author

I added poc code for testing socket permissions. Test fails without the fix.


private void openSocket() {
try {
Socket socket = new Socket("localhost", 9200);
Copy link
Contributor Author

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.

@joachimdraeger
Copy link
Contributor Author

Just found out about MockSocket, I can probably make this work nicely now.

@joachimdraeger
Copy link
Contributor Author

@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.

@jasontedor
Copy link
Member

Yes, mock socket is the way to go. I'll look closely soon.

@jasontedor
Copy link
Member

test this please

@joachimdraeger
Copy link
Contributor Author

Did you forget to tag elasticmachine, @jasontedor?

@s1monw
Copy link
Contributor

s1monw commented Jun 26, 2017

@elasticmachine test this please

@jasontedor
Copy link
Member

@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.

Copy link
Member

@jasontedor jasontedor left a 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
Copy link
Member

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);
Copy link
Member

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);
Copy link
Member

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()) {
Copy link
Member

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);
Copy link
Member

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(() -> {
Copy link
Member

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.
@joachimdraeger
Copy link
Contributor Author

Thanks for the review @jasontedor, I implemented the suggested changes and hope that the additional documentation makes it clearer.

Copy link
Member

@jasontedor jasontedor left a 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
Copy link
Member

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?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure, no problem

Copy link
Contributor

@Tim-Brooks Tim-Brooks left a 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);
Copy link
Contributor

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?

Copy link
Member

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.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll remove it

@joachimdraeger
Copy link
Contributor Author

Thanks for the review @tbrooks8. Could you have another look?

Copy link
Contributor

@Tim-Brooks Tim-Brooks left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@joachimdraeger
Copy link
Contributor Author

Ready to merge @jasontedor ?

@Tim-Brooks Tim-Brooks merged commit 1ff2c13 into elastic:master Jul 7, 2017
jasontedor added a commit to jasontedor/elasticsearch that referenced this pull request Jul 7, 2017
* 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)
jasontedor added a commit to jasontedor/elasticsearch that referenced this pull request Jul 7, 2017
* 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)
  ...
@jasontedor
Copy link
Member

Thanks for merging @tbrooks8.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

>bug :Distributed Coordination/Snapshot/Restore Anything directly related to the `_snapshot/*` APIs v6.0.0-beta1

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants