如何给llvm添加一个pass

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

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

记录,没什么实际内容,参照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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值