Bug 17681

Summary: XDR does not handle 64bit data types correctly
Product: Base System Reporter: David E. Cross <crossd>
Component: binAssignee: dec
Status: Closed FIXED    
Severity: Affects Only Me    
Priority: Normal    
Version: 4.0-STABLE   
Hardware: Any   
OS: Any   

Description David E. Cross 2000-03-30 08:20:01 UTC
	The XDR routines for 64bit data types do not propperly byte-swap 
        the data.

Fix: 

Apply the patch derived from NetBSD which is available at

http://www.cs.rpi.edu/~crossd/FreeBSD/xdr.diff
How-To-Repeat: 	Write an NFSv4 Locking implimentation.  Submit it for public testing, 
 get back many error reports.
Comment 1 Sheldon Hearn 2000-03-30 12:57:38 UTC
On Thu, 30 Mar 2000 02:11:08 EST, "David E. Cross" wrote:

> http://www.cs.rpi.edu/~crossd/FreeBSD/xdr.diff

Let us know when that server accepts connections to port 80. :-)

Ciao,
Sheldon.
Comment 2 David E. Cross 2000-03-30 16:13:24 UTC
It does now.   *sigh*

--
David Cross                               | email: crossd@cs.rpi.edu 
Acting Lab Director                       | NYSLP: FREEBSD
Systems Administrator/Research Programmer | Web: http://www.cs.rpi.edu/~crossd 
Rensselaer Polytechnic Institute,         | Ph: 518.276.2860            
Department of Computer Science            | Fax: 518.276.4033
I speak only for myself.                  | WinNT:Linux::Linux:FreeBSD
Comment 3 Sheldon Hearn 2000-03-31 10:14:44 UTC
On Thu, 30 Mar 2000 10:13:24 EST, "David E. Cross" wrote:

> It does now.   *sigh*

By the way... You said that your fix is derived from NetBSD.  Given
their wild fanaticism for portable code, I'm surprised that your patch
is so much more complicated than theirs.

What gives?

Ciao,
Sheldon.
Comment 4 David E. Cross 2000-03-31 17:33:02 UTC
> > It does now.   *sigh*
> 
> By the way... You said that your fix is derived from NetBSD.  Given
> their wild fanaticism for portable code, I'm surprised that your patch
> is so much more complicated than theirs.
> 
> What gives?

Hmm?  It shouldn't be.  The aforementioned patch should make our xdr*()
routines look identical to NetBSDs.  A patch that I posted earlier to
the mailing list was more complicated, and less portable, that is why I 
switched to the NetBSD version.

--
David Cross                               | email: crossd@cs.rpi.edu 
Acting Lab Director                       | NYSLP: FREEBSD
Systems Administrator/Research Programmer | Web: http://www.cs.rpi.edu/~crossd 
Rensselaer Polytechnic Institute,         | Ph: 518.276.2860            
Department of Computer Science            | Fax: 518.276.4033
I speak only for myself.                  | WinNT:Linux::Linux:FreeBSD
Comment 5 Sheldon Hearn 2000-04-03 10:59:26 UTC
On Fri, 31 Mar 2000 11:33:02 EST, "David E. Cross" wrote:

> Hmm?  It shouldn't be.  The aforementioned patch should make our xdr*()
> routines look identical to NetBSDs.

I'm looking at http://www.cs.rpi.edu/~crossd/FreeBSD/xdr.diff.  It
results in code that doesn't seem to look anything like the code at
http://www.freebsd.org/cgi/cvsweb.cgi/basesrc/lib/libc/rpc/xdr.c?rev=1.21&cvsroot=netbsd
.

Am I being stupid?

Ciao,
Sheldon.
Comment 6 David E. Cross 2000-04-06 19:19:01 UTC
Hmm.. I feel one of us is probably doing something stupid :)

This is a bit long as it includes the multiple copies of the source to
try to clear things up (only the XDR64 routines are here, as that is
the only thing I touched.)

The XDR patch that I gave out only touches the 64bit routines in the
XDR library, so here is the XDR library before my patch:

/*
 * XDR 64-bit integers
 */
