Skip to content

Commit

Permalink
[7.17] Add doPrivileged section in deprecation logger backport(#81819) (
Browse files Browse the repository at this point in the history
#81922)

Scripts using deprecation logger can trigger log files rolling over.
Scripts also run with a very limited permissions and without
doPrivileged section would cause SM exception

closes #81708
backport #81819
  • Loading branch information
pgomulka committed Dec 23, 2021
1 parent 373bd0f commit 7463a18
Show file tree
Hide file tree
Showing 3 changed files with 68 additions and 4 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -168,7 +168,7 @@ public void testConcurrentDeprecationLogger() throws IOException, UserException,
assertLogLine(
deprecationEvents.get(i),
Level.WARN,
"org.elasticsearch.common.logging.DeprecationLogger.logDeprecation",
"org.elasticsearch.common.logging.DeprecationLogger.lambda\\$doPrivilegedLog\\$0",
"This is a maybe logged deprecation message" + i
);
}
Expand Down Expand Up @@ -201,7 +201,7 @@ public void testDeprecatedSettings() throws IOException, UserException {
assertLogLine(
deprecationEvents.get(0),
DeprecationLogger.CRITICAL,
"org.elasticsearch.common.logging.DeprecationLogger.logDeprecation",
"org.elasticsearch.common.logging.DeprecationLogger.lambda\\$doPrivilegedLog\\$0",
"\\[deprecated.foo\\] setting was deprecated in Elasticsearch and will be removed in a future release! "
+ "See the breaking changes documentation for the next major version."
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@
import org.elasticsearch.common.regex.Regex;
import org.elasticsearch.common.settings.Settings;

import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.Collections;
import java.util.List;

Expand Down Expand Up @@ -114,9 +116,15 @@ private DeprecationLogger logDeprecation(Level level, DeprecationCategory catego
String opaqueId = HeaderWarning.getXOpaqueId();
String productOrigin = HeaderWarning.getProductOrigin();
ESLogMessage deprecationMessage = new DeprecatedMessage(category, key, opaqueId, productOrigin, msg, params);
logger.log(level, deprecationMessage);
doPrivilegedLog(level, deprecationMessage);
}
return this;
}

private void doPrivilegedLog(Level level, ESLogMessage deprecationMessage) {
AccessController.doPrivileged((PrivilegedAction<Void>) () -> {
logger.log(level, deprecationMessage);
return null;
});
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,16 +8,35 @@

package org.elasticsearch.common.logging;

import org.apache.logging.log4j.Level;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.core.Logger;
import org.apache.logging.log4j.core.LoggerContext;
import org.apache.logging.log4j.spi.LoggerContextFactory;
import org.elasticsearch.test.ESTestCase;
import org.mockito.Mockito;

import java.security.AccessControlContext;
import java.security.AccessController;
import java.security.Permissions;
import java.security.PrivilegedAction;
import java.security.ProtectionDomain;
import java.util.concurrent.atomic.AtomicBoolean;

import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.is;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;

public class DeprecationLoggerTests extends ESTestCase {

public void testMultipleSlowLoggersUseSingleLog4jLogger() {
LoggerContext context = (LoggerContext) LogManager.getContext(false);
org.apache.logging.log4j.core.LoggerContext context = (org.apache.logging.log4j.core.LoggerContext) LogManager.getContext(false);

DeprecationLogger deprecationLogger = DeprecationLogger.getLogger(DeprecationLoggerTests.class);
int numberOfLoggersBefore = context.getLoggers().size();
Expand All @@ -30,4 +49,41 @@ class LoggerTest {}

assertThat(numberOfLoggersAfter, equalTo(numberOfLoggersBefore + 1));
}

public void testLogPermissions() {
final LoggerContextFactory originalFactory = LogManager.getFactory();
try {
AtomicBoolean supplierCalled = new AtomicBoolean(false);
// mocking the logger used inside DeprecationLogger requires heavy hacking...

Logger mockLogger = mock(Logger.class);
doAnswer(invocationOnMock -> {
supplierCalled.set(true);
createTempDir(); // trigger file permission, like rolling logs would
return null;
}).when(mockLogger).log(eq(Level.WARN), any(ESLogMessage.class));

final LoggerContext context = Mockito.mock(LoggerContext.class);
when(context.getLogger(anyString())).thenReturn(mockLogger);

// "extending" the existing factory to avoid creating new one which
// would result in LoaderUtil.getParent SM permission exception
final LoggerContextFactory spy = Mockito.spy(originalFactory);
Mockito.doReturn(context).when(spy).getContext(any(), any(), any(), anyBoolean(), any(), any());
LogManager.setFactory(spy);

DeprecationLogger deprecationLogger = DeprecationLogger.getLogger("name");

AccessControlContext noPermissionsAcc = new AccessControlContext(
new ProtectionDomain[] { new ProtectionDomain(null, new Permissions()) }
);
AccessController.doPrivileged((PrivilegedAction<Void>) () -> {
deprecationLogger.warn(DeprecationCategory.API, "key", "foo", "bar");
return null;
}, noPermissionsAcc);
assertThat("supplier called", supplierCalled.get(), is(true));
} finally {
LogManager.setFactory(originalFactory);
}
}
}

0 comments on commit 7463a18

Please sign in to comment.