LINUX: Properly revert creds in osi_UFSTruncate 98/14098/2
authorAndrew Deason <adeason@sinenomine.net>
Fri, 13 Mar 2020 18:00:35 +0000 (13:00 -0500)
committerBenjamin Kaduk <kaduk@mit.edu>
Fri, 13 Mar 2020 19:28:31 +0000 (15:28 -0400)
Commit cd3221d3 (Linux: use override_creds when available) caused us
to force the current process's creds to the creds of afsd during
osi_file.c file ops, to avoid access errors in some cases.

However, in osi_UFSTruncate, one code path was missed to revert our
creds back to the original user's creds: when the afs_osi_Stat call
fails or deems the truncate unnecessary. In this case, the calling
process keeps the creds for afsd after osi_UFSTruncate returns,
causing our subsequent access-checking code to think that the current
process is in the same context as afsd (typically uid 0 without a
pag).

This can cause the calling process to appear to transiently have the
same access as non-pag uid 0; typically this will be unauthenticated
access, but could be authenticated if uid 0 has tokens.

To fix this, modify the early return in osi_UFSTruncate to go through
a 'goto done' destructor instead, and make sure we revert our creds in
that destructor.

Thanks to cwills@sinenomine.net for finding and helping reproduce the
issue.

Change-Id: I6820af675edcb7aa00542ba40fc52430d68c05e8
Reviewed-on: https://gerrit.openafs.org/14098
Tested-by: BuildBot <buildbot@rampaginggeek.com>
Reviewed-by: Benjamin Kaduk <kaduk@mit.edu>
Reviewed-by: Jeffrey Hutzelman <jhutz@cmu.edu>
Reviewed-by: Cheyenne Wills <cwills@sinenomine.net>
Tested-by: Cheyenne Wills <cwills@sinenomine.net>

src/afs/LINUX/osi_file.c

index 7a14729..e2218ad 100644 (file)
@@ -218,7 +218,7 @@ osi_UFSTruncate(struct osi_file *afile, afs_int32 asize)
 #endif
     code = afs_osi_Stat(afile, &tstat);
     if (code || tstat.size <= asize)
-       return code;
+       goto done;
     AFS_GUNLOCK();
     afs_linux_lock_inode(inode);
 #ifdef STRUCT_INODE_HAS_I_ALLOC_SEM
@@ -243,10 +243,11 @@ osi_UFSTruncate(struct osi_file *afile, afs_int32 asize)
     up_write(&inode->i_alloc_sem);
 #endif
     afs_linux_unlock_inode(inode);
+    AFS_GLOCK();
+ done:
 #if defined(HAVE_LINUX_OVERRIDE_CREDS)
     revert_creds(cur_cred);
 #endif
-    AFS_GLOCK();
     return code;
 }