Skip to content

Commit 3ef54df

Browse files
committed
fs: validate fd for sync calls on c++
1 parent 2e458d9 commit 3ef54df

File tree

3 files changed

+65
-36
lines changed

3 files changed

+65
-36
lines changed

lib/fs.js

Lines changed: 2 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -528,8 +528,6 @@ function close(fd, callback = defaultCloseCallback) {
528528
* @returns {void}
529529
*/
530530
function closeSync(fd) {
531-
fd = getValidatedFd(fd);
532-
533531
binding.close(fd);
534532
}
535533

@@ -709,8 +707,6 @@ ObjectDefineProperty(read, kCustomPromisifyArgsSymbol,
709707
* @returns {number}
710708
*/
711709
function readSync(fd, buffer, offsetOrOptions, length, position) {
712-
fd = getValidatedFd(fd);
713-
714710
validateBuffer(buffer);
715711

716712
let offset = offsetOrOptions;
@@ -798,7 +794,6 @@ ObjectDefineProperty(readv, kCustomPromisifyArgsSymbol,
798794
* @returns {number}
799795
*/
800796
function readvSync(fd, buffers, position) {
801-
fd = getValidatedFd(fd);
802797
validateBufferArray(buffers);
803798

804799
const ctx = {};
@@ -899,7 +894,6 @@ ObjectDefineProperty(write, kCustomPromisifyArgsSymbol,
899894
* @returns {number}
900895
*/
901896
function writeSync(fd, buffer, offsetOrOptions, length, position) {
902-
fd = getValidatedFd(fd);
903897
const ctx = {};
904898
let result;
905899

@@ -988,7 +982,6 @@ ObjectDefineProperty(writev, kCustomPromisifyArgsSymbol, {
988982
* @returns {number}
989983
*/
990984
function writevSync(fd, buffers, position) {
991-
fd = getValidatedFd(fd);
992985
validateBufferArray(buffers);
993986

994987
if (buffers.length === 0) {
@@ -1127,7 +1120,6 @@ function ftruncate(fd, len = 0, callback) {
11271120
* @returns {void}
11281121
*/
11291122
function ftruncateSync(fd, len = 0) {
1130-
fd = getValidatedFd(fd);
11311123
validateInteger(len, 'len');
11321124
len = MathMax(0, len);
11331125
binding.ftruncate(fd, len);
@@ -1293,7 +1285,6 @@ function fdatasync(fd, callback) {
12931285
* @returns {void}
12941286
*/
12951287
function fdatasyncSync(fd) {
1296-
fd = getValidatedFd(fd);
12971288
binding.fdatasync(fd);
12981289
}
12991290

@@ -1318,7 +1309,6 @@ function fsync(fd, callback) {
13181309
* @returns {void}
13191310
*/
13201311
function fsyncSync(fd) {
1321-
fd = getValidatedFd(fd);
13221312
binding.fsync(fd);
13231313
}
13241314

@@ -1622,7 +1612,6 @@ function statfs(path, options = { bigint: false }, callback) {
16221612
* @returns {Stats | undefined}
16231613
*/
16241614
function fstatSync(fd, options = { bigint: false }) {
1625-
fd = getValidatedFd(fd);
16261615
const stats = binding.fstat(fd, options.bigint, undefined, false);
16271616
if (stats === undefined) {
16281617
return;
@@ -1905,7 +1894,7 @@ function fchmod(fd, mode, callback) {
19051894
*/
19061895
function fchmodSync(fd, mode) {
19071896
binding.fchmod(
1908-
getValidatedFd(fd),
1897+
fd,
19091898
parseFileMode(mode, 'mode'),
19101899
);
19111900
}
@@ -2051,7 +2040,6 @@ function fchown(fd, uid, gid, callback) {
20512040
* @returns {void}
20522041
*/
20532042
function fchownSync(fd, uid, gid) {
2054-
fd = getValidatedFd(fd);
20552043
validateInteger(uid, 'uid', -1, kMaxUserId);
20562044
validateInteger(gid, 'gid', -1, kMaxUserId);
20572045

@@ -2168,7 +2156,7 @@ function futimes(fd, atime, mtime, callback) {
21682156
*/
21692157
function futimesSync(fd, atime, mtime) {
21702158
binding.futimes(
2171-
getValidatedFd(fd),
2159+
fd,
21722160
toUnixTimestamp(atime, 'atime'),
21732161
toUnixTimestamp(mtime, 'mtime'),
21742162
);

src/node_file.cc

Lines changed: 35 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838
#include "req_wrap-inl.h"
3939
#include "stream_base-inl.h"
4040
#include "string_bytes.h"
41+
#include "util.h"
4142

4243
#include <fcntl.h>
4344
#include <sys/types.h>
@@ -1405,13 +1406,14 @@ static void FTruncate(const FunctionCallbackInfo<Value>& args) {
14051406
const int argc = args.Length();
14061407
CHECK_GE(argc, 2);
14071408

1408-
CHECK(args[0]->IsInt32());
1409+
const bool is_async_call = argc > 2;
1410+
VALIDATE_FD(env, args[0], is_async_call);
14091411
const int fd = args[0].As<Int32>()->Value();
14101412

14111413
CHECK(IsSafeJsInt(args[1]));
14121414
const int64_t len = args[1].As<Integer>()->Value();
14131415

1414-
if (argc > 2) {
1416+
if (is_async_call) {
14151417
FSReqBase* req_wrap_async = GetReqWrap(args, 2);
14161418
FS_ASYNC_TRACE_BEGIN0(UV_FS_FTRUNCATE, req_wrap_async)
14171419
AsyncCall(env, req_wrap_async, args, "ftruncate", UTF8, AfterNoArgs,
@@ -1430,10 +1432,11 @@ static void Fdatasync(const FunctionCallbackInfo<Value>& args) {
14301432
const int argc = args.Length();
14311433
CHECK_GE(argc, 1);
14321434

1433-
CHECK(args[0]->IsInt32());
1435+
const bool is_async_call = argc > 1;
1436+
VALIDATE_FD(env, args[0], is_async_call);
14341437
const int fd = args[0].As<Int32>()->Value();
14351438

1436-
if (argc > 1) { // fdatasync(fd, req)
1439+
if (is_async_call) { // fdatasync(fd, req)
14371440
FSReqBase* req_wrap_async = GetReqWrap(args, 1);
14381441
CHECK_NOT_NULL(req_wrap_async);
14391442
FS_ASYNC_TRACE_BEGIN0(UV_FS_FDATASYNC, req_wrap_async)
@@ -1453,10 +1456,11 @@ static void Fsync(const FunctionCallbackInfo<Value>& args) {
14531456
const int argc = args.Length();
14541457
CHECK_GE(argc, 1);
14551458

1456-
CHECK(args[0]->IsInt32());
1459+
const bool is_async_call = argc > 1;
1460+
VALIDATE_FD(env, args[0], is_async_call);
14571461
const int fd = args[0].As<Int32>()->Value();
14581462

1459-
if (argc > 1) {
1463+
if (is_async_call) {
14601464
FSReqBase* req_wrap_async = GetReqWrap(args, 1);
14611465
CHECK_NOT_NULL(req_wrap_async);
14621466
FS_ASYNC_TRACE_BEGIN0(UV_FS_FSYNC, req_wrap_async)
@@ -2033,7 +2037,8 @@ static void WriteBuffer(const FunctionCallbackInfo<Value>& args) {
20332037
const int argc = args.Length();
20342038
CHECK_GE(argc, 4);
20352039

2036-
CHECK(args[0]->IsInt32());
2040+
const bool is_async_call = !args[5]->IsUndefined();
2041+
VALIDATE_FD(env, args[0], is_async_call);
20372042
const int fd = args[0].As<Int32>()->Value();
20382043

20392044
CHECK(Buffer::HasInstance(args[1]));
@@ -2088,7 +2093,8 @@ static void WriteBuffers(const FunctionCallbackInfo<Value>& args) {
20882093
const int argc = args.Length();
20892094
CHECK_GE(argc, 3);
20902095

2091-
CHECK(args[0]->IsInt32());
2096+
const bool is_async_call = argc > 3;
2097+
VALIDATE_FD(env, args[0], is_async_call);
20922098
const int fd = args[0].As<Int32>()->Value();
20932099

20942100
CHECK(args[1]->IsArray());
@@ -2104,7 +2110,7 @@ static void WriteBuffers(const FunctionCallbackInfo<Value>& args) {
21042110
iovs[i] = uv_buf_init(Buffer::Data(chunk), Buffer::Length(chunk));
21052111
}
21062112

2107-
if (argc > 3) { // writeBuffers(fd, chunks, pos, req)
2113+
if (is_async_call) { // writeBuffers(fd, chunks, pos, req)
21082114
FSReqBase* req_wrap_async = GetReqWrap(args, 3);
21092115
FS_ASYNC_TRACE_BEGIN0(UV_FS_WRITE, req_wrap_async)
21102116
AsyncCall(env,
@@ -2146,7 +2152,9 @@ static void WriteString(const FunctionCallbackInfo<Value>& args) {
21462152

21472153
const int argc = args.Length();
21482154
CHECK_GE(argc, 4);
2149-
CHECK(args[0]->IsInt32());
2155+
2156+
const bool is_async_call = !args[4]->IsUndefined();
2157+
VALIDATE_FD(env, args[0], is_async_call);
21502158
const int fd = args[0].As<Int32>()->Value();
21512159

21522160
const int64_t pos = GetOffset(args[2]);
@@ -2326,7 +2334,8 @@ static void Read(const FunctionCallbackInfo<Value>& args) {
23262334
const int argc = args.Length();
23272335
CHECK_GE(argc, 5);
23282336

2329-
CHECK(args[0]->IsInt32());
2337+
const bool is_async_call = argc > 5;
2338+
VALIDATE_FD(env, args[0], is_async_call);
23302339
const int fd = args[0].As<Int32>()->Value();
23312340

23322341
CHECK(Buffer::HasInstance(args[1]));
@@ -2352,7 +2361,7 @@ static void Read(const FunctionCallbackInfo<Value>& args) {
23522361
char* buf = buffer_data + off;
23532362
uv_buf_t uvbuf = uv_buf_init(buf, len);
23542363

2355-
if (argc > 5) { // read(fd, buffer, offset, len, pos, req)
2364+
if (is_async_call) { // read(fd, buffer, offset, len, pos, req)
23562365
FSReqBase* req_wrap_async = GetReqWrap(args, 5);
23572366
CHECK_NOT_NULL(req_wrap_async);
23582367
FS_ASYNC_TRACE_BEGIN0(UV_FS_READ, req_wrap_async)
@@ -2450,7 +2459,8 @@ static void ReadBuffers(const FunctionCallbackInfo<Value>& args) {
24502459
const int argc = args.Length();
24512460
CHECK_GE(argc, 3);
24522461

2453-
CHECK(args[0]->IsInt32());
2462+
const bool is_async_call = !args[3]->IsUndefined();
2463+
VALIDATE_FD(env, args[0], is_async_call);
24542464
const int fd = args[0].As<Int32>()->Value();
24552465

24562466
CHECK(args[1]->IsArray());
@@ -2467,8 +2477,8 @@ static void ReadBuffers(const FunctionCallbackInfo<Value>& args) {
24672477
iovs[i] = uv_buf_init(Buffer::Data(buffer), Buffer::Length(buffer));
24682478
}
24692479

2470-
FSReqBase* req_wrap_async = GetReqWrap(args, 3);
2471-
if (req_wrap_async != nullptr) { // readBuffers(fd, buffers, pos, req)
2480+
if (is_async_call) { // readBuffers(fd, buffers, pos, req)
2481+
FSReqBase* req_wrap_async = GetReqWrap(args, 3);
24722482
FS_ASYNC_TRACE_BEGIN0(UV_FS_READ, req_wrap_async)
24732483
AsyncCall(env, req_wrap_async, args, "read", UTF8, AfterInteger,
24742484
uv_fs_read, fd, *iovs, iovs.length(), pos);
@@ -2525,13 +2535,14 @@ static void FChmod(const FunctionCallbackInfo<Value>& args) {
25252535
const int argc = args.Length();
25262536
CHECK_GE(argc, 2);
25272537

2528-
CHECK(args[0]->IsInt32());
2538+
const bool is_async_call = argc > 2;
2539+
VALIDATE_FD(env, args[0], is_async_call);
25292540
const int fd = args[0].As<Int32>()->Value();
25302541

25312542
CHECK(args[1]->IsInt32());
25322543
const int mode = args[1].As<Int32>()->Value();
25332544

2534-
if (argc > 2) { // fchmod(fd, mode, req)
2545+
if (is_async_call) { // fchmod(fd, mode, req)
25352546
FSReqBase* req_wrap_async = GetReqWrap(args, 2);
25362547
FS_ASYNC_TRACE_BEGIN0(UV_FS_FCHMOD, req_wrap_async)
25372548
AsyncCall(env, req_wrap_async, args, "fchmod", UTF8, AfterNoArgs,
@@ -2588,7 +2599,8 @@ static void FChown(const FunctionCallbackInfo<Value>& args) {
25882599
const int argc = args.Length();
25892600
CHECK_GE(argc, 3);
25902601

2591-
CHECK(args[0]->IsInt32());
2602+
const bool is_async_call = !args[3]->IsUndefined();
2603+
VALIDATE_FD(env, args[0], is_async_call);
25922604
const int fd = args[0].As<Int32>()->Value();
25932605

25942606
CHECK(IsSafeJsInt(args[1]));
@@ -2597,8 +2609,8 @@ static void FChown(const FunctionCallbackInfo<Value>& args) {
25972609
CHECK(IsSafeJsInt(args[2]));
25982610
const uv_gid_t gid = static_cast<uv_gid_t>(args[2].As<Integer>()->Value());
25992611

2600-
FSReqBase* req_wrap_async = GetReqWrap(args, 3);
2601-
if (req_wrap_async != nullptr) { // fchown(fd, uid, gid, req)
2612+
if (is_async_call) { // fchown(fd, uid, gid, req)
2613+
FSReqBase* req_wrap_async = GetReqWrap(args, 3);
26022614
FS_ASYNC_TRACE_BEGIN0(UV_FS_FCHOWN, req_wrap_async)
26032615
AsyncCall(env, req_wrap_async, args, "fchown", UTF8, AfterNoArgs,
26042616
uv_fs_fchown, fd, uid, gid);
@@ -2683,7 +2695,8 @@ static void FUTimes(const FunctionCallbackInfo<Value>& args) {
26832695
const int argc = args.Length();
26842696
CHECK_GE(argc, 3);
26852697

2686-
CHECK(args[0]->IsInt32());
2698+
const bool is_async_call = argc > 3;
2699+
VALIDATE_FD(env, args[0], is_async_call);
26872700
const int fd = args[0].As<Int32>()->Value();
26882701

26892702
CHECK(args[1]->IsNumber());
@@ -2692,7 +2705,7 @@ static void FUTimes(const FunctionCallbackInfo<Value>& args) {
26922705
CHECK(args[2]->IsNumber());
26932706
const double mtime = args[2].As<Number>()->Value();
26942707

2695-
if (argc > 3) { // futimes(fd, atime, mtime, req)
2708+
if (is_async_call) { // futimes(fd, atime, mtime, req)
26962709
FSReqBase* req_wrap_async = GetReqWrap(args, 3);
26972710
FS_ASYNC_TRACE_BEGIN0(UV_FS_FUTIME, req_wrap_async)
26982711
AsyncCall(env, req_wrap_async, args, "futime", UTF8, AfterNoArgs,

src/util.h

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -195,6 +195,34 @@ void DumpJavaScriptBacktrace(FILE* fp);
195195
#define UNREACHABLE(...) \
196196
ERROR_AND_ABORT("Unreachable code reached" __VA_OPT__(": ") __VA_ARGS__)
197197

198+
#define VALIDATE_FD(env, input, is_async_call) \
199+
do { \
200+
if (is_async_call) { \
201+
CHECK(input->IsInt32()); \
202+
return; \
203+
} \
204+
if (!input->IsInt32()) { \
205+
Utf8Value value(env->isolate(), \
206+
input->ToString(env->context()).ToLocalChecked()); \
207+
Utf8Value type(env->isolate(), input->TypeOf(env->isolate())); \
208+
THROW_ERR_INVALID_ARG_TYPE(env, \
209+
"The \"fd\" argument must be of type " \
210+
"number. Received type %s (%s)", \
211+
type.out(), \
212+
value.out()); \
213+
return; \
214+
} \
215+
const int fd = input.As<Int32>()->Value(); \
216+
if (fd < 0 || fd > INT32_MAX) { \
217+
THROW_ERR_OUT_OF_RANGE(env, \
218+
"The value of \"fd\" is out of range. " \
219+
"It must be >= 0 && <= %s. Received %d", \
220+
std::to_string(INT32_MAX), \
221+
fd); \
222+
return; \
223+
} \
224+
} while (0);
225+
198226
// ECMA262 20.1.2.6 Number.MAX_SAFE_INTEGER (2^53-1)
199227
constexpr int64_t kMaxSafeJsInteger = 9007199254740991;
200228

0 commit comments

Comments
 (0)