Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 29 additions & 0 deletions Documentation/implementation/user_identity.rst
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,24 @@ the saved ID. Otherwise the function returns ``-1`` with ``errno`` set to
This implements the standard POSIX pattern of temporarily dropping privileges
with ``seteuid()`` or ``setegid()`` and later restoring them to the saved value.

``setreuid()`` and ``setregid()``
---------------------------------

These functions set the real and/or effective IDs in a single call. When the
effective ID is zero, any requested real and effective values may be assigned
and the saved set-ID is updated accordingly. When the effective ID is
non-zero, each requested value must equal the current effective ID, saved
set-ID, or (for the effective argument only) the real ID; otherwise the call
returns ``-1`` with ``errno`` set to ``EPERM``. When the real ID is changed,
or the effective ID is changed to a value not equal to the real ID, the saved
set-ID is set to the new effective ID.

``getresuid()`` and ``getresgid()``
-----------------------------------

These functions return the real, effective, and saved set-IDs for the calling
task group. Any output pointer may be ``NULL`` if that ID is not needed.

Configuration
=============

Expand All @@ -69,3 +87,14 @@ Configuration
``CONFIG_FS_PERMISSION``
Enables filesystem ownership and permission enforcement. Requires
``CONFIG_SCHED_USER_IDENTITY``.

Pseudo-Filesystem Ownership
===========================

When ``CONFIG_PSEUDOFS_ATTRIBUTES`` and ``CONFIG_SCHED_USER_IDENTITY`` are both
enabled, ``inode_alloc()`` assigns ``i_owner`` and ``i_group`` from the
caller's effective credentials. This covers
message queues (``mq_open()``), named semaphores (``sem_open()``), shared
memory objects (``shm_open()``), FIFOs (``mkfifo()``), and pseudo-files
created through the same inode reservation path. Open-time permission checks
use ``inode_checkopenperm()`` (or ``inode_checkperm()`` for message queues).
15 changes: 14 additions & 1 deletion fs/inode/fs_inode.c
Original file line number Diff line number Diff line change
Expand Up @@ -229,6 +229,10 @@ void inode_runlock(void)
*
****************************************************************************/

/****************************************************************************
* Name: inode_checkperm
****************************************************************************/

