Merge remote-tracking branch 'origin/GP-5238_d-millar_ctadl_mods--SQUASHED'

This commit is contained in:
Ryan Kurtz
2025-01-16 06:11:42 -05:00
20 changed files with 393 additions and 126 deletions

View File

@@ -124,6 +124,17 @@
</p>
</div>
<div class="sect2">
<div class="titlepage"><div><div><h3 class="title">
<a name="ForceDirection"></a>Force Direction</h3></div></div></div>
<p>
May be "forward", "backward", "all", or blank. Forward computes all source-to-sink
slices, backward sink-to-source slices, and all both. Blank chooses source-to-sink
or sink-to-source based on whether the number of sources or the number of sinks is
greater.
</p>
</div>
<div class="sect2">
<div class="titlepage"><div><div><h3 class="title">
<a name="TaintTokenColor"></a>Highlight Color</h3></div></div></div>
@@ -144,15 +155,17 @@
<div class="titlepage"><div><div><h3 class="title">
<a name="TaintOutputFormat"></a>Output Format</h3></div></div></div>
<p>
Currently always "sarif+all".
Describes the output set. Currently default to "sarif+all", which should be appropriate
for most cases. Other options are "sarif" (output paths only), "sarif+instructions"
(output paths and instructions), and "sarif+graphs" (output paths and graphs).
</p>
</div>
<div class="sect2">
<div class="titlepage"><div><div><h3 class="title">
<a name="TaintAllAccess"></a>Use all access paths</h3></div></div></div>
<a name="TaintAllAccess"></a>Match on Fields</h3></div></div></div>
<p>
Use all access paths for sink/source variables.
Use all access paths, including field references, for sink/source variables.
</p>
</div>

View File

