[openssl-dev] [openssl.org #4443] Re: VIA C7-D processor: Hang in 30-test_afalg.t

Jeffrey Walton noloader at gmail.com
Fri Mar 18 02:52:30 UTC 2016


>> Yeah, this looks fishy... According to the libc manual, 13.10 Perform
>> I/O Operations in Parallel
>> (https://www.gnu.org/software/libc/manual/html_node/Asynchronous-I_002fO.html):
>>
>>    volatile void *aio_buf
>>
>>        This is a pointer to the buffer with the data to
>>        be written or the place where the read data is
>>        stored.
>>
>> That cast should be to a void*, not an unsigned long.
>
> Wrong interface.  Here, OpenSSL is using "struct iocb" from the kernel ABI via
> <linux/aio_abi.h>, not glibc's "struct aiocb".  In the kernel structure, the
> definition is:
>
>         __u64 aio_buf;
>

This is bad news... A 32-bit pointer's sign extension is
implementation defined, which means it may as well be undefined
behavior...

GCC sign extends. I think you can get around it with an intermediate
cast to uintptr_t:

    cb->aio_buf = (uint64_t)(uintptr_t)buf;

But that's C99, and I'm not sure what happens under C89/90. I guess a
compile error if uintptr_t is not available in stdint.h?

*****

Testing with a cast to just uint64_t:

    cb->aio_buf = (uint64_t)buf;

Produces a warning:

engines/afalg/e_afalg.c: In function ‘afalg_fin_cipher_aio’:
engines/afalg/e_afalg.c:274:19: warning: cast from pointer to integer
of different size [-Wpointer-to-int-cast]
     cb->aio_buf = (uint64_t)buf;

And results in:

    test$ ./afalgtest
    ALG_PERR: afalg_fin_cipher_aio: io_read failed : Invalid argument
    test_afalg_aes_128_cbc() failed encryption

*****

Testing with an intermediate cast to uintptr_t:

    cb->aio_buf = (uint64_t)(uintptr_t)buf;

Produces the same hang. From dmesg:

[145719.753869] BUG: unable to handle kernel NULL pointer dereference
at 00000008
[145719.753884] IP: [<f8a31cf2>]
skcipher_recvmsg_async.isra.13+0x4b2/0x500 [algif_skcipher]
[145719.753899] *pdpt = 0000000032f1d001 *pde = 0000000000000000
[145719.753906] Oops: 0000 [#1] SMP
...

*****

For completeness, aio_abi.h is below.

$ find /usr -name aio_abi.h
/usr/include/linux/aio_abi.h

$ cat /usr/include/linux/aio_abi.h
/* include/linux/aio_abi.h
 *
 * Copyright 2000,2001,2002 Red Hat.
 *
 * Written by Benjamin LaHaise <bcrl at kvack.org>
 *
 * Distribute under the terms of the GPLv2 (see ../../COPYING) or under
 * the following terms.
 *
 * Permission to use, copy, modify, and distribute this software and its
 * documentation is hereby granted, provided that the above copyright
 * notice appears in all copies.  This software is provided without any
 * warranty, express or implied.  Red Hat makes no representations about
 * the suitability of this software for any purpose.
 *
 * IN NO EVENT SHALL RED HAT BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT,
 * SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OF
 * THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF RED HAT HAS BEEN ADVISED
 * OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * RED HAT DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND
 * RED HAT HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES,
 * ENHANCEMENTS, OR MODIFICATIONS.
 */
#ifndef __LINUX__AIO_ABI_H
#define __LINUX__AIO_ABI_H

#include <linux/types.h>
#include <asm/byteorder.h>

typedef __kernel_ulong_t aio_context_t;

enum {
    IOCB_CMD_PREAD = 0,
    IOCB_CMD_PWRITE = 1,
    IOCB_CMD_FSYNC = 2,
    IOCB_CMD_FDSYNC = 3,
    /* These two are experimental.
     * IOCB_CMD_PREADX = 4,
     * IOCB_CMD_POLL = 5,
     */
    IOCB_CMD_NOOP = 6,
    IOCB_CMD_PREADV = 7,
    IOCB_CMD_PWRITEV = 8,
};

/*
 * Valid flags for the "aio_flags" member of the "struct iocb".
 *
 * IOCB_FLAG_RESFD - Set if the "aio_resfd" member of the "struct iocb"
 *                   is valid.
 */
#define IOCB_FLAG_RESFD        (1 << 0)

/* read() from /dev/aio returns these structures. */
struct io_event {
    __u64        data;        /* the data field from the iocb */
    __u64        obj;        /* what iocb this event came from */
    __s64        res;        /* result code for this event */
    __s64        res2;        /* secondary result */
};

#if defined(__BYTE_ORDER) ? __BYTE_ORDER == __LITTLE_ENDIAN :
defined(__LITTLE_ENDIAN)
#define PADDED(x,y)    x, y
#elif defined(__BYTE_ORDER) ? __BYTE_ORDER == __BIG_ENDIAN :
defined(__BIG_ENDIAN)
#define PADDED(x,y)    y, x
#else
#error edit for your odd byteorder.
#endif

/*
 * we always use a 64bit off_t when communicating
 * with userland.  its up to libraries to do the
 * proper padding and aio_error abstraction
 */

struct iocb {
    /* these are internal to the kernel/libc. */
    __u64    aio_data;    /* data to be returned in event's data */
    __u32    PADDED(aio_key, aio_reserved1);
                /* the kernel sets aio_key to the req # */

    /* common fields */
    __u16    aio_lio_opcode;    /* see IOCB_CMD_ above */
    __s16    aio_reqprio;
    __u32    aio_fildes;

    __u64    aio_buf;
    __u64    aio_nbytes;
    __s64    aio_offset;

    /* extra parameters */
    __u64    aio_reserved2;    /* TODO: use this for a (struct sigevent *) */

    /* flags for the "struct iocb" */
    __u32    aio_flags;

    /*
     * if the IOCB_FLAG_RESFD flag of "aio_flags" is set, this is an
     * eventfd to signal AIO readiness to
     */
    __u32    aio_resfd;
}; /* 64 bytes */

#undef IFBIG
#undef IFLITTLE

#endif /* __LINUX__AIO_ABI_H */


More information about the openssl-dev mailing list