LINUX: defer afs_remunlink when current->fs==NULL 91/14691/6
authorYadavendra Yadav <yadayada@in.ibm.com>
Wed, 7 Jul 2021 16:32:36 +0000 (12:32 -0400)
committerBenjamin Kaduk <kaduk@mit.edu>
Thu, 29 Jul 2021 15:55:09 +0000 (11:55 -0400)
afs_remunlink is called to delete a file on the fileserver after it
has been silly-renamed (due to being unlinked while the file is open).
Sometimes current->fs is NULL when this happens, typically when the
process is shutting down, after current->fs has been freed and file
handles are getting released. During afs_remunlink, we need to
interact with our cache files, and so we call dentry_open, which calls
security_file_open, which calls into the configured LSM for security
checks. Certain LSMs (e.g. Crowdstrike Falcon) will panic the kernel
in this situation if current->fs is NULL.

There's no way to skip the LSM hooks, or to flag to the LSM that we're
making an in-kernel VFS call, so the only way to avoid these panics is
to do our I/O in another thread. Fortunately, we already have a way to
defer afs_remunlink calls to a background daemon (CUnlinkedDel), since
we already do this in some cases (when someone else is holding
afs_xvcache or afs_xdcache).

So, to avoid the panic in the above scenario, defer calls to
afs_remunlink to a background daemon using CUnlinkedDel when
current->fs is NULL, and we're using a disk cache.

More details on this issue is discussed at following thread:
https://lists.openafs.org/pipermail/openafs-info/2021-March/043073.html

Change-Id: I1ee83d088a9b661d2974ce24b36bfd9f6ea4e7e9
Reviewed-on: https://gerrit.openafs.org/14691
Tested-by: BuildBot <buildbot@rampaginggeek.com>
Tested-by: Jonathan Billings <jsbillings@jsbillings.org>
Reviewed-by: Benjamin Kaduk <kaduk@mit.edu>
Reviewed-by: Andrew Deason <adeason@sinenomine.net>

src/afs/LINUX/osi_vcache.c
src/afs/afs_osi.h
src/afs/afs_vcache.c

index 0d810b1..478602b 100644 (file)
@@ -251,3 +251,32 @@ osi_vnhold(struct vcache *avc)
     VN_HOLD(AFSTOV(avc));
     return 0;
 }
+
+/**
+ * Should we defer calling afs_remunlink(avc) to a background daemon, or can we
+ * call it in the current process?
+ *
+ * @param[in] avc   The vcache we're going to call afs_remunlink on
+ *
+ * @retval 0   call afs_remunlink in the current task
+ * @retval 1   call afs_remunlink in the background
+ */
+int
+osi_ShouldDeferRemunlink(struct vcache *avc)
+{
+    if (cacheDiskType == AFS_FCACHE_TYPE_UFS && current->fs == NULL) {
+       /*
+        * If current->fs is NULL (which can happen when the current process is
+        * in the middle of exiting), then calling dentry_open can result in a
+        * kernel panic with certain LSMs (e.g. Crowdstrike Falcon).
+        *
+        * If we have a disk cache, calling afs_remunlink generally involves
+        * calling dentry_open, since we need to interact with the disk cache,
+        * and so calling afs_remunlink can cause a panic. So, make sure we
+        * defer afs_remunlink to a background daemon, where current->fs is not
+        * NULL, and so it won't panic the machine.
+        */
+       return 1;
+    }
+    return 0;
+}
index 4dc6101..f8a6316 100644 (file)
@@ -440,4 +440,10 @@ extern afs_ucred_t afs_osi_cred, *afs_osi_credp;
 #define AFS_NUMPAGGROUPS 2
 #endif
 
+#ifdef AFS_LINUX_ENV
+extern int osi_ShouldDeferRemunlink(struct vcache *avc);
+#else
+# define osi_ShouldDeferRemunlink(avc) 0
+#endif
+
 #endif /* _AFS_OSI_ */
index 80ddfb4..6ff81b9 100644 (file)
@@ -322,7 +322,8 @@ afs_InactiveVCache(struct vcache *avc, afs_ucred_t *acred)
     avc->f.states &= ~CMAPPED;
     avc->f.states &= ~CDirty;  /* Turn it off */
     if (avc->f.states & CUnlinked) {
-       if (CheckLock(&afs_xvcache) || CheckLock(&afs_xdcache)) {
+       if (CheckLock(&afs_xvcache) || CheckLock(&afs_xdcache) ||
+           osi_ShouldDeferRemunlink(avc)) {
            avc->f.states |= CUnlinkedDel;
            ReleaseWriteLock(&avc->lock);
            return;