From 33ffdaaae93b37210bb86457434328d5f8c8fade Mon Sep 17 00:00:00 2001 From: Tim Brooks Date: Tue, 20 Feb 2018 12:42:04 -0700 Subject: [PATCH 1/2] Ensure that azure stream has socket privileges This is related to #28662. It wraps the azure repository inputstream in an inputstream that ensures `read` calls have socket permissions. This is because the azure inputstream internally makes service calls. --- .../azure/AzureStorageServiceImpl.java | 25 ++++++++++++++++--- .../repositories/azure/SocketAccess.java | 9 +++++++ 2 files changed, 31 insertions(+), 3 deletions(-) diff --git a/plugins/repository-azure/src/main/java/org/elasticsearch/repositories/azure/AzureStorageServiceImpl.java b/plugins/repository-azure/src/main/java/org/elasticsearch/repositories/azure/AzureStorageServiceImpl.java index 2b8992386eb2d..5746e3eda3c88 100644 --- a/plugins/repository-azure/src/main/java/org/elasticsearch/repositories/azure/AzureStorageServiceImpl.java +++ b/plugins/repository-azure/src/main/java/org/elasticsearch/repositories/azure/AzureStorageServiceImpl.java @@ -25,6 +25,7 @@ import com.microsoft.azure.storage.RetryExponentialRetry; import com.microsoft.azure.storage.RetryPolicy; import com.microsoft.azure.storage.StorageException; +import com.microsoft.azure.storage.blob.BlobInputStream; import com.microsoft.azure.storage.blob.BlobListingDetails; import com.microsoft.azure.storage.blob.BlobProperties; import com.microsoft.azure.storage.blob.CloudBlobClient; @@ -41,6 +42,7 @@ import org.elasticsearch.common.settings.Settings; import org.elasticsearch.repositories.RepositoryException; +import java.io.IOException; import java.io.InputStream; import java.net.URI; import java.net.URISyntaxException; @@ -249,12 +251,29 @@ public void deleteBlob(String account, LocationMode mode, String container, Stri } @Override - public InputStream getInputStream(String account, LocationMode mode, String container, String blob) - throws URISyntaxException, StorageException { + public InputStream getInputStream(String account, LocationMode mode, String container, String blob) throws URISyntaxException, + StorageException { logger.trace("reading container [{}], blob [{}]", container, blob); CloudBlobClient client = this.getSelectedClient(account, mode); CloudBlockBlob blockBlobReference = client.getContainerReference(container).getBlockBlobReference(blob); - return SocketAccess.doPrivilegedException(() -> blockBlobReference.openInputStream(null, null, generateOperationContext(account))); + BlobInputStream is = SocketAccess.doPrivilegedException(() -> + blockBlobReference.openInputStream(null, null, generateOperationContext(account))); + return new InputStream() { + @Override + public int read() throws IOException { + return SocketAccess.doPrivilegedIOException(is::read); + } + + @Override + public int read(byte[] b) throws IOException { + return SocketAccess.doPrivilegedIOException(() -> is.read(b)); + } + + @Override + public int read(byte[] b, int off, int len) throws IOException { + return SocketAccess.doPrivilegedIOException(() -> is.read(b, off, len)); + } + }; } @Override diff --git a/plugins/repository-azure/src/main/java/org/elasticsearch/repositories/azure/SocketAccess.java b/plugins/repository-azure/src/main/java/org/elasticsearch/repositories/azure/SocketAccess.java index c4db24a97e958..da8b85430067c 100644 --- a/plugins/repository-azure/src/main/java/org/elasticsearch/repositories/azure/SocketAccess.java +++ b/plugins/repository-azure/src/main/java/org/elasticsearch/repositories/azure/SocketAccess.java @@ -39,6 +39,15 @@ public final class SocketAccess { private SocketAccess() {} + public static T doPrivilegedIOException(PrivilegedExceptionAction operation) throws IOException { + SpecialPermission.check(); + try { + return AccessController.doPrivileged(operation); + } catch (PrivilegedActionException e) { + throw (IOException) e.getCause(); + } + } + public static T doPrivilegedException(PrivilegedExceptionAction operation) throws StorageException, URISyntaxException { SpecialPermission.check(); try { From 539025162cefab5547c87a1f3c76dfa66d6bf50e Mon Sep 17 00:00:00 2001 From: Tim Brooks Date: Tue, 20 Feb 2018 16:03:36 -0700 Subject: [PATCH 2/2] Add permissions to test --- .../azure/AzureStorageService.java | 19 ++++++++++++ .../azure/AzureStorageServiceImpl.java | 18 +----------- .../azure/AzureStorageServiceMock.java | 29 ++++++++++++++++++- 3 files changed, 48 insertions(+), 18 deletions(-) diff --git a/plugins/repository-azure/src/main/java/org/elasticsearch/repositories/azure/AzureStorageService.java b/plugins/repository-azure/src/main/java/org/elasticsearch/repositories/azure/AzureStorageService.java index 78eee24a34de5..3337c07e6eece 100644 --- a/plugins/repository-azure/src/main/java/org/elasticsearch/repositories/azure/AzureStorageService.java +++ b/plugins/repository-azure/src/main/java/org/elasticsearch/repositories/azure/AzureStorageService.java @@ -62,4 +62,23 @@ void moveBlob(String account, LocationMode mode, String container, String source void writeBlob(String account, LocationMode mode, String container, String blobName, InputStream inputStream, long blobSize) throws URISyntaxException, StorageException; + + static InputStream giveSocketPermissionsToStream(InputStream stream) { + return new InputStream() { + @Override + public int read() throws IOException { + return SocketAccess.doPrivilegedIOException(stream::read); + } + + @Override + public int read(byte[] b) throws IOException { + return SocketAccess.doPrivilegedIOException(() -> stream.read(b)); + } + + @Override + public int read(byte[] b, int off, int len) throws IOException { + return SocketAccess.doPrivilegedIOException(() -> stream.read(b, off, len)); + } + }; + } } diff --git a/plugins/repository-azure/src/main/java/org/elasticsearch/repositories/azure/AzureStorageServiceImpl.java b/plugins/repository-azure/src/main/java/org/elasticsearch/repositories/azure/AzureStorageServiceImpl.java index 5746e3eda3c88..f21dbdfd269f4 100644 --- a/plugins/repository-azure/src/main/java/org/elasticsearch/repositories/azure/AzureStorageServiceImpl.java +++ b/plugins/repository-azure/src/main/java/org/elasticsearch/repositories/azure/AzureStorageServiceImpl.java @@ -42,7 +42,6 @@ import org.elasticsearch.common.settings.Settings; import org.elasticsearch.repositories.RepositoryException; -import java.io.IOException; import java.io.InputStream; import java.net.URI; import java.net.URISyntaxException; @@ -258,22 +257,7 @@ public InputStream getInputStream(String account, LocationMode mode, String cont CloudBlockBlob blockBlobReference = client.getContainerReference(container).getBlockBlobReference(blob); BlobInputStream is = SocketAccess.doPrivilegedException(() -> blockBlobReference.openInputStream(null, null, generateOperationContext(account))); - return new InputStream() { - @Override - public int read() throws IOException { - return SocketAccess.doPrivilegedIOException(is::read); - } - - @Override - public int read(byte[] b) throws IOException { - return SocketAccess.doPrivilegedIOException(() -> is.read(b)); - } - - @Override - public int read(byte[] b, int off, int len) throws IOException { - return SocketAccess.doPrivilegedIOException(() -> is.read(b, off, len)); - } - }; + return AzureStorageService.giveSocketPermissionsToStream(is); } @Override diff --git a/plugins/repository-azure/src/test/java/org/elasticsearch/repositories/azure/AzureStorageServiceMock.java b/plugins/repository-azure/src/test/java/org/elasticsearch/repositories/azure/AzureStorageServiceMock.java index 6dfe2db628013..68b84594d62ca 100644 --- a/plugins/repository-azure/src/test/java/org/elasticsearch/repositories/azure/AzureStorageServiceMock.java +++ b/plugins/repository-azure/src/test/java/org/elasticsearch/repositories/azure/AzureStorageServiceMock.java @@ -32,8 +32,10 @@ import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; +import java.net.SocketPermission; import java.net.URISyntaxException; import java.nio.file.NoSuchFileException; +import java.security.AccessController; import java.util.Locale; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; @@ -81,7 +83,7 @@ public InputStream getInputStream(String account, LocationMode mode, String cont if (!blobExists(account, mode, container, blob)) { throw new NoSuchFileException("missing blob [" + blob + "]"); } - return new ByteArrayInputStream(blobs.get(blob).toByteArray()); + return AzureStorageService.giveSocketPermissionsToStream(new PermissionRequiringInputStream(blobs.get(blob).toByteArray())); } @Override @@ -170,4 +172,29 @@ public static boolean endsWithIgnoreCase(String str, String suffix) { String lcPrefix = suffix.toLowerCase(Locale.ROOT); return lcStr.equals(lcPrefix); } + + private static class PermissionRequiringInputStream extends ByteArrayInputStream { + + private PermissionRequiringInputStream(byte[] buf) { + super(buf); + } + + @Override + public synchronized int read() { + AccessController.checkPermission(new SocketPermission("*", "connect")); + return super.read(); + } + + @Override + public int read(byte[] b) throws IOException { + AccessController.checkPermission(new SocketPermission("*", "connect")); + return super.read(b); + } + + @Override + public synchronized int read(byte[] b, int off, int len) { + AccessController.checkPermission(new SocketPermission("*", "connect")); + return super.read(b, off, len); + } + } }