Skip to content

Chapter 8: JVM #10

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

Merged
merged 65 commits into from
Jun 13, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
65 commits
Select commit Hold shift + click to select a range
e42d588
Add a Makefile git cloning the FBEE into examples/jvm/src
seeker89 May 31, 2020
d74afc5
Add the jvm target to the main target of the repo
seeker89 May 31, 2020
4590d88
New lines
seeker89 May 31, 2020
735d027
Install jdk 8
seeker89 Jun 2, 2020
f9cc5f3
Add building the jar for FizzBuzzEnterpriseEdition
seeker89 Jun 2, 2020
a431c27
Use the distribution
seeker89 Jun 2, 2020
0d4c8bd
Add make run
seeker89 Jun 2, 2020
490cf4b
And dont' forget to run the dependency
seeker89 Jun 2, 2020
8610910
Revert "And dont' forget to run the dependency"
seeker89 Jun 2, 2020
56e55d9
Add make run2 target
seeker89 Jun 2, 2020
30cc619
Add a wrapper script for fbee
seeker89 Jun 2, 2020
c25479e
Add auto-login for the chaos user
seeker89 Jun 3, 2020
2b229d8
Add a basic example of how to compile, run and see the bytecode of a …
seeker89 Jun 3, 2020
8b520f4
Fix path
seeker89 Jun 3, 2020
e4a26f5
FIx the path
seeker89 Jun 3, 2020
d2e87f2
Add example2 throwing an IOException
seeker89 Jun 3, 2020
3313a0e
Obligatory hello chaos notion
seeker89 Jun 4, 2020
6e994c4
Add a very simple agent1.jar
seeker89 Jun 5, 2020
eb89e52
The ClassFIleTransformer needs to be a public class
seeker89 Jun 5, 2020
b343636
Public class
seeker89 Jun 5, 2020
2795d8e
Missing imports
seeker89 Jun 5, 2020
64f9270
Fix the import
seeker89 Jun 5, 2020
eebe9c1
Missing import
seeker89 Jun 5, 2020
21bc734
G I can't type
seeker89 Jun 5, 2020
9894c08
add make example1-agent
seeker89 Jun 5, 2020
57d41d9
Specify the manifest file
seeker89 Jun 5, 2020
6af29f6
No public classes
seeker89 Jun 5, 2020
b202e3c
Remove unused attributes from the manifest
seeker89 Jun 5, 2020
b1d5c44
Add another agent, that we'll use to inject some code
seeker89 Jun 5, 2020
1656f34
Add make agent2.jar
seeker89 Jun 5, 2020
d2763a0
Make agent1.jar depend on its manifest
seeker89 Jun 5, 2020
ad35c9d
Minimal manifest
seeker89 Jun 5, 2020
513fcd0
Find the target class in the fizzbuzz enterprise
seeker89 Jun 9, 2020
25f3427
Make it agent2
seeker89 Jun 9, 2020
e2df6cb
Fix the Makefile
seeker89 Jun 9, 2020
55d792b
Fix building the jar
seeker89 Jun 9, 2020
c2dbb09
Update example2 to call static method
seeker89 Jun 9, 2020
30b1bc0
Attempt to inject a static method invocation
seeker89 Jun 9, 2020
f5680fe
Allow for using jdk.internal
seeker89 Jun 9, 2020
553ec6e
Missing imports
seeker89 Jun 9, 2020
4e4d43c
Deprecated
seeker89 Jun 9, 2020
2624aba
Split the line in two
seeker89 Jun 9, 2020
4c50e66
:trollface:
seeker89 Jun 9, 2020
ad0c551
Print a message when the overwritting method is in use
seeker89 Jun 9, 2020
018d618
Add some nicer messages on instrumentation
seeker89 Jun 9, 2020
b269788
Typo
seeker89 Jun 9, 2020
079f5ca
Return the modified method
seeker89 Jun 9, 2020
dee132c
Use the right method name
seeker89 Jun 9, 2020
494568a
Make the class public
seeker89 Jun 9, 2020
fec56b6
No return value
seeker89 Jun 9, 2020
fab1507
Make the code a little bit more compact
seeker89 Jun 9, 2020
cdcd94f
Print the chaos stuff to stderr
seeker89 Jun 9, 2020
4b1e2db
COmpact
seeker89 Jun 9, 2020
2e8718f
Shorten the line
seeker89 Jun 10, 2020
2cfe098
Delete wrapper.sh
seeker89 Jun 10, 2020
0b653e3
Merge branch 'master' into jvm
seeker89 Jun 11, 2020
71f42cb
Add make byteman-download-4.0.11
seeker89 Jun 11, 2020
3e4ba32
Add a byteman example
seeker89 Jun 11, 2020
bb094f0
Add a make run6 target to run with byteman
seeker89 Jun 11, 2020
04f6749
Fully qualified name of the class
seeker89 Jun 11, 2020
f47e20d
Fix the format of the byteman experiment
seeker89 Jun 11, 2020
a23baec
Add make byte-monkey
seeker89 Jun 11, 2020
16590eb
It's a jar already
seeker89 Jun 11, 2020
d0e798c
Add make run7 with bytemonkey
seeker89 Jun 11, 2020
06536c1
Do only 50% of calls, and only to the output method
seeker89 Jun 11, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
all: killer-whiles who-you-gonna-call
all: killer-whiles who-you-gonna-call jvm

