vfs/{b|btr|package|b}fs/ext2/exfat: common access check.

* Added VFS helper function check_access_permissions() that combines
  several partially correct versions to the one true version (tm).
* All but BFS (since recently) missed the S_IXOTH for root on directories,
  and all but packagefs missed proper group handling.
This commit is contained in:
Axel Dörfler 2014-10-25 16:50:48 +02:00
parent 2ce0d69a7e
commit 5a95af70a2
8 changed files with 84 additions and 219 deletions

View File

@ -1,10 +1,11 @@
/*
* Copyright 2004-2010, Haiku Inc. All Rights Reserved.
* Copyright 2004-2014, Haiku Inc. All Rights Reserved.
* Distributed under the terms of the MIT License.
*/
#ifndef _FS_INTERFACE_H
#define _FS_INTERFACE_H
/*! File System Interface Layer Definition */
@ -330,6 +331,8 @@ extern status_t unremove_vnode(fs_volume* volume, ino_t vnodeID);
extern status_t get_vnode_removed(fs_volume* volume, ino_t vnodeID,
bool* _removed);
extern fs_volume* volume_for_vnode(fs_vnode* vnode);
extern status_t check_access_permissions(int accessMode, mode_t mode,
gid_t nodeGroupID, uid_t nodeUserID);
extern status_t read_pages(int fd, off_t pos, const struct iovec* vecs,
size_t count, size_t* _numBytes);

View File

@ -506,37 +506,8 @@ Inode::CheckPermissions(int accessMode) const
if ((accessMode & W_OK) != 0 && fVolume->IsReadOnly())
return B_READ_ONLY_DEVICE;
// get node permissions
mode_t mode = Mode();
int userPermissions = (mode & S_IRWXU) >> 6;
int groupPermissions = (mode & S_IRWXG) >> 3;
int otherPermissions = mode & S_IRWXO;
// get the node permissions for this uid/gid
int permissions = 0;
uid_t uid = geteuid();
gid_t gid = getegid();
if (uid == 0) {
// user is root
// root has always read/write permission, but at least one of the
// X bits must be set for execute permission
permissions = userPermissions | groupPermissions | otherPermissions
| R_OK | W_OK;
if (IsDirectory())
permissions |= X_OK;
} else if (uid == (uid_t)fNode.UserID()) {
// user is node owner
permissions = userPermissions;
} else if (gid == (gid_t)fNode.GroupID()) {
// user is in owning group
permissions = groupPermissions;
} else {
// user is one of the others
permissions = otherPermissions;
}
return (accessMode & ~permissions) == 0 ? B_OK : B_NOT_ALLOWED;
return check_access_permissions(accessMode, Mode(), (gid_t)fNode.GroupID(),
(uid_t)fNode.UserID());
}

View File

