diff --git a/fs/inode/fs_inode.c b/fs/inode/fs_inode.c index 2505fbc2e3e..bb04ea0d65b 100644 --- a/fs/inode/fs_inode.c +++ b/fs/inode/fs_inode.c @@ -53,57 +53,46 @@ static rw_semaphore_t g_inode_lock = RWSEM_INITIALIZER; * Private Functions ****************************************************************************/ +#ifdef CONFIG_FS_PERMISSION /**************************************************************************** - * Name: _inode_checkmode + * Name: fs_checkmode * * Description: - * Test effective credentials against 'inode' for 'amode' access. - * Kernel threads always pass. - * - * Returned Value: - * Zero (OK) or -EACCES. + * Test the calling task's effective credentials against the owner, group, + * and mode of a file or directory. Kernel threads always pass. * ****************************************************************************/ -#if defined(CONFIG_PSEUDOFS_ATTRIBUTES) && defined(CONFIG_SCHED_USER_IDENTITY) -static int _inode_checkmode(FAR struct inode *inode, int amode) +int fs_checkmode(uid_t owner, gid_t group, mode_t mode, int amode) { FAR struct tcb_s *rtcb; mode_t perm; uid_t uid; gid_t gid; - /* Kernel threads are always granted access */ - rtcb = nxsched_self(); if ((rtcb->flags & TCB_FLAG_TTYPE_MASK) == TCB_FLAG_TTYPE_KERNEL) { return OK; } - /* Use effective credentials */ - DEBUGASSERT(rtcb->group != NULL); uid = rtcb->group->tg_euid; gid = rtcb->group->tg_egid; - /* Select the applicable permission-bit triplet */ - - if (uid == inode->i_owner) + if (uid == owner) { - perm = (inode->i_mode >> 6) & 7; + perm = (mode >> 6) & 7; } - else if (gid == inode->i_group) + else if (gid == group) { - perm = (inode->i_mode >> 3) & 7; + perm = (mode >> 3) & 7; } else { - perm = inode->i_mode & 7; + perm = mode & 7; } - /* Every requested bit must be present in the selected triplet */ - if ((amode & perm) != amode) { return -EACCES; @@ -111,7 +100,45 @@ static int _inode_checkmode(FAR struct inode *inode, int amode) return OK; } -#endif /* CONFIG_PSEUDOFS_ATTRIBUTES && CONFIG_SCHED_USER_IDENTITY */ + +/**************************************************************************** + * Name: fs_open_amode + * + * Description: + * Map open flags to a permission access mode bitmask. + * + ****************************************************************************/ + +int fs_open_amode(int oflags) +{ + int amode = 0; + + if ((oflags & O_RDOK) != 0) + { + amode |= R_OK; + } + + if ((oflags & O_WROK) != 0) + { + amode |= W_OK; + } + + return amode; +} + +/**************************************************************************** + * Name: fs_checkopenperm + * + * Description: + * Test open access for the calling task against owner, group, and mode. + * + ****************************************************************************/ + +int fs_checkopenperm(uid_t owner, gid_t group, mode_t mode, int oflags) +{ + return fs_checkmode(owner, group, mode, fs_open_amode(oflags)); +} +#endif /* CONFIG_FS_PERMISSION */ /**************************************************************************** * Public Functions @@ -189,6 +216,43 @@ void inode_runlock(void) * Name: inode_checkperm * * Description: + * Check 'inode' for 'amode' access on pseudo-filesystem inodes. + * NULL 'inode' (root) and mountpoints are exempt. + * + * Input Parameters: + * inode - Inode to check, or NULL for a root-level path + * amode - Access mode bitmask (R_OK / W_OK / X_OK) + * + * Returned Value: + * Zero (OK) on success, or -EACCES if permission is denied. + * + ****************************************************************************/ + +int inode_checkperm(FAR struct inode *inode, int amode) +{ +#ifdef CONFIG_FS_PERMISSION + + if (inode == NULL) + { + return OK; + } + + if (INODE_IS_MOUNTPT(inode)) + { + return OK; + } + + return fs_checkmode(inode->i_owner, inode->i_group, inode->i_mode, amode); + +#else + return OK; +#endif /* CONFIG_FS_PERMISSION */ +} + +/**************************************************************************** + * Name: inode_checkopenperm + * + * Description: * Validate open access to 'inode' for 'oflags'. Checks driver operation * support, then pseudo-filesystem mode bits when enabled. Mountpoints * are exempt from mode checks. @@ -202,29 +266,14 @@ void inode_runlock(void) * ****************************************************************************/ -int inode_checkperm(FAR struct inode *inode, int oflags) +int inode_checkopenperm(FAR struct inode *inode, int oflags) { -#if defined(CONFIG_PSEUDOFS_ATTRIBUTES) && defined(CONFIG_SCHED_USER_IDENTITY) - int amode = 0; -#endif FAR const struct file_operations *ops; -#if defined(CONFIG_PSEUDOFS_ATTRIBUTES) && defined(CONFIG_SCHED_USER_IDENTITY) - if ((oflags & O_RDOK) != 0) - { - amode |= R_OK; - } - - if ((oflags & O_WROK) != 0) - { - amode |= W_OK; - } -#endif - if (INODE_IS_PSEUDODIR(inode)) { -#if defined(CONFIG_PSEUDOFS_ATTRIBUTES) && defined(CONFIG_SCHED_USER_IDENTITY) - return _inode_checkmode(inode, amode); +#ifdef CONFIG_FS_PERMISSION + return inode_checkperm(inode, fs_open_amode(oflags)); #else return OK; #endif @@ -244,53 +293,11 @@ int inode_checkperm(FAR struct inode *inode, int oflags) return -EACCES; } -#if defined(CONFIG_PSEUDOFS_ATTRIBUTES) && defined(CONFIG_SCHED_USER_IDENTITY) +#ifdef CONFIG_FS_PERMISSION - if (INODE_IS_MOUNTPT(inode)) - { - return OK; - } - - return _inode_checkmode(inode, amode); - -#endif /* CONFIG_PSEUDOFS_ATTRIBUTES && CONFIG_SCHED_USER_IDENTITY */ - - return OK; -} - -/**************************************************************************** - * Name: inode_checkdirperm - * - * Description: - * Check parent directory 'dir' for 'amode' access on pseudo-filesystem - * inodes. NULL 'dir' (root) and mountpoints are exempt. - * - * Input Parameters: - * dir - Parent directory inode, or NULL for a root-level path - * amode - Access mode bitmask (R_OK / W_OK / X_OK) - * - * Returned Value: - * Zero (OK) on success, or -EACCES if permission is denied. - * - ****************************************************************************/ - -int inode_checkdirperm(FAR struct inode *dir, int amode) -{ -#if defined(CONFIG_PSEUDOFS_ATTRIBUTES) && defined(CONFIG_SCHED_USER_IDENTITY) - - if (dir == NULL) - { - return OK; - } - - if (INODE_IS_MOUNTPT(dir)) - { - return OK; - } - - return _inode_checkmode(dir, amode); + return inode_checkperm(inode, fs_open_amode(oflags)); #else return OK; -#endif /* CONFIG_PSEUDOFS_ATTRIBUTES && CONFIG_SCHED_USER_IDENTITY */ +#endif /* CONFIG_FS_PERMISSION */ } diff --git a/fs/inode/inode.h b/fs/inode/inode.h index 3735d9a566c..7cacd0697f3 100644 --- a/fs/inode/inode.h +++ b/fs/inode/inode.h @@ -422,6 +422,24 @@ void inode_release(FAR struct inode *inode); * Name: inode_checkperm * * Description: + * Check 'inode' for 'amode' access on pseudo-filesystem inodes. + * NULL 'inode' (root) and mountpoints are exempt. + * + * Input Parameters: + * inode - Inode to check, or NULL for a root-level path + * amode - Access mode bitmask (R_OK / W_OK / X_OK) + * + * Returned Value: + * Zero (OK) on success, or -EACCES if permission is denied. + * + ****************************************************************************/ + +int inode_checkperm(FAR struct inode *inode, int amode); + +/**************************************************************************** + * Name: inode_checkopenperm + * + * Description: * Validate open access to 'inode' for 'oflags'. Checks driver operation * support, then pseudo-filesystem mode bits when enabled. Mountpoints * are exempt from mode checks. @@ -435,25 +453,13 @@ void inode_release(FAR struct inode *inode); * ****************************************************************************/ -int inode_checkperm(FAR struct inode *inode, int oflags); +int inode_checkopenperm(FAR struct inode *inode, int oflags); -/**************************************************************************** - * Name: inode_checkdirperm - * - * Description: - * Check parent directory 'dir' for 'amode' access on pseudo-filesystem - * inodes. NULL 'dir' (root) and mountpoints are exempt. - * - * Input Parameters: - * dir - Parent directory inode, or NULL for a root-level path - * amode - Access mode bitmask (R_OK / W_OK / X_OK) - * - * Returned Value: - * Zero (OK) on success, or -EACCES if permission is denied. - * - ****************************************************************************/ - -int inode_checkdirperm(FAR struct inode *dir, int amode); +#ifdef CONFIG_FS_PERMISSION +int fs_checkmode(uid_t owner, gid_t group, mode_t mode, int amode); +int fs_open_amode(int oflags); +int fs_checkopenperm(uid_t owner, gid_t group, mode_t mode, int oflags); +#endif /**************************************************************************** * Name: foreach_inode diff --git a/fs/vfs/fs_mkdir.c b/fs/vfs/fs_mkdir.c index bfd66a25834..65b0fdb1f1b 100644 --- a/fs/vfs/fs_mkdir.c +++ b/fs/vfs/fs_mkdir.c @@ -142,7 +142,7 @@ int mkdir(const char *pathname, mode_t mode) * both W_OK and X_OK to create a directory entry. */ - ret = inode_checkdirperm(desc.parent, W_OK | X_OK); + ret = inode_checkperm(desc.parent, W_OK | X_OK); if (ret < 0) { errcode = -ret; diff --git a/fs/vfs/fs_open.c b/fs/vfs/fs_open.c index 4131d14b36e..d1944bc184c 100644 --- a/fs/vfs/fs_open.c +++ b/fs/vfs/fs_open.c @@ -172,7 +172,7 @@ static int file_vopen(FAR struct file *filep, FAR const char *path, /* Validate operation support and pseudo-filesystem permissions */ - ret = inode_checkperm(inode, oflags); + ret = inode_checkopenperm(inode, oflags); if (ret < 0) { goto errout_with_inode; diff --git a/fs/vfs/fs_rename.c b/fs/vfs/fs_rename.c index 11ea28a3b3f..8d9840aeb4a 100644 --- a/fs/vfs/fs_rename.c +++ b/fs/vfs/fs_rename.c @@ -86,7 +86,7 @@ static int pseudorename(FAR const char *oldpath, FAR struct inode *oldinode, /* Verify source parent write permission. */ - ret = inode_checkdirperm(oldparent, W_OK); + ret = inode_checkperm(oldparent, W_OK); if (ret < 0) { goto errout; @@ -177,7 +177,7 @@ static int pseudorename(FAR const char *oldpath, FAR struct inode *oldinode, inode_find(&pardesc); /* pardesc.parent valid even if node not found */ parnode = pardesc.node; - ret = inode_checkdirperm(pardesc.parent, W_OK); + ret = inode_checkperm(pardesc.parent, W_OK); /* inode_find() holds a reference on parnode; RELEASE_SEARCH() only * frees pardesc.buffer. diff --git a/fs/vfs/fs_unlink.c b/fs/vfs/fs_unlink.c index a8c70f66b86..7f4d3ffaadf 100644 --- a/fs/vfs/fs_unlink.c +++ b/fs/vfs/fs_unlink.c @@ -123,7 +123,7 @@ int nx_unlink(FAR const char *pathname) /* Verify parent-directory write permission before unlink. */ - ret = inode_checkdirperm(desc.parent, W_OK); + ret = inode_checkperm(desc.parent, W_OK); if (ret < 0) { goto errout_with_inode;