@@ -51,7 +51,9 @@ public abstract class AbstractTaintState implements TaintState {
private AddressSet taintAddressSet = new AddressSet();
private Map<Address, Set<TaintQueryResult>> taintVarnodeMap = new HashMap<>();
/// private QueryDataFrame currentQueryData;
private AddressSet deltaAddressSet = new AddressSet();
private Map<Address, Set<TaintQueryResult>> deltaVarnodeMap = new HashMap<>();
private SarifSchema210 currentQueryData;
protected TaintOptions taintOptions;
@@ -59,6 +61,8 @@ public abstract class AbstractTaintState implements TaintState {
private boolean cancellation;
private TaskType taskType;
public AbstractTaintState(TaintPlugin plugin) {
this.plugin = plugin;
}
@@ -281,10 +285,15 @@ public abstract class AbstractTaintState implements TaintState {
if (queryType.equals(QueryType.SRCSINK) || queryType.equals(QueryType.CUSTOM)) {
// The datalog that specifies the query.
if (queryType.equals(QueryType.CUSTOM)) {
if (queryType.equals(QueryType.CUSTOM)) {
Path queryPath = Path.of(taintOptions.getTaintOutputDirectory(),
taintOptions.getTaintQueryDLName());
queryFile = queryPath.toFile();
GhidraFileChooser chooser = new GhidraFileChooser(plugin.getProvider().getComponent());
chooser.setCurrentDirectory(queryPath.toFile());
queryFile = chooser.getSelectedFile();
if (queryFile == null) {
return false;
}
}
param_list.add(queryFile.getAbsolutePath());
}
@@ -296,12 +305,8 @@ public abstract class AbstractTaintState implements TaintState {
pb.redirectError(Redirect.INHERIT);
Process p = pb.start();
switch (taintOptions.getTaintOutputForm()) {
case "sarif+all":
readQueryResultsIntoDataFrame(program, p.getInputStream());
break;
default:
}
readQueryResultsIntoDataFrame(program, p.getInputStream());
// We wait for the process to finish after starting to read the input stream,
// otherwise waitFor() might wait for a running process trying to write to
// a filled output buffer. This causes waitFor() to wait indefinitely.
@@ -401,25 +406,54 @@ public abstract class AbstractTaintState implements TaintState {
@Override
public void setTaintAddressSet(AddressSet aset) {
taintAddressSet = aset;
switch (taskType) {
case SET_TAINT -> taintAddressSet = aset;
case SET_DELTA -> deltaAddressSet = aset;
case APPLY_DELTA -> {
// Empty
}
}
}
@Override
public AddressSet getTaintAddressSet() {
return taintAddressSet;
return switch(taskType) {
case SET_TAINT -> taintAddressSet;
case SET_DELTA -> deltaAddressSet;
case APPLY_DELTA -> taintAddressSet.subtract(deltaAddressSet);
default -> new AddressSet();
};
}
@Override
public void setTaskType(TaskType taskType) {
this.taskType = taskType;
}
@Override
public void augmentAddressSet(ClangToken token) {
Address addr = token.getMinAddress();
if (addr != null) {
taintAddressSet.add(addr);
if (addr == null) {
return;
}
switch (taskType) {
case SET_TAINT -> taintAddressSet.add(addr);
case SET_DELTA -> deltaAddressSet.add(addr);
case APPLY_DELTA -> {
if (!deltaAddressSet.contains(addr)) {
taintAddressSet.add(addr);
}
}
}
}
@Override
public void setTaintVarnodeMap(Map<Address, Set<TaintQueryResult>> vmap) {
taintVarnodeMap = vmap;
public void setTaintVarnodeMap(Map<Address, Set<TaintQueryResult>> vmap, TaskType delta) {
switch (delta) {
case SET_TAINT -> taintVarnodeMap = vmap;
case SET_DELTA -> deltaVarnodeMap = vmap;
case APPLY_DELTA -> taintVarnodeMap = vmap;
}
}
@Override
@@ -427,11 +461,42 @@ public abstract class AbstractTaintState implements TaintState {
return taintVarnodeMap;
}
@Override
public Set<TaintQueryResult> getQuerySet(Address key) {
Set<TaintQueryResult> set = new HashSet<>();
switch (taskType) {
case SET_TAINT -> set = taintVarnodeMap.get(key);
case SET_DELTA -> set = deltaVarnodeMap.get(key);
case APPLY_DELTA -> {
Set<TaintQueryResult> A = taintVarnodeMap.get(key);
if (A != null) {
set.addAll(A);
}
Set<TaintQueryResult> B = deltaVarnodeMap.get(key);
if (A != null) {
set.removeAll(B);
}
}
}
return set;
}
@Override
public void clearTaint() {
Msg.info(this, "TaintState: clearTaint() - clearing address set");
taintAddressSet.clear();
taintVarnodeMap.clear();
switch (taskType) {
case SET_TAINT -> {
taintAddressSet.clear();
taintVarnodeMap.clear();
}
case SET_DELTA -> {
deltaAddressSet.clear();
deltaVarnodeMap.clear();
}
case APPLY_DELTA -> {
// EMPTY
}
}
}
@Override

View File

@@ -51,8 +51,11 @@ public class TaintLabel {
}
Varnode exactSpot = token.getVarnode();
if (exactSpot != null) { // The user pointed at a particular usage, not just the vardecl
highVar = hfun.splitOutMergeGroup(exactSpot.getHigh(), exactSpot);
if (exactSpot != null) { // The user pointed at a particular usage, not just the vardecl
HighVariable high = exactSpot.getHigh();
if (high instanceof HighLocal) {
highVar = hfun.splitOutMergeGroup(high, exactSpot);
}
}
String fn = token instanceof ClangFuncNameToken ftoken ? ftoken.getText()

View File

@@ -18,7 +18,7 @@ package ghidra.app.plugin.core.decompiler.taint;
import java.awt.Color;
import generic.theme.GColor;
import ghidra.app.plugin.core.decompiler.taint.TaintPlugin.Highlighter;
import ghidra.app.plugin.core.decompiler.taint.TaintPlugin.*;
import ghidra.app.util.HelpTopics;
import ghidra.framework.options.ToolOptions;
import ghidra.framework.plugintool.Plugin;
@@ -45,12 +45,13 @@ public class TaintOptions {
/* The default name of the index database file. */
public final static String OP_KEY_TAINT_DB = "Taint.Query.Index";
public final static String OP_KEY_TAINT_QUERY_DIRECTION = "Taint.Force Direction";
public final static String OP_KEY_TAINT_QUERY_OUTPUT_FORM = "Taint.Output Format";
/* Color used in the decompiler to highlight taint. */
public final static String TAINT_HIGHLIGHT = "Taint.Highlight Color";
/* How to apply highlight taint. */
public final static String TAINT_HIGHLIGHT_STYLE = "Taint.Highlight Style";
public final static String TAINT_ALL_ACCESS = "Taint.Use all access paths";
public final static String TAINT_ALL_ACCESS = "Taint.Match on Fields";
private final static Boolean TAINT_ALL_ACCESS_PATHS = true;
public final static String DEFAULT_TAINT_ENGINE_PATH = "";
@@ -60,7 +61,6 @@ public class TaintOptions {
/* this is the text code that contains the datalog query the plugin writes. */
public final static String DEFAULT_TAINT_QUERY = "taintquery.dl";
public final static String DEFAULT_TAINT_DB = "ctadlir.db";
public final static String DEFAULT_TAINT_OUTPUT_FORM = "sarif+all";
public final static Boolean DEFAULT_GET_PATHS = true;
@@ -75,7 +75,8 @@ public class TaintOptions {
private String taintQuery;
private String taintDB;
private String taintQueryOutputForm;
private TaintDirection taintQueryDirection;
private TaintFormat taintQueryOutputForm;
private Highlighter taintHighlightStyle;
private Color taintHighlightColor;
@@ -110,7 +111,8 @@ public class TaintOptions {
taintOutputDir = DEFAULT_TAINT_OUTPUT_DIR;
taintQuery = DEFAULT_TAINT_QUERY;
taintDB = DEFAULT_TAINT_DB;
taintQueryOutputForm = DEFAULT_TAINT_OUTPUT_FORM;
taintQueryOutputForm = TaintFormat.ALL;
taintQueryDirection = TaintDirection.DEFAULT;
taintUseAllAccess = TAINT_ALL_ACCESS_PATHS;
}
@@ -125,7 +127,7 @@ public class TaintOptions {
*/
public void registerOptions(Plugin ownerPlugin, ToolOptions opt, Program program) {
opt.registerOption(OP_KEY_TAINT_QUERY_OUTPUT_FORM, DEFAULT_TAINT_OUTPUT_FORM,
opt.registerOption(OP_KEY_TAINT_QUERY_OUTPUT_FORM, TaintFormat.ALL,
new HelpLocation(HelpTopics.DECOMPILER, "Taint Output Type"),
"The type of Source-Sink query output (e.g., sarif, summary, text");
@@ -181,7 +183,8 @@ public class TaintOptions {
taintOutputDir = opt.getString(OP_KEY_TAINT_OUTPUT_DIR, "");
taintDB = opt.getString(OP_KEY_TAINT_DB, "");
taintQueryOutputForm = opt.getString(OP_KEY_TAINT_QUERY_OUTPUT_FORM, "");
taintQueryDirection = opt.getEnum(OP_KEY_TAINT_QUERY_DIRECTION, TaintDirection.DEFAULT);
taintQueryOutputForm = opt.getEnum(OP_KEY_TAINT_QUERY_OUTPUT_FORM, TaintFormat.ALL);
taintHighlightStyle = opt.getEnum(TAINT_HIGHLIGHT_STYLE, TAINT_HIGHLIGHT_STYLE_DEFAULT);
taintHighlightColor = opt.getColor(TAINT_HIGHLIGHT, TAINT_HIGHLIGHT_COLOR);
@@ -189,7 +192,7 @@ public class TaintOptions {
}
public String getTaintOutputForm() {
public TaintFormat getTaintOutputForm() {
return taintQueryOutputForm;
}
@@ -233,13 +236,17 @@ public class TaintOptions {
return taintHighlightStyle;
}
public TaintDirection getTaintDirection() {
return taintQueryDirection;
}
public Boolean getTaintUseAllAccess() {
return taintUseAllAccess;
}
public void setTaintOutputForm(String form) {
public void setTaintOutputForm(TaintFormat form) {
this.taintQueryOutputForm = form;
taintProvider.setOption(OP_KEY_TAINT_QUERY_OUTPUT_FORM, form);
taintProvider.setOption(OP_KEY_TAINT_QUERY_OUTPUT_FORM, form.getOptionString());
}
public void setTaintFactsDirectory(String path) {
@@ -269,12 +276,16 @@ public class TaintOptions {
public void setTaintHighlightStyle(Highlighter style) {
this.taintHighlightStyle = style;
taintProvider.setOption(TAINT_HIGHLIGHT_STYLE, style.name());
taintProvider.setOption(TAINT_HIGHLIGHT_STYLE, style.getOptionString());
taintProvider.changeHighlighter(style);
}
public void setTaintDirection(TaintDirection direction) {
this.taintQueryDirection = direction;
taintProvider.setOption(OP_KEY_TAINT_QUERY_DIRECTION, direction.getOptionString());
}
public void setTaintAllAccess(Boolean allAccess) {
this.taintUseAllAccess = allAccess;
taintProvider.setAllAccess(TAINT_ALL_ACCESS, allAccess);
}
}

View File

@@ -34,6 +34,7 @@ import ghidra.app.plugin.PluginCategoryNames;
import ghidra.app.plugin.ProgramPlugin;
import ghidra.app.plugin.core.decompile.DecompilerProvider;
import ghidra.app.plugin.core.decompiler.taint.TaintState.MarkType;
import ghidra.app.plugin.core.decompiler.taint.TaintState.TaskType;
import ghidra.app.script.GhidraScript;
import ghidra.app.script.GhidraState;
import ghidra.app.services.ConsoleService;
@@ -89,16 +90,66 @@ public class TaintPlugin extends ProgramPlugin implements TaintService {
private TaintDecompilerMarginProvider taintDecompMarginProvider;
public static enum Highlighter {
ALL("Taint Variables"), LABELS("Taint Labels"), DEFAULT("Default");
ALL("all", "variables"), LABELS("labels", "labels"), DEFAULT("default", "default");
private String name;
private String label;
private String optionString;
private Highlighter(String name) {
this.name = name;
private Highlighter(String optString, String label) {
this.label = label;
this.optionString = optString;
}
public String getName() {
return this.name;
public String getOptionString() {
return optionString;
}
@Override
public String toString() {
return label;
}
}
public static enum TaintFormat {
ALL("all", "sarif+all"), GRAPHS("graphs", "sarif+graphs"),
INSTS("insts", "sarif+instructions"), PATHS("paths", "sarif");
private String label;
private String optionString;
private TaintFormat(String optString, String label) {
this.label = label;
this.optionString = optString;
}
public String getOptionString() {
return optionString;
}
@Override
public String toString() {
return label;
}
}
public static enum TaintDirection {
BOTH("all", "both"), FORWARD("fwd", "forward"), BACKWARD("bwd", "backward"), DEFAULT("auto", "auto");
private String label;
private String optionString;
private TaintDirection(String optString, String label) {
this.label = label;
this.optionString = optString;
}
public String getOptionString() {
return optionString;
}
@Override
public String toString() {
return label;
}
}
@@ -638,12 +689,12 @@ public class TaintPlugin extends ProgramPlugin implements TaintService {
}
@Override
public void setVarnodeMap(Map<Address, Set<TaintQueryResult>> vmap, boolean clear) {
public void setVarnodeMap(Map<Address, Set<TaintQueryResult>> vmap, boolean clear, TaskType delta) {
if (clear) {
taintProvider.clearTaint();
}
state.setTaintVarnodeMap(vmap);
taintProvider.setTaint();
state.setTaintVarnodeMap(vmap, delta);
taintProvider.setTaint(delta);
}
@Override

View File

@@ -34,6 +34,7 @@ import ghidra.app.nav.Navigatable;
import ghidra.app.plugin.core.decompile.DecompilerActionContext;
import ghidra.app.plugin.core.decompile.DecompilerProvider;
import ghidra.app.plugin.core.decompiler.taint.TaintPlugin.Highlighter;
import ghidra.app.plugin.core.decompiler.taint.TaintState.TaskType;
import ghidra.app.plugin.core.decompiler.taint.actions.*;
import ghidra.app.services.CodeViewerService;
import ghidra.framework.options.OptionsChangeListener;
@@ -64,8 +65,6 @@ public class TaintProvider extends ComponentProviderAdapter implements OptionsCh
private DecompilerHighlighter highlighter;
private Boolean allAccess;
private TaintCTokenHighlighterPalette highlightPalette;
private int paletteIndex;
@@ -250,12 +249,15 @@ public class TaintProvider extends ComponentProviderAdapter implements OptionsCh
* <p>
* TODO: We could limit our taint addresses to those in this function...? TODO:
* We should reset the palette cache to start coloring from the start.
*
* @param taskType subtract previous result
*/
public void setTaint() {
public void setTaint(TaskType taskType) {
if (navigatable == null) {
navigatable = tool.getService(CodeViewerService.class).getNavigatable();
}
state.setTaskType(taskType);
AddressSet taintAddressSet = state.getTaintAddressSet();
Msg.info(this, "setTaint(): " + taintAddressSet.toString());
@@ -274,14 +276,16 @@ public class TaintProvider extends ComponentProviderAdapter implements OptionsCh
// apply highlights to the decompiler window.
highlighter.applyHighlights();
state.setTaskType(TaskType.SET_TAINT);
}
public void setTaint() {
setTaint(TaskType.SET_TAINT);
}
public boolean matchOn(ClangToken token) {
Map<Address, Set<TaintQueryResult>> taintVarnodeMap = state.getTaintVarnodeMap();
if (taintVarnodeMap == null || taintVarnodeMap.isEmpty() ||
token instanceof ClangBreak ||
if (token instanceof ClangBreak ||
token instanceof ClangTypeToken ||
token instanceof ClangSyntaxToken ||
token instanceof ClangCommentToken) {
@@ -298,7 +302,8 @@ public class TaintProvider extends ComponentProviderAdapter implements OptionsCh
Address tokenFuncEntryAddr = hf.getFunction().getEntryPoint();
// Just the tainted elements that are in this function.
Set<TaintQueryResult> funcTaintSet = taintVarnodeMap.get(tokenFuncEntryAddr);
Set<TaintQueryResult> funcTaintSet = state.getQuerySet(tokenFuncEntryAddr);
//Set<TaintQueryResult> funcTaintSet = taintVarnodeMap.get(tokenFuncEntryAddr);
if (funcTaintSet == null || funcTaintSet.isEmpty()) {
return false;
}
@@ -458,14 +463,6 @@ public class TaintProvider extends ComponentProviderAdapter implements OptionsCh
plugin.changeHighlighter(hl);
}
public boolean isAllAccess() {
return allAccess;
}
public void setAllAccess(String taintAllAccess, Boolean allAccess) {
this.allAccess = allAccess;
}
public int getTokenCount() {
return matchCount;
}

View File

@@ -41,8 +41,8 @@ public record TaintQueryResult(String name,String fqname, Address iaddr, Address
public TaintQueryResult(Map<String, Object> result, Run run, LogicalLocation ll) {
this(
SarifUtils.extractDisplayName(fqnFromLoc(run, ll)),
fqnFromLoc(run, ll).getFullyQualifiedName(),
SarifUtils.extractDisplayName(ll),
ll.getFullyQualifiedName(),
(Address) result.get("Address"),
(Address) result.get("entry"),
new ArrayList<String>(),
@@ -51,14 +51,6 @@ public record TaintQueryResult(String name,String fqname, Address iaddr, Address
addLabel(value);
}
private static LogicalLocation fqnFromLoc(Run run, LogicalLocation ll) {
String fqn = ll.getFullyQualifiedName();
if (fqn == null) {
ll = SarifUtils.getLogicalLocation(run, ll.getIndex());
}
return ll;
}
public String getLabel() {
return this.labels.get(0);
}
@@ -111,8 +103,11 @@ public record TaintQueryResult(String name,String fqname, Address iaddr, Address
}
else {
// if neither are function-level, the addresses must match
// NB: parameter/local use matches on the representative
if (!iaddr.equals(vaddr)) {
return null;
if (!(hv instanceof HighParam) || !iaddr.equals(hv.getRepresentative().getPCAddress())) {
return null;
}
}
}
if (hvName.startsWith(":")) { // fqname is FUN@FUN:name:vname

View File

@@ -18,6 +18,7 @@ package ghidra.app.plugin.core.decompiler.taint;
import java.util.Map;
import java.util.Set;
import ghidra.app.plugin.core.decompiler.taint.TaintState.TaskType;
import ghidra.framework.plugintool.ServiceInfo;
import ghidra.program.model.address.Address;
import ghidra.program.model.address.AddressSet;
@@ -56,8 +57,9 @@ public interface TaintService {
*
* @param vmap tainted addresses
* @param clear before setting
* @param taskType operation to be performed
*/
public void setVarnodeMap(Map<Address, Set<TaintQueryResult>> vmap, boolean clear);
public void setVarnodeMap(Map<Address, Set<TaintQueryResult>> vmap, boolean clear, TaskType taskType);
/**
* Clear existing taint

View File

@@ -46,6 +46,10 @@ public interface TaintState {
SRCSINK, DEFAULT, CUSTOM
}
public enum TaskType {
SET_TAINT, SET_DELTA, APPLY_DELTA
}
public static TaintState newInstance(TaintPlugin plugin) {
return new TaintStateCTADL(plugin);
}
@@ -93,10 +97,12 @@ public interface TaintState {
public void setCancellation(boolean status);
public void setTaintVarnodeMap(Map<Address, Set<TaintQueryResult>> vmap);
public void setTaintVarnodeMap(Map<Address, Set<TaintQueryResult>> vmap, TaskType delta);
public Map<Address, Set<TaintQueryResult>> getTaintVarnodeMap();
public Set<TaintQueryResult> getQuerySet(Address addr);
public void buildIndex(List<String> param_list, String engine_path, String facts_path,
String index_directory);
@@ -153,4 +159,6 @@ public interface TaintState {
return false;
}
public void setTaskType(TaskType taskType);
}

View File

@@ -39,12 +39,13 @@ public abstract class TaintAbstractQueryAction extends TaintAbstractDecompilerAc
protected TaintPlugin plugin;
protected TaintState state;
protected String desc;
protected String title;
protected String executeTaintQueryIconString;
protected Icon executeTaintQueryIcon;
protected QueryType queryType;
public TaintAbstractQueryAction(TaintPlugin plugin, TaintState state, String desc, String cmd) {
public TaintAbstractQueryAction(TaintPlugin plugin, TaintState state, String desc, String title, String cmd) {
super(cmd);
setHelpLocation(new HelpLocation(TaintPlugin.HELP_LOCATION, "Taint"+desc));
@@ -53,6 +54,7 @@ public abstract class TaintAbstractQueryAction extends TaintAbstractDecompilerAc
this.plugin = plugin;
this.state = state;
this.desc = desc;
this.title = title;
}
/*
@@ -68,7 +70,7 @@ public abstract class TaintAbstractQueryAction extends TaintAbstractDecompilerAc
Program program = context.getProgram();
PluginTool tool = context.getTool();
Task defaultQueryTask = new Task("Source-Sink Query Task", true, true, true, true) {
Task defaultQueryTask = new Task(title, true, true, true, true) {
@Override
public void run(TaskMonitor monitor) {
state.setCancellation(false);

View File

@@ -28,13 +28,13 @@ import ghidra.app.plugin.core.decompiler.taint.TaintState.QueryType;
public class TaintQueryAction extends TaintAbstractQueryAction {
public TaintQueryAction(TaintPlugin plugin, TaintState state) {
super(plugin, state, "Query", "Run taint query");
super(plugin, state, "Query", "Source-Sink Taint Query", "Run taint query");
executeTaintQueryIconString = "icon.graph.default.display.program.graph";
executeTaintQueryIcon = new GIcon(executeTaintQueryIconString);
queryType = QueryType.SRCSINK;
setToolBarData(new ToolBarData(executeTaintQueryIcon));
setKeyBindingData(new KeyBindingData(KeyEvent.VK_Q, 0));
setKeyBindingData(new KeyBindingData(KeyEvent.VK_Y, 0));
}
@Override

View File

@@ -15,6 +15,10 @@
*/
package ghidra.app.plugin.core.decompiler.taint.actions;
import java.awt.event.InputEvent;
import java.awt.event.KeyEvent;
import docking.action.KeyBindingData;
import ghidra.app.plugin.core.decompiler.taint.TaintPlugin;
import ghidra.app.plugin.core.decompiler.taint.TaintState;
import ghidra.app.plugin.core.decompiler.taint.TaintState.QueryType;
@@ -22,8 +26,9 @@ import ghidra.app.plugin.core.decompiler.taint.TaintState.QueryType;
public class TaintQueryCustomAction extends TaintAbstractQueryAction {
public TaintQueryCustomAction(TaintPlugin plugin, TaintState state) {
super(plugin, state, "CustomQuery", "Run custom taint query");
super(plugin, state, "CustomQuery", "Custom Taint Query", "Run custom taint query");
queryType = QueryType.CUSTOM;
setKeyBindingData(new KeyBindingData(KeyEvent.VK_Y, InputEvent.CTRL_DOWN_MASK));
}
}

View File

@@ -15,6 +15,10 @@
*/
package ghidra.app.plugin.core.decompiler.taint.actions;
import java.awt.event.InputEvent;
import java.awt.event.KeyEvent;
import docking.action.KeyBindingData;
import docking.action.ToolBarData;
import generic.theme.GIcon;
import ghidra.app.plugin.core.decompiler.taint.TaintPlugin;
@@ -24,12 +28,13 @@ import ghidra.app.plugin.core.decompiler.taint.TaintState.QueryType;
public class TaintQueryDefaultAction extends TaintAbstractQueryAction {
public TaintQueryDefaultAction(TaintPlugin plugin, TaintState state) {
super(plugin, state, "DefaultQuery", "Run default taint query");
super(plugin, state, "DefaultQuery", "Default Taint Query", "Run default taint query");
executeTaintQueryIconString = "icon.version.tracking.markup.status.conflict";
executeTaintQueryIcon = new GIcon(executeTaintQueryIconString);
queryType = QueryType.DEFAULT;
setToolBarData(new ToolBarData(executeTaintQueryIcon));
setKeyBindingData(new KeyBindingData(KeyEvent.VK_Y, InputEvent.SHIFT_DOWN_MASK));
}
}

View File

@@ -23,6 +23,7 @@ import java.util.List;
import generic.jar.ResourceFile;
import ghidra.app.decompiler.*;
import ghidra.app.plugin.core.decompiler.taint.*;
import ghidra.app.plugin.core.decompiler.taint.TaintPlugin.TaintDirection;
import ghidra.app.plugin.core.osgi.BundleHost;
import ghidra.app.script.*;
import ghidra.app.services.ConsoleService;
@@ -48,8 +49,23 @@ public class TaintStateCTADL extends AbstractTaintState {
paramList.add("--directory");
paramList.add(indexDirectory);
paramList.add("query");
Comparable<TaintDirection> direction = taintOptions.getTaintDirection();
if (!direction.equals(TaintDirection.DEFAULT)) {
paramList.add("--compute-slices");
switch (taintOptions.getTaintDirection()) {
case TaintDirection.BOTH ->
paramList.add("all");
case TaintDirection.FORWARD ->
paramList.add("fwd");
case TaintDirection.BACKWARD ->
paramList.add("bwd");
default -> {
// No action
}
}
}
paramList.add("-j8");
paramList.add("--format=" + taintOptions.getTaintOutputForm());
paramList.add("--format=" + taintOptions.getTaintOutputForm().toString());
}
@Override
@@ -132,6 +148,10 @@ public class TaintStateCTADL extends AbstractTaintState {
if (!TaintState.isActualParam(token) && !(hv instanceof HighParam)) {
writer.println("\tVNODE_PC_ADDRESS(vn, " + addr.getOffset() + "),");
}
else { // NB: we still want a local match
writer.println("\t(PCODE_INPUT(i, _, vn) ; PCODE_OUTPUT(i, vn)),");
writer.println("\tPCODE_TARGET(i, " + addr.getOffset() + "),");
}
}
if (mark.bySymbol()) {
writer.println("\tSYMBOL_NAME(sym, \"" + token.getText() + "\"),");

View File

@@ -41,12 +41,12 @@ public class SarifTaintCodeFlowResultHandler extends SarifResultHandler {
}
@Override
public void handle(SarifDataFrame dframe, Run run, Result result, Map<String, Object> map) {
public void handle(SarifDataFrame dframe, Run r, Result res, Map<String, Object> map) {
this.df = dframe;
this.controller = df.getController();
this.run = run;
this.result = result;
this.run = r;
this.result = res;
List<Map<String, Object>> tableResults = df.getTableResults();
String ruleId = result.getRuleId();

View File

@@ -23,6 +23,7 @@ import com.contrastsecurity.sarif.*;
import docking.ActionContext;
import docking.action.*;
import ghidra.app.plugin.core.decompiler.taint.*;
import ghidra.app.plugin.core.decompiler.taint.TaintState.TaskType;
import ghidra.framework.plugintool.PluginTool;
import ghidra.program.model.address.Address;
import ghidra.program.model.address.AddressRange;
@@ -49,12 +50,12 @@ public class SarifTaintResultHandler extends SarifResultHandler {
}
@Override
public void handle(SarifDataFrame dframe, Run run, Result result, Map<String, Object> map) {
public void handle(SarifDataFrame dframe, Run r, Result res, Map<String, Object> map) {
this.df = dframe;
this.controller = df.getController();
this.run = run;
this.result = result;
this.run = r;
this.result = res;
String ruleId = result.getRuleId();
if (ruleId == null || ruleId.equals("C0001")) {
@@ -199,6 +200,7 @@ public class SarifTaintResultHandler extends SarifResultHandler {
private class ApplyTaintViaVarnodesTask extends ProgramTask {
private SarifResultsTableProvider tableProvider;
protected TaskType taskType = TaskType.SET_TAINT;
protected ApplyTaintViaVarnodesTask(SarifResultsTableProvider provider) {
super(provider.getController().getProgram(), "ApplyTaintViaVarnodesTask", true, true,
@@ -224,7 +226,7 @@ public class SarifTaintResultHandler extends SarifResultHandler {
PluginTool tool = tableProvider.getController().getPlugin().getTool();
TaintService service = tool.getService(TaintService.class);
if (service != null) {
service.setVarnodeMap(map, true);
service.setVarnodeMap(map, true, taskType);
}
}
@@ -318,7 +320,7 @@ public class SarifTaintResultHandler extends SarifResultHandler {
}
}
service.setVarnodeMap(map, false);
service.setVarnodeMap(map, false, TaskType.SET_TAINT);
service.setAddressSet(set, false);
}
@@ -363,4 +365,68 @@ public class SarifTaintResultHandler extends SarifResultHandler {
return vset;
}
// Saving these for later - on the fence re use case
/*
DockingAction applyDelta = new DockingAction("Apply delta", getKey()) {
@Override
public void actionPerformed(ActionContext context) {
provider.filterTable.getTable().selectAll();
TaskLauncher.launch(new ApplyDeltaViaVarnodesTask(provider));
}
@Override
public boolean isEnabledForContext(ActionContext context) {
return isEnabled;
}
@Override
public boolean isAddToPopup(ActionContext context) {
return isEnabled;
}
};
applyDelta.setDescription("Apply delta");
applyDelta.setToolBarData(new ToolBarData(Icons.COLLAPSE_ALL_ICON));
provider.addLocalAction(applyDelta);
DockingAction initDelta = new DockingAction("Set base for delta", getKey()) {
@Override
public void actionPerformed(ActionContext context) {
TaskLauncher.launch(new SetDeltaBaseTask(provider));
}
@Override
public boolean isEnabledForContext(ActionContext context) {
return isEnabled;
}
@Override
public boolean isAddToPopup(ActionContext context) {
return isEnabled;
}
};
initDelta.setDescription("Initialize delta");
initDelta.setToolBarData(new ToolBarData(Icons.INFO_ICON));
provider.addLocalAction(initDelta);
*/
/*
private class ApplyDeltaViaVarnodesTask extends ApplyTaintViaVarnodesTask {
protected ApplyDeltaViaVarnodesTask(SarifResultsTableProvider provider) {
super(provider);
this.delta = TaskType.APPLY_DELTA;
}
}
private class SetDeltaBaseTask extends ApplyTaintViaVarnodesTask {
protected SetDeltaBaseTask(SarifResultsTableProvider provider) {
super(provider);
this.delta = TaskType.SET_DELTA;
}
}
*/
}

View File

@@ -32,8 +32,7 @@ import ghidra.app.decompiler.*;
import ghidra.app.plugin.core.codebrowser.CodeBrowserPlugin;
import ghidra.app.plugin.core.decompile.DecompilePlugin;
import ghidra.app.plugin.core.decompile.DecompilerProvider;
import ghidra.app.plugin.core.decompiler.taint.TaintState.MarkType;
import ghidra.app.plugin.core.decompiler.taint.TaintState.QueryType;
import ghidra.app.plugin.core.decompiler.taint.TaintState.*;
import ghidra.app.plugin.core.decompiler.taint.sarif.SarifTaintGraphRunHandler;
import ghidra.app.services.CodeViewerService;
import ghidra.framework.Application;
@@ -186,7 +185,7 @@ public class DecompilerTaintTest extends AbstractGhidraHeadedIntegrationTest {
for (Map<String, Object> result : df.getTableResults()) {
processResult(map, result);
}
taintService.setVarnodeMap(map, true);
taintService.setVarnodeMap(map, true, TaskType.SET_TAINT);
validateResult(token, map);
}

View File

@@ -139,6 +139,7 @@ public class SarifPlugin extends ProgramPlugin implements SarifService, OptionsC
return io.readSarif(sarif);
}
@Override
public SarifController getController() {
currentProgram = getCurrentProgram();
if (currentProgram != null) {
@@ -156,9 +157,10 @@ public class SarifPlugin extends ProgramPlugin implements SarifService, OptionsC
* Ultimately both selections end up calling this to actually show something on
* the Ghidra gui
*
* @param logName
* @param sarif
* @param logName display name
* @param sarif the raw sarif
*/
@Override
public void showSarif(String logName, SarifSchema210 sarif) {
SarifController currentController = getController();
if (currentController != null) {

View File

@@ -68,13 +68,17 @@ public class SarifUtils {
// artifactLocation/uri <= the overlayED space name (typically OTHER)
private static Run currentRun = null;
// llocs has indexed per run and is not valid across runs
// Attempts to access llocs outside the population phase will throw an error
private static LogicalLocation[] llocs;
// All of the following have keys that are valid across queries
private static List<com.contrastsecurity.sarif.Address> addresses;
private static Map<String, Long> nameToOffset = new HashMap<>();
private static Map<String, LogicalLocation[]> nodeLocs = new HashMap<>();
private static Map<String, String> edgeSrcs = new HashMap<>();
private static Map<String, String> edgeDsts = new HashMap<>();
private static Map<String, String> edgeDescs = new HashMap<>();
private static boolean populating = false;
public static JsonArray setLocations(Address min, Address max) {
AddressSet set = new AddressSet(min, max);
@@ -141,6 +145,9 @@ public class SarifUtils {
}
public static Address locationToAddress(Location location, Program program, boolean useOverlays) {
if (!populating) {
throw new RuntimeException("Locations valid only during population phase");
}
Long addr = -1L;
PhysicalLocation physicalLocation = location.getPhysicalLocation();
if (location.getPhysicalLocation() != null) {
@@ -244,7 +251,9 @@ public class SarifUtils {
public static Address extractFunctionEntryAddr(Program program, String fqname) {
String addr = null;
if (fqname.contains("!")) {
// NB: ! can be used both as a delimiter and part of an operator
// TODO: This may eventually require a more complicated check
if (fqname.contains("!") && !fqname.contains("!=")) {
fqname = fqname.substring(0, fqname.indexOf("!"));
}
String[] parts = fqname.split("@");
@@ -263,10 +272,6 @@ public class SarifUtils {
return program.getAddressFactory().getAddress(addr);
}
/**
* @param fqname
* @return
*/
public static List<Address> extractFQNameAddrPair(Program program, String fqname) {
List<Address> addr_pair = new ArrayList<Address>();
String[] parts = fqname.split("@");
@@ -350,6 +355,9 @@ public class SarifUtils {
}
public static LogicalLocation getLogicalLocation(Run run, Location loc) {
if (!populating) {
throw new RuntimeException("Locations valid only during population phase");
}
Set<LogicalLocation> llocset = loc.getLogicalLocations();
if (llocset == null) {
return null;
@@ -366,10 +374,6 @@ public class SarifUtils {
return null;
}
public static LogicalLocation getLogicalLocation(Run run, Long index) {
return llocs[index.intValue()];
}
public static void validateRun(Run run) {
if (!run.equals(currentRun) || llocs == null) {
initRun(run);
@@ -407,9 +411,18 @@ public class SarifUtils {
Location loc = n.getLocation();
if (loc != null) {
Set<LogicalLocation> logicalLocations = loc.getLogicalLocations();
LogicalLocation[] llocs = new LogicalLocation[logicalLocations.size()];
logicalLocations.toArray(llocs);
nodeLocs.put(id, llocs);
LogicalLocation[] nodells = new LogicalLocation[logicalLocations.size()];
int i = 0;
for (LogicalLocation ll : logicalLocations) {
// NB: These have to be derefenced immediately as they will be invalid for subsequent queries
if (ll.getFullyQualifiedName() != null) {
nodells[i++] = ll;
}
else {
nodells[i++] = llocs[ll.getIndex().intValue()];
}
}
nodeLocs.put(id, nodells);
}
}
}
@@ -439,4 +452,8 @@ public class SarifUtils {
return nodeLocs.get(id);
}
public static void setPopulating(boolean b) {
populating = b;
}
}

View File

@@ -4,9 +4,9 @@
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*
* http://www.apache.org/licenses/LICENSE-2.0
*
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -82,28 +82,34 @@ public class SarifDataFrame {
columns.add(new SarifColumnKey(entry.getKey(), entry.getValue()));
}
SarifUtils.validateRun(run);
for (Result result : run.getResults()) {
compileTaxaMap(run, result);
Map<String, Object> curTableResult = new HashMap<>();
for (SarifResultHandler handler : resultHandlers) {
SarifUtils.setPopulating(true);
try {
for (Result result : run.getResults()) {
compileTaxaMap(run, result);
Map<String, Object> curTableResult = new HashMap<>();
for (SarifResultHandler handler : resultHandlers) {
if (handler.isEnabled(this)) {
handler.handle(this, run, result, curTableResult);
}
}
tableResults.add(curTableResult);
String ruleid = (String) curTableResult.get("RuleId");
List<Map<String, Object>> list = tableResultsAsMap.get(ruleid);
if (list == null) {
list = new ArrayList<>();
tableResultsAsMap.put(ruleid, list);
}
list.add(curTableResult);
}
for (SarifRunHandler handler : controller.getSarifRunHandlers()) {
if (handler.isEnabled(this)) {
handler.handle(this, run, result, curTableResult);
handler.handle(this, run);
}
}
tableResults.add(curTableResult);
String ruleid = (String) curTableResult.get("RuleId");
List<Map<String, Object>> list = tableResultsAsMap.get(ruleid);
if (list == null) {
list = new ArrayList<>();
tableResultsAsMap.put(ruleid, list);
}
list.add(curTableResult);
}
for (SarifRunHandler handler : controller.getSarifRunHandlers()) {
if (handler.isEnabled(this)) {
handler.handle(this, run);
}
}
finally {
SarifUtils.setPopulating(false);
}
}
}
@@ -147,7 +153,7 @@ public class SarifDataFrame {
Set<ReportingDescriptorReference> taxa = result.getTaxa();
if (taxa != null) {
for (ReportingDescriptorReference ref : taxa) {
long idx = (long) ref.getToolComponent().getIndex();
long idx = ref.getToolComponent().getIndex();
if (idx >= 0 && idx < view.size()) {
ToolComponent tc = view.get((int) idx);
taxaMap.put(tc.getName(), ref);