bool_t
xdr_int64_t(xdrs, int64_p)
        register XDR *xdrs;
        int64_t *int64_p;
{
        int64_t x;

        switch (xdrs->x_op) {

        case XDR_ENCODE:
                return (xdr_opaque(xdrs, (caddr_t)int64_p, sizeof(int64_t)));

        case XDR_DECODE:
                if (!xdr_opaque(xdrs, (caddr_t)&x, sizeof x)) {
                        return (FALSE);
                }
                *int64_p = x;
                return (TRUE);

        case XDR_FREE:
                return (TRUE);
        }
        return (FALSE);
}

/*
 * XDR unsigned 64-bit integers
 */
bool_t
xdr_u_int64_t(xdrs, uint64_p)
        register XDR *xdrs;
        u_int64_t *uint64_p;
{
        u_int64_t x;

        switch (xdrs->x_op) {

        case XDR_ENCODE:
                return (xdr_opaque(xdrs, (caddr_t)uint64_p, sizeof(u_int64_t)));

        case XDR_DECODE:
                if (!xdr_opaque(xdrs, (caddr_t)&x, sizeof x)) {
                        return (FALSE);
                }
                *uint64_p = x;
                return (TRUE);

        case XDR_FREE:
                return (TRUE);
        }
        return (FALSE);
}


The following is from:
http://www.freebsd.org/cgi/cvsweb.cgi/basesrc/lib/libc/rpc/xdr.c?rev=1.21&cvsroot=netbsd

/*
 * XDR 64-bit integers
 */
bool_t
xdr_int64_t(xdrs, llp)
        XDR *xdrs;
        int64_t *llp;
{
        u_long ul[2];

        switch (xdrs->x_op) {
        case XDR_ENCODE:
                ul[0] = (u_long)((u_int64_t)*llp >> 32) & 0xffffffff;
                ul[1] = (u_long)((u_int64_t)*llp) & 0xffffffff;
                if (XDR_PUTLONG(xdrs, (long *)&ul[0]) == FALSE)
                        return (FALSE);
                return (XDR_PUTLONG(xdrs, (long *)&ul[1]));
        case XDR_DECODE:
                if (XDR_GETLONG(xdrs, (long *)&ul[0]) == FALSE)
                        return (FALSE);
                if (XDR_GETLONG(xdrs, (long *)&ul[1]) == FALSE)
                        return (FALSE);
                *llp = (int64_t)
                    (((u_int64_t)ul[0] << 32) | ((u_int64_t)ul[1]));
                return (TRUE);
        case XDR_FREE:
                return (TRUE);
        }
        /* NOTREACHED */
        return (FALSE);
}


/*
 * XDR unsigned 64-bit integers
 */
bool_t
xdr_u_int64_t(xdrs, ullp)
        XDR *xdrs;
        u_int64_t *ullp;
{
        u_long ul[2];

        switch (xdrs->x_op) {
        case XDR_ENCODE:
                ul[0] = (u_long)(*ullp >> 32) & 0xffffffff;
                ul[1] = (u_long)(*ullp) & 0xffffffff;
                if (XDR_PUTLONG(xdrs, (long *)&ul[0]) == FALSE)
                        return (FALSE);
                return (XDR_PUTLONG(xdrs, (long *)&ul[1]));
        case XDR_DECODE:
                if (XDR_GETLONG(xdrs, (long *)&ul[0]) == FALSE)
                        return (FALSE);
                if (XDR_GETLONG(xdrs, (long *)&ul[1]) == FALSE)
                        return (FALSE);
                *ullp = (u_int64_t)
                    (((u_int64_t)ul[0] << 32) | ((u_int64_t)ul[1]));
                return (TRUE);
        case XDR_FREE:
                return (TRUE);
        }
        /* NOTREACHED */
        return (FALSE);
}

The following is a result of:
patch <xdr.diff

/*
 * XDR 64-bit integers
 */
