From 61aabcf11fb6ff69ad218bca376dfe0cf5e68344 Mon Sep 17 00:00:00 2001 From: Simon Wilkinson Date: Fri, 3 Jul 2009 14:17:28 +0000 Subject: [PATCH] DEVEL15-linux-vnop-return-value-cleanup-20090703 LICENSE IPL10 rework all linux vnode ops so the vulnerability we previously had can't recur later just because someone makes a change that would leak a negative error (cherry picked from commit ebc4f737ae8f8056de1a7f80828a6173ebb24292) --- src/afs/LINUX/osi_vnodeops.c | 80 ++++++++++++++++++++++-------------- 1 file changed, 50 insertions(+), 30 deletions(-) diff --git a/src/afs/LINUX/osi_vnodeops.c b/src/afs/LINUX/osi_vnodeops.c index cd26276927..25f546230e 100644 --- a/src/afs/LINUX/osi_vnodeops.c +++ b/src/afs/LINUX/osi_vnodeops.c @@ -80,6 +80,22 @@ extern struct afs_cacheOps afs_UfsCacheOps; } while(0); #endif /* AFS_LINUX24_ENV */ + +/* This function converts a positive error code from AFS into a negative + * code suitable for passing into the Linux VFS layer. It checks that the + * error code is within the permissable bounds for the ERR_PTR mechanism. + * + * _All_ error codes which come from the AFS layer should be passed through + * this function before being returned to the kernel. + */ + +static inline int afs_convert_code(int code) { + if ((code >= 0) && (code <= MAX_ERRNO)) + return -code; + else + return -EIO; +} + static ssize_t afs_linux_read(struct file *fp, char *buf, size_t count, loff_t * offp) { @@ -98,7 +114,7 @@ afs_linux_read(struct file *fp, char *buf, size_t count, loff_t * offp) code = afs_VerifyVCache(vcp, &treq); if (code) - code = -code; + code = afs_convert_code(code); else { #if defined(AFS_CACHE_BYPASS) #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) @@ -158,7 +174,7 @@ afs_linux_write(struct file *fp, const char *buf, size_t count, loff_t * offp) afs_FakeOpen(vcp); ReleaseWriteLock(&vcp->lock); if (code) - code = -code; + code = afs_convert_code(code); else { AFS_GUNLOCK(); #ifdef DO_SYNC_READ @@ -212,19 +228,25 @@ afs_linux_readdir(struct file *fp, void *dirbuf, filldir_t filldir) code = afs_InitReq(&treq, credp); crfree(credp); - if (code) + if (code) { + code = afs_convert_code(code); goto out1; + } afs_InitFakeStat(&fakestat); code = afs_EvalFakeStat(&avc, &fakestat, &treq); - if (code) + if (code) { + code = afs_convert_code(code); goto out; + } /* update the cache entry */ tagain: code = afs_VerifyVCache(avc, &treq); - if (code) + if (code) { + code = afs_convert_code(code); goto out; + } /* get a reference to the entire directory */ tdc = afs_GetDCache(avc, (afs_size_t) 0, &treq, &origOffset, &tlen, 1); @@ -425,7 +447,7 @@ out: return code; out_err: - code = -code; + code = afs_convert_code(code); goto out; } @@ -447,7 +469,7 @@ afs_linux_open(struct inode *ip, struct file *fp) #endif crfree(credp); - return -code; + return afs_convert_code(code); } static int @@ -468,7 +490,7 @@ afs_linux_release(struct inode *ip, struct file *fp) #endif crfree(credp); - return -code; + return afs_convert_code(code); } static int @@ -492,7 +514,7 @@ afs_linux_fsync(struct file *fp, struct dentry *dp) maybe_unlock_kernel(); #endif crfree(credp); - return -code; + return afs_convert_code(code); } @@ -586,7 +608,7 @@ afs_linux_lock(struct file *fp, int cmd, struct file_lock *flp) flp->fl_end = flock.l_start + flock.l_len - 1; crfree(credp); - return -code; + return afs_convert_code(code); } #ifdef STRUCT_FILE_OPERATIONS_HAS_FLOCK @@ -636,7 +658,7 @@ afs_linux_flock(struct file *fp, int cmd, struct file_lock *flp) { flp->fl_pid = flock.l_pid; crfree(credp); - return -code; + return afs_convert_code(code); } #endif @@ -711,7 +733,7 @@ out: AFS_GUNLOCK(); crfree(credp); - return -code; + return afs_convert_code(code); } #if !defined(AFS_LINUX24_ENV) @@ -868,7 +890,7 @@ afs_linux_revalidate(struct dentry *dp) #endif crfree(credp); - return -code; + return afs_convert_code(code); } #if defined(AFS_LINUX26_ENV) @@ -1121,7 +1143,7 @@ afs_linux_create(struct inode *dip, struct dentry *dp, int mode) maybe_unlock_kernel(); #endif crfree(credp); - return -code; + return afs_convert_code(code); } /* afs_linux_lookup */ @@ -1221,14 +1243,12 @@ afs_linux_lookup(struct inode *dip, struct dentry *dp) if (code == ENOENT) return ERR_PTR(0); #endif - else if ((code >= 0) && (code <= MAX_ERRNO)) - return ERR_PTR(-code); else - return ERR_PTR(-EIO); + return ERR_PTR(afs_convert_code(code)); #else if (code == ENOENT) code = 0; - return -code; + return afs_convert_code(code); #endif } @@ -1250,7 +1270,7 @@ afs_linux_link(struct dentry *olddp, struct inode *dip, struct dentry *newdp) AFS_GUNLOCK(); crfree(credp); - return -code; + return afs_convert_code(code); } static int @@ -1329,7 +1349,7 @@ out: maybe_unlock_kernel(); #endif crfree(credp); - return -code; + return afs_convert_code(code); } @@ -1351,7 +1371,7 @@ afs_linux_symlink(struct inode *dip, struct dentry *dp, const char *target) code = afs_symlink(VTOAFS(dip), name, &vattr, target, credp); AFS_GUNLOCK(); crfree(credp); - return -code; + return afs_convert_code(code); } static int @@ -1388,7 +1408,7 @@ afs_linux_mkdir(struct inode *dip, struct dentry *dp, int mode) maybe_unlock_kernel(); #endif crfree(credp); - return -code; + return afs_convert_code(code); } static int @@ -1417,7 +1437,7 @@ afs_linux_rmdir(struct inode *dip, struct dentry *dp) } crfree(credp); - return -code; + return afs_convert_code(code); } @@ -1466,7 +1486,7 @@ afs_linux_rename(struct inode *oldip, struct dentry *olddp, #endif crfree(credp); - return -code; + return afs_convert_code(code); } @@ -1489,7 +1509,7 @@ afs_linux_ireadlink(struct inode *ip, char *target, int maxlen, uio_seg_t seg) if (!code) return maxlen - tuio.uio_resid; else - return -code; + return afs_convert_code(code); } #if !defined(USABLE_KERNEL_PAGE_SYMLINK_CACHE) @@ -1728,7 +1748,7 @@ afs_linux_readpages(struct file *fp, struct address_space *mapping, crfree(credp); out: - return -code; + return afs_convert_code(code); } #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) */ @@ -1900,7 +1920,7 @@ afs_linux_readpage(struct file *fp, struct page *pp) done: crfree(credp); - return -code; + return afs_convert_code(code); } @@ -1963,7 +1983,7 @@ afs_linux_writepage_sync(struct inode *ip, struct page *pp, if (!afs_InitReq(&treq, credp)) code = afs_DoPartialWrite(vcp, &treq); } - code = code ? -code : count - tuio.uio_resid; + code = code ? afs_convert_code(code) : count - tuio.uio_resid; vcp->f.states &= ~CPageWrite; ReleaseWriteLock(&vcp->lock); @@ -2077,7 +2097,7 @@ afs_linux_updatepage(struct file *fp, struct page *pp, unsigned long offset, ReleaseWriteLock(&vcp->lock); } - code = code ? -code : count - tuio.uio_resid; + code = code ? afs_convert_code(code) : count - tuio.uio_resid; afs_Trace4(afs_iclSetp, CM_TRACE_UPDATEPAGE, ICL_TYPE_POINTER, vcp, ICL_TYPE_POINTER, pp, ICL_TYPE_INT32, page_count(pp), ICL_TYPE_INT32, code); @@ -2116,7 +2136,7 @@ afs_linux_permission(struct inode *ip, int mode) AFS_GUNLOCK(); crfree(credp); - return -code; + return afs_convert_code(code); } #if defined(AFS_LINUX24_ENV) && !defined(HAVE_WRITE_BEGIN)