Fix pioctl input and output handling
authorSimon Wilkinson <sxw@your-file-system.com>
Wed, 3 Feb 2010 00:31:32 +0000 (00:31 +0000)
committerDerrick Brashear <shadow|account-1000005@unknown>
Wed, 3 Feb 2010 21:29:38 +0000 (13:29 -0800)
Pioctl input and output handling was being handled in an adhoc
manner, with little or no detection of input and output buffer
overflow. Whilst overflow is difficult to provoke on a real system,
due to the size of the buffers being allocated for output, the code
was difficult to read, and fragile to maintain.

This patch adds an XDR like abstraction for marshalling and
unmarshalling pioctl data. Whilst the real XDR can't be used and
maintain backwards compatibility, this gives a similar elegance.

Input and output pointers are replaced with instances of
struct afs_pdata, which store both a pointer to the current position
in the data stream, and a note of where the stream ends.

All access to a data stream is now performed through a set of helper
functions, which handle the reading and writing of integers, strings,
and arbitrary blocks of bytes. An 'inline' function is provided for
those cases where direct access to the stream is required.

Change-Id: I6ed2e8e80cebde2abc6a517f4dbef09042b47037
Reviewed-on: http://gerrit.openafs.org/1223
Tested-by: Simon Wilkinson <sxw@inf.ed.ac.uk>
Reviewed-by: Derrick Brashear <shadow@dementia.org>
Tested-by: Derrick Brashear <shadow@dementia.org>

src/afs/afs_pioctl.c

index 3ac472b..26f45c6 100644 (file)
@@ -38,24 +38,185 @@ afs_int32 afs_is_discon_rw;
 afs_int32 afs_in_sync = 0;
 #endif
 
+struct afs_pdata {
+    char *ptr;
+    size_t remaining;
+};
+
+/*
+ * A set of handy little functions for encoding and decoding
+ * pioctls without losing your marbles, or memory integrity
+ */
+
+static_inline int
+afs_pd_alloc(struct afs_pdata *apd, size_t size) {
+
+    if (size > AFS_LRALLOCSIZ)
+       apd->ptr = osi_Alloc(size + 1);
+    else
+       apd->ptr = osi_AllocLargeSpace(AFS_LRALLOCSIZ);
+
+    if (apd->ptr == NULL)
+       return ENOMEM;
+
+    apd->remaining = size;
+
+    return 0;
+}
+
+static_inline void
+afs_pd_free(struct afs_pdata *apd) {
+    if (apd->ptr == NULL)
+       return;
+
+    if (apd->remaining > AFS_LRALLOCSIZ)
+       osi_Free(apd->ptr, apd->remaining + 1);
+    else
+       osi_FreeLargeSpace(apd->ptr);
+
+    apd->ptr = NULL;
+    apd->remaining = 0;
+}
+
+static_inline char *
+afs_pd_where(struct afs_pdata *apd) {
+    return apd ? apd->ptr : NULL;
+}
+
+static_inline size_t
+afs_pd_remaining(struct afs_pdata *apd) {
+    return apd ? apd->remaining : 0;
+}
+
+static_inline int
+afs_pd_skip(struct afs_pdata *apd, size_t skip) {
+    if (apd == NULL || apd->remaining < skip)
+       return EINVAL;
+    apd->remaining -= skip;
+    apd->ptr += skip;
+
+    return 0;
+}
+
+static_inline int
+afs_pd_getInt(struct afs_pdata *apd, afs_int32 *val) {
+    if (apd == NULL || apd->remaining < sizeof(afs_int32))
+       return EINVAL;
+    apd->remaining -= sizeof(afs_int32);
+    *val = *(afs_int32 *)apd->ptr;
+    apd->ptr += sizeof(afs_int32);
+    return 0;
+}
+
+static_inline int
+afs_pd_getUint(struct afs_pdata *apd, afs_uint32 *val) {
+    return afs_pd_getInt(apd, (afs_int32 *)val);
+}
+
+static_inline int
+afs_pd_getBytes(struct afs_pdata *apd, void *dest, size_t bytes) {
+    if (apd == NULL || apd->remaining < bytes)
+       return EINVAL;
+    apd->remaining -= bytes;
+    memcpy(dest, apd->ptr, bytes);
+    apd->ptr += bytes;
+    return 0;
+}
+
+static_inline void *
+afs_pd_inline(struct afs_pdata *apd, size_t bytes) {
+    void *ret;
+
+    if (apd == NULL || apd->remaining < bytes)
+       return NULL;
+
+    ret = apd->ptr;
+
+    apd->remaining -= bytes;
+    apd->ptr += bytes;
+
+    return ret;
+}
+
+static_inline int
+afs_pd_getString(struct afs_pdata *apd, char *str, size_t maxLen) {
+    size_t len;
+
+    if (apd == NULL || apd->remaining <= 0)
+       return EINVAL;
+    len = strlen(apd->ptr) + 1;
+    if (len > maxLen)
+       return E2BIG;
+    memcpy(str, apd->ptr, len);
+    apd->ptr += len;
+    apd->remaining -= len;
+    return 0;
+}
+
+static_inline int
+afs_pd_getStringPtr(struct afs_pdata *apd, char **str) {
+    size_t len;
+
+    if (apd == NULL || apd->remaining <= 0)
+       return EINVAL;
+    len = strlen(apd->ptr) + 1;
+    *str = apd->ptr;
+    apd->ptr += len;
+    apd->remaining -= len;
+    return 0;
+}
+
+static_inline int
+afs_pd_putInt(struct afs_pdata *apd, afs_int32 val) {
+    if (apd == NULL || apd->remaining < sizeof(afs_int32))
+       return E2BIG;
+    *(afs_int32 *)apd->ptr = val;
+    apd->ptr += sizeof(afs_int32);
+    apd->remaining -= sizeof(afs_int32);
+
+    return 0;
+}
+
+static_inline int
+afs_pd_putBytes(struct afs_pdata *apd, const void *bytes, size_t len) {
+    if (apd == NULL || apd->remaining < len)
+       return E2BIG;
+    memcpy(apd->ptr, bytes, len);
+    apd->ptr += len;
+    apd->remaining -= len;
+    return 0;
+}
+
+static_inline int
+afs_pd_putString(struct afs_pdata *apd, char *str) {
+
+    /* Add 1 so we copy the NULL too */
+    return afs_pd_putBytes(apd, str, strlen(str) +1);
+}
+
 /*!
  * \defgroup pioctl Path IOCTL functions
  *
  * DECL_PIOCTL is a macro defined to contain the following parameters for functions:
  *
- * \param[in] avc      the AFS vcache structure in use by pioctl
- * \param[in] afun     not in use
- * \param[in] areq     the AFS vrequest structure
- * \param[in] ain      as defined by the function
- * \param[in] aout     as defined by the function
- * \param[in] ainSize  size of ain
- * \param[in] aoutSize size of aout
- * \param[in] acred    UNIX credentials structure underlying the operation
+ * \param[in] avc
+ *     the AFS vcache structure in use by pioctl
+ * \param[in] afun
+ *     not in use
+ * \param[in] areq
+ *     the AFS vrequest structure
+ * \param[in] ain
+ *     an afs_pdata block describing the data received from the caller
+ * \param[in] aout
+ *     an afs_pdata block describing a pre-allocated block for output
+ * \param[in] acred
+ *     UNIX credentials structure underlying the operation
  */
 
-#define DECL_PIOCTL(x) static int x(struct vcache *avc, int afun, struct vrequest *areq, \
-       char *ain, char *aout, afs_int32 ainSize, afs_int32 *aoutSize, \
-       afs_ucred_t **acred)
+#define DECL_PIOCTL(x) \
+       static int x(struct vcache *avc, int afun, struct vrequest *areq, \
+                    struct afs_pdata *ain, struct afs_pdata *aout, \
+                    afs_ucred_t **acred)
 
 /* Prototypes for pioctl routines */
 DECL_PIOCTL(PGetFID);
