OPENAFS-SA-2016-002 AFSStoreStatus information leak
[openafs.git] / src / afs / VNOPS / afs_vnop_attrs.c
index 4278cd8..3b065fd 100644 (file)
@@ -17,6 +17,8 @@
  * afs_getattr
  * afs_VAttrToAS
  * afs_setattr
+ * afs_CreateAttr
+ * afs_DestroyAttr
  *
  */
 
@@ -51,11 +53,11 @@ afs_CopyOutAttrs(struct vcache *avc, struct vattr *attrs)
     int fakedir = 0;
 
     AFS_STATCNT(afs_CopyOutAttrs);
-    if (afs_fakestat_enable && avc->mvstat == 1)
+    if (afs_fakestat_enable && avc->mvstat == AFS_MVSTAT_MTPT)
        fakedir = 1;
     attrs->va_type = fakedir ? VDIR : vType(avc);
-#if defined(AFS_SGI_ENV) || defined(AFS_AIX32_ENV) || defined(AFS_SUN5_ENV)
-    attrs->va_mode = fakedir ? 0755 : (mode_t) (avc->f.m.Mode & 0xffff);
+#if defined(AFS_SGI_ENV) || defined(AFS_AIX32_ENV) || defined(AFS_SUN5_ENV) || defined(AFS_DARWIN_ENV)
+    attrs->va_mode = fakedir ? S_IFDIR | 0755 : (mode_t) (avc->f.m.Mode & 0xffff);
 #else
     attrs->va_mode = fakedir ? VDIR | 0755 : avc->f.m.Mode;
 #endif
@@ -99,7 +101,7 @@ afs_CopyOutAttrs(struct vcache *avc, struct vattr *attrs)
 #else /* ! AFS_DARWIN_ENV */
     attrs->va_fsid = 1;
 #endif 
