如何给llvm添加一个pass

本文介绍如何使用 LLVM 的新传递管理器实现一个名为 NonConstant 的传递,用于检测 printf 函数的非常量格式字符串参数,从而预警潜在的安全风险。通过具体的代码示例和调用方式,展示了如何在 LLVM 中添加和运行自定义的分析传递。

记录,没什么实际内容,参照PLCT talk2019 LLVM Developers’ Meeting: A. Warzynski “Writing an LLVM Pass: 101”*

注:部分内容摘自PLCT开放日talk2019 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

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值