@ -1,6 +1,6 @@
/*
* Copyright 2011, Jérôme Duval, korli@users.berlios.de.
* Copyright 2008, Axel Dörfler, axeld@pinc-software.de.
* Copyright 2008-2014, Axel Dörfler, axeld@pinc-software.de.
* Copyright 2005-2007, Ingo Weinhold, bonefish@cs.tu-berlin.de.
* This file may be used under the terms of the MIT License.
*/
@ -104,35 +104,8 @@ Inode::CheckPermissions(int accessMode) const
if ((accessMode & W_OK) != 0 && fVolume->IsReadOnly())
return B_READ_ONLY_DEVICE;
// get node permissions
mode_t mode = Mode();
int userPermissions = (mode & S_IRWXU) >> 6;
int groupPermissions = (mode & S_IRWXG) >> 3;
int otherPermissions = mode & S_IRWXO;
// get the node permissions for this uid/gid
int permissions = 0;
uid_t uid = geteuid();
gid_t gid = getegid();
if (uid == 0) {
// user is root
// root has always read/write permission, but at least one of the
// X bits must be set for execute permission
permissions = userPermissions | groupPermissions | otherPermissions
| R_OK | W_OK;
} else if (uid == (uid_t)fNode.UserID()) {
// user is node owner
permissions = userPermissions;
} else if (gid == (gid_t)fNode.GroupID()) {
// user is in owning group
permissions = groupPermissions;
} else {
// user is one of the others
permissions = otherPermissions;
}
return (accessMode & ~permissions) == 0 ? B_OK : B_NOT_ALLOWED;
return check_access_permissions(accessMode, Mode(), (gid_t)fNode.GroupID(),
(uid_t)fNode.UserID());
}
@ -162,12 +135,12 @@ Inode::FindBlock(off_t pos, off_t& physical, off_t *_length)
logical = diff + extent_data->disk_offset;
else
panic("unknown extent type; %d\n", extent_data->Type());
status = fVolume->FindBlock(logical, physical);
status = fVolume->FindBlock(logical, physical);
if (_length != NULL)
*_length = extent_data->Size() - diff;
TRACE("Inode::FindBlock(%" B_PRIdINO ") %" B_PRIdOFF " physical %"
B_PRIdOFF "\n", ID(), pos, physical);
free(extent_data);
return status;
}
@ -180,7 +153,7 @@ Inode::ReadAt(off_t pos, uint8* buffer, size_t* _length)
// set/check boundaries for pos/length
if (pos < 0) {
ERROR("inode %" B_PRIdINO ": ReadAt failed(pos %" B_PRIdOFF
ERROR("inode %" B_PRIdINO ": ReadAt failed(pos %" B_PRIdOFF
", length %lu)\n", ID(), pos, length);
return B_BAD_VALUE;
}
@ -212,7 +185,7 @@ Inode::ReadAt(off_t pos, uint8* buffer, size_t* _length)
uint8 compression = extent_data->Compression();
if (FileCache() != NULL
&& extent_data->Type() == BTRFS_EXTENT_DATA_REGULAR) {
TRACE("inode %" B_PRIdINO ": ReadAt cache (pos %" B_PRIdOFF ", length %lu)\n",
TRACE("inode %" B_PRIdINO ": ReadAt cache (pos %" B_PRIdOFF ", length %lu)\n",
ID(), pos, length);
free(extent_data);
if (compression == BTRFS_EXTENT_COMPRESS_NONE)
@ -313,7 +286,7 @@ Inode::ReadAt(off_t pos, uint8* buffer, size_t* _length)
panic("unknown extent compression; %d\n", compression);
free(extent_data);
return B_OK;
}
@ -336,7 +309,7 @@ Inode::FindParent(ino_t *id)
*id = search_key.Offset();
TRACE("Inode::FindParent() for %" B_PRIdINO ": %" B_PRIdINO "\n", fID,
*id);
return B_OK;
}

View File

@ -1,6 +1,6 @@
/*
* Copyright 2011, Jérôme Duval, korli@users.berlios.de.
* Copyright 2008, Axel Dörfler, axeld@pinc-software.de.
* Copyright 2008-2014, Axel Dörfler, axeld@pinc-software.de.
* This file may be used under the terms of the MIT License.
*/
@ -157,36 +157,8 @@ Inode::CheckPermissions(int accessMode) const
if ((accessMode & W_OK) != 0 && fVolume->IsReadOnly())
return B_READ_ONLY_DEVICE;
// get node permissions
mode_t mode = Mode();
int userPermissions = (mode & S_IRWXU) >> 6;
int groupPermissions = (mode & S_IRWXG) >> 3;
int otherPermissions = mode & S_IRWXO;
// get the node permissions for this uid/gid
int permissions = 0;
uid_t uid = geteuid();
gid_t gid = getegid();
if (uid == 0) {
// user is root
// root has always read/write permission, but at least one of the
// X bits must be set for execute permission
permissions = userPermissions | groupPermissions | otherPermissions
| R_OK | W_OK;
} else if (uid == (uid_t)UserID()) {
// user is node owner
permissions = userPermissions;
} else if (gid == (gid_t)GroupID()) {
// user is in owning group
permissions = groupPermissions;
} else {
// user is one of the others
permissions = otherPermissions;
}
return (accessMode & ~permissions) == 0 ? B_OK : B_NOT_ALLOWED;
return B_OK;
return check_access_permissions(accessMode, Mode(), (gid_t)GroupID(),
(uid_t)UserID());
}
@ -217,7 +189,7 @@ Inode::ReadAt(off_t pos, uint8* buffer, size_t* _length)
return B_NO_ERROR;
}
return file_cache_read(FileCache(), NULL, pos, buffer, _length);
return file_cache_read(FileCache(), NULL, pos, buffer, _length);
}