killer-whiles:
(cd examples/killer-whiles && make)
Expand All @@ -7,6 +7,9 @@ who-you-gonna-call:
(cd examples/who-you-gonna-call && make)
(cd examples/who-you-gonna-call/src && make gen && make)

jvm:
(cd examples/jvm && make)

clean:
rm -rf vm/vm.zip vm/parts.sha256 vm/chaos-engineering-VM*

Expand Down
75 changes: 75 additions & 0 deletions examples/jvm/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
CFLAGS=-O0

all: FizzBuzzEnterpriseEdition/bin/FizzBuzzEnterpriseEdition byteman-download-4.0.11 byte-monkey.jar

src:
git clone https://github.com/EnterpriseQualityCoding/FizzBuzzEnterpriseEdition.git src

byteman-download-4.0.11:
wget https://downloads.jboss.org/byteman/4.0.11/byteman-download-4.0.11-bin.zip
unzip byteman-download-4.0.11-bin.zip
rm byteman-download-4.0.11-bin.zip

byte-monkey.jar:
wget https://github.com/mrwilson/byte-monkey/releases/download/1.0.0/byte-monkey.jar

FizzBuzzEnterpriseEdition/bin/FizzBuzzEnterpriseEdition: src
(cd src && ./gradlew assemble && ./gradlew build)
unzip src/build/distributions/FizzBuzzEnterpriseEdition.zip

run:
./FizzBuzzEnterpriseEdition/bin/FizzBuzzEnterpriseEdition

run2:
java -classpath "./FizzBuzzEnterpriseEdition/lib/*" com.seriouscompany.business.java.fizzbuzz.packagenamingpackage.impl.Main

run3:
javap -classpath "./FizzBuzzEnterpriseEdition/lib/*" -c com.seriouscompany.business.java.fizzbuzz.packagenamingpackage.impl.Main

run4:
java -javaagent:./agent1.jar -classpath "./FizzBuzzEnterpriseEdition/lib/*" com.seriouscompany.business.java.fizzbuzz.packagenamingpackage.impl.Main

run5:
java -javaagent:./agent2.jar -classpath "./FizzBuzzEnterpriseEdition/lib/*" com.seriouscompany.business.java.fizzbuzz.packagenamingpackage.impl.Main

run6:
java \
-javaagent:./byteman-download-4.0.11/lib/byteman.jar=script:throw.btm \
-classpath "./FizzBuzzEnterpriseEdition/lib/*" \
com.seriouscompany.business.java.fizzbuzz.packagenamingpackage.impl.Main

run7:
java \
-javaagent:byte-monkey.jar=mode:fault,rate:0.5,filter:com/seriouscompany/business/java/fizzbuzz/packagenamingpackage/impl/strategies/SystemOutFizzBuzzOutputStrategy/output \
-classpath "./FizzBuzzEnterpriseEdition/lib/*" \
com.seriouscompany.business.java.fizzbuzz.packagenamingpackage.impl.Main



example1-compile:
javac ./org/my/example1.java
example1-run:
java org.my.Example1
example1-bytecode:
javap -c org.my.Example1
example1-agent:
java -javaagent:./agent1.jar org.my.Example1

example2-compile:
javac ./org/my/example2.java
example2-run:
java org.my.Example2
example2-bytecode:
javap -c org.my.Example2

.PHONY: run run2 run3 example1-compile example1-run example1-bytecode example2-compile example2-run example2-bytecode

agent1.jar: org/agent/Agent.java org/agent/ClassPrinter.java org/agent/manifest.mf
javac org/agent/Agent.java
javac org/agent/ClassPrinter.java
jar vcmf org/agent/manifest.mf agent1.jar org/agent

agent2.jar: org/agent2/Agent.java org/agent2/ClassInjector.java org/agent2/manifest.mf
javac -XDignore.symbol.file org/agent2/Agent.java
javac -XDignore.symbol.file org/agent2/ClassInjector.java
jar vcmf org/agent2/manifest.mf agent2.jar org/agent2
10 changes: 10 additions & 0 deletions examples/jvm/org/agent/Agent.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package org.agent;

import java.lang.instrument.Instrumentation;

class Agent {
public static void premain(String args, Instrumentation instrumentation){
ClassPrinter transformer = new ClassPrinter();
instrumentation.addTransformer(transformer);
}
}
17 changes: 17 additions & 0 deletions examples/jvm/org/agent/ClassPrinter.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package org.agent;

