From 8b6ae2893b517bd4e008cae94acff70abe4d2227 Mon Sep 17 00:00:00 2001 From: Andrew Deason Date: Thu, 21 Mar 2019 15:24:06 -0500 Subject: [PATCH] LINUX: Avoid lookup ENOENT on fatal signals Various Linux kernel operations on various Linux kernel versions can fail if the current process has a pending fatal signal (i.e. SIGKILL), including reads and writes to our local disk cache. Depending on what and when something fails because of this, some parts of libafs throw an ENOENT error, which may propagate up to callers, and be returned from afs_lookup(). Notably this can happen via some functions in src/dir/dir.c, and previously was possible with some code paths before they were fixed by commit 2aa4cb04 (afs: Stop abusing ENOENT). For the most part, the exact error given to the userspace caller doesn't matter, since the process will die as soon as we return to userspace. However, for ENOENT errors specifically for lookups, we interpret this to mean that the target filename is known to not exist, and so we create a negative dentry for that name, which is cached. Future lookups for that filename will then result in ENOENT before any AFS functions are called. The lingering abuses of the ENOENT error code should be removed from libafs entirely, but as an extra layer of safety, we can just avoid returning ENOENT from lookups if the current process has a pending fatal signal. So to do that, change all afs_lookup() callers in src/afs/LINUX to translate ENOENT to EINTR if we have a pending fatal signal. If fatal_signal_pending() is not available, then we don't do this translation. FIXES 134904 Change-Id: I00f1516c2aa0f45f1129f5d5a44150b7539c31cc Reviewed-on: https://gerrit.openafs.org/13530 Tested-by: BuildBot Reviewed-by: Cheyenne Wills Reviewed-by: Michael Meffie Reviewed-by: Benjamin Kaduk --- src/afs/LINUX/osi_vnodeops.c | 13 +++++++++++++ src/cf/linux-kernel-func.m4 | 3 +++ 2 files changed, 16 insertions(+) diff --git a/src/afs/LINUX/osi_vnodeops.c b/src/afs/LINUX/osi_vnodeops.c index ee8b414..e3422ca 100644 --- a/src/afs/LINUX/osi_vnodeops.c +++ b/src/afs/LINUX/osi_vnodeops.c @@ -1141,6 +1141,17 @@ parent_vcache_dv(struct inode *inode, cred_t *credp) return hgetlo(pvcp->f.m.DataVersion); } +static inline int +filter_enoent(int code) +{ +#ifdef HAVE_LINUX_FATAL_SIGNAL_PENDING + if (code == ENOENT && fatal_signal_pending(current)) { + return EINTR; + } +#endif + return code; +} + #ifndef D_SPLICE_ALIAS_RACE static inline void dentry_race_lock(void) {} @@ -1310,6 +1321,7 @@ afs_linux_dentry_revalidate(struct dentry *dp, int flags) credp = crref(); } code = afs_lookup(pvcp, (char *)dp->d_name.name, &tvc, credp); + code = filter_enoent(code); if (code) { /* We couldn't perform the lookup, so we're not okay. */ @@ -1601,6 +1613,7 @@ afs_linux_lookup(struct inode *dip, struct dentry *dp) AFS_GLOCK(); code = afs_lookup(VTOAFS(dip), (char *)comp, &vcp, credp); + code = filter_enoent(code); if (code == ENOENT) { /* It's ok for the file to not be found. That's noted by the caller by * seeing that the dp->d_inode field is NULL (set by d_splice_alias or diff --git a/src/cf/linux-kernel-func.m4 b/src/cf/linux-kernel-func.m4 index 34c5fa4..597730f 100644 --- a/src/cf/linux-kernel-func.m4 +++ b/src/cf/linux-kernel-func.m4 @@ -42,6 +42,9 @@ AC_CHECK_LINUX_FUNC([d_make_root], AC_CHECK_LINUX_FUNC([do_sync_read], [#include ], [do_sync_read(NULL, NULL, 0, NULL);]) +AC_CHECK_LINUX_FUNC([fatal_signal_pending], + [#include ], + [fatal_signal_pending(NULL);]) AC_CHECK_LINUX_FUNC([file_dentry], [#include ], [struct file *f; file_dentry(f);]) -- 1.9.4