EIM on verify: what can it do and what cannot
Below is a high-level discussion of how the Extension Interface Model (EIM) could help mitigate or prevent many of the bugs uncovered in the three “bug study” sets (browser/IDE extensions, database/webserver modules, and hypervisor/container plugins)—and what additional features or details EIM might need in practice, especially if relying on an eBPF-style verification in userspace.
1. Recap: How EIM Helps
EIM’s core strength is fine-grained capability control for extensions. In all three bug sets, a dominant root cause was that plugins/extensions had too much power (e.g., full read/write to critical host APIs, or unconstrained code execution in a single large address space). EIM addresses this by:
- Enumerating Resources and Capabilities
- Instead of letting an extension do “whatever it wants,” we precisely list which host variables, functions, or data structures the extension can access.
-
Example: If a plugin only needs to read a database’s “timestamp” function, EIM’s development-time spec declares that function as a capability—then the deployment-time spec can decide whether a particular extension instance actually gets that function or not.
-
Separating Development-time vs. Deployment-time
- The development-time spec (written by the host’s authors) enumerates all possible resources and extension points in the host.
- The deployment-time spec (defined by the system admin or security team) grants only the subset of capabilities needed by each specific plugin in a real deployment.
-
This separation often blocks the typical “install an extension, it auto-gets all privileges” scenario that caused many of the vulnerabilities in the bug studies.
-
Resource Limits
- EIM supports bounding CPU instructions or memory usage:
instructions<10000
,memory<1MB
, etc. -
If enforced by a runtime that can measure or intercept extension behavior (eBPF-style, or a process sandbox), such resource limits throttle infinite loops or memory leaks that might otherwise bring down the host.
-
Function and Data Constraints
- EIM can attach pre-/post-conditions or argument constraints to capabilities (e.g., “The extension can call
foo()
, but must not pass null pointers,” or “return value must be non-negative”). - This helps mitigate some logic errors or injection-type flaws, because the extension framework can intercept calls that violate constraints.
Overall, EIM can substantially reduce the attack surface by preventing an extension from (1) calling unexpected host APIs, (2) reading/writing uninitialized or privileged memory, or (3) hogging resources. These measures cut off many vectors of exploitation or catastrophic failure.
2. Gaps in the Current EIM Spec
While EIM is already powerful, some of the bugs from the studies highlight areas where we might need more expressiveness or runtime checks than the current EIM draft describes. Below are the most relevant gaps and how to address them.
2.1 Concurrency and Race Conditions
Many real extension bugs involved race conditions or concurrency issues (e.g., the Eclipse PMD plugin deadlock, or Gatekeeper/Kyverno race conditions in Kubernetes). EIM currently allows specifying function/variable access capabilities, but not:
- Thread/locking constraints
- Ordering constraints (e.g., “Extension must run after the host has locked resource X”)
- Atomic or transaction boundaries around extension code
Potential EIM Addition: Let EIM declare concurrency models or “locking capabilities.” For instance:
Then the extension either has or does not have permission to hold certain locks—enforced by the runtime’s lock manager. Alternatively, the host’s concurrency policies might require that certain extension entries are single-threaded. EIM would need to:
- Identify concurrency-critical resources at development time.
- Allow the deployment spec to say, e.g., “This extension can only be called from a single thread,” or “This extension must run under lock X.”
This approach helps reduce or prevent subtle concurrency flaws.
2.2 Complex Data Structures and Partial Field Access
Some vulnerabilities (e.g., certain XSS bugs, or read/write out of bounds in memory) occur when an extension manipulates a large data structure it shouldn’t fully control. EIM’s current approach—read(r)
or write(r)
—is somewhat coarse if r
is a pointer to a big struct or buffer.
Potential EIM Addition: More granular field-level constraints, for instance:
This means an extension can read only the “headers” field of a request, but not the entire request. If your verifying runtime (like an eBPF loader) can track pointer offsets and check that the extension never goes beyond “headers,” you effectively reduce the risk of out-of-bounds or unauthorized data access.
2.3 Protocol or Semantic Constraints
A few examples from the bug sets revolve around logic vulnerabilities—like “this plugin must not forward traffic to an internal admin endpoint unless the user is authenticated.” EIM’s existing constraints can check argument values for a function call, but does not define a protocol-level logic policy (e.g., request-smuggling checks, cross-origin validation).
Potential EIM Addition: EIM could let developers define “semantic constraints” for critical calls—like a rewriting or proxying function. For instance:
Function_Capability(
name = "rewriteUrl",
prototype = (char *url) -> int,
constraints = {
// Pseudocode: no internal IP addresses allowed
"!(url in 127.0.0.0/8 || url in 10.0.0.0/8)",
"must match a certain domain pattern"
}
)
The extension loader or an inlined checker would refuse calls that break these rules. This technique is somewhat advanced—one either needs a domain-specific language to express these rules or a hooking mechanism that checks them at runtime. But it’s exactly how one might block SSRF or request smuggling.
2.4 Handling “User Logic” or Untrusted Scripts
Many plugin frameworks (like browser extensions or IDE plugins) let you embed arbitrary scripts. EIM only enumerates resources and usage constraints at a high level. For memory-safe code or eBPF, that’s feasible—the eBPF verifier can ensure you do not step out of bounds or call disallowed helpers. However, if the plugin is just plain Java or JavaScript code, we still need some sort of sandbox or “verifier” that enforces EIM constraints in practice.
Potential EIM Addition: A standard library or “host runtime” that:
- Intercepts calls to host functions (matching the function capabilities).
- Enforces memory access limitations (in Java, that might be done with a special classloader; in C/C++, that might be an SFI or eBPF JIT approach).
- Checks concurrency constraints or resource usage (like CPU time or memory).
In short: EIM by itself is “policy specification.” We also need a policy enforcement mechanism. If that enforcement uses an “eBPF-style” bytecode check in userspace, then the extension code presumably compiles to eBPF or some bytecode that can be validated. The EIM rules become an input to that validator. Once validated, the extension runs in a restricted environment.
2.5 Observability and Logging
In the bug studies, some critical vulnerabilities (e.g., Falco dropping events, or memory leaks in Adblock Plus’s $rewrite
) were made worse by insufficient logging or monitoring that the plugin was stuck in a loop. EIM doesn’t explicitly define how to log extension behavior or notify administrators if an extension is over resource limits or hits an illegal call.
Potential EIM Addition: “Observer capabilities” that let the host watch the extension’s usage. For example:
onExceedMemory
: an event if the extension crosses memory < 1 MB.onForbiddenCall
: if the extension tries to call a disallowed function.Event_Capability
: could define a structured event feed that logs extension misbehavior.
This helps detect issues early, especially for performance or DoS bugs.
3. Mapping EIM to the Bug Studies
Below are a few concrete examples of how EIM could mitigate some typical bugs from the bug sets:
- Browser Extensions:
- Suppose you have a password manager extension like LastPass. Instead of letting it read any DOM content, EIM’s deployment-time spec might say “this extension can only read from a small set of fields, and can only call an encryption function with certain arguments.” That significantly reduces the chance of credentials leaking to random pages.
-
If the extension tries to open arbitrary iframes or run code in the background, the EIM runtime can block those calls unless the extension is explicitly granted the
openIframe
orspawnBackgroundScript
capabilities. -
IDE Plugins:
- In an IDE plugin that performs code analysis (e.g., SonarLint), EIM can require it to call only certain scanning APIs and read only certain parts of the file system. If it tries to load user credentials or memory from the IDE process, it gets blocked by the capability checks.
-
This also helps with performance: you can set
instructions < 1 billion
so a plugin can’t hog CPU forever. -
Database Extensions:
- For Postgres or MySQL add-ons, EIM would define each “UDF or extension function” as a potential extension entry. The capability list might restrict which core DB functions (e.g.,
SPI_exec
,malloc()
, etc.) the extension can call, and put a memory limit on each call. That stops the extension from corrupting data or hogging memory. -
If the extension wants “read table X, but not table Y,” you could define a partial read capability that only includes certain table handles.
-
Web Server / Modules:
-
The next time Nginx or Apache loads a module, EIM ensures the module can only parse certain request data, or only call the official server API for logging, not raw pointer arithmetic over the server’s memory. Overflows and injection flaws become less likely (though not fully eliminated if the code has internal logic errors).
-
Hypervisor / Container Plugins:
- For something like Docker or Kubernetes, EIM can tie directly into the eBPF-based extension system. The deployment spec would say, “This plugin can call helper BPF functions for networking, but can’t read or write arbitrary kernel memory,” or “This extension has concurrency constraints with no direct spinlocks.”
- That would thwart RCE on the host if a malicious container tries to load a plugin that calls unauthorized kernel helpers or manipulates privileges.
4. Putting It All Together
4.1 How EIM “Solves” or Mitigates the Bug Study Problems
- Least Privilege: If each plugin/extension from the bug sets had been restricted by an EIM policy, then:
- A malicious or buggy extension would not see unauthorized global variables, privileged host functions, or unlimited memory.
- This eliminates entire classes of vulnerabilities where the plugin did something the host never intended (like reading credentials from memory or calling privileged code to bypass security checks).
- Enforced Resource Limits: Many DoS or infinite loop style bugs would be partly mitigated by bounding CPU instructions or memory usage in EIM. The plugin might still fail internally, but it can’t crash the entire system.
- Runtime Checks: If we specify logic constraints (e.g., “URL rewriting can’t target internal subnets”), that would have blocked some SSRF or request-smuggling vulnerabilities in web server modules. Likewise, concurrency constraints might reduce race conditions in certain plugin frameworks.
4.2 What Must Be Added or Clarified
- Concurrency Control: EIM should have a way to specify or limit how the extension uses threads/locks.
- Granular Data Structure Access: Possibly a more advanced “field-level read/write” declaration so that an extension can’t alter fields it shouldn’t.
- Protocol / Logic Constraints: If you want to protect against advanced logic flaws like request smuggling or malicious traffic rewriting, you’ll need a way to describe semantic checks in EIM (or do them in the verifying loader).
- Robust Runtime / Verifier: The host system must have a mechanism to interpret EIM specs and enforce them. An eBPF-like user-space verifier is an excellent approach if your extensions can compile to eBPF or a similar bytecode.
- Observability: Additional EIM declarations or host APIs to track extension misbehavior (like event counters or logs) so that silent bugs don’t remain undetected.
5. Conclusion
EIM, as presented, already addresses many of the root causes observed in the plugin/extension bugs: overly broad privileges, unrestricted memory access, lack of clear resource bounds, etc. By enumerating resources (variables, functions) and restricting them via capabilities, we can prevent entire classes of security and stability failures.
However, to fully tackle the range of real-world bugs (especially concurrency, complex logic checks, or partial data structure access), EIM may need:
- Extended concurrency and data-structure constraints
- More advanced “semantic checking” for sensitive function calls
- A robust “verifier” or sandbox that can interpret and enforce EIM policies at runtime, much like eBPF or RLBox approaches do with safe interposition
In essence, EIM is an ideal policy framework for specifying “who can do what,” while an eBPF-style verifier in userspace is an ideal enforcement mechanism—they complement each other. With a few additions to EIM’s specification (concurrency, deeper structural or protocol constraints), many of the bugs in the three large sets of extension vulnerabilities could be drastically mitigated or outright prevented.