@@ -146,7 +307,7 @@ static int Prefetch(uparmtype apath, struct afs_ioctl *adata, int afollow,
                    afs_ucred_t *acred);
 
 typedef int (*pioctlFunction) (struct vcache *, int, struct vrequest *,
-                              char *, char *, afs_int32, afs_int32 *,
+                              struct afs_pdata *, struct afs_pdata *,
                               afs_ucred_t **);
 
 static pioctlFunction VpioctlSw[] = {
@@ -976,25 +1137,30 @@ afs_HandlePioctl(struct vnode *avp, afs_int32 acom,
     struct vrequest treq;
     register afs_int32 code;
     register afs_int32 function, device;
-    afs_int32 inSize, outSize, outSizeMax;
-    char *inData, *outData;
+    struct afs_pdata input, output;
+    struct afs_pdata copyInput, copyOutput;
+    size_t outSize;
     pioctlFunction *pioctlSw;
     int pioctlSwSize;
     struct afs_fakestat_state fakestate;
 
+    memset(&input, 0, sizeof(input));
+    memset(&output, 0, sizeof(output));
+
     avc = avp ? VTOAFS(avp) : NULL;
     afs_Trace3(afs_iclSetp, CM_TRACE_PIOCTL, ICL_TYPE_INT32, acom & 0xff,
               ICL_TYPE_POINTER, avc, ICL_TYPE_INT32, afollow);
     AFS_STATCNT(HandlePioctl);
-    if ((code = afs_InitReq(&treq, *acred)))
+
+    code = afs_InitReq(&treq, *acred);
+    if (code)
        return code;
+
     afs_InitFakeStat(&fakestate);
     if (avc) {
        code = afs_EvalFakeStat(&avc, &fakestate, &treq);
-       if (code) {
-           afs_PutFakeStat(&fakestate);
-           return code;
-       }
+       if (code)
+           goto out;
     }
     device = (acom & 0xff00) >> 8;
     switch (device) {
@@ -1011,79 +1177,62 @@ afs_HandlePioctl(struct vnode *avp, afs_int32 acom,
        pioctlSwSize = sizeof(OpioctlSw);
        break;
     default:
-       afs_PutFakeStat(&fakestate);
-       return EINVAL;
+       code = EINVAL;
+       goto out;
     }
     function = acom & 0xff;
     if (function >= (pioctlSwSize / sizeof(char *))) {
-       afs_PutFakeStat(&fakestate);
-       return EINVAL;          /* out of range */
+       code = EINVAL;
+       goto out;
     }
-    inSize = ablob->in_size;
 
     /* Do all range checking before continuing */
-    if (inSize > MAXPIOCTLTOKENLEN || inSize < 0 || ablob->out_size < 0)
-       return E2BIG;
-
-    /* Note that we use osi_Alloc for large allocs and osi_AllocLargeSpace for small ones */
-    if (inSize > AFS_LRALLOCSIZ) {
-       inData = osi_Alloc(inSize + 1);
-    } else {
-       inData = osi_AllocLargeSpace(AFS_LRALLOCSIZ);
+    if (ablob->in_size > MAXPIOCTLTOKENLEN ||
+        ablob->in_size < 0 || ablob->out_size < 0) {
+       code = EINVAL;
+       goto out;
     }
-    if (!inData)
-       return ENOMEM;
-    if (inSize > 0) {
-       AFS_COPYIN(ablob->in, inData, inSize, code);
-       inData[inSize] = '\0';
-    } else
-       code = 0;
-    if (code) {
-       if (inSize > AFS_LRALLOCSIZ) {
-           osi_Free(inData, inSize + 1);
-       } else {
-           osi_FreeLargeSpace(inData);
-       }
-       afs_PutFakeStat(&fakestate);
-       return code;
+
+    code = afs_pd_alloc(&input, ablob->in_size);
+    if (code)
+       goto out;
+
+    if (ablob->in_size > 0) {
+       AFS_COPYIN(ablob->in, input.ptr, ablob->in_size, code);
+       input.ptr[input.remaining] = '\0';
     }
+    if (code)
+       goto out;
+
     if (function == 8 && device == 'V') {      /* PGetTokens */
-       outSizeMax = MAXPIOCTLTOKENLEN;
-       outData = osi_Alloc(outSizeMax);
+       code = afs_pd_alloc(&output, MAXPIOCTLTOKENLEN);
     } else {
-       outSizeMax = AFS_LRALLOCSIZ;
-       outData = osi_AllocLargeSpace(AFS_LRALLOCSIZ);
-    }
-    if (!outData) {
-       if (inSize > AFS_LRALLOCSIZ) {
-           osi_Free(inData, inSize + 1);
-       } else {
-           osi_FreeLargeSpace(inData);
-       }
-       afs_PutFakeStat(&fakestate);
-       return ENOMEM;
+       code = afs_pd_alloc(&output, AFS_LRALLOCSIZ);
     }
-    outSize = 0;
+    if (code)
+       goto out;
+
+    copyInput = input;
+    copyOutput = output;
+
     code =
-       (*pioctlSw[function]) (avc, function, &treq, inData, outData, inSize,
-                              &outSize, acred);
-    if (inSize > AFS_LRALLOCSIZ) {
-       osi_Free(inData, inSize + 1);
-    } else {
-       osi_FreeLargeSpace(inData);
-    }
+       (*pioctlSw[function]) (avc, function, &treq, &copyInput,
+                              &copyOutput, acred);
+
+    outSize = copyOutput.ptr - output.ptr;
+
     if (code == 0 && ablob->out_size > 0) {
        if (outSize > ablob->out_size) {
            code = E2BIG;       /* data wont fit in user buffer */
        } else if (outSize) {
-           AFS_COPYOUT(outData, ablob->out, outSize, code);
+           AFS_COPYOUT(output.ptr, ablob->out, outSize, code);
        }
     }
-    if (outSizeMax > AFS_LRALLOCSIZ) {
-       osi_Free(outData, outSizeMax);
-    } else {
-       osi_FreeLargeSpace(outData);
-    }
+
+out:
+    afs_pd_free(&input);
+    afs_pd_free(&output);
+
     afs_PutFakeStat(&fakestate);
     return afs_CheckCode(code, &treq, 41);
 }
@@ -1105,8 +1254,8 @@ DECL_PIOCTL(PGetFID)
     AFS_STATCNT(PGetFID);
     if (!avc)
        return EINVAL;
-    memcpy(aout, (char *)&avc->f.fid, sizeof(struct VenusFid));
-    *aoutSize = sizeof(struct VenusFid);
+    if (afs_pd_putBytes(aout, &avc->f.fid, sizeof(struct VenusFid)) != 0)
+       return EINVAL;
     return 0;
 }
 
@@ -1139,10 +1288,13 @@ DECL_PIOCTL(PSetAcl)
     AFS_STATCNT(PSetAcl);
     if (!avc)
        return EINVAL;
-    if ((acl.AFSOpaque_len = strlen(ain) + 1) > 1024 /* AFSOPAQUEMAX */)
+
+    if (afs_pd_getStringPtr(ain, &acl.AFSOpaque_val) != 0)
+       return EINVAL;
+    acl.AFSOpaque_len = strlen(acl.AFSOpaque_val) + 1;
+    if (acl.AFSOpaque_len > 1024)
        return EINVAL;
 
-    acl.AFSOpaque_val = ain;
     do {
        tconn = afs_Conn(&avc->f.fid, areq, SHARED_LOCK);
        if (tconn) {
@@ -1189,33 +1341,33 @@ int afs_defaultAsynchrony = 0;
  */
 DECL_PIOCTL(PStoreBehind)
 {
-    afs_int32 code = 0;
-    struct sbstruct *sbr;
+    struct sbstruct sbr;
+
+    if (afs_pd_getBytes(ain, &sbr, sizeof(struct sbstruct)) != 0)
+       return EINVAL;
 
-    sbr = (struct sbstruct *)ain;
-    if (sbr->sb_default != -1) {
+    if (sbr.sb_default != -1) {
        if (afs_osi_suser(*acred))
-           afs_defaultAsynchrony = sbr->sb_default;
+           afs_defaultAsynchrony = sbr.sb_default;
        else
-           code = EPERM;
+           return EPERM;
     }
 
-    if (avc && (sbr->sb_thisfile != -1)) {
+    if (avc && (sbr.sb_thisfile != -1)) {
        if (afs_AccessOK
            (avc, PRSFS_WRITE | PRSFS_ADMINISTER, areq, DONT_CHECK_MODE_BITS))
-           avc->asynchrony = sbr->sb_thisfile;
+           avc->asynchrony = sbr.sb_thisfile;
        else
-           code = EACCES;
+           return EACCES;
     }
 
-    *aoutSize = sizeof(struct sbstruct);
-    sbr = (struct sbstruct *)aout;
-    sbr->sb_default = afs_defaultAsynchrony;
+    memset(&sbr, 0, sizeof(sbr));
+    sbr.sb_default = afs_defaultAsynchrony;
     if (avc) {
-       sbr->sb_thisfile = avc->asynchrony;
+       sbr.sb_thisfile = avc->asynchrony;
     }
 
-    return code;
+    return afs_pd_putBytes(aout, &sbr, sizeof(sbr));
 }
 
 /*!
@@ -1281,13 +1433,13 @@ DECL_PIOCTL(PGetAcl)
         */
        if (Fid.Vnode & 0xc0000000)
            return ERANGE;
-       Fid.Vnode |= (ainSize << 30);
+       Fid.Vnode |= (ain->remaining << 30);
     }
-    acl.AFSOpaque_val = aout;
+    acl.AFSOpaque_val = aout->ptr;
     do {
        tconn = afs_Conn(&avc->f.fid, areq, SHARED_LOCK);
        if (tconn) {
-           *aout = 0;
+           acl.AFSOpaque_val[0] = '\0';
            XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_FETCHACL);
            RX_AFS_GUNLOCK();
            code = RXAFS_FetchACL(tconn->id, &Fid, &acl, &OutStatus, &tsync);
@@ -1300,7 +1452,10 @@ DECL_PIOCTL(PGetAcl)
              SHARED_LOCK, NULL));
 
     if (code == 0) {
-       *aoutSize = (acl.AFSOpaque_len == 0 ? 1 : acl.AFSOpaque_len);
+       if (acl.AFSOpaque_len == 0)
+           afs_pd_skip(aout, 1); /* leave the NULL */
+       else
+           afs_pd_skip(aout, acl.AFSOpaque_len); /* Length of the ACL */
     }
     return code;
 }
@@ -1356,9 +1511,11 @@ DECL_PIOCTL(PGetFileCell)
     tcell = afs_GetCell(avc->f.fid.Cell, READ_LOCK);
     if (!tcell)
        return ESRCH;
-    strcpy(aout, tcell->cellName);
+
+    if (afs_pd_putString(aout, tcell->cellName) != 0)
+       return EINVAL;
+
     afs_PutCell(tcell, READ_LOCK);
-    *aoutSize = strlen(aout) + 1;
     return 0;
 }
 
@@ -1386,8 +1543,9 @@ DECL_PIOCTL(PGetWSCell)
     tcell = afs_GetPrimaryCell(READ_LOCK);
     if (!tcell)                        /* no primary cell? */
        return ESRCH;
-    strcpy(aout, tcell->cellName);
-    *aoutSize = strlen(aout) + 1;
+
+    if (afs_pd_putString(aout, tcell->cellName) != 0)
+       return EINVAL;
     afs_PutCell(tcell, READ_LOCK);
     return 0;
 }
@@ -1430,14 +1588,12 @@ DECL_PIOCTL(PGetUserCell)
        if (!tcell)
            return ESRCH;
        else {
-           strcpy(aout, tcell->cellName);
+           if (afs_pd_putString(aout, tcell->cellName) != 0)
+               return E2BIG;
            afs_PutCell(tcell, READ_LOCK);
-           *aoutSize = strlen(aout) + 1;       /* 1 for the null */
        }
     } else {
        ReleaseWriteLock(&afs_xuser);
-       *aout = 0;
-       *aoutSize = 1;
     }
     return 0;
 }
@@ -1464,6 +1620,7 @@ DECL_PIOCTL(PSetTokens)
     struct ClearToken clear;
     register struct cell *tcell;
     char *stp;
+    char *cellName;
     int stLen;
     struct vrequest treq;
     afs_int32 flag, set_parent_pag = 0;
@@ -1472,33 +1629,44 @@ DECL_PIOCTL(PSetTokens)
     if (!afs_resourceinit_flag) {
        return EIO;
     }
-    memcpy((char *)&i, ain, sizeof(afs_int32));
-    ain += sizeof(afs_int32);
-    stp = ain;                 /* remember where the ticket is */
-    if (i < 0 || i > MAXKTCTICKETLEN)
+
+    if (afs_pd_getInt(ain, &stLen) != 0)
+       return EINVAL;
+
+    stp = afs_pd_where(ain);   /* remember where the ticket is */
+    if (stLen < 0 || stLen > MAXKTCTICKETLEN)
        return EINVAL;          /* malloc may fail */
-    stLen = i;
-    ain += i;                  /* skip over ticket */
-    memcpy((char *)&i, ain, sizeof(afs_int32));
-    ain += sizeof(afs_int32);
-    if (i != sizeof(struct ClearToken)) {
+    if (afs_pd_skip(ain, stLen) != 0)
        return EINVAL;
-    }
-    memcpy((char *)&clear, ain, sizeof(struct ClearToken));
+
+    if (afs_pd_getInt(ain, &i) != 0)
+       return EINVAL;
+    if (i != sizeof(struct ClearToken))
+       return EINVAL;
+
+    if (afs_pd_getBytes(ain, &clear, sizeof(struct ClearToken)) !=0)
+       return EINVAL;
+
     if (clear.AuthHandle == -1)
        clear.AuthHandle = 999; /* more rxvab compat stuff */
