-
Notifications
You must be signed in to change notification settings - Fork 874
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
Replacing SecurityManager with a tracking agent #3386
base: master
Are you sure you want to change the base?
Conversation
this is pretty cool! |
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.
Magnificent work.
I'd prefer if the code was packaged as NetBeans module for ease of tooling as well as packaging and deploying. With proper Javadoc it could even be used as a great standalone library.
Inviting @sdedic as a reviewer. I'd say Sváťa is long time NetBeans expert when it comes to bytecode patching.
@@ -192,7 +192,7 @@ fi | |||
# rename old heap dump to .old | |||
mv "${userdir}/var/log/heapdump.hprof" "${userdir}/var/log/heapdump.hprof.old" > /dev/null 2>&1 | |||
|
|||
jargs_without_clusters="$jargs -Djava.security.manager=allow" | |||
jargs_without_clusters="$jargs -Djava.security.manager=allow -javaagent:${plathome}/core/tracking-agent.jar -Xbootclasspath/a:${plathome}/core/tracking-hooks.jar" |
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.
By default all JARs in core
directory are added to fixed modules classpath. Does this mean we have to tracking-agent.jar
used three times?
- put on bootclasspath
- used as javaagent
- added on fixed module classpath
@@ -558,27 +499,17 @@ meth public abstract void flushCaches(java.io.DataOutputStream) throws java.io.I | |||
|
|||
CLSS public org.netbeans.TopSecurityManager |
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.
Keeping the TopSecurityManager
class and replacing its superclass is one option. I'd like to ask @sdedic for his opinion: there is a support for patching classes and even for changing superclass - possibly we could use it here? If we want to be really compatible? Do we want to?
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.
Given this is a friend API, I don't see such a strong need to keep compatibility, esp. in an aspect that will cease to work at some point.
@@ -26,3 +26,5 @@ test.qa-functional.cp.extra=${openide.nodes.dir}/modules/org-openide-nodes.jar:\ | |||
test.config.stable.includes=**/hgStableTest.class | |||
# #178009 | |||
disable.qa-functional.tests=true | |||
|
|||
test.unit.cp.extra=${nb_all}/platform/o.n.bootstrap/netbeans-tracking-agent/tracking-hooks/dist/tracking-hooks.jar |
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.
Rather than using test.unit.cp.extra
I'd prefer making tracing-hooks
real module of the platform. Then we can:
- have test/regular dependencies when using it
- packaging into NBM & Maven repository is straighforward
Is there any downside of having the functionality as a NetBeans module?
@@ -88,7 +89,7 @@ | |||
private static final Logger LOG = Logger.getLogger(Install.class.getName()); | |||
|
|||
public @Override void run() { | |||
TopSecurityManager.register(SecMan.DEFAULT); | |||
TrackingHooks.register(SecMan.DEFAULT, 100, TrackingHooks.HOOK_EXIT, TrackingHooks.HOOK_NEW_AWT_WINDOW); |
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.
Would it be possible to have declarative registration of the TracingHooks
? E.g. Lookup.getDefault()
or ServiceLoader.load
instead of register
method?
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.
Seems fairly complex, as there are uses that actively use the pre-existing register/unregister mechanism in TopSecurityManager
:
TopSecurityManager.register(SecMan.DEFAULT); |
TopSecurityManager.unregister(SecMan.DEFAULT); |
It is not clear to me how to replace that with a Lookup-based registration. But if you can provide a patch to resolve all existing uses of TopSecurityManager.register/unregister
, then we can switch to a Lookup-based registration.
File wd = getWorkDir(); | ||
File classes = new File(wd, "classes"); | ||
classes.mkdirs(); | ||
CompilationTask compilation = ToolProvider.getSystemJavaCompiler().getTask(null, null, null, Arrays.asList("-classpath", CloseTest.class.getProtectionDomain().getCodeSource().getLocation().getPath(), "-d", classes.getAbsolutePath()), null, Arrays.asList(new SimpleJavaFileObject(new URI("mem://Test.java"), Kind.SOURCE) { |
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.
What a test!
platform/o.n.bootstrap/build.xml
Outdated
@@ -38,4 +40,13 @@ | |||
<compilerarg line="${javac.compilerargs}"/> | |||
</javac> | |||
</target> | |||
<target name="-build-hooks"> |
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.
I'd prefer to put the tracing agent/hooks into its own module.
@@ -0,0 +1,1789 @@ | |||
<?xml version="1.0" encoding="UTF-8"?> |
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.
Avoiding old Ant projects in NetBeans code base would make me happier.
additionalConstantPool.write(data); | ||
} | ||
|
||
int maxStack = readShort(classfileBuffer, pp); pp += 2; |
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.
Patching classfile manually by hand! @sdedic has already introduced asm.jar
into the platform. It'd be good to consider some synergy among this and his code.
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.
On one hand, it would be easier to use ASM. On the other hand, ASM cannot handle new classfiles - we could workaround that by downgrading the versions of the classfiles sent to ASM; it would also mean to place ASM into the agent path, or doing some trampoline from the agent to a normal module. I guess I'd try with the handcoded bytecode patcher, and we'll see what are the experiences with that.
|
||
protected void checkFileWrite(String path) {} | ||
protected void checkFileRead(String path) {} | ||
protected void checkDelete(String path) {} |
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.
This class is mixing API and SPI. Wouldn't it be cleaner to separate the two concepts into own files?
nbbuild/templates/common.xml
Outdated
<available file="${nbplatform.active.dir}/platform/core" type="dir" /> | ||
</condition> | ||
<property name="test.tracking.agent.dir" location="${o.n.bootstrap.dir}/core/" /> | ||
<property name="test.tracking.agent.args" value="-javaagent:${test.tracking.agent.dir}/tracking-agent.jar -Xbootclasspath/a:${test.tracking.agent.dir}/tracking-hooks.jar"/> |
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.
Having to manually modify -Xbootclasspath
is annoying. Can't agent modify classpath programatically? There are methods like appendToBootstrap....
I wonder if there are any further comments on this. It might be reasonable to try to avoid too much dependency on the SecurityManager. |
Given that we are early in the NB16 cycle, now would be a good time to merge this if ready. |
@@ -232,25 +232,27 @@ public void testAccessClassPathDefinedAutoload() { | |||
public void testModulesForCL() throws Exception { | |||
Set<String> s = NbModuleSuite.S.findEnabledModules(ClassLoader.getSystemClassLoader()); | |||
s.remove("org.netbeans.modules.nbjunit"); | |||
assertEquals("Four modules left: " + s, 5, s.size()); | |||
assertEquals("Four modules left: " + s, 6, s.size()); |
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.
four > six ?
@@ -88,7 +88,7 @@ public class Install implements Runnable { | |||
private static final Logger LOG = Logger.getLogger(Install.class.getName()); | |||
|
|||
public @Override void run() { | |||
TopSecurityManager.register(SecMan.DEFAULT); | |||
TrackingHooks.register(SecMan.DEFAULT, 100, TrackingHooks.Hooks.EXIT, Hooks.NEW_AWT_WINDOW); |
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.
Nitpick: TrackingHooks.
redundant.
# KIND, either express or implied. See the License for the | ||
# specific language governing permissions and limitations | ||
# under the License. | ||
javac.source=1.8 |
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.
autoload ?
for (Iterator<HookDescription> it = delegates.iterator(); it.hasNext();) { | ||
HookDescription hd = it.next(); | ||
if (hd.hooks == toRemove) { | ||
it.remove(); |
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.
stop after first removed ?
return classfileBuffer; | ||
} | ||
try { | ||
List<MethodEnhancement> thisClassEnhancements = toInject.stream().filter(me -> {/*System.err.println("className=" + className); */return className.equals(me.className);}).collect(Collectors.toList()); |
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.
Wouldn't it be better to organize toInject
as a Map keyed by FQN ? It would allow faster lookup here. Also not sure about effectivness of the stream filter approach for that small number of items.
constantPool.add(null); | ||
break; | ||
default: | ||
System.err.println("unknown constant pool tag: " + tag); |
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.
Use Logger.
System.arraycopy(classfileBuffer, lastCopySource, newBuffer, lastCopyDest, len); lastCopySource += len; lastCopyDest += len; | ||
return newBuffer; | ||
} catch (Throwable t) { | ||
t.printStackTrace(); |
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.
Use logger; it is really useful to catch all Throwable
s ?
Class<?> stackWalker = Class.forName("java.lang.StackWalker"); | ||
Class<?> stackWalkerOption = Class.forName("java.lang.StackWalker$Option"); | ||
Class<?> stackWalkerStackFrame = Class.forName("java.lang.StackWalker$StackFrame"); | ||
Method getInstance = stackWalker.getDeclaredMethod("getInstance", stackWalkerOption); |
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.
Perhaps this reflective lookups could be done just once ?
@@ -67,9 +67,6 @@ public static void advancePolicy() { | |||
if (!Boolean.getBoolean("TopSecurityManager.disable")) { | |||
// set security manager | |||
TopSecurityManager.install(); | |||
if (CLIOptions.isGui()) { | |||
TopSecurityManager.makeSwingUseSpecialClipboard(Lookup.getDefault().lookup(ExClipboard.class)); |
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.
What was this supposed to do ?
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.
I believe this was part of a workaround for JDK-4818143. That bug is marked as fixed in JDK 6. So, it seems that keeping the workaround is probably not useful anymore (and, in case the problem would not be actually fixed, this is a way to find out).
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.
Doesn't that also stop the system clipboard being an instance of ExClipboard? If so, seem a bunch of places that expect it to be one.
all green. excellent! |
JEP 451: Prepare to Disallow the Dynamic Loading of Agents It might be better to load the agent using JVM flags on startup (instead of dynamically), since there are probably good reasons JEPs like that exist. |
@mbien isn't it already doing this - https://github.com/apache/netbeans/pull/3386/files#diff-d4b605d5fdbc82d1afa51dc1d6c3ce44516cf46c5e2ac0c79a98118bdcefb896R195 Or are there other uses in there? I assume we'll need a Windows launcher update too? Wish that could be a script too! |
This is a prototype of an attempt to replace the deprecated SecurityManager with a custom agent-based hooks.
What functionality is kept:
-preventing inadvertent System.exit
-tracking file I/O (probably the most complex part, might be missing some hooks)
-checking for deprecated system property access
-checking calls to setAccessible to open Unsafe (this didn't work on JDK 8+, but can be fixed)
-checking/preventing calls to System.setSecurityManager. Possibly no longer that critical, as it is not possible to disable the hooks using this method.
-tracking new Window creation (used by internal execution)
What functionality is not kept:
-
checkConnect
for connecting over network. This didn't seem to be actually used, as the original code was:But
checkPermission
seems to always(?) pass, so the check was never performed-
checkLogger
, which was disabled anyway-tweaks related to installation of a custom Swing clipboard - these appear to exists for JDK-4818143, which is marked as fixed, so presumably not needed anymore.
When looking at the patch,
TrackingAgent
is the agent class that does various transformations to install hooks,TrackingHooks
are the callback,TopSecurityManager
(o.n.bootstrap
),FileChangedManager
(masterfs
),SecMan
(core.execution
) are the actual uses of the hooks.