From a4d2ad6dfad9138c097144c4216682a602720b3c Mon Sep 17 00:00:00 2001 From: "Hana (Hyang-Ah) Kim" Date: Wed, 3 Jun 2020 20:05:57 +0000 Subject: [PATCH] third_party/tree-kill: vendor to fix the pgrep issue We will need to invoke the default pgrep (/usr/bin/pgrep) and prevent a buggy pgrep from getting in the way. This CL checks in the copy of tree-kill (tree-kill-1.2.2) under third_party. Updates golang/vscode-go#90 Change-Id: Ibd8d1ecb15a8a09c2d638eabff1c4069eff8c97b GitHub-Last-Rev: 591b59de138f614d4beefa25c507c668b660e385 GitHub-Pull-Request: golang/vscode-go#167 Reviewed-on: https://go-review.googlesource.com/c/vscode-go/+/236145 Reviewed-by: Rebecca Stambler --- .vscodeignore | 1 + package-lock.json | 3 +- package.json | 2 +- third_party/README.md | 26 +++++++ third_party/tree-kill/LICENSE | 21 +++++ third_party/tree-kill/README.md | 89 ++++++++++++++++++++++ third_party/tree-kill/cli.js | 14 ++++ third_party/tree-kill/index.d.ts | 13 ++++ third_party/tree-kill/index.js | 118 +++++++++++++++++++++++++++++ third_party/tree-kill/package.json | 82 ++++++++++++++++++++ tsconfig.json | 3 +- 11 files changed, 368 insertions(+), 4 deletions(-) create mode 100644 third_party/README.md create mode 100644 third_party/tree-kill/LICENSE create mode 100644 third_party/tree-kill/README.md create mode 100755 third_party/tree-kill/cli.js create mode 100644 third_party/tree-kill/index.d.ts create mode 100755 third_party/tree-kill/index.js create mode 100644 third_party/tree-kill/package.json diff --git a/.vscodeignore b/.vscodeignore index 9d45b80b5e..5de59889d7 100644 --- a/.vscodeignore +++ b/.vscodeignore @@ -1,5 +1,6 @@ src/**/* test/ +third_party/ typings/**/* .vscode/**/* tsconfig.json diff --git a/package-lock.json b/package-lock.json index e87fd0f068..33723b0c32 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1712,8 +1712,7 @@ } }, "tree-kill": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/tree-kill/-/tree-kill-1.2.2.tgz", + "version": "file:third_party/tree-kill", "integrity": "sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==" }, "tslib": { diff --git a/package.json b/package.json index 8fb9b57b75..6bdbcab763 100644 --- a/package.json +++ b/package.json @@ -51,7 +51,7 @@ "json-rpc2": "^1.0.2", "moment": "^2.24.0", "semver": "^7.3.2", - "tree-kill": "^1.2.2", + "tree-kill": "file:third_party/tree-kill", "vscode-debugadapter": "^1.40.0", "vscode-debugprotocol": "^1.40.0", "vscode-languageclient": "6.1.0", diff --git a/third_party/README.md b/third_party/README.md new file mode 100644 index 0000000000..07a562b238 --- /dev/null +++ b/third_party/README.md @@ -0,0 +1,26 @@ +# Vendored dependencies + +third_party directory contains code from the third party including +vendored modules that need local modifications (e.g. bug fixes or +necessary enhancement before they are incorporated and released +in the upstream). Every directory must contain LICENSE files. + +The vendored node modules still need to be specified in the dependencies. +For example, after copying the `tree-kill` module to this directory +and applying necessary local modification, run from the root of this +project directory: + +``` +$ npm install --save ./third_party/tree-kill + +``` + +This will update `package.json` and `package-lock.json` to point to +the local dependency. + +Note: We didn't test vendoring platform-dependent modules yet. + + +## List of local modification + +`tree-kill`: vendored 1.2.2 with a fix for https://github.com/golang/vscode-go/issues/90 diff --git a/third_party/tree-kill/LICENSE b/third_party/tree-kill/LICENSE new file mode 100644 index 0000000000..aa86c2df61 --- /dev/null +++ b/third_party/tree-kill/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2018 Peter Krumins + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/third_party/tree-kill/README.md b/third_party/tree-kill/README.md new file mode 100644 index 0000000000..59a00ea102 --- /dev/null +++ b/third_party/tree-kill/README.md @@ -0,0 +1,89 @@ +Tree Kill +========= + +Kill all processes in the process tree, including the root process. + +Examples +======= + +Kill all the descendent processes of the process with pid `1`, including the process with pid `1` itself: +```js +var kill = require('tree-kill'); +kill(1); +``` + +Send a signal other than SIGTERM.: +```js +var kill = require('tree-kill'); +kill(1, 'SIGKILL'); +``` + +Run a callback when done killing the processes. Passes an error argument if there was an error. +```js +var kill = require('tree-kill'); +kill(1, 'SIGKILL', function(err) { + // Do things +}); +``` + +You can also install tree-kill globally and use it as a command: +```sh +tree-kill 1 # sends SIGTERM to process 1 and its descendents +tree-kill 1 SIGTERM # same +tree-kill 1 SIGKILL # sends KILL instead of TERMINATE +``` + +Methods +======= + +## require('tree-kill')(pid, [signal], [callback]); + +Sends signal `signal` to all children processes of the process with pid `pid`, including `pid`. Signal defaults to `SIGTERM`. + +For Linux, this uses `ps -o pid --no-headers --ppid PID` to find the parent pids of `PID`. + +For Darwin/OSX, this uses `pgrep -P PID` to find the parent pids of `PID`. + +For Windows, this uses `'taskkill /pid PID /T /F'` to kill the process tree. Note that on Windows, sending the different kinds of POSIX signals is not possible. + +Install +======= + +With [npm](https://npmjs.org) do: + +``` +npm install tree-kill +``` + +License +======= + +MIT + +Changelog +========= + + +## [1.2.2] - 2019-12-11 +### Changed +- security fix: sanitize `pid` parameter to fix arbitrary code execution vulnerability + +## [1.2.1] - 2018-11-05 +### Changed +- added missing LICENSE file +- updated TypeScript definitions + +## [1.2.0] - 2017-09-19 +### Added +- TypeScript definitions +### Changed +- `kill(pid, callback)` works. Before you had to use `kill(pid, signal, callback)` + +## [1.1.0] - 2016-05-13 +### Added +- A `tree-kill` CLI + +## [1.0.0] - 2015-09-17 +### Added +- optional callback +- Darwin support diff --git a/third_party/tree-kill/cli.js b/third_party/tree-kill/cli.js new file mode 100755 index 0000000000..1acb815895 --- /dev/null +++ b/third_party/tree-kill/cli.js @@ -0,0 +1,14 @@ +#!/usr/bin/env node +kill = require('.') +try { + kill(process.argv[2], process.argv[3], function(err){ + if (err) { + console.log(err.message) + process.exit(1) + } + }) +} +catch (err) { + console.log(err.message) + process.exit(1) +} diff --git a/third_party/tree-kill/index.d.ts b/third_party/tree-kill/index.d.ts new file mode 100644 index 0000000000..e0b1302265 --- /dev/null +++ b/third_party/tree-kill/index.d.ts @@ -0,0 +1,13 @@ +/** + * Kills process identified by `pid` and all its children + * + * @param pid + * @param signal 'SIGTERM' by default + * @param callback + */ +declare function treeKill(pid: number, callback?: (error?: Error) => void): void; +declare function treeKill(pid: number, signal?: string | number, callback?: (error?: Error) => void): void; + +declare namespace treeKill {} + +export = treeKill; diff --git a/third_party/tree-kill/index.js b/third_party/tree-kill/index.js new file mode 100755 index 0000000000..8df6a0fb2f --- /dev/null +++ b/third_party/tree-kill/index.js @@ -0,0 +1,118 @@ +'use strict'; + +var childProcess = require('child_process'); +var spawn = childProcess.spawn; +var exec = childProcess.exec; + +module.exports = function (pid, signal, callback) { + if (typeof signal === 'function' && callback === undefined) { + callback = signal; + signal = undefined; + } + + pid = parseInt(pid); + if (Number.isNaN(pid)) { + if (callback) { + return callback(new Error("pid must be a number")); + } else { + throw new Error("pid must be a number"); + } + } + + var tree = {}; + var pidsToProcess = {}; + tree[pid] = []; + pidsToProcess[pid] = 1; + + switch (process.platform) { + case 'win32': + exec('taskkill /pid ' + pid + ' /T /F', callback); + break; + case 'darwin': + buildProcessTree(pid, tree, pidsToProcess, function (parentPid) { + return spawn('pgrep', ['-P', parentPid]); + }, function () { + killAll(tree, signal, callback); + }); + break; + // case 'sunos': + // buildProcessTreeSunOS(pid, tree, pidsToProcess, function () { + // killAll(tree, signal, callback); + // }); + // break; + default: // Linux + buildProcessTree(pid, tree, pidsToProcess, function (parentPid) { + return spawn('ps', ['-o', 'pid', '--no-headers', '--ppid', parentPid]); + }, function () { + killAll(tree, signal, callback); + }); + break; + } +}; + +function killAll (tree, signal, callback) { + var killed = {}; + try { + Object.keys(tree).forEach(function (pid) { + tree[pid].forEach(function (pidpid) { + if (!killed[pidpid]) { + killPid(pidpid, signal); + killed[pidpid] = 1; + } + }); + if (!killed[pid]) { + killPid(pid, signal); + killed[pid] = 1; + } + }); + } catch (err) { + if (callback) { + return callback(err); + } else { + throw err; + } + } + if (callback) { + return callback(); + } +} + +function killPid(pid, signal) { + try { + process.kill(parseInt(pid, 10), signal); + } + catch (err) { + if (err.code !== 'ESRCH') throw err; + } +} + +function buildProcessTree (parentPid, tree, pidsToProcess, spawnChildProcessesList, cb) { + var ps = spawnChildProcessesList(parentPid); + var allData = ''; + ps.stdout.on('data', function (data) { + var data = data.toString('ascii'); + allData += data; + }); + + var onClose = function (code) { + delete pidsToProcess[parentPid]; + + if (code != 0) { + // no more parent processes + if (Object.keys(pidsToProcess).length == 0) { + cb(); + } + return; + } + + allData.match(/\d+/g).forEach(function (pid) { + pid = parseInt(pid, 10); + tree[parentPid].push(pid); + tree[pid] = []; + pidsToProcess[pid] = 1; + buildProcessTree(pid, tree, pidsToProcess, spawnChildProcessesList, cb); + }); + }; + + ps.on('close', onClose); +} diff --git a/third_party/tree-kill/package.json b/third_party/tree-kill/package.json new file mode 100644 index 0000000000..68f0c49bbb --- /dev/null +++ b/third_party/tree-kill/package.json @@ -0,0 +1,82 @@ +{ + "_args": [ + [ + "tree-kill@1.2.2", + "/Users/hakim/projects/google/vscode-go" + ] + ], + "_from": "tree-kill@1.2.2", + "_id": "tree-kill@1.2.2", + "_inBundle": false, + "_integrity": "sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==", + "_location": "/tree-kill", + "_phantomChildren": {}, + "_requested": { + "type": "version", + "registry": true, + "raw": "tree-kill@1.2.2", + "name": "tree-kill", + "escapedName": "tree-kill", + "rawSpec": "1.2.2", + "saveSpec": null, + "fetchSpec": "1.2.2" + }, + "_requiredBy": [ + "/" + ], + "_resolved": "https://registry.npmjs.org/tree-kill/-/tree-kill-1.2.2.tgz", + "_spec": "1.2.2", + "_where": "/Users/hakim/projects/google/vscode-go", + "author": { + "name": "Peteris Krumins", + "email": "peteris.krumins@gmail.com", + "url": "http://www.catonmat.net" + }, + "bin": { + "tree-kill": "cli.js" + }, + "bugs": { + "url": "https://github.com/pkrumins/node-tree-kill/issues" + }, + "contributors": [ + { + "name": "Todd Wolfson", + "email": "todd@twolfson.com", + "url": "http://twolfson.com/" + }, + { + "name": "William Hilton", + "email": "wmhilton@gmail.com", + "url": "http://wmhilton.com/" + }, + { + "name": "Fabrício Matté", + "url": "http://ultcombo.js.org/" + } + ], + "description": "kill trees of processes", + "devDependencies": { + "mocha": "^2.2.5" + }, + "homepage": "https://github.com/pkrumins/node-tree-kill", + "keywords": [ + "tree", + "trees", + "process", + "processes", + "kill", + "signal" + ], + "license": "MIT", + "main": "index.js", + "name": "tree-kill", + "repository": { + "type": "git", + "url": "git://github.com/pkrumins/node-tree-kill.git" + }, + "scripts": { + "test": "mocha" + }, + "types": "index.d.ts", + "version": "1.2.2" +} diff --git a/tsconfig.json b/tsconfig.json index 4960e626e7..6045bef5f7 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -17,6 +17,7 @@ //"strictPropertyInitialization": true, }, "exclude": [ - "node_modules" + "node_modules", + "third_party" ] } \ No newline at end of file