diff --git a/node.gyp b/node.gyp index 778162119a0006..720d51946976b2 100644 --- a/node.gyp +++ b/node.gyp @@ -117,6 +117,7 @@ 'src/node_javascript.cc', 'src/node_main.cc', 'src/node_os.cc', + 'src/node_revert.cc', 'src/node_util.cc', 'src/node_v8.cc', 'src/node_stat_watcher.cc', @@ -156,6 +157,7 @@ 'src/node_version.h', 'src/node_watchdog.h', 'src/node_wrap.h', + 'src/node_revert.h', 'src/node_i18n.h', 'src/pipe_wrap.h', 'src/tty_wrap.h', diff --git a/src/node.cc b/src/node.cc index 65afc8c1fe02f2..830ff8b0106620 100644 --- a/src/node.cc +++ b/src/node.cc @@ -6,6 +6,7 @@ #include "node_javascript.h" #include "node_version.h" #include "node_internals.h" +#include "node_revert.h" #if defined HAVE_PERFCTR #include "node_counters.h" @@ -2976,6 +2977,16 @@ void SetupProcessObject(Environment* env, READONLY_PROPERTY(process, "traceDeprecation", True(env->isolate())); } + // --security-revert flags +#define V(code, _, __) \ + do { \ + if (IsReverted(REVERT_ ## code)) { \ + READONLY_PROPERTY(process, "REVERT_" #code, True(env->isolate())); \ + } \ + } while (0); + REVERSIONS(V) +#undef V + size_t exec_path_len = 2 * PATH_MAX; char* exec_path = new char[exec_path_len]; Local exec_path_value; @@ -3339,6 +3350,9 @@ static void ParseArgs(int* argc, track_heap_objects = true; } else if (strcmp(arg, "--throw-deprecation") == 0) { throw_deprecation = true; + } else if (strncmp(arg, "--security-revert=", 18) == 0) { + const char* cve = arg + 18; + Revert(cve); } else if (strcmp(arg, "--v8-options") == 0) { new_v8_argv[new_v8_argc] = "--help"; new_v8_argc += 1; diff --git a/src/node_revert.cc b/src/node_revert.cc new file mode 100644 index 00000000000000..7a4f59d0cdedcd --- /dev/null +++ b/src/node_revert.cc @@ -0,0 +1,53 @@ +#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 diff --git a/src/node_revert.h b/src/node_revert.h new file mode 100644 index 00000000000000..7a779ff4962e60 --- /dev/null +++ b/src/node_revert.h @@ -0,0 +1,43 @@ +#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_