View File

@ -1,6 +1,6 @@
/*
* Copyright 2011, Jérôme Duval, korli@users.berlios.de.
* Copyright 2008, Axel Dörfler, axeld@pinc-software.de.
* Copyright 2008-2014, Axel Dörfler, axeld@pinc-software.de.
* This file may be used under the terms of the MIT License.
*/
@ -186,35 +186,8 @@ Inode::CheckPermissions(int accessMode) const
if ((accessMode & W_OK) != 0 && fVolume->IsReadOnly())
return B_READ_ONLY_DEVICE;
// get node permissions
mode_t mode = Mode();
int userPermissions = (mode & S_IRWXU) >> 6;
int groupPermissions = (mode & S_IRWXG) >> 3;
int otherPermissions = mode & S_IRWXO;
// get the node permissions for this uid/gid
int permissions = 0;
uid_t uid = geteuid();
gid_t gid = getegid();
if (uid == 0) {
// user is root
// root has always read/write permission, but at least one of the
// X bits must be set for execute permission
permissions = userPermissions | groupPermissions | otherPermissions
| R_OK | W_OK;
} else if (uid == (uid_t)fNode.UserID()) {
// user is node owner
permissions = userPermissions;
} else if (gid == (gid_t)fNode.GroupID()) {
// user is in owning group
permissions = groupPermissions;
} else {
// user is one of the others
permissions = otherPermissions;
}
return (accessMode & ~permissions) == 0 ? B_OK : B_NOT_ALLOWED;
return check_access_permissions(accessMode, Mode(), (gid_t)fNode.GroupID(),
(uid_t)fNode.UserID());
}

View File

@ -36,20 +36,6 @@ static const uint32 kOptimalIOSize = 64 * 1024;
// #pragma mark - helper functions
static bool
is_user_in_group(gid_t gid)
{
gid_t groups[NGROUPS_MAX];
int groupCount = getgroups(NGROUPS_MAX, groups);
for (int i = 0; i < groupCount; i++) {
if (gid == groups[i])
return true;
}
return (gid == getegid());
}
static status_t
check_access(Node* node, int mode)
{
@ -57,33 +43,8 @@ check_access(Node* node, int mode)
if (mode & W_OK)
return B_READ_ONLY_DEVICE;
// get node permissions
int userPermissions = (node->Mode() & S_IRWXU) >> 6;
int groupPermissions = (node->Mode() & S_IRWXG) >> 3;
int otherPermissions = node->Mode() & S_IRWXO;
// get the permissions for this uid/gid
int permissions = 0;
uid_t uid = geteuid();
if (uid == 0) {
// user is root
// root has always read/write permission, but at least one of the
// X bits must be set for execute permission
permissions = userPermissions | groupPermissions | otherPermissions
| S_IROTH | S_IWOTH;
} else if (uid == node->UserID()) {
// user is node owner
permissions = userPermissions;
} else if (is_user_in_group(node->GroupID())) {
// user is in owning group
permissions = groupPermissions;
} else {
// user is one of the others
permissions = otherPermissions;
}
return (mode & ~permissions) == 0 ? B_OK : B_NOT_ALLOWED;
return check_access_permissions(mode, node->Mode(), node->GroupID(),
node->UserID());
}

View File

