@@ -213,8 +213,10 @@ static void cred_init_security(void)
213213{
214214 struct task_security_struct * tsec ;
215215
216+ /* NOTE: the lsm framework zeros out the buffer on allocation */
217+
216218 tsec = selinux_cred (unrcu_pointer (current -> real_cred ));
217- tsec -> osid = tsec -> sid = SECINITSID_KERNEL ;
219+ tsec -> osid = tsec -> sid = tsec -> avdcache . sid = SECINITSID_KERNEL ;
218220}
219221
220222/*
@@ -278,27 +280,21 @@ static int __inode_security_revalidate(struct inode *inode,
278280 struct dentry * dentry ,
279281 bool may_sleep )
280282{
281- struct inode_security_struct * isec = selinux_inode (inode );
283+ if (!selinux_initialized ())
284+ return 0 ;
282285
283- might_sleep_if (may_sleep );
286+ if (may_sleep )
287+ might_sleep ();
288+ else
289+ return - ECHILD ;
284290
285291 /*
286- * The check of isec->initialized below is racy but
287- * inode_doinit_with_dentry() will recheck with
288- * isec->lock held.
292+ * Check to ensure that an inode's SELinux state is valid and try
293+ * reloading the inode security label if necessary. This will fail if
294+ * @dentry is NULL and no dentry for this inode can be found; in that
295+ * case, continue using the old label.
289296 */
290- if (selinux_initialized () &&
291- data_race (isec -> initialized != LABEL_INITIALIZED )) {
292- if (!may_sleep )
293- return - ECHILD ;
294-
295- /*
296- * Try reloading the inode security label. This will fail if
297- * @opt_dentry is NULL and no dentry for this inode can be
298- * found; in that case, continue using the old label.
299- */
300- inode_doinit_with_dentry (inode , dentry );
301- }
297+ inode_doinit_with_dentry (inode , dentry );
302298 return 0 ;
303299}
304300
@@ -307,41 +303,53 @@ static struct inode_security_struct *inode_security_novalidate(struct inode *ino
307303 return selinux_inode (inode );
308304}
309305
310- static struct inode_security_struct * inode_security_rcu (struct inode * inode , bool rcu )
306+ static inline struct inode_security_struct * inode_security_rcu (struct inode * inode ,
307+ bool rcu )
311308{
312- int error ;
309+ int rc ;
310+ struct inode_security_struct * isec = selinux_inode (inode );
313311
314- error = __inode_security_revalidate (inode , NULL , !rcu );
315- if (error )
316- return ERR_PTR (error );
317- return selinux_inode (inode );
312+ /* check below is racy, but revalidate will recheck with lock held */
313+ if (data_race (likely (isec -> initialized == LABEL_INITIALIZED )))
314+ return isec ;
315+ rc = __inode_security_revalidate (inode , NULL , !rcu );
316+ if (rc )
317+ return ERR_PTR (rc );
318+ return isec ;
318319}
319320
320321/*
321322 * Get the security label of an inode.
322323 */
323- static struct inode_security_struct * inode_security (struct inode * inode )
324+ static inline struct inode_security_struct * inode_security (struct inode * inode )
324325{
326+ struct inode_security_struct * isec = selinux_inode (inode );
327+
328+ /* check below is racy, but revalidate will recheck with lock held */
329+ if (data_race (likely (isec -> initialized == LABEL_INITIALIZED )))
330+ return isec ;
325331 __inode_security_revalidate (inode , NULL , true);
326- return selinux_inode ( inode ) ;
332+ return isec ;
327333}
328334
329- static struct inode_security_struct * backing_inode_security_novalidate (struct dentry * dentry )
335+ static inline struct inode_security_struct * backing_inode_security_novalidate (struct dentry * dentry )
330336{
331- struct inode * inode = d_backing_inode (dentry );
332-
333- return selinux_inode (inode );
337+ return selinux_inode (d_backing_inode (dentry ));
334338}
335339
336340/*
337341 * Get the security label of a dentry's backing inode.
338342 */
339- static struct inode_security_struct * backing_inode_security (struct dentry * dentry )
343+ static inline struct inode_security_struct * backing_inode_security (struct dentry * dentry )
340344{
341345 struct inode * inode = d_backing_inode (dentry );
346+ struct inode_security_struct * isec = selinux_inode (inode );
342347
348+ /* check below is racy, but revalidate will recheck with lock held */
349+ if (data_race (likely (isec -> initialized == LABEL_INITIALIZED )))
350+ return isec ;
343351 __inode_security_revalidate (inode , dentry , true);
344- return selinux_inode ( inode ) ;
352+ return isec ;
345353}
346354
347355static void inode_free_security (struct inode * inode )
@@ -1683,12 +1691,15 @@ static inline int dentry_has_perm(const struct cred *cred,
16831691 struct dentry * dentry ,
16841692 u32 av )
16851693{
1686- struct inode * inode = d_backing_inode (dentry );
16871694 struct common_audit_data ad ;
1695+ struct inode * inode = d_backing_inode (dentry );
1696+ struct inode_security_struct * isec = selinux_inode (inode );
16881697
16891698 ad .type = LSM_AUDIT_DATA_DENTRY ;
16901699 ad .u .dentry = dentry ;
1691- __inode_security_revalidate (inode , dentry , true);
1700+ /* check below is racy, but revalidate will recheck with lock held */
1701+ if (data_race (unlikely (isec -> initialized != LABEL_INITIALIZED )))
1702+ __inode_security_revalidate (inode , dentry , true);
16921703 return inode_has_perm (cred , inode , av , & ad );
16931704}
16941705
@@ -1699,12 +1710,15 @@ static inline int path_has_perm(const struct cred *cred,
16991710 const struct path * path ,
17001711 u32 av )
17011712{
1702- struct inode * inode = d_backing_inode (path -> dentry );
17031713 struct common_audit_data ad ;
1714+ struct inode * inode = d_backing_inode (path -> dentry );
1715+ struct inode_security_struct * isec = selinux_inode (inode );
17041716
17051717 ad .type = LSM_AUDIT_DATA_PATH ;
17061718 ad .u .path = * path ;
1707- __inode_security_revalidate (inode , path -> dentry , true);
1719+ /* check below is racy, but revalidate will recheck with lock held */
1720+ if (data_race (unlikely (isec -> initialized != LABEL_INITIALIZED )))
1721+ __inode_security_revalidate (inode , path -> dentry , true);
17081722 return inode_has_perm (cred , inode , av , & ad );
17091723}
17101724
@@ -3088,44 +3102,147 @@ static noinline int audit_inode_permission(struct inode *inode,
30883102 audited , denied , result , & ad );
30893103}
30903104
3091- static int selinux_inode_permission (struct inode * inode , int mask )
3105+ /**
3106+ * task_avdcache_reset - Reset the task's AVD cache
3107+ * @tsec: the task's security state
3108+ *
3109+ * Clear the task's AVD cache in @tsec and reset it to the current policy's
3110+ * and task's info.
3111+ */
3112+ static inline void task_avdcache_reset (struct task_security_struct * tsec )
3113+ {
3114+ memset (& tsec -> avdcache .dir , 0 , sizeof (tsec -> avdcache .dir ));
3115+ tsec -> avdcache .sid = tsec -> sid ;
3116+ tsec -> avdcache .seqno = avc_policy_seqno ();
3117+ tsec -> avdcache .dir_spot = TSEC_AVDC_DIR_SIZE - 1 ;
3118+ }
3119+
3120+ /**
3121+ * task_avdcache_search - Search the task's AVD cache
3122+ * @tsec: the task's security state
3123+ * @isec: the inode to search for in the cache
3124+ * @avdc: matching avd cache entry returned to the caller
3125+ *
3126+ * Search @tsec for a AVD cache entry that matches @isec and return it to the
3127+ * caller via @avdc. Returns 0 if a match is found, negative values otherwise.
3128+ */
3129+ static inline int task_avdcache_search (struct task_security_struct * tsec ,
3130+ struct inode_security_struct * isec ,
3131+ struct avdc_entry * * avdc )
3132+ {
3133+ int orig , iter ;
3134+
3135+ /* focused on path walk optimization, only cache directories */
3136+ if (isec -> sclass != SECCLASS_DIR )
3137+ return - ENOENT ;
3138+
3139+ if (unlikely (tsec -> sid != tsec -> avdcache .sid ||
3140+ tsec -> avdcache .seqno != avc_policy_seqno ())) {
3141+ task_avdcache_reset (tsec );
3142+ return - ENOENT ;
3143+ }
3144+
3145+ orig = iter = tsec -> avdcache .dir_spot ;
3146+ do {
3147+ if (tsec -> avdcache .dir [iter ].isid == isec -> sid ) {
3148+ /* cache hit */
3149+ tsec -> avdcache .dir_spot = iter ;
3150+ * avdc = & tsec -> avdcache .dir [iter ];
3151+ return 0 ;
3152+ }
3153+ iter = (iter - 1 ) & (TSEC_AVDC_DIR_SIZE - 1 );
3154+ } while (iter != orig );
3155+
3156+ return - ENOENT ;
3157+ }
3158+
3159+ /**
3160+ * task_avdcache_update - Update the task's AVD cache
3161+ * @tsec: the task's security state
3162+ * @isec: the inode associated with the cache entry
3163+ * @avd: the AVD to cache
3164+ * @audited: the permission audit bitmask to cache
3165+ *
3166+ * Update the AVD cache in @tsec with the @avdc and @audited info associated
3167+ * with @isec.
3168+ */
3169+ static inline void task_avdcache_update (struct task_security_struct * tsec ,
3170+ struct inode_security_struct * isec ,
3171+ struct av_decision * avd ,
3172+ u32 audited )
30923173{
3174+ int spot ;
3175+
3176+ /* focused on path walk optimization, only cache directories */
3177+ if (isec -> sclass != SECCLASS_DIR )
3178+ return ;
3179+
3180+ /* update cache */
3181+ spot = (tsec -> avdcache .dir_spot + 1 ) & (TSEC_AVDC_DIR_SIZE - 1 );
3182+ tsec -> avdcache .dir_spot = spot ;
3183+ tsec -> avdcache .dir [spot ].isid = isec -> sid ;
3184+ tsec -> avdcache .dir [spot ].audited = audited ;
3185+ tsec -> avdcache .dir [spot ].allowed = avd -> allowed ;
3186+ tsec -> avdcache .dir [spot ].permissive = avd -> flags & AVD_FLAGS_PERMISSIVE ;
3187+ }
3188+
3189+ /**
3190+ * selinux_inode_permission - Check if the current task can access an inode
3191+ * @inode: the inode that is being accessed
3192+ * @requested: the accesses being requested
3193+ *
3194+ * Check if the current task is allowed to access @inode according to
3195+ * @requested. Returns 0 if allowed, negative values otherwise.
3196+ */
3197+ static int selinux_inode_permission (struct inode * inode , int requested )
3198+ {
3199+ int mask ;
30933200 u32 perms ;
3094- bool from_access ;
3095- bool no_block = mask & MAY_NOT_BLOCK ;
3201+ struct task_security_struct * tsec ;
30963202 struct inode_security_struct * isec ;
3097- u32 sid = current_sid ();
3098- struct av_decision avd ;
3203+ struct avdc_entry * avdc ;
30993204 int rc , rc2 ;
31003205 u32 audited , denied ;
31013206
3102- from_access = mask & MAY_ACCESS ;
3103- mask &= (MAY_READ |MAY_WRITE |MAY_EXEC |MAY_APPEND );
3207+ mask = requested & (MAY_READ |MAY_WRITE |MAY_EXEC |MAY_APPEND );
31043208
31053209 /* No permission to check. Existence test. */
31063210 if (!mask )
31073211 return 0 ;
31083212
3109- if (unlikely (IS_PRIVATE (inode )))
3110- return 0 ;
3111-
3112- perms = file_mask_to_av (inode -> i_mode , mask );
3113-
3114- isec = inode_security_rcu (inode , no_block );
3213+ isec = inode_security_rcu (inode , requested & MAY_NOT_BLOCK );
31153214 if (IS_ERR (isec ))
31163215 return PTR_ERR (isec );
3216+ tsec = selinux_cred (current_cred ());
3217+ perms = file_mask_to_av (inode -> i_mode , mask );
3218+
3219+ rc = task_avdcache_search (tsec , isec , & avdc );
3220+ if (likely (!rc )) {
3221+ /* Cache hit. */
3222+ audited = perms & avdc -> audited ;
3223+ denied = perms & ~avdc -> allowed ;
3224+ if (unlikely (denied && enforcing_enabled () &&
3225+ !avdc -> permissive ))
3226+ rc = - EACCES ;
3227+ } else {
3228+ struct av_decision avd ;
3229+
3230+ /* Cache miss. */
3231+ rc = avc_has_perm_noaudit (tsec -> sid , isec -> sid , isec -> sclass ,
3232+ perms , 0 , & avd );
3233+ audited = avc_audit_required (perms , & avd , rc ,
3234+ (requested & MAY_ACCESS ) ? FILE__AUDIT_ACCESS : 0 ,
3235+ & denied );
3236+ task_avdcache_update (tsec , isec , & avd , audited );
3237+ }
31173238
3118- rc = avc_has_perm_noaudit (sid , isec -> sid , isec -> sclass , perms , 0 ,
3119- & avd );
3120- audited = avc_audit_required (perms , & avd , rc ,
3121- from_access ? FILE__AUDIT_ACCESS : 0 ,
3122- & denied );
31233239 if (likely (!audited ))
31243240 return rc ;
31253241
31263242 rc2 = audit_inode_permission (inode , perms , audited , denied , rc );
31273243 if (rc2 )
31283244 return rc2 ;
3245+
31293246 return rc ;
31303247}
31313248
0 commit comments