-    if (avc->mvstat == 2) {
+    if (avc->mvstat == AFS_MVSTAT_ROOT) {
        tvp = afs_GetVolume(&avc->f.fid, 0, READ_LOCK);
        /* The mount point's vnode. */
        if (tvp) {
@@ -117,6 +119,7 @@ afs_CopyOutAttrs(struct vcache *avc, struct vattr *attrs)
              afs_calc_inum(avc->f.fid.Cell,
                            avc->f.fid.Fid.Volume,
                            avc->f.fid.Fid.Vnode);
+    attrs->va_nodeid &= 0x7fffffff;    /* Saber C hates negative inode #s! */
     attrs->va_nlink = fakedir ? 100 : avc->f.m.LinkCount;
     attrs->va_size = fakedir ? 4096 : avc->f.m.Length;
 #if defined(AFS_FBSD_ENV) || defined(AFS_DFBSD_ENV)
@@ -193,7 +196,7 @@ afs_getattr(OSI_VC_DECL(avc), struct vattr *attrs, afs_ucred_t *acred)
 #endif
 {
     afs_int32 code;
-    struct vrequest treq;
+    struct vrequest *treq = NULL;
     struct unixuser *au;
     int inited = 0;
     OSI_VC_CONVERT(avc);
@@ -202,21 +205,25 @@ afs_getattr(OSI_VC_DECL(avc), struct vattr *attrs, afs_ucred_t *acred)
     afs_Trace2(afs_iclSetp, CM_TRACE_GETATTR, ICL_TYPE_POINTER, avc,
               ICL_TYPE_OFFSET, ICL_HANDLE_OFFSET(avc->f.m.Length));
 
-    if (afs_fakestat_enable && avc->mvstat == 1) {
+    if (afs_fakestat_enable && avc->mvstat == AFS_MVSTAT_MTPT) {
        struct afs_fakestat_state fakestat;
+       struct vrequest *ureq = NULL;
 
-       code = afs_InitReq(&treq, acred);
-       if (code)
+       code = afs_CreateReq(&ureq, acred);
+       if (code) {
            return code;
+       }
        afs_InitFakeStat(&fakestat);
-       code = afs_TryEvalFakeStat(&avc, &fakestat, &treq);
+       code = afs_TryEvalFakeStat(&avc, &fakestat, ureq);
        if (code) {
            afs_PutFakeStat(&fakestat);
+           afs_DestroyReq(ureq);
            return code;
        }
 
        code = afs_CopyOutAttrs(avc, attrs);
        afs_PutFakeStat(&fakestat);
+       afs_DestroyReq(ureq);
        return code;
     }
 #if defined(AFS_SUN5_ENV)
@@ -234,29 +241,23 @@ afs_getattr(OSI_VC_DECL(avc), struct vattr *attrs, afs_ucred_t *acred)
 
     AFS_DISCON_LOCK();
 
-#ifdef AFS_BOZONLOCK_ENV
-    afs_BozonLock(&avc->pvnLock, avc);
-#endif
-
-    if (afs_shuttingdown)
+    if (afs_shuttingdown != AFS_RUNNING) {
+       AFS_DISCON_UNLOCK();
        return EIO;
+    }
 
     if (!(avc->f.states & CStatd)) {
-       if (!(code = afs_InitReq(&treq, acred))) {
-           code = afs_VerifyVCache2(avc, &treq);
+       if (!(code = afs_CreateReq(&treq, acred))) {
+           code = afs_VerifyVCache2(avc, treq);
            inited = 1;
        }
     } else
        code = 0;
 
-#if defined(AFS_SUN5_ENV) || defined(AFS_BOZONLOCK_ENV)
+#if defined(AFS_SUN5_ENV)
     if (code == 0)
        osi_FlushPages(avc, acred);
 #endif
-#ifdef AFS_BOZONLOCK_ENV
-    afs_BozonUnlock(&avc->pvnLock, avc);
-#endif
-
 
     if (code == 0) {
        osi_FlushText(avc);     /* only needed to flush text if text locked last time */
@@ -264,19 +265,21 @@ afs_getattr(OSI_VC_DECL(avc), struct vattr *attrs, afs_ucred_t *acred)
 
        if (afs_nfsexporter) {
            if (!inited) {
-               if ((code = afs_InitReq(&treq, acred)))
+               if ((code = afs_CreateReq(&treq, acred))) {
                    return code;
+               }
                inited = 1;
            }
            if (AFS_NFSXLATORREQ(acred)) {
                if ((vType(avc) != VDIR)
-                   && !afs_AccessOK(avc, PRSFS_READ, &treq,
+                   && !afs_AccessOK(avc, PRSFS_READ, treq,
                                     CHECK_MODE_BITS |
                                     CMB_ALLOW_EXEC_AS_READ)) {
+                   afs_DestroyReq(treq);
                    return EACCES;
                }
            }
-           if ((au = afs_FindUser(treq.uid, -1, READ_LOCK))) {
+           if ((au = afs_FindUser(treq->uid, -1, READ_LOCK))) {
                struct afs_exporter *exporter = au->exporter;
 
                if (exporter && !(afs_nfsexporter->exp_states & EXP_UNIXMODE)) {
@@ -339,9 +342,12 @@ afs_getattr(OSI_VC_DECL(avc), struct vattr *attrs, afs_ucred_t *acred)
 
     AFS_DISCON_UNLOCK();
 
-    if (!code)
+    if (!code) {
+       afs_DestroyReq(treq);
        return 0;
-    code = afs_CheckCode(code, &treq, 14);
+    }
+    code = afs_CheckCode(code, treq, 14);
+    afs_DestroyReq(treq);
     return code;
 }
 
@@ -352,6 +358,7 @@ afs_VAttrToAS(struct vcache *avc, struct vattr *av,
 {
     int mask;
     mask = 0;
+
     AFS_STATCNT(afs_VAttrToAS);
 #if     defined(AFS_DARWIN80_ENV)
     if (VATTR_IS_ACTIVE(av, va_mode)) {
@@ -453,7 +460,7 @@ afs_setattr(OSI_VC_DECL(avc), struct vattr *attrs,
            afs_ucred_t *acred)
 #endif
 {
-    struct vrequest treq;
+    struct vrequest *treq = NULL;
     struct AFSStoreStatus astat;
     afs_int32 code;
 #if defined(AFS_FBSD_ENV) || defined(AFS_DFBSD_ENV)
@@ -474,13 +481,15 @@ afs_setattr(OSI_VC_DECL(avc), struct vattr *attrs,
               ICL_HANDLE_OFFSET(attrs->va_size), ICL_TYPE_OFFSET,
               ICL_HANDLE_OFFSET(avc->f.m.Length));
 #endif
-    if ((code = afs_InitReq(&treq, acred)))
+    if ((code = afs_CreateReq(&treq, acred)))
        return code;
 
+    memset(&astat, 0, sizeof(astat));
+
     AFS_DISCON_LOCK();
 
     afs_InitFakeStat(&fakestate);
-    code = afs_EvalFakeStat(&avc, &fakestate, &treq);
+    code = afs_EvalFakeStat(&avc, &fakestate, treq);
     if (code)
        goto done;
 
@@ -512,7 +521,7 @@ afs_setattr(OSI_VC_DECL(avc), struct vattr *attrs,
 #else
     if (attrs->va_size != ~0) {
 #endif
-       if (!afs_AccessOK(avc, PRSFS_WRITE, &treq, DONT_CHECK_MODE_BITS)) {
+       if (!afs_AccessOK(avc, PRSFS_WRITE, treq, DONT_CHECK_MODE_BITS)) {
            code = EACCES;
            goto done;
        }
@@ -525,9 +534,6 @@ afs_setattr(OSI_VC_DECL(avc), struct vattr *attrs,
 
     afs_VAttrToAS(avc, attrs, &astat); /* interpret request */
     code = 0;
-#ifdef AFS_BOZONLOCK_ENV
-    afs_BozonLock(&avc->pvnLock, avc);
-#endif
 #if    defined(AFS_SUN5_ENV) || defined(AFS_SGI_ENV)
     if (AFS_NFSXLATORREQ(acred)) {
        avc->execsOrWriters++;
@@ -557,9 +563,9 @@ afs_setattr(OSI_VC_DECL(avc), struct vattr *attrs,
         if (AFS_IS_DISCONNECTED && tsize >=avc->f.m.Length) {
            /* If we're growing the file, and we're disconnected, we need
             * to make the relevant dcache chunks appear ourselves. */
-           code = afs_ExtendSegments(avc, tsize, &treq);
+           code = afs_ExtendSegments(avc, tsize, treq);
        } else {
-           code = afs_TruncateAllSegments(avc, tsize, &treq, acred);
+           code = afs_TruncateAllSegments(avc, tsize, treq, acred);
        }
 #ifdef AFS_LINUX26_ENV
        /* We must update the Linux kernel's idea of file size as soon as
@@ -585,7 +591,7 @@ afs_setattr(OSI_VC_DECL(avc), struct vattr *attrs,
                /* Store files now if not disconnected. */
                /* XXX: AFS_IS_DISCON_RW handled. */
                if (!AFS_IS_DISCONNECTED) {
-                       code = afs_StoreAllSegments(avc, &treq, AFS_ASYNC);
+                       code = afs_StoreAllSegments(avc, treq, AFS_ASYNC);
                        if (!code)
                                avc->f.states &= ~CDirty;
                }
@@ -601,7 +607,7 @@ afs_setattr(OSI_VC_DECL(avc), struct vattr *attrs,
     if (!AFS_IS_DISCONNECTED) {
         if (code == 0) {
            ObtainSharedLock(&avc->lock, 16);   /* lock entry */
-           code = afs_WriteVCache(avc, &astat, &treq); /* send request */
+           code = afs_WriteVCache(avc, &astat, treq);  /* send request */
            ReleaseSharedLock(&avc->lock);      /* release lock */
         }
         if (code) {
@@ -625,9 +631,6 @@ afs_setattr(OSI_VC_DECL(avc), struct vattr *attrs,
        avc->execsOrWriters--;
     }
 #endif
-#ifdef AFS_BOZONLOCK_ENV
-    afs_BozonUnlock(&avc->pvnLock, avc);
-#endif
 #if defined(AFS_SGI_ENV)
     AFS_RWUNLOCK((vnode_t *) avc, VRWLOCK_WRITE);
 #endif
@@ -635,6 +638,53 @@ afs_setattr(OSI_VC_DECL(avc), struct vattr *attrs,
     afs_PutFakeStat(&fakestate);
 
     AFS_DISCON_UNLOCK();
-    code = afs_CheckCode(code, &treq, 15);
+    code = afs_CheckCode(code, treq, 15);
+    afs_DestroyReq(treq);
     return code;
 }
+
+/*!
+ * Allocate a vattr.
+ *
+ * \note The caller must free the allocated vattr with
+ *       afs_DestroyAttr() if this function returns successfully (zero).
+ *
+ * \note The GLOCK must be held on platforms which require the GLOCK
+ *       for osi_AllocSmallSpace() and osi_FreeSmallSpace().
+ *
+ * \param[out] out   address of the vattr pointer
+ * \return     0 on success
+ */
+int
+afs_CreateAttr(struct vattr **out)
+{
+    struct vattr *vattr = NULL;
+
+    if (!out) {
+       return EINVAL;
+    }
+    vattr = osi_AllocSmallSpace(sizeof(struct vattr));
+    if (!vattr) {
+       return ENOMEM;
+    }
+    memset(vattr, 0, sizeof(struct vattr));
+    *out = vattr;
+    return 0;
+}
+
+/*!
+ * Deallocate a vattr.
+ *
+ * \note The GLOCK must be held on platforms which require the GLOCK
+ *       for osi_FreeSmallSpace().
+ *
+ * \param[in]  vattr  pointer to the vattr to free; may be NULL
+ */
+void
+afs_DestroyAttr(struct vattr *vattr)
+{
+    if (vattr) {
+       osi_FreeSmallSpace(vattr);
+    }
+}
+