Subject: Re: sysctl function and ROUNDUP kernel bug
To: None <Chris_G_Demetriou@niagara.nectar.cs.cmu.edu>
From: David Waitzman <djw@bbnplanet.com>
List: port-alpha
Date: 01/30/1996 21:05:36
> > I am trying to port gated to netbsd/alpha (sys.951220) and am having
> > problems with reading the interface list using the sysctl function on
> > variable CTL_NET, PF_ROUTE, 0, 0, NET_RT_IFLIST.  Dereferencing longs
> > in the middle of the returned data causes bus errors.  It appears that
> > the longs are embedded in structures that are on 4 byte but not 8 byte
> > alignment.  
> 
> could you provide some sample code that demonstrates this?  I'd like
> to replicate the problem before i fix it.  8-)

The only source I have is actually gated, version gated-R3_6Alpha_1
(though the bus error is in file src/krt_ifread_kinfo.c), and it would
be painful to extract the relevant code.  I could send you the gated
configuration file, but I suspect that installing and compiling gated
might be too heavyweight.  Please let me know what to provide.

> > Can anyone suggest if changing ROUNDUP is the right thing to do?
> 
> It might be; i'm running a test kernel with that change, now...
> It seems to work OK, but i dunno if i have any code that actually
> tests that code path.

Further testing shows that I did not solve the problem just by changing
ROUNDUP.  The problem still occured.  The misaligned sysctl data is 
being put together in file net/rtsock.c function rt_msg2() handling 
the cases:
        case RTM_DELADDR:
        case RTM_NEWADDR:
                len = sizeof(struct ifa_msghdr);
                break;

Struct ifa_msghdr is 20 bytes long.  rt_msg2() puts one into a data stream,
followed by some sockaddrs (whose length is passed through ROUNDUP).  The
sockaddrs do not start on a 8 byte boundary-- that is my bus error.

For reference, here is struct isa_msghdr (with three lines I added):

/*
 * Message format for use in obtaining information about interface addresses
 * from sysctl and the routing socket.
 */
struct ifa_msghdr {
        u_short ifam_msglen;    /* to skip over non-understood messages */
        u_char  ifam_version;   /* future binary compatability */
        u_char  ifam_type;      /* message type */
        int     ifam_addrs;     /* like rtm_addrs */
        int     ifam_flags;     /* value of ifa_flags */
        u_short ifam_index;     /* index for associated ifp */
        int     ifam_metric;    /* value of ifa_metric */
#ifdef __alpha__                                                   /*ADDED*/
        int     :32;            /* padding for 8 byte alignment */ /*ADDED*/
#endif /* __alpha__ */                                             /*ADDED*/
};


If a user program were to allocate a struct ifa_msghdr (the original
version, not my version) inside a larger struct then the compiler would
add 4 bytes of padding:

    struct outside {
        struct ifa_msghdr xx;
        /* four pad bytes added */
        long aligned_right;
    };

But the kernel code in rtsock.c is doing the equivalent of:
    struct ifa_msghdr xx;
    long a_long;
    char *cp = malloc(...);
    bcopy(&xx, cp, sizeof(xx));
    cp += sizeof(xx);
    bcopy(&a_long, cp, sizeof(long));

Gated assumes that the long is aligned properly when it reads it.
Should it be?

As I showed in my version of struct ifa_msghdr, I put in 4 bytes of
padding on alpha for forced alignment.  I think that this is a bad hack.

Should a compiler do this automatically, e.g. pad *all* structures to 8
byte alignment?  I think that the answer to that is "No".

The reason I am giving so much detail in this email is that I think
that this is a general 64 bit code issue which may affect other
programs.

-david