From cd3221d3532a28111ad22d4090ec913cbbff40da Mon Sep 17 00:00:00 2001 From: Jeffrey Hutzelman Date: Thu, 2 May 2019 16:02:47 -0400 Subject: [PATCH] Linux: use override_creds when available Linux may perform some access control checks at the time of an I/O operation, rather than relying solely on checks done when the file is opened. In some cases (e.g. AppArmor), these checks are done based on the current tasks's creds at the time of the I/O operation, not those used when the file was open. Because of this, we must use override_creds() / revert_creds() to make sure we are using privileged credentials when performing I/O operations on cache files. Otherwise, cache I/O operations done in the context of a task with a restrictive AppArmor profile will fail. Change-Id: Icbe60874c348d6cd92b0a186d426918b0db9b0f9 Reviewed-on: https://gerrit.openafs.org/13751 Tested-by: BuildBot Reviewed-by: Andrew Deason Reviewed-by: Benjamin Kaduk --- src/afs/LINUX/osi_file.c | 34 ++++++++++++++++++++++++++++++++++ src/cf/linux-kernel-func.m4 | 3 +++ 2 files changed, 37 insertions(+) diff --git a/src/afs/LINUX/osi_file.c b/src/afs/LINUX/osi_file.c index bb7cb77101..7a147293f9 100644 --- a/src/afs/LINUX/osi_file.c +++ b/src/afs/LINUX/osi_file.c @@ -59,6 +59,9 @@ afs_linux_raw_open(afs_dcache_id_t *ainode) struct inode *tip = NULL; struct dentry *dp = NULL; struct file* filp; +#if defined(HAVE_LINUX_OVERRIDE_CREDS) + const struct cred *cur_cred; +#endif dp = afs_get_dentry_from_fh(afs_cacheSBp, ainode, cache_fh_len, cache_fh_type, afs_fh_acceptable); @@ -67,6 +70,9 @@ afs_linux_raw_open(afs_dcache_id_t *ainode) tip = dp->d_inode; tip->i_flags |= S_NOATIME; /* Disable updating access times. */ +#if defined(HAVE_LINUX_OVERRIDE_CREDS) + cur_cred = override_creds(cache_creds); +#endif #if defined(STRUCT_TASK_STRUCT_HAS_CRED) /* Use stashed credentials - prevent selinux/apparmor problems */ filp = afs_dentry_open(dp, afs_cacheMnt, O_RDWR, cache_creds); @@ -74,6 +80,9 @@ afs_linux_raw_open(afs_dcache_id_t *ainode) filp = afs_dentry_open(dp, afs_cacheMnt, O_RDWR, current_cred()); #else filp = dentry_open(dget(dp), mntget(afs_cacheMnt), O_RDWR); +#endif +#if defined(HAVE_LINUX_OVERRIDE_CREDS) + revert_creds(cur_cred); #endif if (IS_ERR(filp)) { afs_warn("afs: Cannot open cache file (code %d). Trying to continue, " @@ -168,10 +177,20 @@ afs_osi_Stat(struct osi_file *afile, struct osi_stat *astat) int osi_UFSClose(struct osi_file *afile) { +#if defined(HAVE_LINUX_OVERRIDE_CREDS) + const struct cred *cur_cred; +#endif + AFS_STATCNT(osi_Close); if (afile) { if (OSIFILE_INODE(afile)) { +#if defined(HAVE_LINUX_OVERRIDE_CREDS) + cur_cred = override_creds(cache_creds); +#endif filp_close(afile->filp, NULL); +#if defined(HAVE_LINUX_OVERRIDE_CREDS) + revert_creds(cur_cred); +#endif } } kfree(afile); @@ -185,12 +204,18 @@ osi_UFSTruncate(struct osi_file *afile, afs_int32 asize) struct osi_stat tstat; struct iattr newattrs; struct inode *inode = OSIFILE_INODE(afile); +#if defined(HAVE_LINUX_OVERRIDE_CREDS) + const struct cred *cur_cred; +#endif AFS_STATCNT(osi_Truncate); /* This routine only shrinks files, and most systems * have very slow truncates, even when the file is already * small enough. Check now and save some time. */ +#if defined(HAVE_LINUX_OVERRIDE_CREDS) + cur_cred = override_creds(cache_creds); +#endif code = afs_osi_Stat(afile, &tstat); if (code || tstat.size <= asize) return code; @@ -218,6 +243,9 @@ osi_UFSTruncate(struct osi_file *afile, afs_int32 asize) up_write(&inode->i_alloc_sem); #endif afs_linux_unlock_inode(inode); +#if defined(HAVE_LINUX_OVERRIDE_CREDS) + revert_creds(cur_cred); +#endif AFS_GLOCK(); return code; } @@ -379,6 +407,9 @@ osi_rdwr(struct osi_file *osifile, struct uio *uiop, int rw) size_t count; unsigned long savelim; loff_t pos; +#if defined(HAVE_LINUX_OVERRIDE_CREDS) + const struct cred *cur_cred = override_creds(cache_creds); +#endif savelim = current->TASK_STRUCT_RLIM[RLIMIT_FSIZE].rlim_cur; current->TASK_STRUCT_RLIM[RLIMIT_FSIZE].rlim_cur = RLIM_INFINITY; @@ -434,6 +465,9 @@ osi_rdwr(struct osi_file *osifile, struct uio *uiop, int rw) #endif /* AFS_FILE_NEEDS_SET_FS */ current->TASK_STRUCT_RLIM[RLIMIT_FSIZE].rlim_cur = savelim; +#if defined(HAVE_LINUX_OVERRIDE_CREDS) + revert_creds(cur_cred); +#endif return code; } diff --git a/src/cf/linux-kernel-func.m4 b/src/cf/linux-kernel-func.m4 index 597730f5f4..0569073fb6 100644 --- a/src/cf/linux-kernel-func.m4 +++ b/src/cf/linux-kernel-func.m4 @@ -86,6 +86,9 @@ AC_CHECK_LINUX_FUNC([ktime_get_real_ts64], AC_CHECK_LINUX_FUNC([locks_lock_file_wait], [#include ], [locks_lock_file_wait(NULL, NULL);]) +AC_CHECK_LINUX_FUNC([override_creds], + [#include ], + [override_creds(0);]) AC_CHECK_LINUX_FUNC([page_follow_link], [#include ], [page_follow_link(0,0);])