-    ain += sizeof(struct ClearToken);
-    if (ainSize != 2 * sizeof(afs_int32) + stLen + sizeof(struct ClearToken)) {
+
+    if (afs_pd_remaining(ain) != 0) {
        /* still stuff left?  we've got primary flag and cell name.  Set these */
-       memcpy((char *)&flag, ain, sizeof(afs_int32));  /* primary id flag */
-       ain += sizeof(afs_int32);       /* skip id field */
-       /* rest is cell name, look it up */
+
+       if (afs_pd_getInt(ain, &flag) != 0)
+           return EINVAL;
+
        /* some versions of gcc appear to need != 0 in order to get this right */
        if ((flag & 0x8000) != 0) {     /* XXX Use Constant XXX */
            flag &= ~0x8000;
            set_parent_pag = 1;
        }
-       tcell = afs_GetCellByName(ain, READ_LOCK);
+
+       if (afs_pd_getStringPtr(ain, &cellName) != 0)
+           return EINVAL;
+
+       /* rest is cell name, look it up */
+       tcell = afs_GetCellByName(cellName, READ_LOCK);
        if (!tcell)
            goto nocell;
     } else {
@@ -1587,8 +1755,7 @@ DECL_PIOCTL(PGetVolumeStatus)
     register struct afs_conn *tc;
     register afs_int32 code = 0;
     struct AFSFetchVolumeStatus volstat;
-    register char *cp;
-    char *Name, *OfflineMsg, *MOTD;
+    char *Name;
     XSTATS_DECLS;
 
     AFS_STATCNT(PGetVolumeStatus);
@@ -1597,8 +1764,6 @@ DECL_PIOCTL(PGetVolumeStatus)
        goto out;
     }
     Name = volName;
-    OfflineMsg = offLineMsg;
-    MOTD = motd;
     do {
        tc = afs_Conn(&avc->f.fid, areq, SHARED_LOCK);
        if (tc) {
@@ -1606,7 +1771,7 @@ DECL_PIOCTL(PGetVolumeStatus)
            RX_AFS_GUNLOCK();
            code =
                RXAFS_GetVolumeStatus(tc->id, avc->f.fid.Fid.Volume, &volstat,
-                                     &Name, &OfflineMsg, &MOTD);
+                                     &Name, &offLineMsg, &motd);
            RX_AFS_GLOCK();
            XSTATS_END_TIME;
        } else
@@ -1618,16 +1783,14 @@ DECL_PIOCTL(PGetVolumeStatus)
     if (code)
        goto out;
     /* Copy all this junk into msg->im_data, keeping track of the lengths. */
-    cp = aout;
-    memcpy(cp, (char *)&volstat, sizeof(VolumeStatus));
-    cp += sizeof(VolumeStatus);
-    strcpy(cp, volName);
-    cp += strlen(volName) + 1;
-    strcpy(cp, offLineMsg);
-    cp += strlen(offLineMsg) + 1;
-    strcpy(cp, motd);
-    cp += strlen(motd) + 1;
-    *aoutSize = (cp - aout);
+    if (afs_pd_putBytes(aout, &volstat, sizeof(VolumeStatus)) != 0)
+       return E2BIG;
+    if (afs_pd_putString(aout, volName) != 0)
+       return E2BIG;
+    if (afs_pd_putString(aout, offLineMsg) != 0)
+       return E2BIG;
+    if (afs_pd_putString(aout, motd) != 0)
+       return E2BIG;
   out:
     afs_osi_Free(offLineMsg, 256);
     afs_osi_Free(motd, 256);
@@ -1651,56 +1814,51 @@ DECL_PIOCTL(PGetVolumeStatus)
  */
 DECL_PIOCTL(PSetVolumeStatus)
 {
-    char volName[32];
-    char *offLineMsg = afs_osi_Alloc(256);
-    char *motd = afs_osi_Alloc(256);
+    char *volName;
+    char *offLineMsg;
+    char *motd;
     register struct afs_conn *tc;
     register afs_int32 code = 0;
     struct AFSFetchVolumeStatus volstat;
     struct AFSStoreVolumeStatus storeStat;
     register struct volume *tvp;
-    register char *cp;
     XSTATS_DECLS;
 
     AFS_STATCNT(PSetVolumeStatus);
-    if (!avc) {
-       code = EINVAL;
-       goto out;
-    }
+    if (!avc)
+       return EINVAL;
 
     tvp = afs_GetVolume(&avc->f.fid, areq, READ_LOCK);
     if (tvp) {
        if (tvp->states & (VRO | VBackup)) {
            afs_PutVolume(tvp, READ_LOCK);
-           code = EROFS;
-           goto out;
+           return EROFS;
        }
        afs_PutVolume(tvp, READ_LOCK);
-    } else {
-       code = ENODEV;
-       goto out;
-    }
-    /* Copy the junk out, using cp as a roving pointer. */
-    cp = ain;
-    memcpy((char *)&volstat, cp, sizeof(AFSFetchVolumeStatus));
-    cp += sizeof(AFSFetchVolumeStatus);
-    if (strlen(cp) >= sizeof(volName)) {
-       code = E2BIG;
-       goto out;
-    }
-    strcpy(volName, cp);
-    cp += strlen(volName) + 1;
-    if (strlen(cp) >= sizeof(offLineMsg)) {
-       code = E2BIG;
-       goto out;
-    }
-    strcpy(offLineMsg, cp);
-    cp += strlen(offLineMsg) + 1;
-    if (strlen(cp) >= sizeof(motd)) {
-       code = E2BIG;
-       goto out;
-    }
-    strcpy(motd, cp);
+    } else
+       return ENODEV;
+
+
+    if (afs_pd_getBytes(ain, &volstat, sizeof(AFSFetchVolumeStatus)) != 0)
+       return EINVAL;
+
+    if (afs_pd_getStringPtr(ain, &volName) != 0)
+       return EINVAL;
+    if (strlen(volName) > 32)
+        return E2BIG;
+
+    if (afs_pd_getStringPtr(ain, &offLineMsg) != 0)
+       return EINVAL;
+    if (strlen(offLineMsg) > 256)
+       return E2BIG;
+
+    if (afs_pd_getStringPtr(ain, &motd) != 0)
+       return EINVAL;
+    if (strlen(motd) > 256)
+       return E2BIG;
+
+    /* Done reading ... */
+
     storeStat.Mask = 0;
     if (volstat.MinQuota != -1) {
        storeStat.MinQuota = volstat.MinQuota;
@@ -1727,22 +1885,21 @@ DECL_PIOCTL(PSetVolumeStatus)
              SHARED_LOCK, NULL));
 
     if (code)
-       goto out;
+       return code;
     /* we are sending parms back to make compat. with prev system.  should
      * change interface later to not ask for current status, just set new status */
-    cp = aout;
-    memcpy(cp, (char *)&volstat, sizeof(VolumeStatus));
-    cp += sizeof(VolumeStatus);
-    strcpy(cp, volName);
-    cp += strlen(volName) + 1;
-    strcpy(cp, offLineMsg);
-    cp += strlen(offLineMsg) + 1;
-    strcpy(cp, motd);
-    cp += strlen(motd) + 1;
-    *aoutSize = cp - aout;
-  out:
-    afs_osi_Free(offLineMsg, 256);
-    afs_osi_Free(motd, 256);
+
+    /* XXX - We really need to check that this doesn't overflow, too, otherwise
+     * bad fileserver status could be _really_ bad */
+    if (afs_pd_putBytes(aout, &volstat, sizeof(VolumeStatus)) != 0)
+       return EINVAL;
+    if (afs_pd_putString(aout, volName) != 0)
+       return EINVAL;
+    if (afs_pd_putString(aout, offLineMsg) != 0)
+       return EINVAL;
+    if (afs_pd_putString(aout, motd) != 0)
+       return EINVAL;
+
     return code;
 }
 
@@ -1796,12 +1953,17 @@ DECL_PIOCTL(PNewStatMount)
     register struct dcache *tdc;
     struct VenusFid tfid;
     char *bufp;
+    char *name;
     struct sysname_info sysState;
     afs_size_t offset, len;
 
     AFS_STATCNT(PNewStatMount);
     if (!avc)
        return EINVAL;
+
+    if (afs_pd_getStringPtr(ain, &name) != 0)
+       return EINVAL;
+
     code = afs_VerifyVCache(avc, areq);
     if (code)
        return code;
@@ -1811,7 +1973,7 @@ DECL_PIOCTL(PNewStatMount)
     tdc = afs_GetDCache(avc, (afs_size_t) 0, areq, &offset, &len, 1);
     if (!tdc)
        return ENOENT;
-    Check_AtSys(avc, ain, &sysState, areq);
+    Check_AtSys(avc, name, &sysState, areq);
     ObtainReadLock(&tdc->lock);
     do {
        code = afs_dir_Lookup(tdc, sysState.name, &tfid.Fid);
@@ -1846,8 +2008,8 @@ DECL_PIOCTL(PNewStatMount)
                code = EINVAL;
            else {
                /* we have the data */
-               strcpy(aout, tvc->linkData);
-               *aoutSize = strlen(tvc->linkData) + 1;
+               if (afs_pd_putString(aout, tvc->linkData) != 0)
+                   code = EINVAL;
            }
        } else
            code = EIO;
@@ -1882,9 +2044,9 @@ DECL_PIOCTL(PGetTokens)
     register struct cell *tcell;
     register afs_int32 i;
     register struct unixuser *tu;
-    register char *cp;
     afs_int32 iterator = 0;
     int newStyle;
+    int code = E2BIG;
 
     AFS_STATCNT(PGetTokens);
     if (!afs_resourceinit_flag)        /* afs daemons haven't started yet */
@@ -1899,8 +2061,10 @@ DECL_PIOCTL(PGetTokens)
      * tokens, the primary cell indicator (an afs_int32 0) and the cell name
      * at the end, in that order.
      */
-    if ((newStyle = (ainSize > 0))) {
-       memcpy((char *)&iterator, ain, sizeof(afs_int32));
+    newStyle = (afs_pd_remaining(ain) > 0);
+    if (newStyle) {
+       if (afs_pd_getInt(ain, &iterator) != 0)
+           return EINVAL;
     }
     i = UHash(areq->uid);
     ObtainReadLock(&afs_xuser);
@@ -1932,36 +2096,45 @@ DECL_PIOCTL(PGetTokens)
        afs_PutUser(tu, READ_LOCK);
        return ENOTCONN;
     }
