Linux: use override_creds when available 51/13751/4
authorJeffrey Hutzelman <jhutz@cmu.edu>
Thu, 2 May 2019 20:02:47 +0000 (16:02 -0400)
committerBenjamin Kaduk <kaduk@mit.edu>
Fri, 28 Feb 2020 03:33:59 +0000 (22:33 -0500)
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>

src/afs/LINUX/osi_file.c
src/cf/linux-kernel-func.m4

index bb7cb77..7a14729 100644 (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);
@@ -75,6 +81,9 @@ afs_linux_raw_open(afs_dcache_id_t *ainode)
 #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, "
                  "but AFS accesses may return errors or panic the system\n",
@@ -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;
 }
index 597730f..0569073 100644 (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);])