-
Notifications
You must be signed in to change notification settings - Fork 24.9k
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
Add doPrivilege blocks for socket connect operations in plugins #22534
Conversation
With this pull request if I do the following the test package passes:
This will require a careful review to see if I caught all the places where connections occur in plugins (there were a lot, so it is possible I missed some). |
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 left a bunch of comments. I think it's hard to really make sure we catch everything by review. We have to rely on the testing and the integration testing with these 3rd party storage backends must be improved. I think we are on that.
import java.security.PrivilegedActionException; | ||
import java.security.PrivilegedExceptionAction; | ||
|
||
public class SocketAccess { |
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 this class be final and abstract then notbody can instantiate it. We also need javadocs on this and all the methods
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.
also explain why it's not in core?
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 can make it final and abstract and add javadocs.
I did not put it in core because then it seems that core would require the SocketPermissions. That is also why I need versions in each plugin.
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.
yeah I can see why I was just asking to put this info on the class so folks see immediately why we duplicate code
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.
Ohhh. Yeah. I'll add docstrings to all of the classes with explanations.
throw new RuntimeException(e); | ||
} | ||
return null; | ||
AccessController.doPrivileged((PrivilegedAction<Void>) () -> { |
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 leave a comment why this is needed in this particular place?
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.
Yes - I can add a comment.
@@ -194,14 +191,14 @@ static Settings getAvailabilityZoneNodeAttributes(Settings settings, String azMe | |||
try { | |||
url = new URL(azMetadataUrl); | |||
logger.debug("obtaining ec2 [placement/availability-zone] from ec2 meta-data url {}", url); | |||
urlConnection = url.openConnection(); |
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 wonder if we can leverage forbidden APIs to restrict the use of openConnection and add a dedicated method that does it with suppressforbidden on it?
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.
shall we spin off anotehr issue for 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 thought that would be good. On #22116 I left a comment a few days ago that maybe we should add another task on that issue to mark relevant APIs as forbidden?
urlConnection.setConnectTimeout(2000); | ||
} catch (IOException e) { | ||
// should not happen, we know the url is not malformed, and openConnection does not actually hit network | ||
throw new UncheckedIOException(e); | ||
} | ||
|
||
try (InputStream in = urlConnection.getInputStream(); | ||
try (InputStream in = SocketAccess.doPrivilegedIOException(urlConnection::getInputStream); |
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.
same here...
* GCE's http client changes access levels. Additionally remote calls need SocketPermissions for 'connect'. | ||
* This class wraps these operations in {@link AccessController#doPrivileged(PrivilegedAction)} blocks. | ||
*/ | ||
public class Access { |
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 we make these classes consistent naming wise etc?
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 specifically name this one differently, because it is used for other permissions than just socket permissions. The GCE plugin requires additional permissions.
// needed because of problems in gce
permission java.lang.RuntimePermission "accessDeclaredMembers";
permission java.lang.RuntimePermission "setFactory";
permission java.lang.reflect.ReflectPermission "suppressAccessChecks";
And some of the usages of this class are unrelated to socket permissions. These usages preexist my PR.
In the other plugins I named the helper classes SocketAccess because that is the only thing I use them for.
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.
ok can you add alls these infos into this class
import java.security.PrivilegedActionException; | ||
import java.security.PrivilegedExceptionAction; | ||
|
||
public class SocketAccess { |
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.
same here javadocs and naming consistency
} | ||
|
||
@FunctionalInterface | ||
public interface VoidOpException { |
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 name this StorageRunnable
?
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
if (blobs.hasNext() == false || deletions.size() == MAX_BATCHING_REQUESTS) { | ||
try { | ||
// Deletions are executed using a batch request | ||
BatchRequest batch = client.batch(); |
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 we sure nothing else in this block needs a privileged block? I'd feel better if we kept the existing wrap
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.
Yeah now that I take another look - I think client.objects().delete
and delete.query
need permissions. I can go back to wrapping the whole block.
import java.security.PrivilegedActionException; | ||
import java.security.PrivilegedExceptionAction; | ||
|
||
public class SocketAccess { |
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.
annoying :) I'd be nice if we could share it somehow
Thanks for the review @s1monw. There are some immediate changes that you pointed out that I can work on implementing. I responded to your comments with some specifics. |
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 a question about forbidden APIs
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 noticed one thing.
private static void checkSpecialPermission() { | ||
SecurityManager sm = System.getSecurityManager(); | ||
if (sm != null) { | ||
sm.checkPermission(new SpecialPermission()); |
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 we can use a singleton instance?
private static void checkSpecialPermission() { | ||
SecurityManager sm = System.getSecurityManager(); | ||
if (sm != null) { | ||
sm.checkPermission(new SpecialPermission()); |
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 we use a singleton instance?
private static void checkSpecialPermission() { | ||
SecurityManager sm = System.getSecurityManager(); | ||
if (sm != null) { | ||
sm.checkPermission(new SpecialPermission()); |
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.
Singleton instance?
private static void checkSpecialPermission() { | ||
SecurityManager sm = System.getSecurityManager(); | ||
if (sm != null) { | ||
sm.checkPermission(new SpecialPermission()); |
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.
One more opportunity to use a singleton instance?
private static void checkSpecialPermission() { | ||
SecurityManager sm = System.getSecurityManager(); | ||
if (sm != null) { | ||
sm.checkPermission(new SpecialPermission()); |
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.
Last one? 😄
That was my bad. I just used field extract in IDEA without thinking about making it a constant. I updated with new commit. |
@jasontedor I made the changes to make the permission a constant and the build is passing. Let me know if you are now okay with me merging 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.
LGTM.
This commit fixes an issue that was missed in elastic#22534. `AWSCredentialsProvider.getCredentials()` appears to potentially open a socket connect. This operation needed to be wrapped in `doPrivileged()`. This should fix issue elastic#23271.
This commit adds a new fixture that emulates a S3 service in order to improve the existing integration tests. This is very similar to what has been made for Google Cloud Storage in elastic#28788, and such tests would have helped a lot to catch bugs like elastic#22534. The AmazonS3Fixture is brittle and only implements the very necessary stuff for the S3 repository to work, but at least it works and can be adapted for specific tests needs.
This commit adds a new fixture that emulates a S3 service in order to improve the existing integration tests. This is very similar to what has been made for Google Cloud Storage in #28788, and such tests would have helped a lot to catch bugs like #22534. The AmazonS3Fixture is brittle and only implements the very necessary stuff for the S3 repository to work, but at least it works and can be adapted for specific tests needs.
This commit adds a new fixture that emulates an Azure Storage service in order to improve the existing integration tests. This is very similar to what has been made for Google Cloud Storage in elastic#28788 and for Amazon S3 in elastic#29296, and it would have helped a lot to catch bugs like elastic#22534.
This is related to #22116. A number of plugins (discovery-azure-classic, discovery-ec2, discovery-gce, repository-azure, repository-gcs, and repository-s3) open socket connections. As
SocketPermissions
are transitioned out of core, these plugins will requireconnect
permission. This pull request wraps operations that require these permissions indoPrivileged
blocks.