-    /* use iterator for temp */
-    cp = aout;
     iterator = tu->stLen;      /* for compat, we try to return 56 byte tix if they fit */
     if (iterator < 56)
        iterator = 56;          /* # of bytes we're returning */
-    memcpy(cp, (char *)&iterator, sizeof(afs_int32));
-    cp += sizeof(afs_int32);
-    memcpy(cp, tu->stp, tu->stLen);    /* copy out st */
-    cp += iterator;
-    iterator = sizeof(struct ClearToken);
-    memcpy(cp, (char *)&iterator, sizeof(afs_int32));
-    cp += sizeof(afs_int32);
-    memcpy(cp, (char *)&tu->ct, sizeof(struct ClearToken));
-    cp += sizeof(struct ClearToken);
+
+    if (afs_pd_putInt(aout, iterator) != 0)
+       goto out;
+    if (afs_pd_putBytes(aout, tu->stp, tu->stLen) != 0)
+       goto out;
+    if (tu->stLen < 56) {
+       /* Tokens are always 56 bytes or larger */
+       if (afs_pd_skip(aout, iterator - tu->stLen) != 0) {
+           goto out;
+       }
+    }
+
+    if (afs_pd_putInt(aout, sizeof(struct ClearToken)) != 0)
+       goto out;
+    if (afs_pd_putBytes(aout, &tu->ct, sizeof(struct ClearToken)) != 0)
+       goto out;
+
     if (newStyle) {
        /* put out primary id and cell name, too */
        iterator = (tu->states & UPrimary ? 1 : 0);
-       memcpy(cp, (char *)&iterator, sizeof(afs_int32));
-       cp += sizeof(afs_int32);
+       if (afs_pd_putInt(aout, iterator) != 0)
+           goto out;
        tcell = afs_GetCell(tu->cell, READ_LOCK);
        if (tcell) {
-           strcpy(cp, tcell->cellName);
-           cp += strlen(tcell->cellName) + 1;
+           if (afs_pd_putString(aout, tcell->cellName) != 0)
+               goto out;
            afs_PutCell(tcell, READ_LOCK);
        } else
-           *cp++ = 0;
+           if (afs_pd_putString(aout, "") != 0)
+               goto out;
     }
-    *aoutSize = cp - aout;
+    /* Got here, all is good */
+    code = 0;
+out:
     afs_PutUser(tu, READ_LOCK);
-    return 0;
+    return code;
 }
 
 /*!
@@ -2046,7 +2219,9 @@ DECL_PIOCTL(PMariner)
     else
        oldHostAddr = 0xffffffff;       /* disabled */
 
-    memcpy((char *)&newHostAddr, ain, sizeof(afs_int32));
+    if (afs_pd_getInt(ain, &newHostAddr) != 0)
+       return EINVAL;
+
     if (newHostAddr == 0xffffffff) {
        /* disable mariner operations */
        afs_mariner = 0;
@@ -2054,8 +2229,10 @@ DECL_PIOCTL(PMariner)
        afs_mariner = 1;
        afs_marinerHost = newHostAddr;
     }
-    memcpy(aout, (char *)&oldHostAddr, sizeof(afs_int32));
-    *aoutSize = sizeof(afs_int32);
+
+    if (afs_pd_putInt(aout, oldHostAddr) != 0)
+       return E2BIG;
+
     return 0;
 }
 
@@ -2075,10 +2252,10 @@ DECL_PIOCTL(PMariner)
  */
 DECL_PIOCTL(PCheckServers)
 {
-    register char *cp = 0;
     register int i;
     register struct server *ts;
-    afs_int32 temp, *lp = (afs_int32 *) ain, havecell = 0;
+    afs_int32 temp;
+    char *cellName = NULL;
     struct cell *cellp;
     struct chservinfo *pcheck;
 
@@ -2087,12 +2264,21 @@ DECL_PIOCTL(PCheckServers)
     if (!afs_resourceinit_flag)        /* afs daemons haven't started yet */
        return EIO;             /* Inappropriate ioctl for device */
 
-    if (*lp == 0x12345678) {   /* For afs3.3 version */
-       pcheck = (struct chservinfo *)ain;
+    /* This is tricky, because we need to peak at the datastream to see
+     * what we're getting. For now, let's cheat. */
+
+    /* ain contains either an int32 or a string */
+    if (ain->remaining == 0)
+       return EINVAL;
+
+    if (*(afs_int32 *)ain->ptr == 0x12345678) {        /* For afs3.3 version */
+       pcheck = afs_pd_inline(ain, sizeof(*pcheck));
+        if (pcheck == NULL)
+           return EINVAL;
+
        if (pcheck->tinterval >= 0) {
-           cp = aout;
-           memcpy(cp, (char *)&afs_probe_interval, sizeof(afs_int32));
-           *aoutSize = sizeof(afs_int32);
+           if (afs_pd_putInt(aout, afs_probe_interval) != 0)
+               return E2BIG;
            if (pcheck->tinterval > 0) {
                if (!afs_osi_suser(*acred))
                    return EACCES;
@@ -2100,24 +2286,25 @@ DECL_PIOCTL(PCheckServers)
            }
            return 0;
        }
-       if (pcheck->tsize)
-           havecell = 1;
        temp = pcheck->tflags;
-       cp = pcheck->tbuffer;
+       if (pcheck->tsize)
+           cellName = pcheck->tbuffer;
     } else {                   /* For pre afs3.3 versions */
-       memcpy((char *)&temp, ain, sizeof(afs_int32));
-       cp = ain + sizeof(afs_int32);
-       if (ainSize > sizeof(afs_int32))
-           havecell = 1;
+       if (afs_pd_getInt(ain, &temp) != 0)
+           return EINVAL;
+       if (afs_pd_remaining(ain) > 0) {
+           if (afs_pd_getStringPtr(ain, &cellName) != 0)
+               return EINVAL;
+       }
     }
 
     /*
      * 1: fast check, don't contact servers.
      * 2: local cell only.
      */
-    if (havecell) {
+    if (cellName) {
        /* have cell name, too */
-       cellp = afs_GetCellByName(cp, READ_LOCK);
+       cellp = afs_GetCellByName(cellName, READ_LOCK);
        if (!cellp)
            return ENOENT;
     } else
@@ -2131,7 +2318,6 @@ DECL_PIOCTL(PCheckServers)
        afs_CheckServers(0, cellp);     /* check up servers */
     }
     /* now return the current down server list */
-    cp = aout;
     ObtainReadLock(&afs_xserver);
     for (i = 0; i < NSERVERS; i++) {
        for (ts = afs_servers[i]; ts; ts = ts->next) {
@@ -2139,15 +2325,13 @@ DECL_PIOCTL(PCheckServers)
                continue;       /* cell spec'd and wrong */
            if ((ts->flags & SRVR_ISDOWN)
                && ts->addr->sa_portal != ts->cell->vlport) {
-               memcpy(cp, (char *)&ts->addr->sa_ip, sizeof(afs_int32));
-               cp += sizeof(afs_int32);
+               afs_pd_putInt(aout, ts->addr->sa_ip);
            }
        }
     }
     ReleaseReadLock(&afs_xserver);
     if (cellp)
        afs_PutCell(cellp, READ_LOCK);
-    *aoutSize = cp - aout;
     return 0;
 }
 
@@ -2226,8 +2410,8 @@ DECL_PIOCTL(PCheckAuth)
        ReleaseReadLock(&afs_xconn);
        afs_PutUser(tu, READ_LOCK);
     }
-    memcpy(aout, (char *)&retValue, sizeof(afs_int32));
-    *aoutSize = sizeof(afs_int32);
+    if (afs_pd_putInt(aout, retValue) != 0)
+       return E2BIG;
     return 0;
 }
 
@@ -2281,32 +2465,34 @@ DECL_PIOCTL(PFindVolume)
     register struct volume *tvp;
     register struct server *ts;
     register afs_int32 i;
-    register char *cp;
+    int code = 0;
 
     AFS_STATCNT(PFindVolume);
     if (!avc)
        return EINVAL;
     tvp = afs_GetVolume(&avc->f.fid, areq, READ_LOCK);
