记录,没什么实际内容,参照PLCT talk和2019 LLVM Developers’ Meeting: A. Warzynski “Writing an LLVM Pass: 101”*
注:部分内容摘自PLCT开放日talk 和 2019 LLVM Developers’ Meeting: A. Warzynski “Writing an LLVM Pass: 101”
Pass分类
- Analysis passes
- 用于信息计算,其它Pass可以使用和调试相关信息- Transform passes
- 可以使用Analysis passes
- 以某种方式转换程序,通常是要对程序做出相应的改变- Utility passes
- 提供了一些实用功能
- 例如-view-cfg可以查看函数的控制流图
但是PLCT使用的方式是legacy pass manager
的方式,我这里使用的new pass manager
。
添加一个LLVM pass来实现Using LLVM For Program
Transformation 中提出的
Lab: Find Non-Constant Format String .
Any time the first parameter to printf, sprintf (others?) is nonconstant, alert for potential security badness
文档中已经给出了大致过程,所以这是一个FunctionPass
。
non-constant pass
这个pass的代码见pass-examples。
// Description:
// Visits all function in a module, collect the calls which accepts format-
// string routine. If it is, retrieve the first parameter and check whether
// it is a non constant global. If not, raise an alert.
//
// Strictly speaking, this is an analysis pass (i.e. the functions are not
// modified).
//
#include "llvm/IR/Function.h"
#include "llvm/IR/LegacyPassManager.h"
#include "llvm/Pass.h"
#include "llvm/Passes/PassBuilder.h"
#include "llvm/Passes/PassPlugin.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Transforms/IPO/PassManagerBuilder.h"
using namespace llvm;
// No need to expose the internal of the pass to the outside world - keep
// everything in an anonymous namespace.
namespace {
// New pass manager implementation
struct NonConstant : PassInfoMixin<NonConstant> {
// Main entry point, takes IR unit to run the pass on (&F) and the
// corresponding pass manager (to be queried if need be)
PreservedAnalyses run(Function &F, FunctionAnalysisManager &) {
for (auto &BB : F) {
runOnBasicBlock(BB);
}
return PreservedAnalyses::all();
}
void runOnBasicBlock(BasicBlock &BB) {
for (auto Inst = BB.begin(), IE = BB.end(); Inst != IE; ++Inst) {
// skip non-call instructions.
auto *inst = dyn_cast<CallInst>(Inst);
if (!inst)
continue;
if (inst->getCalledFunction()->getName() != "printf")
continue;
auto *op = dyn_cast<GlobalValue>(inst->getOperand(0));
if (!op) {
errs() << "Function: " << inst->getCalledFunction()->getName()
<< " has non constant format string"
<< "\n";
}
}
}
};
//------------------------------------------------------------------------------
// New PM Registration
//------------------------------------------------------------------------------
llvm::PassPluginLibraryInfo getNonConstantPluginInfo() {
return {LLVM_PLUGIN_API_VERSION, "NonConstant", LLVM_VERSION_STRING,
[](PassBuilder &PB) {
PB.registerPipelineParsingCallback(
[](StringRef Name, FunctionPassManager &FPM,
ArrayRef<PassBuilder::PipelineElement>) {
if (Name == "non-constant") {
FPM.addPass(NonConstant());
return true;
}
return false;
});
}};
}
// This is the core interface for pass plugins - with this 'opt' will be able
// to recoganize NonConstant when added to the pass pipeline on the command
// line, i.e. via '-pass=hello-world'
extern "C" LLVM_ATTRIBUTE_WEAK ::llvm::PassPluginLibraryInfo
llvmGetPassPluginInfo() {
return getNonConstantPluginInfo();
}
} // namespace
对于下面的代码来说,
// This code from https://help.semmle.com/wiki/display/CCPPOBJ/Non-constant+format+string
// clang -S -emit-llvm test.c -o test.ll
#include <stdio.h>
int main(int argc, char** argv) {
for(int i = 1; i < argc; ++i) {
printf(argv[i]);
}
}
我们使用下面的方式调用我们写的pass,会打印出"Function: printf has non constant format string",证明我成功发现了这个bug。
/usr/local/bin/opt -load-pass-plugin libNonConstant.dylib -passes=non-constant -disable-output ~/Test/test.ll
Function: printf has non constant format string
参考资料
Introduction to LLVM Building simple program analysis tools and instrumentation