Skip to content

Commit 5e70d2f

Browse files
committed
wip
1 parent 1ea5e42 commit 5e70d2f

File tree

6 files changed

+137
-138
lines changed

6 files changed

+137
-138
lines changed

js/private/js_binary.bzl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -209,7 +209,7 @@ _ATTRS = {
209209
the execroot, runfiles and the sandbox even when using the ESM loader.
210210
211211
This flag only has an effect when `patch_node_fs` is True.""",
212-
default = False,
212+
default = True,
213213
),
214214
"include_sources": attr.bool(
215215
doc = """When True, `sources` from `JsInfo` providers in `data` targets are included in the runfiles of the target.""",

js/private/node-patches/fs.cjs

Lines changed: 65 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -112,80 +112,82 @@ function patcher(roots, useInternalLstatPatch = false) {
112112
// =========================================================================
113113
// fs.lstat
114114
// =========================================================================
115-
fs.lstat = function lstat(...args) {
116-
// preserve error when calling function without required callback
117-
if (typeof args[args.length - 1] !== 'function') {
118-
return origLstat(...args);
119-
}
120-
const cb = once(args[args.length - 1]);
121-
// override the callback
122-
args[args.length - 1] = function lstatCb(err, stats) {
123-
if (err)
124-
return cb(err);
125-
if (!stats.isSymbolicLink()) {
115+
if (!useInternalLstatPatch) {
116+
fs.lstat = function lstat(...args) {
117+
// preserve error when calling function without required callback
118+
if (typeof args[args.length - 1] !== 'function') {
119+
return origLstat(...args);
120+
}
121+
const cb = once(args[args.length - 1]);
122+
// override the callback
123+
args[args.length - 1] = function lstatCb(err, stats) {
124+
if (err)
125+
return cb(err);
126+
if (!stats.isSymbolicLink()) {
127+
// the file is not a symbolic link so there is nothing more to do
128+
return cb(null, stats);
129+
}
130+
args[0] = resolvePathLike(args[0]);
131+
if (!canEscape(args[0])) {
132+
// the file can not escaped the sandbox so there is nothing more to do
133+
return cb(null, stats);
134+
}
135+
return guardedReadLink(args[0], guardedReadLinkCb);
136+
function guardedReadLinkCb(str) {
137+
if (str != args[0]) {
138+
// there are one or more hops within the guards so there is nothing more to do
139+
return cb(null, stats);
140+
}
141+
// there are no hops so lets report the stats of the real file;
142+
// we can't use origRealPath here since that function calls lstat internally
143+
// which can result in an infinite loop
144+
return unguardedRealPath(args[0], unguardedRealPathCb);
145+
function unguardedRealPathCb(err, str) {
146+
if (err) {
147+
if (err.code === 'ENOENT') {
148+
// broken link so there is nothing more to do
149+
return cb(null, stats);
150+
}
151+
return cb(err);
152+
}
153+
return origLstat(str, cb);
154+
}
155+
}
156+
};
157+
origLstat(...args);
158+
};
159+
fs.lstatSync = function lstatSync(...args) {
160+
const stats = origLstatSync(...args);
161+
if (!(stats === null || stats === void 0 ? void 0 : stats.isSymbolicLink())) {
126162
// the file is not a symbolic link so there is nothing more to do
127-
return cb(null, stats);
163+
return stats;
128164
}
129165
args[0] = resolvePathLike(args[0]);
130166
if (!canEscape(args[0])) {
131167
// the file can not escaped the sandbox so there is nothing more to do
132-
return cb(null, stats);
168+
return stats;
133169
}
134-
return guardedReadLink(args[0], guardedReadLinkCb);
135-
function guardedReadLinkCb(str) {
136-
if (str != args[0]) {
137-
// there are one or more hops within the guards so there is nothing more to do
138-
return cb(null, stats);
139-
}
170+
const guardedReadLink = guardedReadLinkSync(args[0]);
171+
if (guardedReadLink != args[0]) {
172+
// there are one or more hops within the guards so there is nothing more to do
173+
return stats;
174+
}
175+
try {
176+
args[0] = unguardedRealPathSync(args[0]);
140177
// there are no hops so lets report the stats of the real file;
141-
// we can't use origRealPath here since that function calls lstat internally
178+
// we can't use origRealPathSync here since that function calls lstat internally
142179
// which can result in an infinite loop
143-
return unguardedRealPath(args[0], unguardedRealPathCb);
144-
function unguardedRealPathCb(err, str) {
145-
if (err) {
146-
if (err.code === 'ENOENT') {
147-
// broken link so there is nothing more to do
148-
return cb(null, stats);
149-
}
150-
return cb(err);
151-
}
152-
return origLstat(str, cb);
180+
return origLstatSync(...args);
181+
}
182+
catch (err) {
183+
if (err.code === 'ENOENT') {
184+
// broken link so there is nothing more to do
185+
return stats;
153186
}
187+
throw err;
154188
}
155189
};
156-
origLstat(...args);
157-
};
158-
fs.lstatSync = function lstatSync(...args) {
159-
const stats = origLstatSync(...args);
160-
if (!(stats === null || stats === void 0 ? void 0 : stats.isSymbolicLink())) {
161-
// the file is not a symbolic link so there is nothing more to do
162-
return stats;
163-
}
164-
args[0] = resolvePathLike(args[0]);
165-
if (!canEscape(args[0])) {
166-
// the file can not escaped the sandbox so there is nothing more to do
167-
return stats;
168-
}
169-
const guardedReadLink = guardedReadLinkSync(args[0]);
170-
if (guardedReadLink != args[0]) {
171-
// there are one or more hops within the guards so there is nothing more to do
172-
return stats;
173-
}
174-
try {
175-
args[0] = unguardedRealPathSync(args[0]);
176-
// there are no hops so lets report the stats of the real file;
177-
// we can't use origRealPathSync here since that function calls lstat internally
178-
// which can result in an infinite loop
179-
return origLstatSync(...args);
180-
}
181-
catch (err) {
182-
if (err.code === 'ENOENT') {
183-
// broken link so there is nothing more to do
184-
return stats;
185-
}
186-
throw err;
187-
}
188-
};
190+
}
189191
// =========================================================================
190192
// fs.realpath
191193
// =========================================================================

js/private/node-patches/fs_stat.cjs

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -24,13 +24,6 @@ class FsInternalStatPatcher {
2424
patch() {
2525
const statPatcher = this;
2626
internalFs.lstat = function (path, bigint, reqCallback, throwIfNoEntry) {
27-
const currentStack = new Error().stack;
28-
const needsGuarding = currentStack &&
29-
(currentStack.includes('finalizeResolution (node:internal/modules/esm/resolve') &&
30-
!currentStack.includes('eeguardStats'));
31-
if (!needsGuarding) {
32-
return statPatcher._originalFsLstat.call(internalFs, path, bigint, reqCallback, throwIfNoEntry);
33-
}
3427
if (reqCallback === internalFs.kUsePromises) {
3528
return statPatcher._originalFsLstat.call(internalFs, path, bigint, reqCallback, throwIfNoEntry).then((stats) => {
3629
return new Promise((resolve, reject) => {

js/private/node-patches/src/fs.cts

Lines changed: 69 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -127,95 +127,97 @@ export function patcher(
127127
// fs.lstat
128128
// =========================================================================
129129

130-
fs.lstat = function lstat(...args: Parameters<typeof FsType.lstat>) {
131-
// preserve error when calling function without required callback
132-
if (typeof args[args.length - 1] !== 'function') {
133-
return origLstat(...args)
134-
}
135-
136-
const cb = once(args[args.length - 1] as Function)
137-
138-
// override the callback
139-
args[args.length - 1] = function lstatCb(err: Error, stats: Stats) {
140-
if (err) return cb(err)
141-
142-
if (!stats.isSymbolicLink()) {
143-
// the file is not a symbolic link so there is nothing more to do
144-
return cb(null, stats)
130+
if (!useInternalLstatPatch) {
131+
fs.lstat = function lstat(...args: Parameters<typeof FsType.lstat>) {
132+
// preserve error when calling function without required callback
133+
if (typeof args[args.length - 1] !== 'function') {
134+
return origLstat(...args)
145135
}
146136

147-
args[0] = resolvePathLike(args[0])
137+
const cb = once(args[args.length - 1] as any)
148138

149-
if (!canEscape(args[0])) {
150-
// the file can not escaped the sandbox so there is nothing more to do
151-
return cb(null, stats)
152-
}
139+
// override the callback
140+
args[args.length - 1] = function lstatCb(err: Error, stats: Stats) {
141+
if (err) return cb(err)
153142

154-
return guardedReadLink(args[0], guardedReadLinkCb)
143+
if (!stats.isSymbolicLink()) {
144+
// the file is not a symbolic link so there is nothing more to do
145+
return cb(null, stats)
146+
}
147+
148+
args[0] = resolvePathLike(args[0])
155149

156-
function guardedReadLinkCb(str: string) {
157-
if (str != args[0]) {
158-
// there are one or more hops within the guards so there is nothing more to do
150+
if (!canEscape(args[0])) {
151+
// the file can not escaped the sandbox so there is nothing more to do
159152
return cb(null, stats)
160153
}
161154

162-
// there are no hops so lets report the stats of the real file;
163-
// we can't use origRealPath here since that function calls lstat internally
164-
// which can result in an infinite loop
165-
return unguardedRealPath(args[0], unguardedRealPathCb)
155+
return guardedReadLink(args[0], guardedReadLinkCb)
166156

167-
function unguardedRealPathCb(err: Error, str: string) {
168-
if (err) {
169-
if ((err as any).code === 'ENOENT') {
170-
// broken link so there is nothing more to do
171-
return cb(null, stats)
157+
function guardedReadLinkCb(str: string) {
158+
if (str != args[0]) {
159+
// there are one or more hops within the guards so there is nothing more to do
160+
return cb(null, stats)
161+
}
162+
163+
// there are no hops so lets report the stats of the real file;
164+
// we can't use origRealPath here since that function calls lstat internally
165+
// which can result in an infinite loop
166+
return unguardedRealPath(args[0], unguardedRealPathCb)
167+
168+
function unguardedRealPathCb(err: Error, str: string) {
169+
if (err) {
170+
if ((err as any).code === 'ENOENT') {
171+
// broken link so there is nothing more to do
172+
return cb(null, stats)
173+
}
174+
return cb(err)
172175
}
173-
return cb(err)
176+
return origLstat(str, cb)
174177
}
175-
return origLstat(str, cb)
176178
}
177179
}
178-
}
179180

180-
origLstat(...args)
181-
}
182-
183-
fs.lstatSync = function lstatSync(
184-
...args: Parameters<typeof FsType.lstatSync>
185-
) {
186-
const stats = origLstatSync(...args)
187-
188-
if (!stats?.isSymbolicLink()) {
189-
// the file is not a symbolic link so there is nothing more to do
190-
return stats
181+
origLstat(...args)
191182
}
192183

193-
args[0] = resolvePathLike(args[0])
184+
fs.lstatSync = function lstatSync(
185+
...args: Parameters<typeof FsType.lstatSync>
186+
) {
187+
const stats = origLstatSync(...args)
194188

195-
if (!canEscape(args[0])) {
196-
// the file can not escaped the sandbox so there is nothing more to do
197-
return stats
198-
}
189+
if (!stats?.isSymbolicLink()) {
190+
// the file is not a symbolic link so there is nothing more to do
191+
return stats
192+
}
199193

200-
const guardedReadLink: string = guardedReadLinkSync(args[0])
201-
if (guardedReadLink != args[0]) {
202-
// there are one or more hops within the guards so there is nothing more to do
203-
return stats
204-
}
194+
args[0] = resolvePathLike(args[0])
205195

206-
try {
207-
args[0] = unguardedRealPathSync(args[0])
196+
if (!canEscape(args[0])) {
197+
// the file can not escaped the sandbox so there is nothing more to do
198+
return stats
199+
}
208200

209-
// there are no hops so lets report the stats of the real file;
210-
// we can't use origRealPathSync here since that function calls lstat internally
211-
// which can result in an infinite loop
212-
return origLstatSync(...args)
213-
} catch (err) {
214-
if (err.code === 'ENOENT') {
215-
// broken link so there is nothing more to do
201+
const guardedReadLink: string = guardedReadLinkSync(args[0])
202+
if (guardedReadLink != args[0]) {
203+
// there are one or more hops within the guards so there is nothing more to do
216204
return stats
217205
}
218-
throw err
206+
207+
try {
208+
args[0] = unguardedRealPathSync(args[0])
209+
210+
// there are no hops so lets report the stats of the real file;
211+
// we can't use origRealPathSync here since that function calls lstat internally
212+
// which can result in an infinite loop
213+
return origLstatSync(...args)
214+
} catch (err) {
215+
if (err.code === 'ENOENT') {
216+
// broken link so there is nothing more to do
217+
return stats
218+
}
219+
throw err
220+
}
219221
}
220222
}
221223

js/private/node-patches/src/fs_stat.cts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ export class FsInternalStatPatcher {
3636
!currentStack.includes('eeguardStats'));
3737

3838
if (!needsGuarding) {
39+
console.log("NO NEED: " + currentStack);
3940
return statPatcher._originalFsLstat.call(
4041
internalFs,
4142
path,

js/private/node_wrapper.sh

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ if [[ "${JS_BINARY__PATCH_NODE_ESM_LOADER:-}" == "1" ]]; then
99

1010
exec "$JS_BINARY__NODE_BINARY" \
1111
--expose-internals \
12+
--inspect-brk \
1213
--require "$JS_BINARY__NODE_PATCHES" "$@"
1314
else
1415
exec "$JS_BINARY__NODE_BINARY" --require "$JS_BINARY__NODE_PATCHES" "$@"

0 commit comments

Comments
 (0)