Skip to content

Commit ac82678

Browse files
committed
Add doPrivileged section in deprecation logger
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 elastic#81708
1 parent b1db7b6 commit ac82678

File tree

2 files changed

+68
-2
lines changed

2 files changed

+68
-2
lines changed

server/src/main/java/org/elasticsearch/common/logging/DeprecationLogger.java

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,9 @@
1212
import org.apache.logging.log4j.LogManager;
1313
import org.apache.logging.log4j.Logger;
1414

15+
import java.security.AccessController;
16+
import java.security.PrivilegedAction;
17+
1518
/**
1619
* A logger that logs deprecation notices. Logger should be initialized with a class or name which will be used
1720
* for deprecation logger. For instance <code>DeprecationLogger.getLogger("org.elasticsearch.test.SomeClass")</code> will
@@ -97,10 +100,17 @@ private DeprecationLogger logDeprecation(Level level, DeprecationCategory catego
97100
String opaqueId = HeaderWarning.getXOpaqueId();
98101
String productOrigin = HeaderWarning.getProductOrigin();
99102
ESLogMessage deprecationMessage = DeprecatedMessage.of(category, key, opaqueId, productOrigin, msg, params);
100-
logger.log(level, deprecationMessage);
103+
doPrivilegedLog(level, deprecationMessage);
101104
return this;
102105
}
103106

107+
private void doPrivilegedLog(Level level, ESLogMessage deprecationMessage) {
108+
AccessController.doPrivileged((PrivilegedAction<Void>) () -> {
109+
logger.log(level, deprecationMessage);
110+
return null;
111+
});
112+
}
113+
104114
/**
105115
* Used for handling previous version RestApiCompatible logic.
106116
* Logs a message at the {@link DeprecationLogger#CRITICAL} level

server/src/test/java/org/elasticsearch/common/logging/DeprecationLoggerTests.java

Lines changed: 57 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,16 +8,35 @@
88

99
package org.elasticsearch.common.logging;
1010

11+
import org.apache.logging.log4j.Level;
1112
import org.apache.logging.log4j.LogManager;
13+
import org.apache.logging.log4j.core.Logger;
1214
import org.apache.logging.log4j.core.LoggerContext;
15+
import org.apache.logging.log4j.spi.LoggerContextFactory;
1316
import org.elasticsearch.test.ESTestCase;
17+
import org.mockito.Mockito;
18+
19+
import java.security.AccessControlContext;
20+
import java.security.AccessController;
21+
import java.security.Permissions;
22+
import java.security.PrivilegedAction;
23+
import java.security.ProtectionDomain;
24+
import java.util.concurrent.atomic.AtomicBoolean;
1425

1526
import static org.hamcrest.Matchers.equalTo;
27+
import static org.hamcrest.Matchers.is;
28+
import static org.mockito.ArgumentMatchers.any;
29+
import static org.mockito.ArgumentMatchers.anyBoolean;
30+
import static org.mockito.ArgumentMatchers.anyString;
31+
import static org.mockito.ArgumentMatchers.eq;
32+
import static org.mockito.Mockito.doAnswer;
33+
import static org.mockito.Mockito.mock;
34+
import static org.mockito.Mockito.when;
1635

1736
public class DeprecationLoggerTests extends ESTestCase {
1837

1938
public void testMultipleSlowLoggersUseSingleLog4jLogger() {
20-
LoggerContext context = (LoggerContext) LogManager.getContext(false);
39+
org.apache.logging.log4j.core.LoggerContext context = (org.apache.logging.log4j.core.LoggerContext) LogManager.getContext(false);
2140

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

3150
assertThat(numberOfLoggersAfter, equalTo(numberOfLoggersBefore + 1));
3251
}
52+
53+
public void testLogPermissions() {
54+
final LoggerContextFactory originalFactory = LogManager.getFactory();
55+
try {
56+
AtomicBoolean supplierCalled = new AtomicBoolean(false);
57+
// mocking the logger used inside DeprecationLogger requires heavy hacking...
58+
59+
Logger mockLogger = mock(Logger.class);
60+
doAnswer(invocationOnMock -> {
61+
supplierCalled.set(true);
62+
createTempDir(); // trigger file permission, like rolling logs would
63+
return null;
64+
}).when(mockLogger).log(eq(Level.WARN), any(ESLogMessage.class));
65+
66+
final LoggerContext context = Mockito.mock(LoggerContext.class);
67+
when(context.getLogger(anyString())).thenReturn(mockLogger);
68+
69+
// "extending" the existing factory to avoid creating new one which
70+
// would result in LoaderUtil.getParent SM permission exception
71+
final LoggerContextFactory spy = Mockito.spy(originalFactory);
72+
Mockito.doReturn(context).when(spy).getContext(any(), any(), any(), anyBoolean(), any(), any());
73+
LogManager.setFactory(spy);
74+
75+
DeprecationLogger deprecationLogger = DeprecationLogger.getLogger("name");
76+
77+
AccessControlContext noPermissionsAcc = new AccessControlContext(
78+
new ProtectionDomain[] { new ProtectionDomain(null, new Permissions()) }
79+
);
80+
AccessController.doPrivileged((PrivilegedAction<Void>) () -> {
81+
deprecationLogger.warn(DeprecationCategory.API, "key", "foo", "bar");
82+
return null;
83+
}, noPermissionsAcc);
84+
assertThat("supplier called", supplierCalled.get(), is(true));
85+
} finally {
86+
LogManager.setFactory(originalFactory);
87+
}
88+
}
3389
}

0 commit comments

Comments
 (0)