Skip to content

Commit

Permalink
lib,src: audit process.env in lib/ for setuid binary
Browse files Browse the repository at this point in the history
Wrap SafeGetenv() in util binding with the purpose of protecting
the cases when env vars are accessed with the privileges of another
user in jsland.

PR-URL: #18511
Fixes: #9160
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Anna Henningsen <anna@addaleax.net>
Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl>
  • Loading branch information
j0t3x authored and BridgeAR committed Feb 16, 2018
1 parent ec9e792 commit 916cfec
Show file tree
Hide file tree
Showing 4 changed files with 31 additions and 7 deletions.
7 changes: 5 additions & 2 deletions lib/module.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ const {
internalModuleReadJSON,
internalModuleStat
} = process.binding('fs');
const { safeGetenv } = process.binding('util');
const internalModule = require('internal/module');
const preserveSymlinks = !!process.binding('config').preserveSymlinks;
const experimentalModules = !!process.binding('config').experimentalModules;
Expand Down Expand Up @@ -697,10 +698,13 @@ Module._initPaths = function() {
const isWindows = process.platform === 'win32';

var homeDir;
var nodePath;
if (isWindows) {
homeDir = process.env.USERPROFILE;
nodePath = process.env.NODE_PATH;
} else {
homeDir = process.env.HOME;
homeDir = safeGetenv('HOME');
nodePath = safeGetenv('NODE_PATH');
}

// $PREFIX/lib/node, where $PREFIX is the root of the Node.js installation.
Expand All @@ -719,7 +723,6 @@ Module._initPaths = function() {
paths.unshift(path.resolve(homeDir, '.node_modules'));
}

var nodePath = process.env.NODE_PATH;
if (nodePath) {
paths = nodePath.split(path.delimiter).filter(function(path) {
return !!path;
Expand Down
8 changes: 4 additions & 4 deletions lib/os.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@

'use strict';

const { pushValToArrayMax } = process.binding('util');
const { pushValToArrayMax, safeGetenv } = process.binding('util');
const constants = process.binding('constants').os;
const { deprecate } = require('internal/util');
const { getCIDRSuffix } = require('internal/os');
Expand Down Expand Up @@ -127,9 +127,9 @@ function tmpdir() {
if (path.length > 1 && path.endsWith('\\') && !path.endsWith(':\\'))
path = path.slice(0, -1);
} else {
path = process.env.TMPDIR ||
process.env.TMP ||
process.env.TEMP ||
path = safeGetenv('TMPDIR') ||
safeGetenv('TMP') ||
safeGetenv('TEMP') ||
'/tmp';
if (path.length > 1 && path.endsWith('/'))
path = path.slice(0, -1);
Expand Down
13 changes: 13 additions & 0 deletions src/node_util.cc
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ using v8::Object;
using v8::Private;
using v8::Promise;
using v8::Proxy;
using v8::String;
using v8::Value;


Expand Down Expand Up @@ -174,6 +175,16 @@ void PromiseReject(const FunctionCallbackInfo<Value>& args) {
args.GetReturnValue().Set(ret.FromMaybe(false));
}

void SafeGetenv(const FunctionCallbackInfo<Value>& args) {
CHECK(args[0]->IsString());
Utf8Value strenvtag(args.GetIsolate(), args[0]);
std::string text;
if (!node::SafeGetenv(*strenvtag, &text)) return;
args.GetReturnValue()
.Set(String::NewFromUtf8(
args.GetIsolate(), text.c_str(),
v8::NewStringType::kNormal).ToLocalChecked());
}

void Initialize(Local<Object> target,
Local<Value> unused,
Expand Down Expand Up @@ -225,6 +236,8 @@ void Initialize(Local<Object> target,
env->SetMethod(target, "createPromise", CreatePromise);
env->SetMethod(target, "promiseResolve", PromiseResolve);
env->SetMethod(target, "promiseReject", PromiseReject);

env->SetMethod(target, "safeGetenv", SafeGetenv);
}

} // namespace util
Expand Down
10 changes: 9 additions & 1 deletion test/parallel/test-util-internal.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,17 @@ const fixtures = require('../common/fixtures');
const {
getHiddenValue,
setHiddenValue,
arrow_message_private_symbol: kArrowMessagePrivateSymbolIndex
arrow_message_private_symbol: kArrowMessagePrivateSymbolIndex,
safeGetenv
} = process.binding('util');

for (const oneEnv in process.env) {
assert.strictEqual(
safeGetenv(oneEnv),
process.env[oneEnv]
);
}

assert.strictEqual(
getHiddenValue({}, kArrowMessagePrivateSymbolIndex),
undefined);
Expand Down

0 comments on commit 916cfec

Please sign in to comment.