-
Notifications
You must be signed in to change notification settings - Fork 0
fix(API): divide dynamic 2 #14
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
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,88 @@ | ||
| package org.tron.core.services.http; | ||
|
|
||
| import static org.junit.Assert.assertFalse; | ||
| import static org.junit.Assert.assertNotNull; | ||
| import static org.junit.Assert.assertNull; | ||
| import static org.junit.Assert.assertTrue; | ||
|
|
||
| import java.lang.reflect.Field; | ||
| import java.util.Map; | ||
| import org.junit.BeforeClass; | ||
| import org.junit.Test; | ||
| import org.tron.core.services.ratelimiter.adapter.DefaultBaseQqsAdapter; | ||
| import org.tron.core.services.ratelimiter.adapter.GlobalPreemptibleAdapter; | ||
| import org.tron.core.services.ratelimiter.adapter.IPQPSRateLimiterAdapter; | ||
| import org.tron.core.services.ratelimiter.adapter.IRateLimiter; | ||
| import org.tron.core.services.ratelimiter.adapter.QpsRateLimiterAdapter; | ||
|
|
||
| /** | ||
| * Security test: verifies that RateLimiterServlet uses a strict whitelist | ||
| * instead of Class.forName(), preventing arbitrary class loading (RCE) | ||
| * via a tampered config file. | ||
| */ | ||
| public class RateLimiterServletWhitelistTest { | ||
|
|
||
| // Derive names from the classes themselves — stays in sync if classes are renamed. | ||
| private static final String GLOBAL_PREEMPTIBLE = GlobalPreemptibleAdapter.class.getSimpleName(); | ||
| private static final String QPS_RATE_LIMITER = QpsRateLimiterAdapter.class.getSimpleName(); | ||
| private static final String IP_QPS_RATE_LIMITER = IPQPSRateLimiterAdapter.class.getSimpleName(); | ||
| private static final String DEFAULT_BASE_QPS = DefaultBaseQqsAdapter.class.getSimpleName(); | ||
|
|
||
| private static Map<String, Class<? extends IRateLimiter>> allowedAdapters; | ||
|
|
||
| @SuppressWarnings("unchecked") | ||
| @BeforeClass | ||
| public static void loadWhitelist() throws Exception { | ||
| Field f = RateLimiterServlet.class.getDeclaredField("ALLOWED_ADAPTERS"); | ||
| f.setAccessible(true); | ||
| allowedAdapters = (Map<String, Class<? extends IRateLimiter>>) f.get(null); | ||
| } | ||
|
|
||
| // Verifies all 4 legitimate adapters are present and map to the correct classes. | ||
| @Test | ||
| public void testWhitelistContents() { | ||
| assertNotNull(allowedAdapters.get(GLOBAL_PREEMPTIBLE)); | ||
| assertTrue(allowedAdapters.get(GLOBAL_PREEMPTIBLE) | ||
| .isAssignableFrom(GlobalPreemptibleAdapter.class)); | ||
|
|
||
| assertNotNull(allowedAdapters.get(QPS_RATE_LIMITER)); | ||
| assertTrue(allowedAdapters.get(QPS_RATE_LIMITER) | ||
| .isAssignableFrom(QpsRateLimiterAdapter.class)); | ||
|
|
||
| assertNotNull(allowedAdapters.get(IP_QPS_RATE_LIMITER)); | ||
| assertTrue(allowedAdapters.get(IP_QPS_RATE_LIMITER) | ||
| .isAssignableFrom(IPQPSRateLimiterAdapter.class)); | ||
|
|
||
| assertNotNull(allowedAdapters.get(DEFAULT_BASE_QPS)); | ||
| assertTrue(allowedAdapters.get(DEFAULT_BASE_QPS) | ||
| .isAssignableFrom(DefaultBaseQqsAdapter.class)); | ||
|
Comment on lines
+43
to
+58
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧩 Analysis chain🏁 Script executed: find framework -name "RateLimiterServletWhitelistTest.java" -type fRepository: Sunny6889/java-tron Length of output: 151 🏁 Script executed: cat -n framework/src/test/java/org/tron/core/services/http/RateLimiterServletWhitelistTest.javaRepository: Sunny6889/java-tron Length of output: 4556 🏁 Script executed: # Check if the adapter classes exist
find framework -name "GlobalPreemptibleAdapter.class" -o -name "GlobalPreemptibleAdapter.java" | head -20Repository: Sunny6889/java-tron Length of output: 159 🏁 Script executed: # Search for the adapter class definitions
rg "class GlobalPreemptibleAdapter|class QpsRateLimiterAdapter|class IPQPSRateLimiterAdapter|class DefaultBaseQqsAdapter" --type javaRepository: Sunny6889/java-tron Length of output: 703 🏁 Script executed: # Verify the current imports in the test file
head -25 framework/src/test/java/org/tron/core/services/http/RateLimiterServletWhitelistTest.javaRepository: Sunny6889/java-tron Length of output: 1066 Use exact assertions for the whitelist contract. The 🧪 Tighten the assertions+import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertTrue;
@@
- assertNotNull(allowedAdapters.get(GLOBAL_PREEMPTIBLE));
- assertTrue(allowedAdapters.get(GLOBAL_PREEMPTIBLE)
- .isAssignableFrom(GlobalPreemptibleAdapter.class));
+ assertSame(GlobalPreemptibleAdapter.class, allowedAdapters.get(GLOBAL_PREEMPTIBLE));
@@
- assertNotNull(allowedAdapters.get(QPS_RATE_LIMITER));
- assertTrue(allowedAdapters.get(QPS_RATE_LIMITER)
- .isAssignableFrom(QpsRateLimiterAdapter.class));
+ assertSame(QpsRateLimiterAdapter.class, allowedAdapters.get(QPS_RATE_LIMITER));
@@
- assertNotNull(allowedAdapters.get(IP_QPS_RATE_LIMITER));
- assertTrue(allowedAdapters.get(IP_QPS_RATE_LIMITER)
- .isAssignableFrom(IPQPSRateLimiterAdapter.class));
+ assertSame(IPQPSRateLimiterAdapter.class, allowedAdapters.get(IP_QPS_RATE_LIMITER));
@@
- assertNotNull(allowedAdapters.get(DEFAULT_BASE_QPS));
- assertTrue(allowedAdapters.get(DEFAULT_BASE_QPS)
- .isAssignableFrom(DefaultBaseQqsAdapter.class));
+ assertSame(DefaultBaseQqsAdapter.class, allowedAdapters.get(DEFAULT_BASE_QPS));
@@
- assertTrue("Whitelist must contain exactly 4 adapters", allowedAdapters.size() == 4);
+ assertEquals("Whitelist must contain exactly 4 adapters", 4, allowedAdapters.size());🤖 Prompt for AI Agents |
||
| } | ||
|
|
||
| // Verifies that arbitrary / malicious class names are rejected by the whitelist. | ||
| @Test | ||
| public void testInvalidClassNameIsRejected() { | ||
| assertNull(allowedAdapters.get("com.evil.MaliciousAdapter")); | ||
| assertNull(allowedAdapters.get("../../../../evil.Payload")); | ||
| assertNull(allowedAdapters.get(Runtime.class.getName())); | ||
| assertNull(allowedAdapters.get(ProcessBuilder.class.getName())); | ||
| assertNull(allowedAdapters.get("")); | ||
| assertNull(allowedAdapters.get(null)); | ||
| } | ||
|
|
||
| // Verifies the whitelist cannot be modified at runtime (unmodifiable map). | ||
| @Test(expected = UnsupportedOperationException.class) | ||
| public void testWhitelistIsImmutable() { | ||
| allowedAdapters.put("Injected", DefaultBaseQqsAdapter.class); | ||
| } | ||
|
|
||
| // Verifies structural invariants: exact size and all entries implement IRateLimiter. | ||
| @Test | ||
| public void testWhitelistStructure() { | ||
| assertFalse("Whitelist must not be empty", allowedAdapters.isEmpty()); | ||
| assertTrue("Whitelist must contain exactly 4 adapters", allowedAdapters.size() == 4); | ||
| for (Map.Entry<String, Class<? extends IRateLimiter>> entry : allowedAdapters.entrySet()) { | ||
| assertTrue(entry.getKey() + " must implement IRateLimiter", | ||
| IRateLimiter.class.isAssignableFrom(entry.getValue())); | ||
| } | ||
| } | ||
| } | ||
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.
🧩 Analysis chain
🏁 Script executed:
Repository: Sunny6889/java-tron
Length of output: 3476
🏁 Script executed:
Repository: Sunny6889/java-tron
Length of output: 45
🏁 Script executed:
Repository: Sunny6889/java-tron
Length of output: 1022
🏁 Script executed:
Repository: Sunny6889/java-tron
Length of output: 941
🏁 Script executed:
Repository: Sunny6889/java-tron
Length of output: 1127
🏁 Script executed:
Repository: Sunny6889/java-tron
Length of output: 1117
🏁 Script executed:
Repository: Sunny6889/java-tron
Length of output: 1392
🏁 Script executed:
Repository: Sunny6889/java-tron
Length of output: 755
Persisted zero window sizes cause division by zero in ResourceProcessor.
The zero window size persistence at line 308 (
newUsage == 0 ? 0L : newSize) and line 326 (newUsage == 0 ? 0L : newSize2) creates a critical issue. WhenResourceProcessor.increase()retrieves the stored window size and callsdivideCeil(lastUsage * precision, oldWindowSize)at line 78, a persisted zero will causeArithmeticException: / by zerosincedivideCeilperforms direct division without checking the denominator.The available variables (
currentSizeat line 295,currentSize2at line 313) enable the proposed fallback: persist a positive value (e.g.,currentSize > 0 ? currentSize : 1L) when usage is zero, rather than persisting0L.Proposed fix
and
🤖 Prompt for AI Agents