@ -54,9 +54,6 @@ extern fs_volume_ops gReiserFSVolumeOps;
extern fs_vnode_ops gReiserFSVnodeOps;
inline static bool is_user_in_group(gid_t gid);
// #pragma mark - FS
@ -307,41 +304,19 @@ static status_t
reiserfs_access(fs_volume *fs, fs_vnode *_node, int mode)
{
TOUCH(fs);
// FUNCTION_START();
// Volume *volume = (Volume*)fs->private_volume;
VNode *node = (VNode*)_node->private_node;
FUNCTION(("node: (%Ld: %lu, %lu)\n", node->GetID(), node->GetDirID(),
FUNCTION(("node: (%Ld: %lu, %lu)\n", node->GetID(), node->GetDirID(),
node->GetObjectID()));
// write access requested?
if (mode & W_OK)
return B_READ_ONLY_DEVICE;
// get node permissions
StatData *statData = node->GetStatData();
int userPermissions = (statData->GetMode() & S_IRWXU) >> 6;
int groupPermissions = (statData->GetMode() & S_IRWXG) >> 3;
int otherPermissions = statData->GetMode() & S_IRWXO;
// get the permissions for this uid/gid
int permissions = 0;
uid_t uid = geteuid();
// user is root
if (uid == 0) {
// root has always read/write permission, but at least one of the
// X bits must be set for execute permission
permissions = userPermissions | groupPermissions | otherPermissions
| S_IROTH | S_IWOTH;
// user is node owner
} else if (uid == statData->GetUID())
permissions = userPermissions;
// user is in owning group
else if (is_user_in_group(statData->GetGID()))
permissions = groupPermissions;
// user is one of the others
else
permissions = otherPermissions;
// do the check
if (mode & ~permissions)
return B_NOT_ALLOWED;
return B_OK;
return check_access_permissions(mode, statData->GetMode(),
statData->GetGID(), statData->GetUID());
}
// reiserfs_read_stat
@ -465,23 +440,7 @@ reiserfs_read(fs_volume *fs, fs_vnode *_node, void *cookie, off_t pos,
RETURN_ERROR(error);
}
// is_user_in_group
inline static bool
is_user_in_group(gid_t gid)
{
// Either I miss something, or we don't have getgroups() in the kernel. :-(
/*
gid_t groups[NGROUPS_MAX];
int groupCount = getgroups(NGROUPS_MAX, groups);
for (int i = 0; i < groupCount; i++) {
if (gid == groups[i])
return true;
}
*/
return (gid == getegid());
}
// DirectoryCookie
class DirectoryCookie : public DirEntryIterator {
public:
DirectoryCookie(Tree *tree, uint32 dirID, uint32 objectID,

View File

@ -1,6 +1,6 @@
/*
* Copyright 2005-2013, Ingo Weinhold, ingo_weinhold@gmx.de.
* Copyright 2002-2011, Axel Dörfler, axeld@pinc-software.de.
* Copyright 2002-2014, Axel Dörfler, axeld@pinc-software.de.
* Distributed under the terms of the MIT License.
*
* Copyright 2001-2002, Travis Geiselbrecht. All rights reserved.
@ -3591,6 +3591,23 @@ common_file_io_vec_pages(struct vnode* vnode, void* cookie,
}
static bool
is_user_in_group(gid_t gid)
{
if (gid == getegid())
return true;
gid_t groups[NGROUPS_MAX];
int groupCount = getgroups(NGROUPS_MAX, groups);
for (int i = 0; i < groupCount; i++) {
if (gid == groups[i])
return true;
}
return false;
}
// #pragma mark - public API for file systems
@ -3876,6 +3893,42 @@ volume_for_vnode(fs_vnode* _vnode)
}
extern "C" status_t
check_access_permissions(int accessMode, mode_t mode, gid_t nodeGroupID,
uid_t nodeUserID)
{
// get node permissions
int userPermissions = (mode & S_IRWXU) >> 6;
int groupPermissions = (mode & S_IRWXG) >> 3;
int otherPermissions = mode & S_IRWXO;
// get the node permissions for this uid/gid
int permissions = 0;
uid_t uid = geteuid();
if (uid == 0) {
// user is root
// root has always read/write permission, but at least one of the
// X bits must be set for execute permission
permissions = userPermissions | groupPermissions | otherPermissions
| S_IROTH | S_IWOTH;
if (S_ISDIR(mode))
permissions |= S_IXOTH;
} else if (uid == nodeUserID) {
// user is node owner
permissions = userPermissions;
} else if (is_user_in_group(nodeGroupID)) {
// user is in owning group
permissions = groupPermissions;
} else {
// user is one of the others
permissions = otherPermissions;
}
return (accessMode & ~permissions) == 0 ? B_OK : B_NOT_ALLOWED;
}
#if 0
extern "C" status_t
read_pages(int fd, off_t pos, const iovec* vecs, size_t count,