2727#include <assert.h>
2828#include <errno.h>
2929#include <fcntl.h>
30+ #include <unistd.h>
3031
3132#include <nuttx/fs/fs.h>
3233#include <nuttx/rwsem.h>
4849
4950static rw_semaphore_t g_inode_lock = RWSEM_INITIALIZER ;
5051
52+ /****************************************************************************
53+ * Private Functions
54+ ****************************************************************************/
55+
56+ /****************************************************************************
57+ * Name: _inode_checkmode
58+ *
59+ * Description:
60+ * Test effective credentials against 'inode' for 'amode' access.
61+ * Kernel threads always pass.
62+ *
63+ * Returned Value:
64+ * Zero (OK) or -EACCES.
65+ *
66+ ****************************************************************************/
67+
68+ #if defined(CONFIG_PSEUDOFS_ATTRIBUTES ) && defined(CONFIG_SCHED_USER_IDENTITY )
69+ static int _inode_checkmode (FAR struct inode * inode , int amode )
70+ {
71+ FAR struct tcb_s * rtcb ;
72+ mode_t perm ;
73+ uid_t uid ;
74+ gid_t gid ;
75+
76+ /* Kernel threads are always granted access */
77+
78+ rtcb = nxsched_self ();
79+ if ((rtcb -> flags & TCB_FLAG_TTYPE_MASK ) == TCB_FLAG_TTYPE_KERNEL )
80+ {
81+ return OK ;
82+ }
83+
84+ /* Use effective credentials */
85+
86+ DEBUGASSERT (rtcb -> group != NULL );
87+ uid = rtcb -> group -> tg_euid ;
88+ gid = rtcb -> group -> tg_egid ;
89+
90+ /* Select the applicable permission-bit triplet */
91+
92+ if (uid == inode -> i_owner )
93+ {
94+ perm = (inode -> i_mode >> 6 ) & 7 ;
95+ }
96+ else if (gid == inode -> i_group )
97+ {
98+ perm = (inode -> i_mode >> 3 ) & 7 ;
99+ }
100+ else
101+ {
102+ perm = inode -> i_mode & 7 ;
103+ }
104+
105+ /* Every requested bit must be present in the selected triplet */
106+
107+ if ((amode & perm ) != amode )
108+ {
109+ return - EACCES ;
110+ }
111+
112+ return OK ;
113+ }
114+ #endif /* CONFIG_PSEUDOFS_ATTRIBUTES && CONFIG_SCHED_USER_IDENTITY */
115+
51116/****************************************************************************
52117 * Public Functions
53118 ****************************************************************************/
@@ -124,49 +189,45 @@ void inode_runlock(void)
124189 * Name: inode_checkperm
125190 *
126191 * Description:
127- * Validate that 'inode' can be opened with the access described by
128- * 'oflags'. Two sequential checks are performed:
129- *
130- * 1. Operation-support check (all inode types, unconditional):
131- * Verifies the driver exposes the read/write entry points required by
132- * 'oflags'. Returns -ENXIO when ops are NULL and -EACCES when the
133- * required entry point is absent. Pseudo-directory inodes
134- * (INODE_IS_PSEUDODIR) are exempted from this step.
135- *
136- * 2. UNIX permission check (pseudo-filesystem inodes only):
137- * Compares effective uid/gid against i_mode owner/group/other bits.
138- * Mountpoint inodes and kernel threads are unconditionally exempted.
139- * Requires CONFIG_PSEUDOFS_ATTRIBUTES and CONFIG_SCHED_USER_IDENTITY;
140- * when either option is disabled this step is a no-op.
192+ * Validate open access to 'inode' for 'oflags'. Checks driver operation
193+ * support, then pseudo-filesystem mode bits when enabled. Mountpoints
194+ * are exempt from mode checks.
141195 *
142196 * Input Parameters:
143197 * inode - The inode to check
144198 * oflags - Open flags (O_RDONLY / O_WRONLY / O_RDWR)
145199 *
146200 * Returned Value:
147- * Zero (OK) on success. Negated errno on failure:
148- * -ENXIO ops pointer is NULL
149- * -EACCES required operation not supported, or permission denied
201+ * Zero (OK) on success, or a negated errno on failure.
150202 *
151203 ****************************************************************************/
152204
153205int inode_checkperm (FAR struct inode * inode , int oflags )
154206{
155207#if defined(CONFIG_PSEUDOFS_ATTRIBUTES ) && defined(CONFIG_SCHED_USER_IDENTITY )
156- FAR struct tcb_s * rtcb ;
157- mode_t perm ;
158- uid_t uid ;
159- gid_t gid ;
208+ int amode = 0 ;
160209#endif
161210 FAR const struct file_operations * ops ;
162211
163- /* === Step 1: operation-support check === */
212+ #if defined(CONFIG_PSEUDOFS_ATTRIBUTES ) && defined(CONFIG_SCHED_USER_IDENTITY )
213+ if ((oflags & O_RDOK ) != 0 )
214+ {
215+ amode |= R_OK ;
216+ }
164217
165- /* Pseudo-directories carry no ops and are always accessible */
218+ if ((oflags & O_WROK ) != 0 )
219+ {
220+ amode |= W_OK ;
221+ }
222+ #endif
166223
167224 if (INODE_IS_PSEUDODIR (inode ))
168225 {
226+ #if defined(CONFIG_PSEUDOFS_ATTRIBUTES ) && defined(CONFIG_SCHED_USER_IDENTITY )
227+ return _inode_checkmode (inode , amode );
228+ #else
169229 return OK ;
230+ #endif
170231 }
171232
172233 ops = inode -> u .i_ops ;
@@ -185,61 +246,51 @@ int inode_checkperm(FAR struct inode *inode, int oflags)
185246
186247#if defined(CONFIG_PSEUDOFS_ATTRIBUTES ) && defined(CONFIG_SCHED_USER_IDENTITY )
187248
188- /* === Step 2: UNIX permission check (pseudo-filesystem inodes only) === */
189-
190- /* Mountpoints delegate permission enforcement to the underlying
191- * filesystem
192- */
193-
194249 if (INODE_IS_MOUNTPT (inode ))
195250 {
196251 return OK ;
197252 }
198253
199- /* Kernel threads are always granted access */
200-
201- rtcb = nxsched_self ();
202- if ((rtcb -> flags & TCB_FLAG_TTYPE_MASK ) == TCB_FLAG_TTYPE_KERNEL )
203- {
204- return OK ;
205- }
206-
207- /* Use effective credentials */
254+ return _inode_checkmode (inode , amode );
208255
209- DEBUGASSERT (rtcb -> group != NULL );
210- uid = rtcb -> group -> tg_euid ;
211- gid = rtcb -> group -> tg_egid ;
256+ #endif /* CONFIG_PSEUDOFS_ATTRIBUTES && CONFIG_SCHED_USER_IDENTITY */
212257
213- /* Select the applicable permission-bit triplet */
258+ return OK ;
259+ }
214260
215- if (uid == inode -> i_owner )
216- {
217- perm = (inode -> i_mode >> 6 ) & 7 ;
218- }
219- else if (gid == inode -> i_group )
220- {
221- perm = (inode -> i_mode >> 3 ) & 7 ;
222- }
223- else
224- {
225- perm = inode -> i_mode & 7 ;
226- }
261+ /****************************************************************************
262+ * Name: inode_checkdirperm
263+ *
264+ * Description:
265+ * Check parent directory 'dir' for 'amode' access on pseudo-filesystem
266+ * inodes. NULL 'dir' (root) and mountpoints are exempt.
267+ *
268+ * Input Parameters:
269+ * dir - Parent directory inode, or NULL for a root-level path
270+ * amode - Access mode bitmask (R_OK / W_OK / X_OK)
271+ *
272+ * Returned Value:
273+ * Zero (OK) on success, or -EACCES if permission is denied.
274+ *
275+ ****************************************************************************/
227276
228- /* Bit 2 (value 4) = read permission */
277+ int inode_checkdirperm (FAR struct inode * dir , int amode )
278+ {
279+ #if defined(CONFIG_PSEUDOFS_ATTRIBUTES ) && defined(CONFIG_SCHED_USER_IDENTITY )
229280
230- if ((( oflags & O_RDOK ) != 0 ) && (( perm & 4 ) == 0 ) )
281+ if (dir == NULL )
231282 {
232- return - EACCES ;
283+ return OK ;
233284 }
234285
235- /* Bit 1 (value 2) = write permission */
236-
237- if (((oflags & O_WROK ) != 0 ) && ((perm & 2 ) == 0 ))
286+ if (INODE_IS_MOUNTPT (dir ))
238287 {
239- return - EACCES ;
288+ return OK ;
240289 }
241290
242- #endif /* CONFIG_PSEUDOFS_ATTRIBUTES && CONFIG_SCHED_USER_IDENTITY */
291+ return _inode_checkmode ( dir , amode );
243292
293+ #else
244294 return OK ;
295+ #endif /* CONFIG_PSEUDOFS_ATTRIBUTES && CONFIG_SCHED_USER_IDENTITY */
245296}
0 commit comments