-    if (tvp) {
-       cp = aout;
-       for (i = 0; i < AFS_MAXHOSTS; i++) {
-           ts = tvp->serverHost[i];
-           if (!ts)
-               break;
-           memcpy(cp, (char *)&ts->addr->sa_ip, sizeof(afs_int32));
-           cp += sizeof(afs_int32);
+    if (!tvp)
+       return ENODEV;
+
+    for (i = 0; i < AFS_MAXHOSTS; i++) {
+       ts = tvp->serverHost[i];
+       if (!ts)
+           break;
+       if (afs_pd_putInt(aout, ts->addr->sa_ip) != 0) {
+           code = E2BIG;
+           goto out;
        }
-       if (i < AFS_MAXHOSTS) {
-           /* still room for terminating NULL, add it on */
-           ainSize = 0;        /* reuse vbl */
-           memcpy(cp, (char *)&ainSize, sizeof(afs_int32));
-           cp += sizeof(afs_int32);
+    }
+    if (i < AFS_MAXHOSTS) {
+       /* still room for terminating NULL, add it on */
+       if (afs_pd_putInt(aout, 0) != 0) {
+           code = E2BIG;
+           goto out;
        }
-       *aoutSize = cp - aout;
-       afs_PutVolume(tvp, READ_LOCK);
-       return 0;
     }
-    return ENODEV;
+out:
+    afs_PutVolume(tvp, READ_LOCK);
+    return code;
 }
 
 /*!
@@ -2330,10 +2516,14 @@ DECL_PIOCTL(PViceAccess)
     AFS_STATCNT(PViceAccess);
     if (!avc)
        return EINVAL;
+
     code = afs_VerifyVCache(avc, areq);
     if (code)
        return code;
-    memcpy((char *)&temp, ain, sizeof(afs_int32));
+
+    if (afs_pd_getInt(ain, &temp) != 0)
+       return EINVAL;
+
     code = afs_AccessOK(avc, temp, areq, CHECK_MODE_BITS);
     if (code)
        return 0;
@@ -2357,9 +2547,7 @@ DECL_PIOCTL(PGetPAG)
 
     pag = PagInCred(*acred);
 
-    memcpy(aout, (char *)&pag, sizeof(afs_int32));
-    *aoutSize = sizeof(afs_int32);
-    return 0;
+    return afs_pd_putInt(aout, pag);
 }
 
 DECL_PIOCTL(PPrecache)
@@ -2369,7 +2557,10 @@ DECL_PIOCTL(PPrecache)
     /*AFS_STATCNT(PPrecache);*/
     if (!afs_osi_suser(*acred))
        return EACCES;
-    memcpy((char *)&newValue, ain, sizeof(afs_int32));
+
+    if (afs_pd_getInt(ain, &newValue) != 0)
+       return EINVAL;
+
     afs_preCache = newValue*1024;
     return 0;
 }
@@ -2395,12 +2586,14 @@ DECL_PIOCTL(PSetCacheSize)
     int waitcnt = 0;
 
     AFS_STATCNT(PSetCacheSize);
+
     if (!afs_osi_suser(*acred))
        return EACCES;
     /* too many things are setup initially in mem cache version */
     if (cacheDiskType == AFS_FCACHE_TYPE_MEM)
        return EROFS;
-    memcpy((char *)&newValue, ain, sizeof(afs_int32));
+    if (afs_pd_getInt(ain, &newValue) != 0)
+       return EINVAL;
     if (newValue == 0)
        afs_cacheBlocks = afs_stats_cmperf.cacheBlocksOrig;
     else {
@@ -2439,9 +2632,9 @@ DECL_PIOCTL(PGetCacheSize)
     
     AFS_STATCNT(PGetCacheSize);
 
-    if (sizeof(afs_int32) == ainSize){
-       memcpy((char *)&flags, ain, sizeof(afs_int32));
-    } else if (0 == ainSize){ 
+    if (afs_pd_remaining(ain) == sizeof(afs_int32)) {
+       afs_pd_getInt(ain, &flags); /* can't error, we just checked size */
+    } else if (afs_pd_remaining(ain) == 0) {
        flags = 0;
     } else {
        return EINVAL;
@@ -2478,9 +2671,7 @@ DECL_PIOCTL(PGetCacheSize)
            }
         }
     }
-    memcpy(aout, (char *)results, sizeof(results));
-    *aoutSize = sizeof(results);
-    return 0;
+    return afs_pd_putBytes(aout, results, sizeof(results));
 }
 
 /*!
@@ -2559,12 +2750,13 @@ DECL_PIOCTL(PRemoveCallBack)
  */
 DECL_PIOCTL(PNewCell)
 {
-    /* create a new cell */
-    afs_int32 cellHosts[AFS_MAXCELLHOSTS], *lp, magic = 0;
-    char *newcell = 0, *linkedcell = 0, *tp = ain;
-    register afs_int32 code, linkedstate = 0, ls;
-    u_short fsport = 0, vlport = 0;
-    afs_int32 scount;
+    afs_int32 cellHosts[AFS_MAXCELLHOSTS], magic = 0;
+    char *newcell = NULL;
+    char *linkedcell = NULL;
+    afs_int32 code, ls;
+    afs_int32 linkedstate = 0;
+    afs_int32 fsport = 0, vlport = 0;
+    int skip;
 
     AFS_STATCNT(PNewCell);
     if (!afs_resourceinit_flag)        /* afs daemons haven't started yet */
@@ -2573,8 +2765,8 @@ DECL_PIOCTL(PNewCell)
     if (!afs_osi_suser(*acred))
        return EACCES;
 
-    memcpy((char *)&magic, tp, sizeof(afs_int32));
-    tp += sizeof(afs_int32);
+    if (afs_pd_getInt(ain, &magic) != 0)
+       return EINVAL;
     if (magic != 0x12345678)
        return EINVAL;
 
@@ -2582,25 +2774,46 @@ DECL_PIOCTL(PNewCell)
      * server addresses while the 3.5 fs newcell command passes
      * AFS_MAXHOSTS. To figure out which is which, check if the cellname
      * is good.
+     *
+     * This whole logic is bogus, because it relies on the newer command
+     * sending its 12th address as 0.
      */
-    newcell = tp + (AFS_MAXCELLHOSTS + 3) * sizeof(afs_int32);
-    scount = ((newcell[0] != '\0') ? AFS_MAXCELLHOSTS : AFS_MAXHOSTS);
+    if ((afs_pd_remaining(ain) < AFS_MAXCELLHOSTS +3) * sizeof(afs_int32))
+       return EINVAL;
+
+    newcell = afs_pd_where(ain) + (AFS_MAXCELLHOSTS + 3) * sizeof(afs_int32);
+    if (newcell[0] != '\0') {
+       skip = 0;
+    } else {
+       skip = AFS_MAXHOSTS - AFS_MAXCELLHOSTS;
+    }
 
     /* AFS_MAXCELLHOSTS (=8) is less than AFS_MAXHOSTS (=13) */
-    memcpy((char *)cellHosts, tp, AFS_MAXCELLHOSTS * sizeof(afs_int32));
-    tp += (scount * sizeof(afs_int32));
+    if (afs_pd_getBytes(ain, &cellHosts,
+                       AFS_MAXCELLHOSTS * sizeof(afs_int32)) != 0)
+       return EINVAL;
+    if (afs_pd_skip(ain, skip * sizeof(afs_int32)) !=0)
+       return EINVAL;
 
-    lp = (afs_int32 *) tp;
-    fsport = *lp++;
-    vlport = *lp++;
+    if (afs_pd_getInt(ain, &fsport) != 0)
+       return EINVAL;
     if (fsport < 1024)
        fsport = 0;             /* Privileged ports not allowed */
+
+    if (afs_pd_getInt(ain, &vlport) != 0)
+       return EINVAL;
     if (vlport < 1024)
        vlport = 0;             /* Privileged ports not allowed */
-    tp += (3 * sizeof(afs_int32));
-    newcell = tp;
-    if ((ls = *lp) & 1) {
-       linkedcell = tp + strlen(newcell) + 1;
+
+    if (afs_pd_getInt(ain, &ls) != 0)
+       return EINVAL;
+
+    if (afs_pd_getStringPtr(ain, &newcell) != 0)
+       return EINVAL;
+
+    if (ls & 1) {
+       if (afs_pd_getStringPtr(ain, &linkedcell) != 0)
+           return EINVAL;
        linkedstate |= CLinkedCell;
     }
 
@@ -2614,8 +2827,6 @@ DECL_PIOCTL(PNewCell)
 DECL_PIOCTL(PNewAlias)
 {
     /* create a new cell alias */
-    char *tp = ain;
-    register afs_int32 code;
     char *realName, *aliasName;
 
     if (!afs_resourceinit_flag)        /* afs daemons haven't started yet */
@@ -2624,13 +2835,12 @@ DECL_PIOCTL(PNewAlias)
     if (!afs_osi_suser(*acred))
        return EACCES;
 
-    aliasName = tp;
-    tp += strlen(aliasName) + 1;
-    realName = tp;
+    if (afs_pd_getStringPtr(ain, &aliasName) != 0)
+       return EINVAL;
+    if (afs_pd_getStringPtr(ain, &realName) != 0)
+       return EINVAL;
 
-    code = afs_NewCellAlias(aliasName, realName);
-    *aoutSize = 0;
-    return code;
+    return afs_NewCellAlias(aliasName, realName);
 }
 
 /*!
@@ -2651,65 +2861,66 @@ DECL_PIOCTL(PListCells)
     afs_int32 whichCell;
     register struct cell *tcell = 0;
     register afs_int32 i;
-    register char *cp, *tp = ain;
+    int code;
 
     AFS_STATCNT(PListCells);
     if (!afs_resourceinit_flag)        /* afs daemons haven't started yet */
        return EIO;             /* Inappropriate ioctl for device */
 
-    memcpy((char *)&whichCell, tp, sizeof(afs_int32));
-    tp += sizeof(afs_int32);
+    if (afs_pd_getInt(ain, &whichCell) != 0)
+       return EINVAL;
+
     tcell = afs_GetCellByIndex(whichCell, READ_LOCK);
-    if (tcell) {
-       cp = aout;
-       memset(cp, 0, AFS_MAXCELLHOSTS * sizeof(afs_int32));
-       for (i = 0; i < AFS_MAXCELLHOSTS; i++) {
-           if (tcell->cellHosts[i] == 0)
-               break;
-           memcpy(cp, (char *)&tcell->cellHosts[i]->addr->sa_ip,
-                  sizeof(afs_int32));
-           cp += sizeof(afs_int32);
-       }
-       cp = aout + AFS_MAXCELLHOSTS * sizeof(afs_int32);
-       strcpy(cp, tcell->cellName);
-       cp += strlen(tcell->cellName) + 1;
-       *aoutSize = cp - aout;
-       afs_PutCell(tcell, READ_LOCK);
-    }
-    if (tcell)
-       return 0;
-    else
+    if (!tcell)
        return EDOM;
+
+    code = E2BIG;
+
+    for (i = 0; i < AFS_MAXCELLHOSTS; i++) {
+       if (tcell->cellHosts[i] == 0)
+           break;
+       if (afs_pd_putInt(aout, tcell->cellHosts[i]->addr->sa_ip) != 0)
+           goto out;
+    }
+    for (;i < AFS_MAXCELLHOSTS; i++) {
+       if (afs_pd_putInt(aout, 0) != 0)
+           goto out;
+    }
+    if (afs_pd_putString(aout, tcell->cellName) != 0)
+       goto out;
+    code = 0;
+
+out:
+    afs_PutCell(tcell, READ_LOCK);
+    return code;
 }
 
 DECL_PIOCTL(PListAliases)
 {
     afs_int32 whichAlias;
     register struct cell_alias *tcalias = 0;
-    register char *cp, *tp = ain;
+    int code;
 
     if (!afs_resourceinit_flag)        /* afs daemons haven't started yet */
        return EIO;             /* Inappropriate ioctl for device */
-    if (ainSize < sizeof(afs_int32))
-       return EINVAL;
 
-    memcpy((char *)&whichAlias, tp, sizeof(afs_int32));
-    tp += sizeof(afs_int32);
+    if (afs_pd_getInt(ain, &whichAlias) != 0)
+       return EINVAL;
 
     tcalias = afs_GetCellAlias(whichAlias);
-    if (tcalias) {
-       cp = aout;
-       strcpy(cp, tcalias->alias);
-       cp += strlen(tcalias->alias) + 1;
-       strcpy(cp, tcalias->cell);
-       cp += strlen(tcalias->cell) + 1;
-       *aoutSize = cp - aout;
-       afs_PutCellAlias(tcalias);
-    }
-    if (tcalias)
-       return 0;
-    else
+    if (tcalias == NULL)
        return EDOM;
+
+    code = E2BIG;
+    if (afs_pd_putString(aout, tcalias->alias) != 0)
+       goto out;
+    if (afs_pd_putString(aout, tcalias->cell) != 0)
+       goto out;
+
+    code = 0;
+out:
+    afs_PutCellAlias(tcalias);
+    return code;
 }
 
 /*!
@@ -2730,6 +2941,7 @@ DECL_PIOCTL(PRemoveMount)
 {
     register afs_int32 code;
     char *bufp;
+    char *name;
     struct sysname_info sysState;
     afs_size_t offset, len;
     register struct afs_conn *tc;
@@ -2740,12 +2952,14 @@ DECL_PIOCTL(PRemoveMount)
     struct AFSVolSync tsync;
     XSTATS_DECLS;
 
-
     /* "ain" is the name of the file in this dir to remove */
 
     AFS_STATCNT(PRemoveMount);
     if (!avc)
        return EINVAL;
+    if (afs_pd_getStringPtr(ain, &name) != 0)
+       return EINVAL;
+
     code = afs_VerifyVCache(avc, areq);
     if (code)
        return code;
@@ -2755,7 +2969,7 @@ DECL_PIOCTL(PRemoveMount)
     tdc = afs_GetDCache(avc, (afs_size_t) 0, areq, &offset, &len, 1);  /* test for error below */
     if (!tdc)
        return ENOENT;
-    Check_AtSys(avc, ain, &sysState, areq);
+    Check_AtSys(avc, name, &sysState, areq);
     ObtainReadLock(&tdc->lock);
     do {
        code = afs_dir_Lookup(tdc, sysState.name, &tfid.Fid);
@@ -2877,20 +3091,23 @@ DECL_PIOCTL(PVenusLogging)
 DECL_PIOCTL(PGetCellStatus)
 {
     register struct cell *tcell;
+    char *cellName;
     afs_int32 temp;
 
     AFS_STATCNT(PGetCellStatus);
     if (!afs_resourceinit_flag)        /* afs daemons haven't started yet */
        return EIO;             /* Inappropriate ioctl for device */
 
-    tcell = afs_GetCellByName(ain, READ_LOCK);
+    if (afs_pd_getStringPtr(ain, &cellName) != 0)
+       return EINVAL;
+
+    tcell = afs_GetCellByName(cellName, READ_LOCK);
     if (!tcell)
        return ENOENT;
     temp = tcell->states;
     afs_PutCell(tcell, READ_LOCK);
-    memcpy(aout, (char *)&temp, sizeof(afs_int32));
-    *aoutSize = sizeof(afs_int32);
-    return 0;
+
+    return afs_pd_putInt(aout, temp);
 }
 
 /*!
@@ -2909,18 +3126,25 @@ DECL_PIOCTL(PGetCellStatus)
 DECL_PIOCTL(PSetCellStatus)
 {
     register struct cell *tcell;
-    afs_int32 temp;
+    char *cellName;
+    afs_int32 flags0, flags1;
 
     if (!afs_osi_suser(*acred))
        return EACCES;
     if (!afs_resourceinit_flag)        /* afs daemons haven't started yet */
        return EIO;             /* Inappropriate ioctl for device */
 
-    tcell = afs_GetCellByName(ain + 2 * sizeof(afs_int32), WRITE_LOCK);
+    if (afs_pd_getInt(ain, &flags0) != 0)
+       return EINVAL;
+    if (afs_pd_getInt(ain, &flags1) != 0)
+       return EINVAL;
+    if (afs_pd_getStringPtr(ain, &cellName) != 0)
+       return EINVAL;
+
+    tcell = afs_GetCellByName(cellName, WRITE_LOCK);
     if (!tcell)
        return ENOENT;
-    memcpy((char *)&temp, ain, sizeof(afs_int32));
-    if (temp & CNoSUID)
+    if (flags0 & CNoSUID)
        tcell->states |= CNoSUID;
     else
        tcell->states &= ~CNoSUID;
@@ -3134,9 +3358,7 @@ DECL_PIOCTL(PGetVnodeXStatus)
     stat.flockCount = avc->flockCount;
     stat.mvstat = avc->mvstat;
     stat.states = avc->f.states;
-    memcpy(aout, (char *)&stat, sizeof(struct vcxstat));
-    *aoutSize = sizeof(struct vcxstat);
-    return 0;
+    return afs_pd_putBytes(aout, &stat, sizeof(struct vcxstat));
 }
 
 
@@ -3165,9 +3387,7 @@ DECL_PIOCTL(PGetVnodeXStatus2)
     stat.mvstat = avc->mvstat;
     stat.callerAccess = afs_GetAccessBits(avc, ~0, areq);
 
-    memcpy(aout, (char *)&stat, sizeof(struct vcxstat2));
-    *aoutSize = sizeof(struct vcxstat2);
-    return 0;
+    return afs_pd_putBytes(aout, &stat, sizeof(struct vcxstat2));
 }
 
 