bool_t
xdr_int64_t(xdrs, int64_p)
        register XDR *xdrs;
        int64_t *int64_p;
{
        u_long ul[2];

        switch (xdrs->x_op) {

        case XDR_ENCODE:
                ul[0] = (u_long)((u_int64_t)*int64_p >> 32) & 0xffffffff;
                ul[1] = (u_long)((u_int64_t)*int64_p) & 0xffffffff;
                if (XDR_PUTLONG(xdrs, (long *)&ul[0]) == FALSE)
                        return (FALSE);
                return (XDR_PUTLONG(xdrs, (long *)&ul[1]));
        case XDR_DECODE:
                if (XDR_GETLONG(xdrs, (long *)&ul[0]) == FALSE)
                        return (FALSE);
                if (XDR_GETLONG(xdrs, (long *)&ul[1]) == FALSE)
                        return (FALSE);
                *int64_p = (int64_t)
                        (((u_int64_t)ul[0] << 32) | ((u_int64_t)ul[1]));
                return (TRUE);
        case XDR_FREE:
                return (TRUE);
        }
        return (FALSE);
}

/*
 * XDR unsigned 64-bit integers
 */
bool_t
xdr_u_int64_t(xdrs, uint64_p)
        register XDR *xdrs;
        u_int64_t *uint64_p;
{
        u_long ul[2];

        switch (xdrs->x_op) {

        case XDR_ENCODE:
                ul[0] = (u_long)(*int64_p >> 32) & 0xffffffff;
                ul[1] = (u_long)(*int64_p) & 0xffffffff;
                if (XDR_PUTLONG(xdrs, (long *)&ul[0]) == FALSE)
                        return (FALSE);
                return (XDR_PUTLONG(xdrs, (long *)&ul[1]));

        case XDR_DECODE:
                if (XDR_GETLONG(xdrs, (long *)&ul[0]) == FALSE)
                        return (FALSE);
                if (XDR_GETLONG(xdrs, (long *)&ul[1]) == FALSE)
                        return (FALSE);
                *int64_p = (u_int64_t)
                        (((u_int64_t)ul[0] << 32) | ((u_int64_t)ul[1]));
                return (TRUE);
        case XDR_FREE:
                return (TRUE);
        }
        return (FALSE);
}

So, if we save the NetBSD and the patched FreeBSD xdr.c (just the XDR64
routeines) to a file, and diff them we get:

1,2d0
< 
< 
7,9c5,7
< xdr_int64_t(xdrs, llp)
<         XDR *xdrs;
<         int64_t *llp;
---
> xdr_int64_t(xdrs, int64_p)
>         register XDR *xdrs;
>         int64_t *int64_p;
13a12
> 
15,16c14,15
<                 ul[0] = (u_long)((u_int64_t)*llp >> 32) & 0xffffffff;
<                 ul[1] = (u_long)((u_int64_t)*llp) & 0xffffffff;
---
>                 ul[0] = (u_long)((u_int64_t)*int64_p >> 32) & 0xffffffff;
>                 ul[1] = (u_long)((u_int64_t)*int64_p) & 0xffffffff;
25,26c24,25
<                 *llp = (int64_t)
<                     (((u_int64_t)ul[0] << 32) | ((u_int64_t)ul[1]));
---
>                 *int64_p = (int64_t)
>                         (((u_int64_t)ul[0] << 32) | ((u_int64_t)ul[1]));
31d29
<         /* NOTREACHED */
35d32
< 
40,42c37,39
< xdr_u_int64_t(xdrs, ullp)
<         XDR *xdrs;
<         u_int64_t *ullp;
---
> xdr_u_int64_t(xdrs, uint64_p)
>         register XDR *xdrs;
>         u_int64_t *uint64_p;
46a44
> 
48,49c46,47
<                 ul[0] = (u_long)(*ullp >> 32) & 0xffffffff;
<                 ul[1] = (u_long)(*ullp) & 0xffffffff;
---
>                 ul[0] = (u_long)(*int64_p >> 32) & 0xffffffff;
>                 ul[1] = (u_long)(*int64_p) & 0xffffffff;
52a51
> 
58,59c57,58
<                 *ullp = (u_int64_t)
<                     (((u_int64_t)ul[0] << 32) | ((u_int64_t)ul[1]));
---
>                 *int64_p = (u_int64_t)
>                         (((u_int64_t)ul[0] << 32) | ((u_int64_t)ul[1]));
64d62
<         /* NOTREACHED */

