This is an automated email from the ASF dual-hosted git repository. acassis pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/nuttx.git
commit 4002e6af5f99ec7bf2fb91335f4c325c1ec95d9c Author: Abhishek Mishra <[email protected]> AuthorDate: Sun Aug 2 17:54:38 2026 +0000 Documentation: describe FS permission interface and mount-crossing Document inode_checkperm / inode_checkpathperm, mountpoint traverse vs open semantics, and the optional mountpt_operations.permission hook in file_permission.rst. Signed-off-by: Abhishek Mishra <[email protected]> --- Documentation/components/filesystem/littlefs.rst | 3 + Documentation/components/filesystem/pseudofs.rst | 4 + Documentation/components/filesystem/tmpfs.rst | 10 ++ Documentation/implementation/file_permission.rst | 137 +++++++++++++++++++++++ Documentation/implementation/index.rst | 1 + Documentation/implementation/user_identity.rst | 13 ++- 6 files changed, 165 insertions(+), 3 deletions(-) diff --git a/Documentation/components/filesystem/littlefs.rst b/Documentation/components/filesystem/littlefs.rst index 35c042cc8f7..7eeb477012e 100644 --- a/Documentation/components/filesystem/littlefs.rst +++ b/Documentation/components/filesystem/littlefs.rst @@ -57,3 +57,6 @@ target directory. Files created before permission support was enabled, or without stored attributes, default to mode ``0777`` until ``chmod``/``chown`` sets explicit metadata. + +Path components above the littlefs mountpoint are enforced by the VFS; see +:ref:`file-permission`. diff --git a/Documentation/components/filesystem/pseudofs.rst b/Documentation/components/filesystem/pseudofs.rst index c8e13cd4007..e8397094fac 100644 --- a/Documentation/components/filesystem/pseudofs.rst +++ b/Documentation/components/filesystem/pseudofs.rst @@ -211,3 +211,7 @@ will also fail. You cannot do this, for example: See also NxFileSystem in `Porting Guide <https://cwiki.apache.org/confluence/display/NUTTX/Porting+Guide>`_ + +When ``CONFIG_FS_PERMISSION`` is enabled, pseudoFS directory modes also gate +access into mounted volumes beneath them. See +:ref:`file-permission`. diff --git a/Documentation/components/filesystem/tmpfs.rst b/Documentation/components/filesystem/tmpfs.rst index 1d0dacb4901..c6f146e9ace 100644 --- a/Documentation/components/filesystem/tmpfs.rst +++ b/Documentation/components/filesystem/tmpfs.rst @@ -11,3 +11,13 @@ At runtime, simply use ``mount -t tmpfs /tmp`` to have a ``/tmp`` folder backed Be aware that TMPFS is backed by kernel memory thus don't expect to store big files on it and its size is limited by free kernel memory. We can watch the size of TMPFS with ``df -h`` command, especially you can see the ``Size`` column of TMPFS changes when files are added or removed in the TMPFS folder. Changes in TMPFS size is always reflected by reverse changes of free kernel memory size. + +Permissions +=========== + +When ``CONFIG_FS_PERMISSION`` is enabled, tmpfs stores per-object owner, group, +and mode and enforces them on path operations inside the volume. It also +implements the optional ``mountpt_operations.permission`` hook. + +Access into the mount from the pseudoFS is gated by the VFS (parent and +mountpoint ``X_OK``). See :ref:`file-permission`. diff --git a/Documentation/implementation/file_permission.rst b/Documentation/implementation/file_permission.rst new file mode 100644 index 00000000000..6b6f50c5118 --- /dev/null +++ b/Documentation/implementation/file_permission.rst @@ -0,0 +1,137 @@ +.. _file-permission: + +======================================== +Filesystem Permission Interface +======================================== + +When ``CONFIG_FS_PERMISSION`` is enabled, the VFS applies POSIX-style +discretionary access control (DAC) using the caller's effective credentials +(``tg_euid`` / ``tg_egid``). This page describes the common inode helpers, +how mountpoints participate, and how access across a mount is gated by +pseudoFS directory modes. + +Prerequisite reading: :ref:`user-identity`. + +Configuration +============= + +=============================== ============================================= +Option Role +=============================== ============================================= +``CONFIG_SCHED_USER_IDENTITY`` Per-task-group UID/GID credentials +``CONFIG_PSEUDOFS_ATTRIBUTES`` Store ``i_mode`` / ``i_owner`` / ``i_group`` + on pseudoFS inodes +``CONFIG_FS_PERMISSION`` Enable DAC helpers and VFS enforcement + (depends on the two options above) +=============================== ============================================= + +Without ``CONFIG_FS_PERMISSION``, the helpers described here return success +and no mode-based checks are performed. + +Helpers +======= + +``inode_checkperm`` + Check ``amode`` (``R_OK`` / ``W_OK`` / ``X_OK``) against an inode's + ``i_owner`` / ``i_group`` / ``i_mode``. Empty macro returning ``0`` + when ``CONFIG_FS_PERMISSION`` is disabled. + +``inode_checkpathperm`` + Require ``X_OK`` on every ancestor of an inode, and on the inode itself + when it is a pseudo directory or a mountpoint (directory search / + traverse). If ``amode`` is non-zero, also require that access on the + inode. Takes the inode tree read lock unless ``INODE_CHECK_LOCKED`` is + set (caller already holds ``inode_lock`` / ``inode_rlock``). Empty + macro returning ``0`` when ``CONFIG_FS_PERMISSION`` is disabled. + +``inode_checkopenperm`` + Validate that the inode supports the requested open access, then apply + mode checks for non-mountpoint inodes. + +``fs_checkmode`` + Core owner/group/other test used by the helpers above and by filesystems + such as tmpfs and littlefs. + +Optional mountpoint hook +------------------------ + +``struct mountpt_operations`` may provide a ``permission`` method for +in-volume DAC. The field is at the **end** of the structure so existing +positional initialisers remain valid. + +* **tmpfs** implements ``tmpfs_permission``. +* Filesystems without Unix ownership on disk (for example FAT and ROMFS) + leave the method ``NULL``. + +The VFS mount-crossing gate does **not** depend on this hook. Entry into a +volume is enforced with ``inode_checkpathperm`` against the mountpoint +inode's stored ``i_mode``. In-volume checks remain the filesystem's job +(tmpfs and littlefs enforce DAC inside their own open/mkdir/path helpers. +``mops->permission`` is an optional common entry point for the same policy; +the VFS does not invoke it for mount-crossing). + +Open vs traverse +================ + +Mountpoint inodes are **not** open-mode-checked by ``inode_checkopenperm``. +Applying the mount directory's mode bits as file open modes would require +read/write on the mount directory merely to open a file beneath it. + +Traverse is separate: callers use ``inode_checkpathperm`` so parent +directories and the mountpoint itself still require ``X_OK``. + +Typical order after a successful ``inode_find``: + +1. ``inode_checkpathperm(inode, 0, 0)`` — search permission on the path + prefix (and on the mountpoint when entering a volume). Call sites that + already hold the tree lock pass ``INODE_CHECK_LOCKED``; mount and + pseudoFS create/remove may pass a non-zero ``amode`` (for example + ``W_OK``) to combine traverse and target checks in one call. +2. Operation-specific checks — ``inode_checkopenperm``, or the + filesystem's own methods for paths inside a mount. + +Mount-crossing +============== + +Path walk stops at a mountpoint and returns that inode plus a relative path +into the volume. Without traverse checks, a restrictive mode on a pseudoFS +parent would not protect objects under a filesystem mounted beneath it. + +Example:: + + /secure_dir # pseudoFS directory, mode 0700, owner root + /secure_dir/mnt # mounted volume (tmpfs, FAT, ...) + /secure_dir/mnt/a # object inside the volume + +``inode_checkpathperm`` requires ``X_OK`` on ``secure_dir`` and on the +mountpoint ``mnt``. A non-root open of ``/secure_dir/mnt/a`` therefore +returns ``EACCES``, even if the mounted filesystem itself has no Unix DAC. + +Where the checks run +-------------------- + +* After ``inode_find`` in open, unlink, mkdir, rmdir, rename, stat, chstat, + statfs, readlink, mount, and umount. ``inode_checkpathperm`` takes + ``inode_rlock`` unless the caller already holds the tree lock + (``INODE_CHECK_LOCKED``). +* Inside ``inode_reserve`` / ``inode_remove`` for pseudoFS create and remove + (ancestor ``X_OK`` and parent ``W_OK`` in one call, under ``inode_lock``). + +Who enforces what +----------------- + +* **PseudoFS parent dirs** — ``X_OK`` (and ``W_OK`` when creating/removing) +* **Mountpoint inode** — ``X_OK`` to enter the volume (stored ``i_mode``) +* **Inside the volume** — Filesystem methods; optional ``mops->permission`` +* **FAT / ROMFS** — No Unix ownership on disk; entry still gated by the + mountpoint ``i_mode`` + +References +========== + +* ``fs/inode/fs_inode.c`` — ``inode_checkperm``, ``inode_checkpathperm`` +* ``include/nuttx/fs/fs.h`` — ``struct mountpt_operations`` +* ``fs/tmpfs/fs_tmpfs.c`` — ``tmpfs_permission`` +* :ref:`user-identity` — credential model +* :doc:`/components/filesystem/littlefs` — littlefs in-volume DAC +* :doc:`/components/filesystem/tmpfs` — tmpfs overview diff --git a/Documentation/implementation/index.rst b/Documentation/implementation/index.rst index 5ea1eaa7224..4d53b205c6d 100644 --- a/Documentation/implementation/index.rst +++ b/Documentation/implementation/index.rst @@ -16,6 +16,7 @@ Implementation Details device_nodes.rst drivers_design.rst file_descriptors.rst + file_permission.rst hardfaults.rst interrupt_controls.rst ioctl.rst diff --git a/Documentation/implementation/user_identity.rst b/Documentation/implementation/user_identity.rst index 5c9486901bd..a831a1f2353 100644 --- a/Documentation/implementation/user_identity.rst +++ b/Documentation/implementation/user_identity.rst @@ -86,7 +86,9 @@ Configuration ``CONFIG_FS_PERMISSION`` Enables filesystem ownership and permission enforcement. Requires - ``CONFIG_SCHED_USER_IDENTITY``. + ``CONFIG_SCHED_USER_IDENTITY`` and ``CONFIG_PSEUDOFS_ATTRIBUTES``. + See :ref:`file-permission` for the VFS helpers, mount-crossing + traverse rules, and testing notes. Pseudo-Filesystem Ownership =========================== @@ -96,5 +98,10 @@ 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). +created through the same inode reservation path. + +Path resolution requires directory search permission (``X_OK``) on ancestors +via ``inode_checkpathperm()``. Open-time checks on the final node use +``inode_checkopenperm()`` (or ``inode_checkperm()`` for named IPC +objects). Full details, including mounts under private pseudoFS parents, +are in :ref:`file-permission`.
