From 85e1d9fb3d74e8ce109a1c2b6ed21f17beaa1e60 Mon Sep 17 00:00:00 2001 From: James M Snell Date: Wed, 3 Feb 2016 22:42:51 -0800 Subject: [PATCH] src: add --security-revert command line flag The `--security-revert={cvenum}` command line flag is a special purpose flag to be used only in stable or LTS branches when a breaking change is required to address a security vulnerability. Whenever a vulnerability requires a breaking change, and a CVE has been assigned, the flag can be used to force Node to revert to the insecure behavior that was implemented before the fix was applied. Note that this flag is intended to be used only as a last resort in the case a security update breaks existing code. When used, a security warning will be printed to stderr when Node launches. The `--security-revert={cvenum}` flag takes a single CVE number as an argument. Multiple instances of the `--security-revert={cvenum}` flag can be used on the command line to revert multiple changes. Whenever a new `--security-revert={cvenum}` is enabled, it should be documented in the release notes and in the API docs. Master and the first release of a new major (e.g. v6.0) should not have any reverts available. Every time a new `--security-revert={cvenum}` is added, there should be a semver-minor bump in the stable and LTS branch. PR-URL: https://github.com/nodejs/node-private/pull/22 --- node.gyp | 2 ++ src/node.cc | 15 ++++++++++ src/node_revert.cc | 73 ++++++++++++++++++++++++++++++++++++++++++++++ src/node_revert.h | 63 +++++++++++++++++++++++++++++++++++++++ 4 files changed, 153 insertions(+) create mode 100644 src/node_revert.cc create mode 100644 src/node_revert.h diff --git a/node.gyp b/node.gyp index 4243ece806d5a3..42051756074eba 100644 --- a/node.gyp +++ b/node.gyp @@ -87,6 +87,7 @@ 'src/node_javascript.cc', 'src/node_main.cc', 'src/node_os.cc', + 'src/node_revert.cc', 'src/node_script.cc', 'src/node_stat_watcher.cc', 'src/node_string.cc', @@ -113,6 +114,7 @@ 'src/node_http_parser.h', 'src/node_javascript.h', 'src/node_os.h', + 'src/node_revert.h', 'src/node_root_certs.h', 'src/node_script.h', 'src/node_string.h', diff --git a/src/node.cc b/src/node.cc index a8e1384e648f5f..cc67927cfd7a34 100644 --- a/src/node.cc +++ b/src/node.cc @@ -23,6 +23,7 @@ #include "req_wrap.h" #include "handle_wrap.h" #include "string_bytes.h" +#include "node_revert.h" #include "ares.h" #include "uv.h" @@ -2386,6 +2387,16 @@ Handle SetupProcessObject(int argc, char *argv[]) { process->Set(String::NewSymbol("traceDeprecation"), True()); } + // --security-revert flags +#define V(code, _, __) \ + do { \ + if (IsReverted(REVERT_ ## code)) { \ + process->Set(String::NewSymbol("REVERT_" #code), True()); \ + } \ + } while (0); + REVERSIONS(V) +#undef V + size_t size = 2*PATH_MAX; char* execPath = new char[size]; if (uv_exepath(execPath, &size) != 0) { @@ -2655,6 +2666,10 @@ static void ParseArgs(int argc, char **argv) { } else if (strcmp(arg, "--throw-deprecation") == 0) { argv[i] = const_cast(""); throw_deprecation = true; + } else if (strncmp(arg, "--security-revert=", 18) == 0) { + const char* cve = arg + 18; + argv[i] = const_cast(""); + Revert(cve); } else if (argv[i][0] != '-') { break; } diff --git a/src/node_revert.cc b/src/node_revert.cc new file mode 100644 index 00000000000000..58a87685d8410a --- /dev/null +++ b/src/node_revert.cc @@ -0,0 +1,73 @@ +// Copyright Node Contributors. +// +// 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. +#include "node_revert.h" +#include +#include + +namespace node { + +unsigned int reverted = 0; + +const char* RevertMessage(const unsigned int cve) { +#define V(code, label, msg) case REVERT_ ## code: return label ": " msg; + switch (cve) { + REVERSIONS(V) + default: + return "Unknown"; + } +#undef V +} + +void Revert(const unsigned int cve) { + reverted |= 1 << cve; + printf("SECURITY WARNING: Reverting %s\n", RevertMessage(cve)); +} + +void Revert(const char* cve) { +#define V(code, label, _) \ + do { \ + if (strcmp(cve, label) == 0) { \ + Revert(REVERT_ ## code); \ + return; \ + } \ + } while (0); + REVERSIONS(V) +#undef V + printf("Error: Attempt to revert an unknown CVE [%s]\n", cve); + exit(12); +} + +bool IsReverted(const unsigned int cve) { + return reverted & (1 << cve); +} + +bool IsReverted(const char * cve) { +#define V(code, label, _) \ + do { \ + if (strcmp(cve, label) == 0) \ + return IsReverted(REVERT_ ## code); \ + } while (0); + REVERSIONS(V) + return false; +#undef V +} + +} // namespace node \ No newline at end of file diff --git a/src/node_revert.h b/src/node_revert.h new file mode 100644 index 00000000000000..bbde63e6f6bb75 --- /dev/null +++ b/src/node_revert.h @@ -0,0 +1,63 @@ +// Copyright Node Contributors. +// +// 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. +#ifndef SRC_NODE_REVERT_H_ +#define SRC_NODE_REVERT_H_ + +#include "node.h" + +/** + * Note that it is expected for this list to vary across specific LTS and + * Stable versions! Only CVE's whose fixes require *breaking* changes within + * a given LTS or Stable may be added to this list, and only with CTC + * consensus. + * + * For *master* this list should always be empty! + * + **/ +#define REVERSIONS(XX) +// XX(CVE_2016_PEND, "CVE-2016-PEND", "Vulnerability Title") + +namespace node { + +typedef enum { +#define V(code, _, __) REVERT_ ## code, + REVERSIONS(V) +#undef V +} reversions_t; + +/* A bit field for tracking the active reverts */ +extern unsigned int reverted; + +/* Revert the given CVE (see reversions_t enum) */ +void Revert(const unsigned int cve); + +/* Revert the given CVE by label */ +void Revert(const char* cve); + +/* true if the CVE has been reverted **/ +bool IsReverted(const unsigned int cve); + +/* true if the CVE has been reverted **/ +bool IsReverted(const char * cve); + +} // namespace node + +#endif // SRC_NODE_REVERT_H_ \ No newline at end of file