动态库注入方式锁分析
This commit is contained in:
parent
d40a0fdb3d
commit
1491ef3061
|
@ -57,7 +57,7 @@
|
||||||
"description": "%deadlockdetect.taskDefinitions.options.cwd.description%"
|
"description": "%deadlockdetect.taskDefinitions.options.cwd.description%"
|
||||||
},
|
},
|
||||||
"env": {
|
"env": {
|
||||||
"type": "array",
|
"type": "object",
|
||||||
"description": "%deadlockdetect.taskDefinitions.options.env.description%"
|
"description": "%deadlockdetect.taskDefinitions.options.env.description%"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,17 +1,23 @@
|
||||||
import * as vscode from 'vscode';
|
import * as vscode from 'vscode';
|
||||||
import * as child from 'child_process';
|
import * as child from 'child_process';
|
||||||
import {execDetect, testPwd, prase_yaml2html} from './utils';
|
import {execDetect, archs, testPwd, prase_yaml2html} from './utils';
|
||||||
import { dirname, join } from 'path';
|
import { dirname, join } from 'path';
|
||||||
import { kill } from 'process';
|
import { kill } from 'process';
|
||||||
import * as fs from 'fs';
|
import * as fs from 'fs';
|
||||||
|
|
||||||
type Options = {
|
type Options = {
|
||||||
cwd?: string;
|
cwd?: string;
|
||||||
env?: string[];
|
env?: {
|
||||||
|
[name: string]: any;
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
var isNotSupport = false;
|
||||||
|
|
||||||
|
const arch = archs.get(process.arch);
|
||||||
const binLoader: string = join(dirname(__dirname), "detect-tools/bincheck_loader.sh");
|
const binLoader: string = join(dirname(__dirname), "detect-tools/bincheck_loader.sh");
|
||||||
|
const hijackLib: string = join(dirname(__dirname), "detect-tools", arch? arch : "x86_64", "");
|
||||||
|
const hijackTool: string = join(dirname(__dirname), "detect-tools", arch? arch : "x86_64", "");
|
||||||
|
|
||||||
interface DetectTaskDefinition extends vscode.TaskDefinition {
|
interface DetectTaskDefinition extends vscode.TaskDefinition {
|
||||||
command: string;
|
command: string;
|
||||||
|
@ -19,14 +25,15 @@ interface DetectTaskDefinition extends vscode.TaskDefinition {
|
||||||
options?: Options;
|
options?: Options;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
export class DetectTaskProvider implements vscode.TaskProvider {
|
export class DetectTaskProvider implements vscode.TaskProvider {
|
||||||
static customBuildScriptType = 'deadlockdetect';
|
static customBuildScriptType = 'deadlockdetect';
|
||||||
private tasks: vscode.Task[] | undefined;
|
private tasks: vscode.Task[] | undefined;
|
||||||
|
|
||||||
private sharedState: string | undefined;
|
private sharedState: string | undefined;
|
||||||
private cmd: child.ChildProcessWithoutNullStreams | undefined;
|
private cmd: child.ChildProcessWithoutNullStreams | undefined;
|
||||||
constructor(private workspaceRoot: string, private context: vscode.ExtensionContext) { }
|
constructor(private workspaceRoot: string, private context: vscode.ExtensionContext, private _isNotSupport: boolean) {
|
||||||
|
isNotSupport = this._isNotSupport;
|
||||||
|
}
|
||||||
|
|
||||||
public async provideTasks(): Promise<vscode.Task[]> {
|
public async provideTasks(): Promise<vscode.Task[]> {
|
||||||
return this.getTasks();
|
return this.getTasks();
|
||||||
|
@ -47,7 +54,6 @@ export class DetectTaskProvider implements vscode.TaskProvider {
|
||||||
}
|
}
|
||||||
this.tasks = [];
|
this.tasks = [];
|
||||||
var option: Options = {
|
var option: Options = {
|
||||||
env: ["程序执行所需额外环境变量:如 DISPALY=1"],
|
|
||||||
};
|
};
|
||||||
this.tasks!.push(this.getTask("被检测可执行程序", ["可执行程序参数(可选)"], option));
|
this.tasks!.push(this.getTask("被检测可执行程序", ["可执行程序参数(可选)"], option));
|
||||||
return this.tasks;
|
return this.tasks;
|
||||||
|
@ -77,16 +83,16 @@ class CustomBuildTaskTerminal implements vscode.Pseudoterminal {
|
||||||
onDidClose?: vscode.Event<number> = this.closeEmitter.event;
|
onDidClose?: vscode.Event<number> = this.closeEmitter.event;
|
||||||
private passwd: string | undefined;
|
private passwd: string | undefined;
|
||||||
private checkedPid: number = 0;
|
private checkedPid: number = 0;
|
||||||
|
private hadChecked: boolean = false;
|
||||||
constructor(private cmd: child.ChildProcessWithoutNullStreams | undefined, private context: vscode.ExtensionContext, private command: string, private args: string[], private option: Options, private getSharedState: () => string | undefined, private setSharedState: (state: string) => void) {
|
constructor(private cmd: child.ChildProcessWithoutNullStreams | undefined, private context: vscode.ExtensionContext, private command: string, private args: string[], private option: Options, private getSharedState: () => string | undefined, private setSharedState: (state: string) => void) {
|
||||||
}
|
}
|
||||||
|
|
||||||
open(initialDimensions: vscode.TerminalDimensions | undefined): void {
|
open(initialDimensions: vscode.TerminalDimensions | undefined): void {
|
||||||
// At this point we can start using the terminal.
|
// At this point we can start using the terminal.
|
||||||
if (this.command.length) {
|
if (this.command.length) {
|
||||||
let found = false;
|
let found = false;
|
||||||
vscode.workspace.workspaceFolders?.forEach((value)=>{
|
vscode.workspace.workspaceFolders?.forEach((value)=>{
|
||||||
// value.uri.fsPath
|
// value.uri.fsPath
|
||||||
if(this.command[0] == '/' && !found){
|
if(this.command[0] === '/' && !found){
|
||||||
this.option.cwd = value.uri.fsPath;
|
this.option.cwd = value.uri.fsPath;
|
||||||
found = true;
|
found = true;
|
||||||
}
|
}
|
||||||
|
@ -131,10 +137,35 @@ class CustomBuildTaskTerminal implements vscode.Pseudoterminal {
|
||||||
this.closeEmitter.fire(0);
|
this.closeEmitter.fire(0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private hijackCheck(){
|
||||||
|
// 注入方式
|
||||||
|
child.exec(`${hijackTool} ${this.checkedPid}`, (err, o, e)=>{
|
||||||
|
if(o.match(/normal/)?.length){
|
||||||
|
const webPanel = vscode.window.createWebviewPanel(
|
||||||
|
'detectResultWebview',
|
||||||
|
"检测结果",
|
||||||
|
vscode.ViewColumn.One,
|
||||||
|
{
|
||||||
|
enableScripts: true,
|
||||||
|
retainContextWhenHidden: true,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
webPanel.webview.html = prase_yaml2html(this.command, this.context.extensionPath, webPanel.webview, o);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
vscode.window.showInformationMessage("未检测到相关锁信息");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
close(): void {
|
close(): void {
|
||||||
if(this.cmd){
|
if(this.cmd){
|
||||||
kill(this.checkedPid, 9);
|
kill(this.checkedPid, 9);
|
||||||
vscode.window.showWarningMessage("检测任务已退出");
|
vscode.window.showWarningMessage("检测任务已退出");
|
||||||
|
if(isNotSupport && !this.hadChecked){
|
||||||
|
this.hadChecked = true;
|
||||||
|
this.hijackCheck();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -142,13 +173,18 @@ class CustomBuildTaskTerminal implements vscode.Pseudoterminal {
|
||||||
private async doExec(): Promise<void> {
|
private async doExec(): Promise<void> {
|
||||||
return new Promise<void>((resolve) => {
|
return new Promise<void>((resolve) => {
|
||||||
this.writeEmitter.fire('正在检测 ...\r\n');
|
this.writeEmitter.fire('正在检测 ...\r\n');
|
||||||
this.option.env?.forEach(e =>{
|
if(this.option.env){
|
||||||
let kv = e.split('=', 2);
|
Object.keys(this.option.env).forEach(key => {
|
||||||
if(kv.length === 2){
|
let value = this.option.env?.[key];
|
||||||
process.env[kv[0]] = kv[1];
|
process.env[key] = value;
|
||||||
}
|
});
|
||||||
});
|
}
|
||||||
let hadPid = false;
|
let hadPid = false;
|
||||||
|
if(isNotSupport){
|
||||||
|
// 库注入
|
||||||
|
this.hadChecked = false;
|
||||||
|
process.env["LD_PRELOAD"] = hijackLib;
|
||||||
|
}
|
||||||
let coption: child.SpawnOptionsWithoutStdio = {
|
let coption: child.SpawnOptionsWithoutStdio = {
|
||||||
env: process.env
|
env: process.env
|
||||||
};
|
};
|
||||||
|
@ -180,6 +216,11 @@ class CustomBuildTaskTerminal implements vscode.Pseudoterminal {
|
||||||
if(errmsg.length){
|
if(errmsg.length){
|
||||||
vscode.window.showErrorMessage(errmsg);
|
vscode.window.showErrorMessage(errmsg);
|
||||||
}
|
}
|
||||||
|
if(errmsg.length === 0 && isNotSupport && !this.hadChecked){
|
||||||
|
// 注入后锁分析
|
||||||
|
this.hadChecked = true;
|
||||||
|
this.hijackCheck();
|
||||||
|
}
|
||||||
this.writeEmitter.fire('被检测程序已终止 ... \r\n');
|
this.writeEmitter.fire('被检测程序已终止 ... \r\n');
|
||||||
const date = new Date();
|
const date = new Date();
|
||||||
this.setSharedState(date.toTimeString() + ' ' + date.toDateString());
|
this.setSharedState(date.toTimeString() + ' ' + date.toDateString());
|
||||||
|
@ -204,6 +245,10 @@ class CustomBuildTaskTerminal implements vscode.Pseudoterminal {
|
||||||
if(result.length >= 4){
|
if(result.length >= 4){
|
||||||
hadPid = true;
|
hadPid = true;
|
||||||
this.checkedPid = parseInt(result[3].trim());
|
this.checkedPid = parseInt(result[3].trim());
|
||||||
|
if(isNotSupport){
|
||||||
|
// 注入方式
|
||||||
|
return;
|
||||||
|
}
|
||||||
execDetect(this.passwd, result[1].trim(), this.checkedPid, (detectResult)=>{
|
execDetect(this.passwd, result[1].trim(), this.checkedPid, (detectResult)=>{
|
||||||
if(detectResult.match(/fatal/)?.length){
|
if(detectResult.match(/fatal/)?.length){
|
||||||
kill(this.checkedPid, 9);
|
kill(this.checkedPid, 9);
|
||||||
|
|
|
@ -5,7 +5,7 @@ import path = require('path');
|
||||||
import fs = require("fs");
|
import fs = require("fs");
|
||||||
import {DetectTaskProvider} from './detectTaskProvider';
|
import {DetectTaskProvider} from './detectTaskProvider';
|
||||||
import { homedir } from 'os';
|
import { homedir } from 'os';
|
||||||
import {exec} from 'child_process';
|
import {exec, execSync} from 'child_process';
|
||||||
import {testPwd} from './utils';
|
import {testPwd} from './utils';
|
||||||
import {doLocalPidLockAnalyse} from './analysePid';
|
import {doLocalPidLockAnalyse} from './analysePid';
|
||||||
// linux命令操作模块
|
// linux命令操作模块
|
||||||
|
@ -157,13 +157,27 @@ export function activate(context: vscode.ExtensionContext) {
|
||||||
vscode.window.showWarningMessage("检测环境失败, C/C++程序锁分析插件功能受限");
|
vscode.window.showWarningMessage("检测环境失败, C/C++程序锁分析插件功能受限");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
exec(`grep -r "^CONFIG_BPF_EVENTS=" /boot/config-${o}`, (e1, o1, err1)=>{
|
var kernelOptions: string[] = [
|
||||||
if(e1){
|
"CONFIG_UPROBES=y",
|
||||||
vscode.window.showWarningMessage("由于内核限制, C/C++程序锁分析插件功能受限");
|
"CONFIG_UPROBE_EVENTS=y",
|
||||||
return;
|
"CONFIG_TRACEPOINTS=y",
|
||||||
|
"CONFIG_PERF_EVENTS=y",
|
||||||
|
"CONFIG_BPF_EVENTS=y"
|
||||||
|
];
|
||||||
|
var isNotSupport = false;
|
||||||
|
fs.readFile(`/boot/config-${o}`, 'utf8', function (err, buffer) {
|
||||||
|
if(err){
|
||||||
|
isNotSupport = true;
|
||||||
|
}else{
|
||||||
|
var str = buffer.toString();
|
||||||
|
kernelOptions.forEach(elem=>{
|
||||||
|
if(!str.includes(elem)){
|
||||||
|
isNotSupport = true;
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
const workspaceRoot = (vscode.workspace.workspaceFolders && (vscode.workspace.workspaceFolders.length > 0)) ? vscode.workspace.workspaceFolders[0].uri.fsPath : homedir();
|
const workspaceRoot = (vscode.workspace.workspaceFolders && (vscode.workspace.workspaceFolders.length > 0)) ? vscode.workspace.workspaceFolders[0].uri.fsPath : homedir();
|
||||||
detectTaskProvider = vscode.tasks.registerTaskProvider(DetectTaskProvider.customBuildScriptType, new DetectTaskProvider(workspaceRoot, context));
|
detectTaskProvider = vscode.tasks.registerTaskProvider(DetectTaskProvider.customBuildScriptType, new DetectTaskProvider(workspaceRoot, context, isNotSupport));
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
context.subscriptions.push(...[disposable,disposable0]);
|
context.subscriptions.push(...[disposable,disposable0]);
|
||||||
|
|
|
@ -3,10 +3,11 @@ import * as vscode from 'vscode';
|
||||||
import { dirname, join } from 'path';
|
import { dirname, join } from 'path';
|
||||||
import * as YAML from 'yaml';
|
import * as YAML from 'yaml';
|
||||||
|
|
||||||
const archs = new Map([
|
export const archs = new Map([
|
||||||
["x86_64", "x86_64"],
|
["x86_64", "x86_64"],
|
||||||
["x64", "x86_64"],
|
["x64", "x86_64"],
|
||||||
["arm64", "arm64"]
|
["arm64", "arm64"],
|
||||||
|
["aarch64", "arm64"]
|
||||||
]);
|
]);
|
||||||
|
|
||||||
const myArch = archs.get(process.arch);
|
const myArch = archs.get(process.arch);
|
||||||
|
|
Loading…
Reference in New Issue