已开启
Fix CVE-2026-58039 #261
易大夫创建于 20 天前
Fix CVE-2026-58039 #261
已开启
共 3 个文件变更+512-0
| @@ -0,0 +1,166 @@ | |||
| 1 | +From 9a6b7e343a42061c44fa567d557fef7a347a8099 Mon Sep 17 00:00:00 2001 | ||
| 2 | +From: RafaelGSS <rafael.nunu@hotmail.com> | ||
| 3 | +Date: Fri, 26 Jun 2026 19:08:22 -0300 | ||
| 4 | +Subject: [PATCH] permission: check final report output path | ||
| 5 | + | ||
| 6 | +Refs: https://hackerone.com/reports/3815767 | ||
| 7 | +Signed-off-by: RafaelGSS <rafael.nunu@hotmail.com> | ||
| 8 | +PR-URL: https://github.com/nodejs-private/node-private/pull/926 | ||
| 9 | +CVE-ID: CVE-2026-58039 | ||
| 10 | +--- | ||
| 11 | + lib/internal/process/report.js | 10 ++- | ||
| 12 | + src/node_report.cc | 22 ++++--- | ||
| 13 | + .../test-permission-fs-write-report.js | 65 +++++++++++++++++++ | ||
| 14 | + 3 files changed, 86 insertions(+), 11 deletions(-) | ||
| 15 | + | ||
| 16 | +diff --git a/lib/internal/process/report.js b/lib/internal/process/report.js | ||
| 17 | +index 7b34af0e289f..c383dc8caeb8 100644 | ||
| 18 | +--- a/lib/internal/process/report.js | ||
| 19 | ++++ b/lib/internal/process/report.js | ||
| 20 | +@@ -9,6 +9,7 @@ const { | ||
| 21 | + ERR_SYNTHETIC, | ||
| 22 | + } = require('internal/errors').codes; | ||
| 23 | + const { getValidatedPath } = require('internal/fs/utils'); | ||
| 24 | ++const { sep } = require('path'); | ||
| 25 | + const permission = require('internal/process/permission'); | ||
| 26 | + const { | ||
| 27 | + validateBoolean, | ||
| 28 | +@@ -29,7 +30,14 @@ const report = { | ||
| 29 | + } | ||
| 30 | + | ||
| 31 | + if (permission.isEnabled()) { | ||
| 32 | +- const resource = file ?? process.cwd(); | ||
| 33 | ++ let resource = file; | ||
| 34 | ++ if (resource !== undefined) { | ||
| 35 | ++ const directory = nr.getDirectory(); | ||
| 36 | ++ if (directory !== '') | ||
| 37 | ++ resource = `${directory}${sep}${resource}`; | ||
| 38 | ++ } else { | ||
| 39 | ++ resource = process.cwd(); | ||
| 40 | ++ } | ||
| 41 | + if (!permission.has('fs.write', resource)) { | ||
| 42 | + throw new ERR_ACCESS_DENIED( | ||
| 43 | + 'Access to this API has been restricted', | ||
| 44 | +diff --git a/src/node_report.cc b/src/node_report.cc | ||
| 45 | +index ba2dd7e676bf..04c5d415c3c6 100644 | ||
| 46 | +--- a/src/node_report.cc | ||
| 47 | ++++ b/src/node_report.cc | ||
| 48 | +@@ -855,13 +855,6 @@ std::string TriggerNodeReport(Isolate* isolate, | ||
| 49 | + filename = *DiagnosticFilename( | ||
| 50 | + env != nullptr ? env->thread_id() : 0, "report", "json"); | ||
| 51 | + } | ||
| 52 | +- if (env != nullptr) { | ||
| 53 | +- THROW_IF_INSUFFICIENT_PERMISSIONS( | ||
| 54 | +- env, | ||
| 55 | +- permission::PermissionScope::kFileSystemWrite, | ||
| 56 | +- Environment::GetCwd(env->exec_path()), | ||
| 57 | +- filename); | ||
| 58 | +- } | ||
| 59 | + } | ||
| 60 | + | ||
| 61 | + // Open the report file stream for writing. Supports stdout/err, | ||
| 62 | +@@ -879,12 +872,21 @@ std::string TriggerNodeReport(Isolate* isolate, | ||
| 63 | + report_directory = per_process::cli_options->report_directory; | ||
| 64 | + } | ||
| 65 | + // Regular file. Append filename to directory path if one was specified | ||
| 66 | ++ std::string pathname; | ||
| 67 | + if (report_directory.length() > 0) { | ||
| 68 | +- std::string pathname = report_directory + kPathSeparator + filename; | ||
| 69 | +- outfile.open(pathname, std::ios::out | std::ios::binary); | ||
| 70 | ++ pathname = report_directory + kPathSeparator + filename; | ||
| 71 | + } else { | ||
| 72 | +- outfile.open(filename, std::ios::out | std::ios::binary); | ||
| 73 | ++ pathname = filename; | ||
| 74 | ++ } | ||
| 75 | ++ | ||
| 76 | ++ // We may not always be in a great state when generating a node report. | ||
| 77 | ++ // Allow for the case where we don't have an env. | ||
| 78 | ++ if (env != nullptr) { | ||
| 79 | ++ THROW_IF_INSUFFICIENT_PERMISSIONS( | ||
| 80 | ++ env, permission::PermissionScope::kFileSystemWrite, pathname, ""); | ||
| 81 | + } | ||
| 82 | ++ | ||
| 83 | ++ outfile.open(pathname, std::ios::out | std::ios::binary); | ||
| 84 | + // Check for errors on the file open | ||
| 85 | + if (!outfile.is_open()) { | ||
| 86 | + std::cerr << "\nFailed to open Node.js report file: " << filename; | ||
| 87 | +diff --git a/test/parallel/test-permission-fs-write-report.js b/test/parallel/test-permission-fs-write-report.js | ||
| 88 | +index 595f83b26807..728bc4d34c85 100644 | ||
| 89 | +--- a/test/parallel/test-permission-fs-write-report.js | ||
| 90 | ++++ b/test/parallel/test-permission-fs-write-report.js | ||
| 91 | +@@ -23,6 +23,7 @@ if (!process.permission) { | ||
| 92 | + } | ||
| 93 | + | ||
| 94 | + const assert = require('assert'); | ||
| 95 | ++const fs = require('fs'); | ||
| 96 | + const path = require('path'); | ||
| 97 | + const tmpdir = require('../common/tmpdir'); | ||
| 98 | + | ||
| 99 | +@@ -73,3 +74,67 @@ spawnSyncAndExitWithoutError( | ||
| 100 | + ], | ||
| 101 | + { cwd: tmpdir.path } | ||
| 102 | + ); | ||
| 103 | ++ | ||
| 104 | ++{ | ||
| 105 | ++ const allowedDir = path.join(tmpdir.path, 'report-allowed'); | ||
| 106 | ++ const deniedDir = path.join(tmpdir.path, 'report-denied'); | ||
| 107 | ++ fs.mkdirSync(allowedDir); | ||
| 108 | ++ fs.mkdirSync(deniedDir); | ||
| 109 | ++ | ||
| 110 | ++ const deniedFile = path.join(deniedDir, 'report.json'); | ||
| 111 | ++ fs.writeFileSync(deniedFile, 'existing content'); | ||
| 112 | ++ spawnSyncAndExitWithoutError( | ||
| 113 | ++ process.execPath, | ||
| 114 | ++ [ | ||
| 115 | ++ '--permission', | ||
| 116 | ++ '--allow-fs-read=*', | ||
| 117 | ++ `--allow-fs-write=${allowedDir}`, | ||
| 118 | ++ '-e', | ||
| 119 | ++ ` | ||
| 120 | ++ const assert = require('assert'); | ||
| 121 | ++ process.report.directory = ${JSON.stringify(deniedDir)}; | ||
| 122 | ++ assert.throws(() => { | ||
| 123 | ++ process.report.writeReport('report.json'); | ||
| 124 | ++ }, { | ||
| 125 | ++ code: 'ERR_ACCESS_DENIED', | ||
| 126 | ++ permission: 'FileSystemWrite', | ||
| 127 | ++ resource: ${JSON.stringify(deniedFile)}, | ||
| 128 | ++ }); | ||
| 129 | ++ `, | ||
| 130 | ++ ], | ||
| 131 | ++ { cwd: allowedDir }, | ||
| 132 | ++ ); | ||
| 133 | ++ assert.strictEqual(fs.readFileSync(deniedFile, 'utf8'), 'existing content'); | ||
| 134 | ++} | ||
| 135 | ++ | ||
| 136 | ++{ | ||
| 137 | ++ const allowedDir = path.join(tmpdir.path, 'report-filename-allowed'); | ||
| 138 | ++ const deniedDir = path.join(tmpdir.path, 'report-filename-denied'); | ||
| 139 | ++ fs.mkdirSync(allowedDir); | ||
| 140 | ++ fs.mkdirSync(deniedDir); | ||
| 141 | ++ | ||
| 142 | ++ const deniedFile = path.join(deniedDir, 'report.json'); | ||
| 143 | ++ spawnSyncAndExitWithoutError( | ||
| 144 | ++ process.execPath, | ||
| 145 | ++ [ | ||
| 146 | ++ '--permission', | ||
| 147 | ++ '--allow-fs-read=*', | ||
| 148 | ++ `--allow-fs-write=${allowedDir}`, | ||
| 149 | ++ '-e', | ||
| 150 | ++ ` | ||
| 151 | ++ const assert = require('assert'); | ||
| 152 | ++ process.report.directory = ${JSON.stringify(deniedDir)}; | ||
| 153 | ++ process.report.filename = 'report.json'; | ||
| 154 | ++ assert.throws(() => { | ||
| 155 | ++ process.report.writeReport(); | ||
| 156 | ++ }, { | ||
| 157 | ++ code: 'ERR_ACCESS_DENIED', | ||
| 158 | ++ permission: 'FileSystemWrite', | ||
| 159 | ++ resource: ${JSON.stringify(deniedFile)}, | ||
| 160 | ++ }); | ||
| 161 | ++ `, | ||
| 162 | ++ ], | ||
| 163 | ++ { cwd: allowedDir }, | ||
| 164 | ++ ); | ||
| 165 | ++ assert.strictEqual(fs.existsSync(deniedFile), false); | ||
| 166 | ++} | ||
| @@ -0,0 +1,166 @@ | |||
| 1 | +From ed18b9cc073f0b63268d6f2c84730b18e90fdd20 Mon Sep 17 00:00:00 2001 | ||
| 2 | +From: RafaelGSS <rafael.nunu@hotmail.com> | ||
| 3 | +Date: Fri, 26 Jun 2026 19:08:22 -0300 | ||
| 4 | +Subject: [PATCH] permission: check final report output path | ||
| 5 | + | ||
| 6 | +Refs: https://hackerone.com/reports/3815767 | ||
| 7 | +Signed-off-by: RafaelGSS <rafael.nunu@hotmail.com> | ||
| 8 | +PR-URL: https://github.com/nodejs-private/node-private/pull/926 | ||
| 9 | +CVE-ID: CVE-2026-58039 | ||
| 10 | +--- | ||
| 11 | + lib/internal/process/report.js | 10 ++- | ||
| 12 | + src/node_report.cc | 22 ++++--- | ||
| 13 | + .../test-permission-fs-write-report.js | 65 +++++++++++++++++++ | ||
| 14 | + 3 files changed, 86 insertions(+), 11 deletions(-) | ||
| 15 | + | ||
| 16 | +diff --git a/lib/internal/process/report.js b/lib/internal/process/report.js | ||
| 17 | +index 7b34af0e289f..c383dc8caeb8 100644 | ||
| 18 | +--- a/lib/internal/process/report.js | ||
| 19 | ++++ b/lib/internal/process/report.js | ||
| 20 | +@@ -9,6 +9,7 @@ const { | ||
| 21 | + ERR_SYNTHETIC, | ||
| 22 | + } = require('internal/errors').codes; | ||
| 23 | + const { getValidatedPath } = require('internal/fs/utils'); | ||
| 24 | ++const { sep } = require('path'); | ||
| 25 | + const permission = require('internal/process/permission'); | ||
| 26 | + const { | ||
| 27 | + validateBoolean, | ||
| 28 | +@@ -29,7 +30,14 @@ const report = { | ||
| 29 | + } | ||
| 30 | + | ||
| 31 | + if (permission.isEnabled()) { | ||
| 32 | +- const resource = file ?? process.cwd(); | ||
| 33 | ++ let resource = file; | ||
| 34 | ++ if (resource !== undefined) { | ||
| 35 | ++ const directory = nr.getDirectory(); | ||
| 36 | ++ if (directory !== '') | ||
| 37 | ++ resource = `${directory}${sep}${resource}`; | ||
| 38 | ++ } else { | ||
| 39 | ++ resource = process.cwd(); | ||
| 40 | ++ } | ||
| 41 | + if (!permission.has('fs.write', resource)) { | ||
| 42 | + throw new ERR_ACCESS_DENIED( | ||
| 43 | + 'Access to this API has been restricted', | ||
| 44 | +diff --git a/src/node_report.cc b/src/node_report.cc | ||
| 45 | +index e1f4e30417d1..ead720dd02dd 100644 | ||
| 46 | +--- a/src/node_report.cc | ||
| 47 | ++++ b/src/node_report.cc | ||
| 48 | +@@ -851,13 +851,6 @@ std::string TriggerNodeReport(Isolate* isolate, | ||
| 49 | + filename = *DiagnosticFilename( | ||
| 50 | + env != nullptr ? env->thread_id() : 0, "report", "json"); | ||
| 51 | + } | ||
| 52 | +- if (env != nullptr) { | ||
| 53 | +- THROW_IF_INSUFFICIENT_PERMISSIONS( | ||
| 54 | +- env, | ||
| 55 | +- permission::PermissionScope::kFileSystemWrite, | ||
| 56 | +- Environment::GetCwd(env->exec_path()), | ||
| 57 | +- filename); | ||
| 58 | +- } | ||
| 59 | + } | ||
| 60 | + | ||
| 61 | + // Open the report file stream for writing. Supports stdout/err, | ||
| 62 | +@@ -875,12 +868,21 @@ std::string TriggerNodeReport(Isolate* isolate, | ||
| 63 | + report_directory = per_process::cli_options->report_directory; | ||
| 64 | + } | ||
| 65 | + // Regular file. Append filename to directory path if one was specified | ||
| 66 | ++ std::string pathname; | ||
| 67 | + if (report_directory.length() > 0) { | ||
| 68 | +- std::string pathname = report_directory + kPathSeparator + filename; | ||
| 69 | +- outfile.open(pathname, std::ios::out | std::ios::binary); | ||
| 70 | ++ pathname = report_directory + kPathSeparator + filename; | ||
| 71 | + } else { | ||
| 72 | +- outfile.open(filename, std::ios::out | std::ios::binary); | ||
| 73 | ++ pathname = filename; | ||
| 74 | ++ } | ||
| 75 | ++ | ||
| 76 | ++ // We may not always be in a great state when generating a node report. | ||
| 77 | ++ // Allow for the case where we don't have an env. | ||
| 78 | ++ if (env != nullptr) { | ||
| 79 | ++ THROW_IF_INSUFFICIENT_PERMISSIONS( | ||
| 80 | ++ env, permission::PermissionScope::kFileSystemWrite, pathname, ""); | ||
| 81 | + } | ||
| 82 | ++ | ||
| 83 | ++ outfile.open(pathname, std::ios::out | std::ios::binary); | ||
| 84 | + // Check for errors on the file open | ||
| 85 | + if (!outfile.is_open()) { | ||
| 86 | + std::cerr << "\nFailed to open Node.js report file: " << filename; | ||
| 87 | +diff --git a/test/parallel/test-permission-fs-write-report.js b/test/parallel/test-permission-fs-write-report.js | ||
| 88 | +index 595f83b26807..728bc4d34c85 100644 | ||
| 89 | +--- a/test/parallel/test-permission-fs-write-report.js | ||
| 90 | ++++ b/test/parallel/test-permission-fs-write-report.js | ||
| 91 | +@@ -23,6 +23,7 @@ if (!process.permission) { | ||
| 92 | + } | ||
| 93 | + | ||
| 94 | + const assert = require('assert'); | ||
| 95 | ++const fs = require('fs'); | ||
| 96 | + const path = require('path'); | ||
| 97 | + const tmpdir = require('../common/tmpdir'); | ||
| 98 | + | ||
| 99 | +@@ -73,3 +74,67 @@ spawnSyncAndExitWithoutError( | ||
| 100 | + ], | ||
| 101 | + { cwd: tmpdir.path } | ||
| 102 | + ); | ||
| 103 | ++ | ||
| 104 | ++{ | ||
| 105 | ++ const allowedDir = path.join(tmpdir.path, 'report-allowed'); | ||
| 106 | ++ const deniedDir = path.join(tmpdir.path, 'report-denied'); | ||
| 107 | ++ fs.mkdirSync(allowedDir); | ||
| 108 | ++ fs.mkdirSync(deniedDir); | ||
| 109 | ++ | ||
| 110 | ++ const deniedFile = path.join(deniedDir, 'report.json'); | ||
| 111 | ++ fs.writeFileSync(deniedFile, 'existing content'); | ||
| 112 | ++ spawnSyncAndExitWithoutError( | ||
| 113 | ++ process.execPath, | ||
| 114 | ++ [ | ||
| 115 | ++ '--permission', | ||
| 116 | ++ '--allow-fs-read=*', | ||
| 117 | ++ `--allow-fs-write=${allowedDir}`, | ||
| 118 | ++ '-e', | ||
| 119 | ++ ` | ||
| 120 | ++ const assert = require('assert'); | ||
| 121 | ++ process.report.directory = ${JSON.stringify(deniedDir)}; | ||
| 122 | ++ assert.throws(() => { | ||
| 123 | ++ process.report.writeReport('report.json'); | ||
| 124 | ++ }, { | ||
| 125 | ++ code: 'ERR_ACCESS_DENIED', | ||
| 126 | ++ permission: 'FileSystemWrite', | ||
| 127 | ++ resource: ${JSON.stringify(deniedFile)}, | ||
| 128 | ++ }); | ||
| 129 | ++ `, | ||
| 130 | ++ ], | ||
| 131 | ++ { cwd: allowedDir }, | ||
| 132 | ++ ); | ||
| 133 | ++ assert.strictEqual(fs.readFileSync(deniedFile, 'utf8'), 'existing content'); | ||
| 134 | ++} | ||
| 135 | ++ | ||
| 136 | ++{ | ||
| 137 | ++ const allowedDir = path.join(tmpdir.path, 'report-filename-allowed'); | ||
| 138 | ++ const deniedDir = path.join(tmpdir.path, 'report-filename-denied'); | ||
| 139 | ++ fs.mkdirSync(allowedDir); | ||
| 140 | ++ fs.mkdirSync(deniedDir); | ||
| 141 | ++ | ||
| 142 | ++ const deniedFile = path.join(deniedDir, 'report.json'); | ||
| 143 | ++ spawnSyncAndExitWithoutError( | ||
| 144 | ++ process.execPath, | ||
| 145 | ++ [ | ||
| 146 | ++ '--permission', | ||
| 147 | ++ '--allow-fs-read=*', | ||
| 148 | ++ `--allow-fs-write=${allowedDir}`, | ||
| 149 | ++ '-e', | ||
| 150 | ++ ` | ||
| 151 | ++ const assert = require('assert'); | ||
| 152 | ++ process.report.directory = ${JSON.stringify(deniedDir)}; | ||
| 153 | ++ process.report.filename = 'report.json'; | ||
| 154 | ++ assert.throws(() => { | ||
| 155 | ++ process.report.writeReport(); | ||
| 156 | ++ }, { | ||
| 157 | ++ code: 'ERR_ACCESS_DENIED', | ||
| 158 | ++ permission: 'FileSystemWrite', | ||
| 159 | ++ resource: ${JSON.stringify(deniedFile)}, | ||
| 160 | ++ }); | ||
| 161 | ++ `, | ||
| 162 | ++ ], | ||
| 163 | ++ { cwd: allowedDir }, | ||
| 164 | ++ ); | ||
| 165 | ++ assert.strictEqual(fs.existsSync(deniedFile), false); | ||
| 166 | ++} | ||
| @@ -0,0 +1,180 @@ | |||
| 1 | +From 61222008b756c6da5e5ccad39e49bb5764379d21 Mon Sep 17 00:00:00 2001 | ||
| 2 | +From: RafaelGSS <rafael.nunu@hotmail.com> | ||
| 3 | +Date: Fri, 26 Jun 2026 19:08:22 -0300 | ||
| 4 | +Subject: [PATCH] permission: check final report output path | ||
| 5 | + | ||
| 6 | +Refs: https://hackerone.com/reports/3815767 | ||
| 7 | +Signed-off-by: RafaelGSS <rafael.nunu@hotmail.com> | ||
| 8 | +PR-URL: https://github.com/nodejs-private/node-private/pull/908 | ||
| 9 | +CVE-ID: CVE-2026-58039 | ||
| 10 | +--- | ||
| 11 | + lib/internal/process/report.js | 10 ++- | ||
| 12 | + src/node_report.cc | 29 ++++----- | ||
| 13 | + .../test-permission-fs-write-report.js | 65 +++++++++++++++++++ | ||
| 14 | + 3 files changed, 86 insertions(+), 18 deletions(-) | ||
| 15 | + | ||
| 16 | +diff --git a/lib/internal/process/report.js b/lib/internal/process/report.js | ||
| 17 | +index 7b34af0e289f..c383dc8caeb8 100644 | ||
| 18 | +--- a/lib/internal/process/report.js | ||
| 19 | ++++ b/lib/internal/process/report.js | ||
| 20 | +@@ -9,6 +9,7 @@ const { | ||
| 21 | + ERR_SYNTHETIC, | ||
| 22 | + } = require('internal/errors').codes; | ||
| 23 | + const { getValidatedPath } = require('internal/fs/utils'); | ||
| 24 | ++const { sep } = require('path'); | ||
| 25 | + const permission = require('internal/process/permission'); | ||
| 26 | + const { | ||
| 27 | + validateBoolean, | ||
| 28 | +@@ -29,7 +30,14 @@ const report = { | ||
| 29 | + } | ||
| 30 | + | ||
| 31 | + if (permission.isEnabled()) { | ||
| 32 | +- const resource = file ?? process.cwd(); | ||
| 33 | ++ let resource = file; | ||
| 34 | ++ if (resource !== undefined) { | ||
| 35 | ++ const directory = nr.getDirectory(); | ||
| 36 | ++ if (directory !== '') | ||
| 37 | ++ resource = `${directory}${sep}${resource}`; | ||
| 38 | ++ } else { | ||
| 39 | ++ resource = process.cwd(); | ||
| 40 | ++ } | ||
| 41 | + if (!permission.has('fs.write', resource)) { | ||
| 42 | + throw new ERR_ACCESS_DENIED( | ||
| 43 | + 'Access to this API has been restricted', | ||
| 44 | +diff --git a/src/node_report.cc b/src/node_report.cc | ||
| 45 | +index 5400ef9f4dbf..a1c954c91e64 100644 | ||
| 46 | +--- a/src/node_report.cc | ||
| 47 | ++++ b/src/node_report.cc | ||
| 48 | +@@ -835,13 +835,6 @@ std::string TriggerNodeReport(Isolate* isolate, | ||
| 49 | + // 1) supplied on API 2) configured on startup 3) default generated | ||
| 50 | + if (!name.empty()) { | ||
| 51 | + filename = name; | ||
| 52 | +- // we may not always be in a great state when generating a node report | ||
| 53 | +- // allow for the case where we don't have an env | ||
| 54 | +- if (env != nullptr) { | ||
| 55 | +- THROW_IF_INSUFFICIENT_PERMISSIONS( | ||
| 56 | +- env, permission::PermissionScope::kFileSystemWrite, name, filename); | ||
| 57 | +- // Filename was specified as API parameter. | ||
| 58 | +- } | ||
| 59 | + } else { | ||
| 60 | + std::string report_filename; | ||
| 61 | + { | ||
| 62 | +@@ -855,13 +848,6 @@ std::string TriggerNodeReport(Isolate* isolate, | ||
| 63 | + filename = *DiagnosticFilename( | ||
| 64 | + env != nullptr ? env->thread_id() : 0, "report", "json"); | ||
| 65 | + } | ||
| 66 | +- if (env != nullptr) { | ||
| 67 | +- THROW_IF_INSUFFICIENT_PERMISSIONS( | ||
| 68 | +- env, | ||
| 69 | +- permission::PermissionScope::kFileSystemWrite, | ||
| 70 | +- Environment::GetCwd(env->exec_path()), | ||
| 71 | +- filename); | ||
| 72 | +- } | ||
| 73 | + } | ||
| 74 | + | ||
| 75 | + // Open the report file stream for writing. Supports stdout/err, | ||
| 76 | +@@ -879,12 +865,21 @@ std::string TriggerNodeReport(Isolate* isolate, | ||
| 77 | + report_directory = per_process::cli_options->report_directory; | ||
| 78 | + } | ||
| 79 | + // Regular file. Append filename to directory path if one was specified | ||
| 80 | ++ std::string pathname; | ||
| 81 | + if (report_directory.length() > 0) { | ||
| 82 | +- std::string pathname = report_directory + kPathSeparator + filename; | ||
| 83 | +- outfile.open(pathname, std::ios::out | std::ios::binary); | ||
| 84 | ++ pathname = report_directory + kPathSeparator + filename; | ||
| 85 | + } else { | ||
| 86 | +- outfile.open(filename, std::ios::out | std::ios::binary); | ||
| 87 | ++ pathname = filename; | ||
| 88 | + } | ||
| 89 | ++ | ||
| 90 | ++ // We may not always be in a great state when generating a node report. | ||
| 91 | ++ // Allow for the case where we don't have an env. | ||
| 92 | ++ if (env != nullptr) { | ||
| 93 | ++ THROW_IF_INSUFFICIENT_PERMISSIONS( | ||
| 94 | ++ env, permission::PermissionScope::kFileSystemWrite, pathname, ""); | ||
| 95 | ++ } | ||
| 96 | ++ | ||
| 97 | ++ outfile.open(pathname, std::ios::out | std::ios::binary); | ||
| 98 | + // Check for errors on the file open | ||
| 99 | + if (!outfile.is_open()) { | ||
| 100 | + std::cerr << "\nFailed to open Node.js report file: " << filename; | ||
| 101 | +diff --git a/test/parallel/test-permission-fs-write-report.js b/test/parallel/test-permission-fs-write-report.js | ||
| 102 | +index 595f83b26807..728bc4d34c85 100644 | ||
| 103 | +--- a/test/parallel/test-permission-fs-write-report.js | ||
| 104 | ++++ b/test/parallel/test-permission-fs-write-report.js | ||
| 105 | +@@ -23,6 +23,7 @@ if (!process.permission) { | ||
| 106 | + } | ||
| 107 | + | ||
| 108 | + const assert = require('assert'); | ||
| 109 | ++const fs = require('fs'); | ||
| 110 | + const path = require('path'); | ||
| 111 | + const tmpdir = require('../common/tmpdir'); | ||
| 112 | + | ||
| 113 | +@@ -73,3 +74,67 @@ spawnSyncAndExitWithoutError( | ||
| 114 | + ], | ||
| 115 | + { cwd: tmpdir.path } | ||
| 116 | + ); | ||
| 117 | ++ | ||
| 118 | ++{ | ||
| 119 | ++ const allowedDir = path.join(tmpdir.path, 'report-allowed'); | ||
| 120 | ++ const deniedDir = path.join(tmpdir.path, 'report-denied'); | ||
| 121 | ++ fs.mkdirSync(allowedDir); | ||
| 122 | ++ fs.mkdirSync(deniedDir); | ||
| 123 | ++ | ||
| 124 | ++ const deniedFile = path.join(deniedDir, 'report.json'); | ||
| 125 | ++ fs.writeFileSync(deniedFile, 'existing content'); | ||
| 126 | ++ spawnSyncAndExitWithoutError( | ||
| 127 | ++ process.execPath, | ||
| 128 | ++ [ | ||
| 129 | ++ '--permission', | ||
| 130 | ++ '--allow-fs-read=*', | ||
| 131 | ++ `--allow-fs-write=${allowedDir}`, | ||
| 132 | ++ '-e', | ||
| 133 | ++ ` | ||
| 134 | ++ const assert = require('assert'); | ||
| 135 | ++ process.report.directory = ${JSON.stringify(deniedDir)}; | ||
| 136 | ++ assert.throws(() => { | ||
| 137 | ++ process.report.writeReport('report.json'); | ||
| 138 | ++ }, { | ||
| 139 | ++ code: 'ERR_ACCESS_DENIED', | ||
| 140 | ++ permission: 'FileSystemWrite', | ||
| 141 | ++ resource: ${JSON.stringify(deniedFile)}, | ||
| 142 | ++ }); | ||
| 143 | ++ `, | ||
| 144 | ++ ], | ||
| 145 | ++ { cwd: allowedDir }, | ||
| 146 | ++ ); | ||
| 147 | ++ assert.strictEqual(fs.readFileSync(deniedFile, 'utf8'), 'existing content'); | ||
| 148 | ++} | ||
| 149 | ++ | ||
| 150 | ++{ | ||
| 151 | ++ const allowedDir = path.join(tmpdir.path, 'report-filename-allowed'); | ||
| 152 | ++ const deniedDir = path.join(tmpdir.path, 'report-filename-denied'); | ||
| 153 | ++ fs.mkdirSync(allowedDir); | ||
| 154 | ++ fs.mkdirSync(deniedDir); | ||
| 155 | ++ | ||
| 156 | ++ const deniedFile = path.join(deniedDir, 'report.json'); | ||
| 157 | ++ spawnSyncAndExitWithoutError( | ||
| 158 | ++ process.execPath, | ||
| 159 | ++ [ | ||
| 160 | ++ '--permission', | ||
| 161 | ++ '--allow-fs-read=*', | ||
| 162 | ++ `--allow-fs-write=${allowedDir}`, | ||
| 163 | ++ '-e', | ||
| 164 | ++ ` | ||
| 165 | ++ const assert = require('assert'); | ||
| 166 | ++ process.report.directory = ${JSON.stringify(deniedDir)}; | ||
| 167 | ++ process.report.filename = 'report.json'; | ||
| 168 | ++ assert.throws(() => { | ||
| 169 | ++ process.report.writeReport(); | ||
| 170 | ++ }, { | ||
| 171 | ++ code: 'ERR_ACCESS_DENIED', | ||
| 172 | ++ permission: 'FileSystemWrite', | ||
| 173 | ++ resource: ${JSON.stringify(deniedFile)}, | ||
| 174 | ++ }); | ||
| 175 | ++ `, | ||
| 176 | ++ ], | ||
| 177 | ++ { cwd: allowedDir }, | ||
| 178 | ++ ); | ||
| 179 | ++ assert.strictEqual(fs.existsSync(deniedFile), false); | ||
| 180 | ++} | ||