@@ -3189,7 +3409,8 @@ DECL_PIOCTL(PGetVnodeXStatus2)
  */
 DECL_PIOCTL(PSetSysName)
 {
-    char *cp, *cp2 = NULL, inname[MAXSYSNAME], outname[MAXSYSNAME];
+    char *inname = NULL;
+    char outname[MAXSYSNAME];
     afs_int32 setsysname;
     int foundname = 0;
     register struct afs_exporter *exporter;
@@ -3197,6 +3418,7 @@ DECL_PIOCTL(PSetSysName)
     register afs_int32 pag, error;
     int t, count, num = 0, allpags = 0;
     char **sysnamelist;
+    struct afs_pdata validate;
 
     AFS_STATCNT(PSetSysName);
     if (!afs_globalVFS) {
@@ -3207,9 +3429,8 @@ DECL_PIOCTL(PSetSysName)
        return (EINVAL);
 #endif
     }
-    memset(inname, 0, MAXSYSNAME);
-    memcpy(&setsysname, ain, sizeof(afs_int32));
-    ain += sizeof(afs_int32);
+    if (afs_pd_getInt(ain, &setsysname) != 0)
+       return EINVAL;
     if (setsysname & 0x8000) {
        allpags = 1;
        setsysname &= ~0x8000;
@@ -3219,23 +3440,22 @@ DECL_PIOCTL(PSetSysName)
        /* Check my args */
        if (setsysname < 0 || setsysname > MAXNUMSYSNAMES)
            return EINVAL;
-       cp2 = ain;
-       for (cp = ain, count = 0; count < setsysname; count++) {
-           /* won't go past end of ain since maxsysname*num < ain length */
-           t = strlen(cp);
+       validate = *ain;
+       for (count = 0; count < setsysname; count++) {
+           if (afs_pd_getStringPtr(&validate, &inname) != 0)
+               return EINVAL;
+           t = strlen(inname);
            if (t >= MAXSYSNAME || t <= 0)
                return EINVAL;
            /* check for names that can shoot us in the foot */
-           if (*cp == '.' && (cp[1] == 0 || (cp[1] == '.' && cp[2] == 0)))
+           if (inname[0] == '.' && (inname[1] == 0
+               || (inname[1] == '.' && inname[2] == 0)))
                return EINVAL;
-           cp += t + 1;
        }
-       /* args ok */
+       /* args ok, so go back to the beginning of that section */
 
-       /* inname gets first entry in case we're being a translator */
-       t = strlen(ain);
-       memcpy(inname, ain, t + 1);     /* include terminating null */
-       ain += t + 1;
+       if (afs_pd_getStringPtr(ain, &inname) != 0)
+           return EINVAL;
        num = count;
     }
     if (afs_cr_gid(*acred) == RMTUSER_REQ ||
@@ -3254,7 +3474,7 @@ DECL_PIOCTL(PSetSysName)
            afs_PutUser(au, READ_LOCK);
            return EINVAL;      /* Better than panicing */
        }
-       error = EXP_SYSNAME(exporter, (setsysname ? cp2 : NULL), &sysnamelist,
+       error = EXP_SYSNAME(exporter, inname, &sysnamelist,
                            &num, allpags);
        if (error) {
            if (error == ENODEV)
@@ -3289,16 +3509,19 @@ DECL_PIOCTL(PSetSysName)
            /* clear @sys entries from the dnlc, once afs_lookup can
             * do lookups of @sys entries and thinks it can trust them */
            /* privs ok, store the entry, ... */
+
+           if (strlen(inname) >= MAXSYSNAME-1)
+               return EINVAL;
            strcpy(afs_sysname, inname);
+
            if (setsysname > 1) {       /* ... or list */
-               cp = ain;
                for (count = 1; count < setsysname; ++count) {
                    if (!afs_sysnamelist[count])
                        osi_Panic
                            ("PSetSysName: no afs_sysnamelist entry to write\n");
-                   t = strlen(cp);
-                   memcpy(afs_sysnamelist[count], cp, t + 1);  /* include null */
-                   cp += t + 1;
+                   if (afs_pd_getString(ain, afs_sysnamelist[count],
+                                        MAXSYSNAME) != 0)
+                       return EINVAL;
                }
            }
            afs_sysnamecount = setsysname;
@@ -3306,12 +3529,11 @@ DECL_PIOCTL(PSetSysName)
        }
     }
     if (!setsysname) {
-       cp = aout;              /* not changing so report back the count and ... */
-       memcpy(cp, (char *)&foundname, sizeof(afs_int32));
-       cp += sizeof(afs_int32);
+       if (afs_pd_putInt(aout, foundname) != 0)
+           return E2BIG;
        if (foundname) {
-           strcpy(cp, outname);        /* ... the entry, ... */
-           cp += strlen(outname) + 1;
+           if (afs_pd_putString(aout, outname) != 0)
+               return E2BIG;
            for (count = 1; count < foundname; ++count) {       /* ... or list. */
                if (!sysnamelist[count])
                    osi_Panic
@@ -3319,11 +3541,10 @@ DECL_PIOCTL(PSetSysName)
                t = strlen(sysnamelist[count]);
                if (t >= MAXSYSNAME)
                    osi_Panic("PSetSysName: sysname entry garbled\n");
-               strcpy(cp, sysnamelist[count]);
-               cp += t + 1;
+               if (afs_pd_putString(aout, sysnamelist[count]) != 0)
+                   return E2BIG;
            }
        }
-       *aoutSize = cp - aout;
     }
     return 0;
 }
@@ -3475,6 +3696,9 @@ afs_setsprefs(struct spref *sp, unsigned int num, unsigned int vlonly)
 DECL_PIOCTL(PSetSPrefs)
 {
     struct setspref *ssp;
+    char *ainPtr;
+    size_t ainSize;
+
     AFS_STATCNT(PSetSPrefs);
 
     if (!afs_resourceinit_flag)        /* afs daemons haven't started yet */
@@ -3483,11 +3707,17 @@ DECL_PIOCTL(PSetSPrefs)
     if (!afs_osi_suser(*acred))
        return EACCES;
 
+    /* The I/O handling here is ghastly, as it relies on overrunning the ends
+     * of arrays. But, i'm not quite brave enough to change it yet. */
+    ainPtr = ain->ptr;
+    ainSize = ain->remaining;
+
     if (ainSize < sizeof(struct setspref))
        return EINVAL;
 
-    ssp = (struct setspref *)ain;
-    if (ainSize < sizeof(struct spref) * ssp->num_servers)
+    ssp = (struct setspref *)ainPtr;
+    if (ainSize < (sizeof(struct setspref)
+                  + sizeof(struct spref) * ssp->num_servers-1))
        return EINVAL;
 
     afs_setsprefs(&(ssp->servers[0]), ssp->num_servers,
@@ -3510,7 +3740,6 @@ DECL_PIOCTL(PSetSPrefs)
  */
 DECL_PIOCTL(PSetSPrefs33)
 {
-    struct spref *sp;
     AFS_STATCNT(PSetSPrefs);
     if (!afs_resourceinit_flag)        /* afs daemons haven't started yet */
        return EIO;             /* Inappropriate ioctl for device */
@@ -3519,8 +3748,9 @@ DECL_PIOCTL(PSetSPrefs33)
     if (!afs_osi_suser(*acred))
        return EACCES;
 
-    sp = (struct spref *)ain;
-    afs_setsprefs(sp, ainSize / (sizeof(struct spref)), 0 /*!vlonly */ );
+    afs_setsprefs((struct spref *)afs_pd_where(ain),
+                 afs_pd_remaining(ain) / sizeof(struct spref),
+                 0 /*!vlonly */ );
     return 0;
 }
 
@@ -3541,7 +3771,7 @@ DECL_PIOCTL(PSetSPrefs33)
  */
 DECL_PIOCTL(PGetSPrefs)
 {
-    struct sprefrequest *spin; /* input */
+    struct sprefrequest spin;  /* input */
     struct sprefinfo *spout;   /* output */
     struct spref *srvout;      /* one output component */
     int i, j;                  /* counters for hash table traversal */
@@ -3554,31 +3784,35 @@ DECL_PIOCTL(PGetSPrefs)
     if (!afs_resourceinit_flag)        /* afs daemons haven't started yet */
        return EIO;             /* Inappropriate ioctl for device */
 
-
-    if (ainSize < sizeof(struct sprefrequest_33)) {
-       return ENOENT;
+    /* Work out from the size whether we've got a new, or old, style pioctl */
+    if (afs_pd_remaining(ain) < sizeof(struct sprefrequest)) {
+       if (afs_pd_getBytes(ain, &spin, sizeof(struct sprefrequest_33)) != 0)
+          return ENOENT;
+       vlonly = 0;
+       spin.flags = 0;
     } else {
-       spin = ((struct sprefrequest *)ain);
+       if (afs_pd_getBytes(ain, &spin, sizeof(struct sprefrequest)) != 0)
+          return EINVAL;
+       vlonly = (spin.flags & DBservers);
     }
 
-    if (ainSize > sizeof(struct sprefrequest_33)) {
-       vlonly = (spin->flags & DBservers);
-    } else
-       vlonly = 0;
+    /* This code relies on overflowing arrays. It's ghastly, but I'm not
+     * quite brave enough to tackle it yet ...
+     */
 
     /* struct sprefinfo includes 1 server struct...  that size gets added
      * in during the loop that follows.
      */
-    *aoutSize = sizeof(struct sprefinfo) - sizeof(struct spref);
-    spout = (struct sprefinfo *)aout;
-    spout->next_offset = spin->offset;
+    spout = afs_pd_inline(aout,
+                         sizeof(struct sprefinfo) - sizeof(struct spref));
+    spout->next_offset = spin.offset;
     spout->num_servers = 0;
     srvout = spout->servers;
 
     ObtainReadLock(&afs_xserver);
     for (i = 0, j = 0; j < NSERVERS; j++) {    /* sift through hash table */
        for (sa = afs_srvAddrs[j]; sa; sa = sa->next_bkt, i++) {
-           if (spin->offset > (unsigned short)i) {
+           if (spin.offset > (unsigned short)i) {
                continue;       /* catch up to where we left off */
            }
            spout->next_offset++;
@@ -3592,21 +3826,22 @@ DECL_PIOCTL(PGetSPrefs)
                continue;
            }
 
+           /* Check we've actually got the space we're about to use */
+           if (afs_pd_inline(aout, sizeof(struct spref)) == NULL) {
+               ReleaseReadLock(&afs_xserver);  /* no more room! */
+               return 0;
+           }
+
            srvout->host.s_addr = sa->sa_ip;
            srvout->rank = sa->sa_iprank;
-           *aoutSize += sizeof(struct spref);
            spout->num_servers++;
            srvout++;
-
-           if (*aoutSize > (PIGGYSIZE - sizeof(struct spref))) {
-               ReleaseReadLock(&afs_xserver);  /* no more room! */
-               return 0;
-           }
        }
     }
     ReleaseReadLock(&afs_xserver);
 
     spout->next_offset = 0;    /* start over from the beginning next time */
+
     return 0;
 }
 
@@ -3635,7 +3870,8 @@ DECL_PIOCTL(PExportAfs)
     register struct afs_exporter *exporter;
 
     AFS_STATCNT(PExportAfs);
-    memcpy((char *)&handleValue, ain, sizeof(afs_int32));
+    if (afs_pd_getInt(ain, &handleValue) != 0)
+       return EINVAL;
     type = handleValue >> 24;
     if (type == 0x71) {
        newint = 1;
@@ -3663,8 +3899,8 @@ DECL_PIOCTL(PExportAfs)
     }
     if (!changestate) {
        handleValue = exporter->exp_states;
-       memcpy(aout, (char *)&handleValue, sizeof(afs_int32));
-       *aoutSize = sizeof(afs_int32);
+       if (afs_pd_putInt(aout, handleValue) != 0)
+           return E2BIG;
     } else {
        if (!afs_osi_suser(*acred))
            return EACCES;      /* Only superuser can do this */
@@ -3709,8 +3945,8 @@ DECL_PIOCTL(PExportAfs)
                    exporter->exp_states &= ~EXP_CALLBACK;
            }
            handleValue = exporter->exp_states;
-           memcpy(aout, (char *)&handleValue, sizeof(afs_int32));
-           *aoutSize = sizeof(afs_int32);
+           if (afs_pd_putInt(aout, handleValue) != 0)
+               return E2BIG;
        } else {
            if (export)
                exporter->exp_states |= EXP_EXPORTED;
@@ -3756,7 +3992,9 @@ DECL_PIOCTL(PGag)
     if (!afs_osi_suser(*acred))
        return EACCES;
 
-    gagflags = (struct gaginfo *)ain;
+    gagflags = afs_pd_inline(ain, sizeof(*gagflags));
+    if (gagflags == NULL)
+       return EINVAL;
     afs_showflags = gagflags->showflags;
 
     return 0;
@@ -3781,7 +4019,9 @@ DECL_PIOCTL(PTwiddleRx)
     if (!afs_osi_suser(*acred))
        return EACCES;
 
-    rxp = (struct rxparams *)ain;
+    rxp = afs_pd_inline(ain, sizeof(*rxp));
+    if (rxp == NULL)
+       return EINVAL;
 
     if (rxp->rx_initReceiveWindow)
        rx_initReceiveWindow = rxp->rx_initReceiveWindow;
@@ -3824,8 +4064,8 @@ DECL_PIOCTL(PGetInitParams)
     if (sizeof(struct cm_initparams) > PIGGYSIZE)
        return E2BIG;
 
-    memcpy(aout, (char *)&cm_initParams, sizeof(struct cm_initparams));
-    *aoutSize = sizeof(struct cm_initparams);
+    return afs_pd_putBytes(aout, &cm_initParams,
+                          sizeof(struct cm_initparams));
     return 0;
 }
 
@@ -3856,9 +4096,7 @@ crget(void)
  */
 DECL_PIOCTL(PGetRxkcrypt)
 {
-    memcpy(aout, (char *)&cryptall, sizeof(afs_int32));
-    *aoutSize = sizeof(afs_int32);
-    return 0;
+    return afs_pd_putInt(aout, cryptall);
 }
 
 /*!
@@ -3882,9 +4120,8 @@ DECL_PIOCTL(PSetRxkcrypt)
 
     if (!afs_osi_suser(*acred))
        return EPERM;
-    if (ainSize != sizeof(afs_int32) || ain == NULL)
+    if (afs_pd_getInt(ain, &tmpval) != 0)
        return EINVAL;
-    memcpy((char *)&tmpval, ain, sizeof(afs_int32));
     /* if new mappings added later this will need to be changed */
     if (tmpval != 0 && tmpval != 1)
        return EINVAL;
@@ -4084,11 +4321,13 @@ DECL_PIOCTL(PGetCPrefs)
     if (!afs_resourceinit_flag)        /* afs daemons haven't started yet */
        return EIO;             /* Inappropriate ioctl for device */
 
-    if (ainSize < sizeof(struct sprefrequest))
+    spin = afs_pd_inline(ain, sizeof(*spin));
+    if (spin == NULL)
        return EINVAL;
 
-    spin = (struct sprefrequest *)ain;
-    spout = (struct sprefinfo *)aout;
+    /* Output spout relies on writing past the end of arrays. It's horrible,
+     * but I'm not quite brave enough to tackle it yet */
+    spout = (struct sprefinfo *)aout->ptr;
 
     maxNumber = spin->num_servers;     /* max addrs this time */
     srvout = spout->servers;
@@ -4103,7 +4342,7 @@ DECL_PIOCTL(PGetCPrefs)
        srvout->host.s_addr = afs_cb_interface.addr_in[i];
 
     spout->num_servers = j;
-    *aoutSize = sizeof(struct sprefinfo) + (j - 1) * sizeof(struct spref);
+    aout->ptr += sizeof(struct sprefinfo) + (j - 1) * sizeof(struct spref);
 
     if (i >= afs_cb_interface.numberOfInterfaces)
        spout->next_offset = 0; /* start from beginning again */
@@ -4130,6 +4369,8 @@ DECL_PIOCTL(PGetCPrefs)
  */
 DECL_PIOCTL(PSetCPrefs)
 {
+    char *ainPtr;
+    size_t ainSize;
     struct setspref *sin;
     int i;
 
@@ -4137,7 +4378,13 @@ DECL_PIOCTL(PSetCPrefs)
     if (!afs_resourceinit_flag)        /* afs daemons haven't started yet */
        return EIO;             /* Inappropriate ioctl for device */
 
-    sin = (struct setspref *)ain;
+    /* Yuck. Input to this function relies on reading past the end of
+     * structures. Bodge it for now.
+     */
+    ainPtr = ain->ptr;
+    ainSize = ain->remaining;
+
+    sin = (struct setspref *)ainPtr;
 
     if (ainSize < sizeof(struct setspref))
        return EINVAL;
@@ -4178,12 +4425,17 @@ DECL_PIOCTL(PFlushMount)
     register struct dcache *tdc;
     struct VenusFid tfid;
     char *bufp;
+    char *mount;
     struct sysname_info sysState;
     afs_size_t offset, len;
 
     AFS_STATCNT(PFlushMount);
     if (!avc)
        return EINVAL;
+
+    if (afs_pd_getStringPtr(ain, &mount) != 0)
+       return EINVAL;
+
     code = afs_VerifyVCache(avc, areq);
     if (code)
        return code;
@@ -4193,7 +4445,7 @@ DECL_PIOCTL(PFlushMount)
     tdc = afs_GetDCache(avc, (afs_size_t) 0, areq, &offset, &len, 1);
     if (!tdc)
        return ENOENT;
-    Check_AtSys(avc, ain, &sysState, areq);
+    Check_AtSys(avc, mount, &sysState, areq);
     ObtainReadLock(&tdc->lock);
     do {
        code = afs_dir_Lookup(tdc, sysState.name, &tfid.Fid);
@@ -4261,22 +4513,17 @@ DECL_PIOCTL(PFlushMount)
  */
 DECL_PIOCTL(PRxStatProc)
 {
-    int code = 0;
     afs_int32 flags;
 
-    if (!afs_osi_suser(*acred)) {
-       code = EACCES;
-       goto out;
-    }
-    if (ainSize != sizeof(afs_int32)) {
-       code = EINVAL;
-       goto out;
-    }
-    memcpy((char *)&flags, ain, sizeof(afs_int32));
-    if (!(flags & AFSCALL_RXSTATS_MASK) || (flags & ~AFSCALL_RXSTATS_MASK)) {
-       code = EINVAL;
-       goto out;
-    }
+    if (!afs_osi_suser(*acred))
+       return EACCES;
+
+    if (afs_pd_getInt(ain, &flags) != 0)
+       return EINVAL;
+
+    if (!(flags & AFSCALL_RXSTATS_MASK) || (flags & ~AFSCALL_RXSTATS_MASK))
+       return EINVAL;
+
     if (flags & AFSCALL_RXSTATS_ENABLE) {
        rx_enableProcessRPCStats();
     }
@@ -4286,9 +4533,7 @@ DECL_PIOCTL(PRxStatProc)
     if (flags & AFSCALL_RXSTATS_CLEAR) {
        rx_clearProcessRPCStats(AFS_RX_STATS_CLEAR_ALL);
     }
-  out:
-    *aoutSize = 0;
-    return code;
+    return 0;
 }
 
 
@@ -4307,22 +4552,17 @@ DECL_PIOCTL(PRxStatProc)
  */
 DECL_PIOCTL(PRxStatPeer)
 {
-    int code = 0;
     afs_int32 flags;
 
-    if (!afs_osi_suser(*acred)) {
-       code = EACCES;
-       goto out;
-    }
-    if (ainSize != sizeof(afs_int32)) {
-       code = EINVAL;
-       goto out;
-    }
-    memcpy((char *)&flags, ain, sizeof(afs_int32));
-    if (!(flags & AFSCALL_RXSTATS_MASK) || (flags & ~AFSCALL_RXSTATS_MASK)) {
-       code = EINVAL;
-       goto out;
-    }
+    if (!afs_osi_suser(*acred))
+       return EACCES;
+
+    if (afs_pd_getInt(ain, &flags) != 0)
+       return EINVAL;
+
+    if (!(flags & AFSCALL_RXSTATS_MASK) || (flags & ~AFSCALL_RXSTATS_MASK))
+       return EINVAL;
+
     if (flags & AFSCALL_RXSTATS_ENABLE) {
        rx_enablePeerRPCStats();
     }
@@ -4332,15 +4572,13 @@ DECL_PIOCTL(PRxStatPeer)
     if (flags & AFSCALL_RXSTATS_CLEAR) {
        rx_clearPeerRPCStats(AFS_RX_STATS_CLEAR_ALL);
     }
-  out:
-    *aoutSize = 0;
-    return code;
+    return 0;
 }
 
 DECL_PIOCTL(PPrefetchFromTape)
 {
     register afs_int32 code, code1;
-    afs_int32 bytes;
+    afs_int32 bytes, outval;
     struct afs_conn *tc;
     struct rx_call *tcall;
     struct AFSVolSync tsync;
@@ -4354,10 +4592,10 @@ DECL_PIOCTL(PPrefetchFromTape)
     if (!avc)
        return EINVAL;
 
-    if (ain && (ainSize == 3 * sizeof(afs_int32)))
-       Fid = (struct AFSFid *)ain;
-    else
+    Fid = afs_pd_inline(ain, sizeof(struct AFSFid));
+    if (Fid == NULL)
        Fid = &avc->f.fid.Fid;
+
     tfid.Cell = avc->f.fid.Cell;
     tfid.Fid.Volume = Fid->Volume;
     tfid.Fid.Vnode = Fid->Vnode;
@@ -4382,7 +4620,7 @@ DECL_PIOCTL(PPrefetchFromTape)
                StartRXAFS_FetchData(tcall, (struct AFSFid *)&tvc->f.fid.Fid, 0,
                                     0);
            if (!code) {
-               bytes = rx_Read(tcall, (char *)aout, sizeof(afs_int32));
+               bytes = rx_Read(tcall, (char *)&outval, sizeof(afs_int32));
                code =
                    EndRXAFS_FetchData(tcall, &OutStatus, &CallBack, &tsync);
            }
@@ -4397,10 +4635,10 @@ DECL_PIOCTL(PPrefetchFromTape)
     afs_FetchStatus(tvc, &tfid, areq, &OutStatus);
     afs_PutVCache(tvc);
 
-    if (!code) {
-       *aoutSize = sizeof(afs_int32);
-    }
-    return code;
+    if (code)
+       return code;
+
+    return afs_pd_putInt(aout, outval);
 }
 
 DECL_PIOCTL(PFsCmd)
@@ -4413,13 +4651,17 @@ DECL_PIOCTL(PFsCmd)
     struct VenusFid tfid;
     struct AFSFid *Fid;
 
-    Inputs = (struct FsCmdInputs *)ain;
-    Outputs = (struct FsCmdOutputs *)aout;
     if (!avc)
        return EINVAL;
-    if (!ain || ainSize != sizeof(struct FsCmdInputs))
+
+    Inputs = afs_pd_inline(ain, sizeof(*Inputs));
+    if (Inputs == NULL)
        return EINVAL;
 
+    Outputs = afs_pd_inline(aout, sizeof(*Outputs));
+    if (Outputs == NULL)
+       return E2BIG;
+
     Fid = &Inputs->fid;
     if (!Fid->Volume)
        Fid = &avc->f.fid.Fid;
@@ -4465,9 +4707,6 @@ DECL_PIOCTL(PFsCmd)
 
     afs_PutVCache(tvc);
 
-    if (!code) {
-       *aoutSize = sizeof(struct FsCmdOutputs);
-    }
     return code;
 }
 
@@ -4491,12 +4730,11 @@ DECL_PIOCTL(PNewUuid)
 
 DECL_PIOCTL(PSetCachingThreshold)
 {
-    afs_int32 getting;
-    afs_int32 setting;
+    afs_int32 getting = 1;
+    afs_int32 setting = 1;
+    afs_int32 threshold;
 
-    setting = getting = 1;
-
-    if (ain == NULL || ainSize < sizeof(afs_int32))
+    if (afs_pd_getInt(ain, &threshold) != 0)
        setting = 0;
 
     if (aout == NULL)
@@ -4509,23 +4747,17 @@ DECL_PIOCTL(PSetCachingThreshold)
      * If setting, set first, and return the value now in effect
      */
     if (setting) {
-       afs_int32 threshold;
-
        if (!afs_osi_suser(*acred))
            return EPERM;
-       memcpy((char *)&threshold, ain, sizeof(afs_int32));
        cache_bypass_threshold = threshold;
         afs_warn("Cache Bypass Threshold set to: %d\n", threshold);            
        /* TODO:  move to separate pioctl, or enhance pioctl */
        cache_bypass_strategy = LARGE_FILES_BYPASS_CACHE;
     }
        
+    /* Return the current size threshold */
     if (getting) {
-       /* Return the current size threshold */
-       afs_int32 oldThreshold = cache_bypass_threshold;
-       memcpy(aout, (char *)&oldThreshold, sizeof(afs_int32));
-       *aoutSize = sizeof(afs_int32);
-    }
+       return afs_pd_putInt32(aout, cache_bypass_threshold);
 
     return(0);
 }
@@ -4551,11 +4783,9 @@ DECL_PIOCTL(PCallBackAddr)
     if (!afs_osi_suser(acred))
        return EACCES;
 
-    if (ainSize < sizeof(afs_int32))
+    if (afs_pd_getInt(ain, &addr) != 0)
        return EINVAL;
 
-    memcpy(&addr, ain, sizeof(afs_int32));
-
     ObtainReadLock(&afs_xinterface);
     for (i = 0; (unsigned short)i < afs_cb_interface.numberOfInterfaces; i++) {
        if (afs_cb_interface.addr_in[i] == addr)
@@ -4636,17 +4866,17 @@ DECL_PIOCTL(PDiscon)
     static afs_int32 mode = 1; /* Start up in 'off' */
     afs_int32 force = 0;
     int code = 0;
+    char flags[3];
 
-    if (ainSize) {
-
+    if (afs_pd_getBytes(ain, &flags, 3) == 0) {
        if (!afs_osi_suser(*acred))
            return EPERM;
 
-       if (ain[0])
-           mode = ain[0] - 1;
-       if (ain[1])
-           afs_ConflictPolicy = ain[1] - 1;
-       if (ain[2])
+       if (flags[0])
+           mode = flags[0] - 1;
+       if (flags[1])
+           afs_ConflictPolicy = flags[1] - 1;
+       if (flags[2])
            force = 1;
 
        /*
@@ -4695,9 +4925,10 @@ DECL_PIOCTL(PDiscon)
        return EINVAL;
     }
 
-    memcpy(aout, &mode, sizeof(afs_int32));
-    *aoutSize = sizeof(afs_int32);
-    return code;
+    if (code)
+       return code;
+
+    return afs_pd_putInt(aout, mode);
 #else
     return EINVAL;
 #endif
@@ -4713,9 +4944,8 @@ DECL_PIOCTL(PNFSNukeCreds)
     if (!afs_resourceinit_flag)        /* afs daemons haven't started yet */
        return EIO;             /* Inappropriate ioctl for device */
 
-    if (ainSize < sizeof(afs_int32))
+    if (afs_pd_getUint(ain, &addr) != 0)
        return EINVAL;
-    memcpy(&addr, ain, sizeof(afs_int32));
 
     if (afs_cr_gid(*acred) == RMTUSER_REQ_PRIV && !addr) {
        tu = afs_GetUser(areq->uid, -1, SHARED_LOCK);