int inode_checkperm(FAR struct inode *inode, int amode)
{
#ifdef CONFIG_FS_PERMISSION
Expand Down Expand Up @@ -271,7 +275,16 @@ int inode_checkopenperm(FAR struct inode *inode, int oflags)
{
FAR const struct file_operations *ops;

if (INODE_IS_PSEUDODIR(inode))
if (INODE_IS_NAMEDSEM(inode))
{
#ifdef CONFIG_FS_PERMISSION
return inode_checkperm(inode, R_OK | W_OK);
#else
return OK;
#endif
}

if (INODE_IS_MQUEUE(inode) || INODE_IS_PSEUDODIR(inode))
{
#ifdef CONFIG_FS_PERMISSION
return inode_checkperm(inode, fs_open_amode(oflags));
Expand Down
13 changes: 13 additions & 0 deletions fs/inode/fs_inodereserve.c
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
#include <errno.h>

#include <nuttx/kmalloc.h>
#include <nuttx/sched.h>
#include <nuttx/fs/fs.h>

#include "inode/inode.h"
Expand Down Expand Up @@ -82,6 +83,9 @@ static FAR struct inode *inode_alloc(FAR const char *name, mode_t mode)
{
FAR struct inode *inode;
int namelen;
#if defined(CONFIG_PSEUDOFS_ATTRIBUTES) && defined(CONFIG_SCHED_USER_IDENTITY)
FAR struct tcb_s *rtcb;
#endif

namelen = inode_namelen(name);
inode = fs_heap_zalloc(FSNODE_SIZE(namelen));
Expand All @@ -94,6 +98,15 @@ static FAR struct inode *inode_alloc(FAR const char *name, mode_t mode)
clock_gettime(CLOCK_REALTIME, &inode->i_atime);
inode->i_mtime = inode->i_atime;
inode->i_ctime = inode->i_atime;
# if defined(CONFIG_SCHED_USER_IDENTITY)
rtcb = nxsched_self();
if (rtcb != NULL && rtcb->group != NULL)
{
inode->i_owner = rtcb->group->tg_euid;
inode->i_group = rtcb->group->tg_egid;
}

# endif
#endif
inode_namecpy(inode->i_name, name);
}
Expand Down
6 changes: 0 additions & 6 deletions fs/inode/inode.h
Original file line number Diff line number Diff line change
Expand Up @@ -461,12 +461,6 @@ int fs_open_amode(int oflags);
int fs_checkopenperm(uid_t owner, gid_t group, mode_t mode, int oflags);
#endif

#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
*
Expand Down
20 changes: 20 additions & 0 deletions fs/mqueue/mq_open.c
Original file line number Diff line number Diff line change
Expand Up @@ -262,6 +262,26 @@ static int file_mq_vopen(FAR struct file *mq, FAR const char *mq_name,
goto errout_with_inode;
}

#ifdef CONFIG_FS_PERMISSION
ret = inode_checkopenperm(inode, oflags);
if (ret < 0)
{
goto errout_with_inode;
}
#endif

if (inode->i_private == NULL)
{
ret = nxmq_alloc_msgq(NULL, &msgq);
if (ret < 0)
{
goto errout_with_inode;
}

inode->i_private = msgq;
msgq->inode = inode;
}

/* Associate the inode with a file structure */

mq->f_oflags = oflags;
Expand Down
8 changes: 8 additions & 0 deletions fs/semaphore/sem_open.c
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,14 @@ int nxsem_open(FAR sem_t **sem, FAR const char *name, int oflags, ...)
goto errout_with_inode;
}

#ifdef CONFIG_FS_PERMISSION
ret = inode_checkopenperm(inode, O_RDWR);
if (ret < 0)
{
goto errout_with_inode;
}
#endif

/* Return a reference to the semaphore, retaining the reference
* count on the inode.
*/
Expand Down
7 changes: 3 additions & 4 deletions fs/shm/shm_open.c
Original file line number Diff line number Diff line change
Expand Up @@ -112,11 +112,10 @@ static int file_shm_open(FAR struct file *shm, FAR const char *name,
goto errout_with_sem;
}

#ifdef CONFIG_PSEUDOFS_ATTRIBUTES
if (((oflags & O_ACCMODE) != O_RDONLY && !(inode->i_mode & S_IWUSR)) ||
((oflags & O_ACCMODE) != O_WRONLY && !(inode->i_mode & S_IRUSR)))
#ifdef CONFIG_FS_PERMISSION
ret = inode_checkopenperm(inode, oflags);
if (ret < 0)
{
ret = -EACCES;
inode_release(inode);
goto errout_with_sem;
}
Expand Down
16 changes: 0 additions & 16 deletions fs/vfs/fs_pseudofile.c
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,6 @@
#include <fcntl.h>
#include <sys/param.h>

#include <nuttx/sched.h>
#include <nuttx/kmalloc.h>
#include <nuttx/fs/fs.h>
#include <nuttx/fs/ioctl.h>
Expand Down Expand Up @@ -468,10 +467,6 @@ int pseudofile_create(FAR struct inode **node, FAR const char *path,
mode_t mode)
{
FAR struct fs_pseudofile_s *pf;
#if defined(CONFIG_PSEUDOFS_ATTRIBUTES) && \
defined(CONFIG_SCHED_USER_IDENTITY)
FAR struct tcb_s *rtcb;
#endif
int ret;

if (node == NULL || path == NULL)
Expand All @@ -498,17 +493,6 @@ int pseudofile_create(FAR struct inode **node, FAR const char *path,
(*node)->u.i_ops = &g_pseudofile_ops;
(*node)->i_private = pf;

#if defined(CONFIG_PSEUDOFS_ATTRIBUTES) && \
defined(CONFIG_SCHED_USER_IDENTITY)

rtcb = nxsched_self();
if (rtcb != NULL && rtcb->group != NULL)
{
(*node)->i_owner = rtcb->group->tg_euid;
(*node)->i_group = rtcb->group->tg_egid;
}
#endif

atomic_fetch_add(&(*node)->i_crefs, 1);

inode_unlock();
Expand Down
4 changes: 4 additions & 0 deletions include/sys/syscall_lookup.h
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,10 @@ SYSCALL_LOOKUP(sethostname, 2)
SYSCALL_LOOKUP(geteuid, 0)
SYSCALL_LOOKUP(setegid, 1)
SYSCALL_LOOKUP(getegid, 0)
SYSCALL_LOOKUP(setreuid, 2)
SYSCALL_LOOKUP(setregid, 2)
SYSCALL_LOOKUP(getresuid, 3)
SYSCALL_LOOKUP(getresgid, 3)
#endif

/* Semaphores */
Expand Down
3 changes: 3 additions & 0 deletions include/unistd.h
Original file line number Diff line number Diff line change
Expand Up @@ -494,6 +494,9 @@ gid_t getegid(void);
int setreuid(uid_t ruid, uid_t euid);
int setregid(gid_t rgid, gid_t egid);

int getresuid(FAR uid_t *ruid, FAR uid_t *euid, FAR uid_t *suid);
int getresgid(FAR gid_t *rgid, FAR gid_t *egid, FAR gid_t *sgid);

int getgroups(int, gid_t[]);

int getentropy(FAR void *buffer, size_t length);
Expand Down
4 changes: 3 additions & 1 deletion libs/libc/pwd/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,15 @@ if LIBC_PASSWD_FILE

config LIBC_PASSWD_FILEPATH
string "Path to passwd file"
default "/tmp/ostest_passwd" if TESTING_OSTEST_MULTIUSER
default "/etc/passwd"
---help---
Provides the location of the passwd file. The default is /etc/passwd
(/tmp/ostest_passwd when CONFIG_TESTING_OSTEST_MULTIUSER is enabled).

config LIBC_PASSWD_LINESIZE
int "Maximum line size"
default 80
default 256
---help---
The maximum length of one line in the passwd file. This determines
the size of the I/O buffer used to access the passwd file.
Expand Down
49 changes: 36 additions & 13 deletions libs/libc/pwd/lib_find_pwdfile.c
Original file line number Diff line number Diff line change
Expand Up @@ -170,14 +170,18 @@ static int pwd_foreach(pwd_foreach_match_t match, uintptr_t arg,
*
* The format of the password file is:
*
* user:x:uid:uid:geos:home
* user:x:uid:gid:home
*
* Or the standard six-field form with an optional gecos field:
*
* user:x:uid:gid:gecos:home
*
* Where:
* user: User name
* x: Encrypted password
* uid: User ID
* uid: Group ID
* geos: User information
* gid: Group ID
* gecos: User information (optional)
* home: Login directory
*/

Expand Down Expand Up @@ -259,26 +263,45 @@ static int pwd_foreach(pwd_foreach_match_t match, uintptr_t arg,
entry->pw_gid = (gid_t)atoi(save);
save = ptr;

/* Skip to the end of the user information and properly terminate it.
* The user information must be terminated with the field delimiter
* ':'.
/* NuttX passwd files use user:hash:uid:gid:home. Standard passwd
* files may include an optional gecos field:
* user:hash:uid:gid:gecos:home
*/

for (; *ptr != '\n' && *ptr != '\0' && *ptr != ':'; ptr++)
if (*ptr == ':')
{
}
/* Skip to the end of the user information and properly terminate
* it. The user information must be terminated with the field
* delimiter ':'.
*/

if (*ptr == '\n' || *ptr == '\0')
for (; *ptr != '\n' && *ptr != '\0' && *ptr != ':'; ptr++)
{
}

if (*ptr == '\n' || *ptr == '\0')
{
/* Bad line format? */

continue;
}

*ptr++ = '\0';
entry->pw_gecos = save;
entry->pw_dir = ptr;
}
else if (*save != '\0' && *save != '\n')
{
entry->pw_gecos = "";
entry->pw_dir = save;
}
else
{
/* Bad line format? */

continue;
}

*ptr++ = '\0';
entry->pw_gecos = save;
entry->pw_dir = ptr;

/* Skip to the end of the home directory and properly terminate it.
* The home directory must be the last thing on the line.
*/
Expand Down
8 changes: 5 additions & 3 deletions libs/libc/unistd/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,6 @@ set(SRCS
lib_statvfs.c
lib_sleep.c
lib_nice.c
lib_setreuid.c
lib_setregid.c
lib_getrusage.c
lib_utime.c
lib_utimes.c
Expand Down Expand Up @@ -87,7 +85,11 @@ if(NOT CONFIG_SCHED_USER_IDENTITY)
lib_seteuid.c
lib_setegid.c
lib_geteuid.c
lib_getegid.c)
lib_getegid.c
lib_setreuid.c
lib_setregid.c
lib_getresuid.c
lib_getresgid.c)
endif()

if(NOT CONFIG_DISABLE_ENVIRON)
Expand Down
3 changes: 2 additions & 1 deletion libs/libc/unistd/Make.defs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ CSRCS += lib_getcwd.c lib_getentropy.c lib_getopt_common.c lib_getopt.c
CSRCS += lib_getopt_long.c lib_getopt_longonly.c lib_getoptvars.c lib_getoptargp.c
CSRCS += lib_getopterrp.c lib_getoptindp.c lib_getoptoptp.c lib_times.c
CSRCS += lib_alarm.c lib_fstatvfs.c lib_statvfs.c lib_sleep.c lib_nice.c
CSRCS += lib_setreuid.c lib_setregid.c lib_getrusage.c lib_utime.c lib_utimes.c
CSRCS += lib_getrusage.c lib_utime.c lib_utimes.c
CSRCS += lib_setrlimit.c lib_getrlimit.c lib_setpriority.c lib_getpriority.c
CSRCS += lib_futimes.c lib_lutimes.c lib_gethostname.c lib_sethostname.c
CSRCS += lib_fchownat.c lib_linkat.c lib_readlinkat.c lib_symlinkat.c
Expand All @@ -39,6 +39,7 @@ CSRCS += lib_chdir.c lib_fchdir.c lib_confstr.c lib_ulimit.c
ifneq ($(CONFIG_SCHED_USER_IDENTITY),y)
CSRCS += lib_setuid.c lib_setgid.c lib_getuid.c lib_getgid.c
CSRCS += lib_seteuid.c lib_setegid.c lib_geteuid.c lib_getegid.c
CSRCS += lib_setreuid.c lib_setregid.c lib_getresuid.c lib_getresgid.c
endif

ifneq ($(CONFIG_DISABLE_ENVIRON),y)
Expand Down
Loading
Loading