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 <buildbot@rampaginggeek.com>
Reviewed-by: Andrew Deason <adeason@sinenomine.net>
Reviewed-by: Benjamin Kaduk <kaduk@mit.edu>
This commit is contained in:
Jeffrey Hutzelman 2019-05-02 16:02:47 -04:00 committed by Benjamin Kaduk
parent 042f809ccf
commit cd3221d353
2 changed files with 37 additions and 0 deletions

View File

@ -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;
}

View File

@ -86,6 +86,9 @@ AC_CHECK_LINUX_FUNC([ktime_get_real_ts64],
AC_CHECK_LINUX_FUNC([locks_lock_file_wait],
[#include <linux/fs.h>],
[locks_lock_file_wait(NULL, NULL);])
AC_CHECK_LINUX_FUNC([override_creds],
[#include <linux/cred.h>],
[override_creds(0);])
AC_CHECK_LINUX_FUNC([page_follow_link],
[#include <linux/fs.h>],
[page_follow_link(0,0);])