Skip to content

Commit

Permalink
Fixes GID set and hasAccess func
Browse files Browse the repository at this point in the history
Signed-off-by: Marcos Candeia <[email protected]>
  • Loading branch information
mcandeia committed Nov 11, 2024
1 parent 9a9f538 commit f32e909
Show file tree
Hide file tree
Showing 4 changed files with 87 additions and 15 deletions.
2 changes: 1 addition & 1 deletion src/file.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import type { FileReadResult } from 'node:fs/promises';
import { O_APPEND, O_CREAT, O_EXCL, O_RDONLY, O_RDWR, O_SYNC, O_TRUNC, O_WRONLY, S_IFMT, size_max } from './emulation/constants.js';
import { config } from './emulation/config.js';
import { O_APPEND, O_CREAT, O_EXCL, O_RDONLY, O_RDWR, O_SYNC, O_TRUNC, O_WRONLY, S_IFMT, size_max } from './emulation/constants.js';
import { Errno, ErrnoError } from './error.js';
import type { FileSystem } from './filesystem.js';
import './polyfills.js';
Expand Down
6 changes: 3 additions & 3 deletions src/inode.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { deserialize, serialize, sizeof, struct, types as t } from 'utilium';
import { Stats, type StatsLike } from './stats.js';
import { types as t, struct, sizeof, serialize, deserialize } from 'utilium';

/**
* Alias for an ino.
Expand Down Expand Up @@ -108,8 +108,8 @@ export class Inode implements StatsLike {
hasChanged = true;
}

if (this.uid !== stats.uid) {
this.uid = stats.uid;
if (this.gid !== stats.gid) {
this.gid = stats.gid;
hasChanged = true;
}

Expand Down
52 changes: 41 additions & 11 deletions src/stats.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,28 @@
import type * as Node from 'node:fs';
import { credentials, type Credentials } from './credentials.js';
import { S_IFBLK, S_IFCHR, S_IFDIR, S_IFIFO, S_IFLNK, S_IFMT, S_IFREG, S_IFSOCK, S_IRWXG, S_IRWXO, S_IRWXU, size_max } from './emulation/constants.js';
import {
R_OK,
S_IFBLK,
S_IFCHR,
S_IFDIR,
S_IFIFO,
S_IFLNK,
S_IFMT,
S_IFREG,
S_IFSOCK,
S_IRGRP,
S_IROTH,
S_IRUSR,
S_IWGRP,
S_IWOTH,
S_IWUSR,
S_IXGRP,
S_IXOTH,
S_IXUSR,
size_max,
W_OK,
X_OK,
} from './emulation/constants.js';

/**
* Indicates the type of a file. Applied to 'mode'.
Expand Down Expand Up @@ -221,24 +243,32 @@ export abstract class StatsCommon<T extends number | bigint> implements Node.Sta
* @internal
*/
public hasAccess(mode: number): boolean {
// Assuming 'credentials' and 'this.uid', 'this.gid', 'this.mode' are accessible
if (credentials.euid === 0 || credentials.egid === 0) {
// Running as root
//Running as root
return true;
}

// Build the adjusted permission mask based on ownership
let adjusted = 0;
let perm = 0;

if (credentials.uid === this.uid) {
adjusted |= S_IRWXU; // Include owner permissions
}
if (credentials.gid === this.gid) {
adjusted |= S_IRWXG; // Include group permissions
// Owner permissions
if (this.mode & S_IRUSR) perm |= R_OK;
if (this.mode & S_IWUSR) perm |= W_OK;
if (this.mode & S_IXUSR) perm |= X_OK;
} else if (credentials.gid === this.gid) {
// Group permissions
if (this.mode & S_IRGRP) perm |= R_OK;
if (this.mode & S_IWGRP) perm |= W_OK;
if (this.mode & S_IXGRP) perm |= X_OK;
} else {
// Others permissions
if (this.mode & S_IROTH) perm |= R_OK;
if (this.mode & S_IWOTH) perm |= W_OK;
if (this.mode & S_IXOTH) perm |= X_OK;
}
adjusted |= S_IRWXO; // Always include others' permissions

// Perform the access check
return (this.mode & adjusted & mode) === mode;
return (perm & mode) === mode;
}

/**
Expand Down
42 changes: 42 additions & 0 deletions tests/fs/stat.test.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import assert from 'node:assert';
import { suite, test } from 'node:test';
import { credentials } from '../../dist/credentials.js';
import { Stats } from '../../dist/stats.js';
import { fs } from '../common.js';

Expand Down Expand Up @@ -34,6 +35,47 @@ suite('Stats', () => {
fs.close(fd);
});

test('hasAccess for non-root access', () => {
const newFile = 'new.txt';

fs.writeFileSync(newFile, 'hello', {
mode: 0o640, // allow group access
});

const prevCredentials = {
...credentials,
};
const uid = 33;
const nonRootCredentials = {
uid,
gid: uid,
euid: uid,
egid: uid,
suid: uid,
sgid: uid,
};

fs.chownSync(newFile, 0, nonRootCredentials.gid); // creating with root-user so that non-root user can access

Object.assign(credentials, nonRootCredentials);
const stat = fs.statSync(newFile);

assert.equal(stat.gid, nonRootCredentials.gid);
assert.equal(stat.uid, 0);
assert.equal(stat.hasAccess(fs.constants.R_OK), true);
assert.equal(stat.hasAccess(fs.constants.W_OK), false);
assert.equal(stat.hasAccess(fs.constants.X_OK), false);
// changing group

Object.assign(credentials, { ...nonRootCredentials, gid: 44 });

assert.equal(stat.hasAccess(fs.constants.R_OK), false);
assert.equal(stat.hasAccess(fs.constants.W_OK), false);
assert.equal(stat.hasAccess(fs.constants.X_OK), false);

Object.assign(credentials, prevCredentials);
});

test('stat file', async () => {
const stats = await fs.promises.stat(existing_file);
assert(!stats.isDirectory());
Expand Down

0 comments on commit f32e909

Please sign in to comment.