frida-fs 4.0.0 → 5.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/README.md +10 -0
  2. package/index.js +75 -21
  3. package/package.json +5 -2
package/README.md CHANGED
@@ -9,3 +9,13 @@ const fs = require('frida-fs');
9
9
 
10
10
  fs.createReadStream('/etc/hosts').pipe(networkStream);
11
11
  ```
12
+
13
+ ```js
14
+ const fs = require('frida-fs');
15
+
16
+ for (const elm of fs.list("/proc/self/")) {
17
+ console.log(JSON.stringify(elm));
18
+ }
19
+
20
+ console.log(fs.readFileSync("/etc/hosts"));
21
+ ```
package/index.js CHANGED
@@ -1,4 +1,7 @@
1
- import stream from 'stream';
1
+ import {Buffer} from 'buffer';
2
+ import process from 'process';
3
+ import {Readable} from 'readable-stream/lib/readable.js';
4
+ import {Writable} from 'readable-stream/lib/writable.js';
2
5
 
3
6
  const {platform, pointerSize} = Process;
4
7
 
@@ -87,7 +90,7 @@ const SEEK_END = 2;
87
90
 
88
91
  const EINTR = 4;
89
92
 
90
- class ReadStream extends stream.Readable {
93
+ class ReadStream extends Readable {
91
94
  constructor(path) {
92
95
  super({
93
96
  highWaterMark: 4 * 1024 * 1024
@@ -99,8 +102,10 @@ class ReadStream extends stream.Readable {
99
102
  const pathStr = Memory.allocUtf8String(path);
100
103
  const fd = getApi().open(pathStr, constants.O_RDONLY, 0);
101
104
  if (fd.value === -1) {
102
- this.emit('error', new Error(`Unable to open file (${getErrorString(fd.errno)})`));
103
- this.push(null);
105
+ process.nextTick(() => {
106
+ this.emit('error', new Error(`Unable to open file (${getErrorString(fd.errno)})`));
107
+ this.push(null);
108
+ });
104
109
  return;
105
110
  }
106
111
 
@@ -127,6 +132,7 @@ class ReadStream extends stream.Readable {
127
132
  .catch(error => {
128
133
  this._readRequest = null;
129
134
  this._closeInput();
135
+ this.emit('error', error);
130
136
  this.push(null);
131
137
  });
132
138
  }
@@ -139,7 +145,7 @@ class ReadStream extends stream.Readable {
139
145
  }
140
146
  }
141
147
 
142
- class WriteStream extends stream.Writable {
148
+ class WriteStream extends Writable {
143
149
  constructor(path) {
144
150
  super({
145
151
  highWaterMark: 4 * 1024 * 1024
@@ -153,8 +159,10 @@ class WriteStream extends stream.Writable {
153
159
  const mode = constants.S_IRUSR | constants.S_IWUSR | constants.S_IRGRP | constants.S_IROTH;
154
160
  const fd = getApi().open(pathStr, flags, mode);
155
161
  if (fd.value === -1) {
156
- this.emit('error', new Error(`Unable to open file (${getErrorString(fd.errno)})`));
157
- this.push(null);
162
+ process.nextTick(() => {
163
+ this.emit('error', new Error(`Unable to open file (${getErrorString(fd.errno)})`));
164
+ this.push(null);
165
+ });
158
166
  return;
159
167
  }
160
168
 
@@ -412,6 +420,24 @@ const statSpecs = {
412
420
  'blksize': [ 48, 'S32' ],
413
421
  }
414
422
  },
423
+ 'linux-32-stat64': {
424
+ size: 104,
425
+ fields: {
426
+ 'dev': [ 0, 'U64' ],
427
+ 'mode': [ 16, 'U32' ],
428
+ 'nlink': [ 20, 'U32' ],
429
+ 'ino': [ 96, 'U64' ],
430
+ 'uid': [ 24, 'U32' ],
431
+ 'gid': [ 28, 'U32' ],
432
+ 'rdev': [ 32, 'U64' ],
433
+ 'atime': [ 72, readTimespec32 ],
434
+ 'mtime': [ 80, readTimespec32 ],
435
+ 'ctime': [ 88, readTimespec32 ],
436
+ 'size': [ 48, 'S64' ],
437
+ 'blocks': [ 64, 'S64' ],
438
+ 'blksize': [ 56, 'S32' ],
439
+ }
440
+ },
415
441
  'linux-64': {
416
442
  size: 144,
417
443
  fields: {
@@ -431,9 +457,34 @@ const statSpecs = {
431
457
  },
432
458
  },
433
459
  };
434
- const statSpec = statSpecs[`${platform}-${pointerSize * 8}`] || null;
460
+ let cachedStatSpec = null;
435
461
  const statBufSize = 256;
436
462
 
463
+ function getStatSpec() {
464
+ if (cachedStatSpec !== null)
465
+ return cachedStatSpec;
466
+
467
+ const api = getApi();
468
+ const stat64Impl = api.stat64 ?? api.__xstat64;
469
+
470
+ let platformId = `${platform}-${pointerSize * 8}`;
471
+ if (platformId === 'linux-32') {
472
+ if (stat64Impl !== undefined)
473
+ platformId += '-stat64';
474
+ }
475
+
476
+ const statSpec = statSpecs[platformId];
477
+ if (statSpec === undefined)
478
+ throw new Error('Current OS is not yet supported; please open a PR');
479
+
480
+ statSpec._stat = stat64Impl ?? api.stat;
481
+ statSpec._lstat = api.lstat64 ?? api.__lxstat64 ?? api.lstat;
482
+
483
+ cachedStatSpec = statSpec;
484
+
485
+ return statSpec;
486
+ }
487
+
437
488
  class Stats {
438
489
  isFile() {
439
490
  return (this.mode & S_IFMT) === S_IFREG;
@@ -465,21 +516,14 @@ class Stats {
465
516
  }
466
517
 
467
518
  function statSync(path) {
468
- const api = getApi();
469
- const impl = api.stat64 || api.stat;
470
- return performStat(impl, path);
519
+ return performStat(getStatSpec()._stat, path);
471
520
  }
472
521
 
473
522
  function lstatSync(path) {
474
- const api = getApi();
475
- const impl = api.lstat64 || api.lstat;
476
- return performStat(impl, path);
523
+ return performStat(getStatSpec()._lstat, path);
477
524
  }
478
525
 
479
526
  function performStat(impl, path) {
480
- if (statSpec === null)
481
- throw new Error('Current OS is not yet supported; please open a PR');
482
-
483
527
  const buf = Memory.alloc(statBufSize);
484
528
  const result = impl(Memory.allocUtf8String(path), buf);
485
529
  if (result.value !== 0)
@@ -529,7 +573,7 @@ function statsHasField(name) {
529
573
  }
530
574
 
531
575
  function statsReadField(name) {
532
- let field = statSpec.fields[name];
576
+ let field = getStatSpec().fields[name];
533
577
  if (field === undefined) {
534
578
  if (name === 'birthtime') {
535
579
  return statsReadField.call(this, 'ctime');
@@ -612,11 +656,18 @@ const apiSpec = [
612
656
  ['unlink', SF, 'int', ['pointer']],
613
657
  ['stat', SF, 'int', ['pointer', 'pointer']],
614
658
  ['stat64', SF, 'int', ['pointer', 'pointer']],
659
+ ['__xstat64', SF, 'int', ['int', 'pointer', 'pointer'], invokeXstat],
615
660
  ['lstat', SF, 'int', ['pointer', 'pointer']],
616
661
  ['lstat64', SF, 'int', ['pointer', 'pointer']],
662
+ ['__lxstat64', SF, 'int', ['int', 'pointer', 'pointer'], invokeXstat],
617
663
  ['strerror', NF, 'pointer', ['int']],
618
664
  ];
619
665
 
666
+ function invokeXstat(impl, path, buf) {
667
+ const STAT_VER_LINUX = 3;
668
+ return impl(STAT_VER_LINUX, path, buf);
669
+ }
670
+
620
671
  let cachedApi = null;
621
672
  function getApi() {
622
673
  if (cachedApi === null) {
@@ -634,13 +685,16 @@ function addApiPlaceholder(api, entry) {
634
685
  Object.defineProperty(api, name, {
635
686
  configurable: true,
636
687
  get() {
637
- const [, Ctor, retType, argTypes] = entry;
688
+ const [, Ctor, retType, argTypes, wrapper] = entry;
638
689
 
639
690
  let impl = null;
640
691
  const address = Module.findExportByName(null, name);
641
692
  if (address !== null)
642
693
  impl = new Ctor(address, retType, argTypes);
643
694
 
695
+ if (wrapper !== undefined)
696
+ impl = wrapper.bind(null, impl);
697
+
644
698
  Object.defineProperty(api, name, { value: impl });
645
699
 
646
700
  return impl;
@@ -649,11 +703,11 @@ function addApiPlaceholder(api, entry) {
649
703
  }
650
704
 
651
705
  export function createReadStream(path) {
652
- return new ReadStream(path);
706
+ return new ReadStream(path);
653
707
  }
654
708
 
655
709
  export function createWriteStream(path) {
656
- return new WriteStream(path);
710
+ return new WriteStream(path);
657
711
  }
658
712
 
659
713
  export const readdir = callbackify(readdirSync);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "frida-fs",
3
- "version": "4.0.0",
3
+ "version": "5.0.0",
4
4
  "description": "Create a stream from a filesystem resource",
5
5
  "main": "index.js",
6
6
  "type": "module",
@@ -15,5 +15,8 @@
15
15
  "bugs": {
16
16
  "url": "https://github.com/nowsecure/frida-fs/issues"
17
17
  },
18
- "homepage": "https://github.com/nowsecure/frida-fs#readme"
18
+ "homepage": "https://github.com/nowsecure/frida-fs#readme",
19
+ "dependencies": {
20
+ "readable-stream": "^4.0.0"
21
+ }
19
22
  }