The only differences that I am seeing in the file are naming conventions.
I decided to stick with ours.  The NetBSD people have the 64bit type as the
long long and the unsigned long long,  where we have the int64_t and
u_int64_t.  They make mention of this being non-portable, and thus in its
own secion.  As we have the 'int64_t' I decided to stick with it.

I will ask the lockd devloper to do an additional set of runs 
just to make absolutely, 100%, definitely, undeniably, sure.

--
David Cross                               | email: crossd@cs.rpi.edu 
Lab Director                              | Rm: 308 Lally Hall
Rensselaer Polytechnic Institute,         | Ph: 518.276.2860            
Department of Computer Science            | Fax: 518.276.4033
I speak only for myself.                  | WinNT:Linux::Linux:FreeBSD
Comment 7 David E. Cross 2000-04-06 21:29:21 UTC
Ok, cool, looking forward to seeing the commit :)


Just as a sidebar, the developer re-tested the NFS locking code against
the changes and everything looks 100% :)

(I will be publishing the second beta shortly, just need to clean up the
makefile, etc.)
--
David Cross                               | email: crossd@cs.rpi.edu 
Lab Director                              | Rm: 308 Lally Hall
Rensselaer Polytechnic Institute,         | Ph: 518.276.2860            
Department of Computer Science            | Fax: 518.276.4033
I speak only for myself.                  | WinNT:Linux::Linux:FreeBSD
Comment 8 Sheldon Hearn freebsd_committer freebsd_triage 2000-04-06 21:47:13 UTC
Responsible Changed
From-To: freebsd-bugs->sheldonh

I'll take this one. 

Comment 9 Sheldon Hearn 2000-04-06 22:14:39 UTC
On Thu, 06 Apr 2000 14:19:01 -0400, "David E. Cross" wrote:

> Hmm.. I feel one of us is probably doing something stupid :)

Ah, yes that would be me. :-)

I don't know how but I managed to look at the wrong functions in the
NetBSD code.  Sorry about the inconvenience.

Ciao,
Sheldon.
Comment 10 David E. Cross 2000-04-08 00:23:16 UTC
When will those hit the CVS tree?

--
David Cross                               | email: crossd@cs.rpi.edu 
Lab Director                              | Rm: 308 Lally Hall
Rensselaer Polytechnic Institute,         | Ph: 518.276.2860            
Department of Computer Science            | Fax: 518.276.4033
I speak only for myself.                  | WinNT:Linux::Linux:FreeBSD
Comment 11 Sheldon Hearn 2000-04-10 16:35:32 UTC
On Fri, 07 Apr 2000 19:23:16 -0400, "David E. Cross" wrote:

> When will those hit the CVS tree?

Sorry, some documentation work that I'm busy with took longer than
expected.  I'll do it in about 19 hours from the time I sent this mail.

Ciao,
Sheldon.
Comment 12 Sheldon Hearn 2000-04-11 10:39:16 UTC
Hi David,

Sorry again for the delay.  I want to test this through a ``make world''
and last night's automated build broke because of CVS conflicts.  I'm
making world as I type.

Ciao,
Sheldon.
Comment 13 Sheldon Hearn freebsd_committer freebsd_triage 2000-04-12 09:41:35 UTC
State Changed
From-To: open->analyzed

Committed in rev 1.10.  David, I know you want this for your lockd 
stuff, but I'm resisting the urge to merge this onto the RELENG_4 
branch immediately.  Would you bug me in 1 week? 

Comment 14 Sheldon Hearn 2000-05-04 18:40:55 UTC
Hi David,

You happy with the XDR stuff being merged into RELENG_4?  Have you
tested it on that branch?

Ciao,
Sheldon.
Comment 15 Sheldon Hearn freebsd_committer freebsd_triage 2000-06-22 10:28:28 UTC
Responsible Changed
From-To: sheldonh->dec

David has a commit bit now.
Comment 16 nbm freebsd_committer freebsd_triage 2000-08-06 18:19:20 UTC
State Changed
From-To: analyzed->closed

dec MFC'd this in revision 1.9.2.1 of libc/xdr/xdr.c