import java.lang.instrument.ClassFileTransformer;
import java.lang.instrument.IllegalClassFormatException;
import java.security.ProtectionDomain;


class ClassPrinter implements ClassFileTransformer {
public byte[] transform(ClassLoader loader,
String className,
Class<?> classBeingRedefined,
ProtectionDomain protectionDomain,
byte[] classfileBuffer) throws IllegalClassFormatException {
System.out.println("Found class: " + className + " (" + classfileBuffer.length + " bytes)");
return classfileBuffer;
}
}
2 changes: 2 additions & 0 deletions examples/jvm/org/agent/manifest.mf
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Manifest-Version: 1.0
Premain-Class: org.agent.Agent
10 changes: 10 additions & 0 deletions examples/jvm/org/agent2/Agent.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package org.agent2;

import java.lang.instrument.Instrumentation;

class Agent {
public static void premain(String args, Instrumentation instrumentation){
ClassInjector transformer = new ClassInjector();
instrumentation.addTransformer(transformer);
}
}
59 changes: 59 additions & 0 deletions examples/jvm/org/agent2/ClassInjector.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
package org.agent2;

import java.io.IOException;
import java.util.List;

import java.lang.instrument.ClassFileTransformer;
import java.lang.instrument.IllegalClassFormatException;
import java.security.ProtectionDomain;

import jdk.internal.org.objectweb.asm.ClassReader;
import jdk.internal.org.objectweb.asm.ClassWriter;
import jdk.internal.org.objectweb.asm.tree.*;
import jdk.internal.org.objectweb.asm.Opcodes;


public class ClassInjector implements ClassFileTransformer {

public String targetClassName = "com/seriouscompany/business/java/fizzbuzz/packagenamingpackage/impl/strategies/SystemOutFizzBuzzOutputStrategy";

public byte[] transform(ClassLoader loader,
String className,
Class<?> classBeingRedefined,
ProtectionDomain protectionDomain,
byte[] classfileBuffer) throws IllegalClassFormatException {
if (className.equals(this.targetClassName)){
System.err.println("[CHAOS] TARGET ACQUIRED: " + className + " (" + classfileBuffer.length + " bytes)");

ClassNode classNode = new ClassNode();
new ClassReader(classfileBuffer).accept(classNode, 0);
classNode.methods.stream()
.filter(method -> method.name.equals("output"))
.forEach(method -> {
InsnList instructions = new InsnList();
instructions.add(new MethodInsnNode(
Opcodes.INVOKESTATIC,
"org/agent2/ClassInjector",
"throwIOException",
"()V",
false // not a method
));
method.maxStack += 1;
method.instructions.insertBefore(method.instructions.getFirst(), instructions);
System.err.println("[CHAOS] Method " + method.name + " modified");
});
final ClassWriter classWriter = new ClassWriter(0);
classNode.accept(classWriter);
byte[] bytes = classWriter.toByteArray();
System.err.println("[CHAOS] Rewrote: " + className + " (" + bytes.length + " bytes)");
return bytes;
}
return classfileBuffer;
}

public static void throwIOException() throws IOException
{
System.err.println("[CHAOS] BOOM! Throwing");
throw new IOException("CHAOS");
}
}
4 changes: 4 additions & 0 deletions examples/jvm/org/agent2/manifest.mf
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
Manifest-Version: 1.0
Premain-Class: org.agent2.Agent
Can-Redefine-Classes: true
Can-Retransform-Classes: true
9 changes: 9 additions & 0 deletions examples/jvm/org/my/example1.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package org.my;

class Example1
{
public static void main(String[] args)
{
System.out.println("Hello chaos!");
}
}
15 changes: 15 additions & 0 deletions examples/jvm/org/my/example2.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package org.my;
import java.io.IOException;

class Example2
{
public static void main(String[] args) throws IOException
{
Example2.throwIOException();
}

public static void throwIOException() throws IOException
{
throw new IOException("Oops");
}
}
9 changes: 9 additions & 0 deletions examples/jvm/throw.btm
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
RULE throw an exception at output
CLASS SystemOutFizzBuzzOutputStrategy
METHOD output
AT ENTRY
IF true
DO
traceln("entering the method output");
throw new java.io.IOException("BOOM");
ENDRULE
2 changes: 2 additions & 0 deletions vm/ansible/prerequisites/defaults/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,8 @@ packages_to_install:
- manpages-posix-dev
# seccomp
- libseccomp-dev
# java
- openjdk-8-jdk

packages_to_remove:
- libreoffice-core
Expand Down
9 changes: 9 additions & 0 deletions vm/ansible/prerequisites/tasks/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -199,3 +199,12 @@
become: false
shell: |
gsettings set org.gnome.desktop.session idle-delay 0

- name: Add auto-login
become: true
lineinfile:
path: /etc/gdm3/custom.conf
line: "{{ item }}"
loop:
- "AutomaticLoginEnable = true"
- "AutomaticLogin = chaos"