Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Permission logic in fs.open(), fs.openSync(), and fsPromises.open() can easily be bypassed #47090

Closed
tniessen opened this issue Mar 14, 2023 · 0 comments · Fixed by #47091
Closed
Labels
confirmed-bug Issues with confirmed bugs. fs Issues and PRs related to the fs subsystem / file system. permission Issues and PRs related to the Permission Model security Issues and PRs related to security.

Comments

@tniessen
Copy link
Member

tniessen commented Mar 14, 2023

The permission logic in these functions seems flawed. Using fs.open() or fs.openSync(), both read and write restrictions can easily be bypassed simply by passing extra flags. Some examples:

  • O_RDWR | 0x10000000 gives both read and write access - regardless of any restrictions.
  • O_RDONLY | O_NOCTTY gives read access - even if all file system access has been blocked.
  • O_RDONLY | O_TEMPORARY allows deleting files on Windows - even without write access.

fsPromises.open() contains similarly obvious flaws, but it also contains a mostly redundant (and likely also incorrect) check that always requires read permission, even if opening in a write-only mode. Still, as long as read permission is granted, code can open the file for writing using, for example, O_RDWR | O_NOFOLLOW.

Overall, this combination of multiple logical flaws trivially allows arbitrary read and write access to any file, even when access should be restricted.


I'm opening this as a public issue because the feature hasn't been released yet due to the previous vulnerability that was found by @cjihrig (see #46975 (comment)).


The flawed validation logic is implemented here:

node/src/node_file.cc

Lines 1968 to 1982 in 334bb17

// Open can be called either in write or read
if (flags == O_RDWR) {
// TODO(rafaelgss): it can be optimized to avoid O(2*n)
THROW_IF_INSUFFICIENT_PERMISSIONS(
env, permission::PermissionScope::kFileSystemRead, pathView);
THROW_IF_INSUFFICIENT_PERMISSIONS(
env, permission::PermissionScope::kFileSystemWrite, pathView);
} else if ((flags & ~(UV_FS_O_RDONLY | UV_FS_O_SYNC)) == 0) {
THROW_IF_INSUFFICIENT_PERMISSIONS(
env, permission::PermissionScope::kFileSystemRead, pathView);
} else if ((flags & (UV_FS_O_APPEND | UV_FS_O_TRUNC | UV_FS_O_CREAT |
UV_FS_O_WRONLY)) != 0) {
THROW_IF_INSUFFICIENT_PERMISSIONS(
env, permission::PermissionScope::kFileSystemWrite, pathView);
}

The incorrect and/or redundant additional check in fsPromises.open() is implemented here:

node/src/node_file.cc

Lines 2014 to 2015 in 334bb17

THROW_IF_INSUFFICIENT_PERMISSIONS(
env, permission::PermissionScope::kFileSystemRead, pathView);

Followed by the same validation logic as above:

node/src/node_file.cc

Lines 2023 to 2037 in 334bb17

// Open can be called either in write or read
if (flags == O_RDWR) {
// TODO(rafaelgss): it can be optimized to avoid O(2*n)
THROW_IF_INSUFFICIENT_PERMISSIONS(
env, permission::PermissionScope::kFileSystemRead, pathView);
THROW_IF_INSUFFICIENT_PERMISSIONS(
env, permission::PermissionScope::kFileSystemWrite, pathView);
} else if ((flags & ~(UV_FS_O_RDONLY | UV_FS_O_SYNC)) == 0) {
THROW_IF_INSUFFICIENT_PERMISSIONS(
env, permission::PermissionScope::kFileSystemRead, pathView);
} else if ((flags & (UV_FS_O_APPEND | UV_FS_O_TRUNC | UV_FS_O_CREAT |
UV_FS_O_WRONLY)) != 0) {
THROW_IF_INSUFFICIENT_PERMISSIONS(
env, permission::PermissionScope::kFileSystemWrite, pathView);
}

@tniessen tniessen added confirmed-bug Issues with confirmed bugs. fs Issues and PRs related to the fs subsystem / file system. security Issues and PRs related to security. labels Mar 14, 2023
tniessen added a commit to tniessen/node that referenced this issue Mar 14, 2023
Without this patch, any restrictions imposed by the permission model can
be easily bypassed, granting full read and write access to any file. On
Windows, this could even be used to delete files that are supposed to be
write-protected.

Fixes: nodejs#47090
tniessen added a commit to tniessen/node that referenced this issue Mar 15, 2023
Without this patch, any restrictions imposed by the permission model can
be easily bypassed, granting full read and write access to any file. On
Windows, this could even be used to delete files that are supposed to be
write-protected.

Fixes: nodejs#47090
nodejs-github-bot pushed a commit that referenced this issue Mar 19, 2023
Without this patch, any restrictions imposed by the permission model can
be easily bypassed, granting full read and write access to any file. On
Windows, this could even be used to delete files that are supposed to be
write-protected.

Fixes: #47090
PR-URL: #47091
Reviewed-By: Rafael Gonzaga <[email protected]>
Reviewed-By: Marco Ippolito <[email protected]>
Reviewed-By: Rich Trott <[email protected]>
@tniessen tniessen added the permission Issues and PRs related to the Permission Model label Aug 10, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
confirmed-bug Issues with confirmed bugs. fs Issues and PRs related to the fs subsystem / file system. permission Issues and PRs related to the Permission Model security Issues and PRs related to security.
Projects
None yet
Development

Successfully merging a pull request may close this issue.

1 participant