[Bug 31192] New: ioctl SG_GET_REQUEST_TABLE returns 64-bit structure to 32-bit app.

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



https://bugzilla.kernel.org/show_bug.cgi?id=31192

           Summary: ioctl SG_GET_REQUEST_TABLE returns 64-bit structure to
                    32-bit app.
           Product: SCSI Drivers
           Version: 2.5
    Kernel Version: 2.6.18-194.32.1.el5
          Platform: All
        OS/Version: Linux
              Tree: Mainline
            Status: NEW
          Severity: normal
          Priority: P1
         Component: Other
        AssignedTo: scsi_drivers-other@xxxxxxxxxxxxxxxxxxxx
        ReportedBy: jbyers@xxxxxxxxxxxx
                CC: jbyers@xxxxxxxxxxxx
        Regression: No


The 'sg' module ioctl 'SG_GET_REQUEST_TABLE', when run on an
2.6.18-194.32.1.el5 x86_64 kernel, from a 32-bit application
seems to return the 64-bit version of the
sg_req_info_t[SG_MAX_QUEUE] table, not the 32-bit version.

Because there is a pointer in the sg_req_info_t structure,
the returned size is (4 * SG_MAX_QUEUE) = 64 bytes too
large, and it corrupts neighboring user memory, as well as
not returning the correct data.

Although there is code in 'fs/compat_ioctl.c' that looks to
be handling the 32-bit user to 64-bit kernel conversion, the
"COMPATIBLE_IOCTL(SG_GET_REQUEST_TABLE)" line in
'include/linux/compat_ioctl.h' conflicts with it and seems
to prevent the conversion code from being called.

The same ioctl called from a 64-bit app works fine.

The problem looks to still be present in the newest kernel
source, although I haven't tested it.

It seems like the "COMPATIBLE_IOCTL(SG_GET_REQUEST_TABLE)"
line should be removed from 'compat_ioctl.h' ('compat_ioctl.c'
in the newest kernel).

~ Jeff Byers ~

# gcc -m32 -Wall -o sg_get_request_table sg_get_request_table.c
# ./sg_get_request_table /dev/sg1
SG Request Table:
Memory fence damaged:
0xff90c034: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0xff90c044: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0xff90c054: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0xff90c064: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0xff90c074: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
0xff90c084: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
0xff90c094: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
0xff90c0a4: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff

============================

// Test sg 'SG_GET_REQUEST_TABLE ioctl.
// Build with:
// gcc -m32 -Wall -o sg_get_request_table sg_get_request_table.c
// gcc -m64 -Wall -o sg_get_request_table sg_get_request_table.c

#include <unistd.h>
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <sys/ioctl.h>
#include <scsi/sg.h> /* take care: fetches glibc's /usr/include/scsi/sg.h */

static void hex_dump(const unsigned char *buf, int len, const char *str);
static int  memunchr(const void *s, int c, size_t n);

int main(int argc, char * argv[])
{
    int sg_fd;
    int idx;
    unsigned char fence[128];
    sg_req_info_t req_info[SG_MAX_QUEUE] = {{0}};

    if (2 != argc) {
        printf("Usage: '%s <sg_device>'\n", argv[0]);
        return 1;
    }
    if ((sg_fd = open(argv[1], O_RDONLY)) < 0) {
        perror("error opening given file name");
        return 1;
    }

    printf("SG Request Table:\n");
    memset(req_info, 0xFF, sizeof(req_info));
    memset(fence, 0xFF, sizeof(fence));
    if (ioctl(sg_fd, SG_GET_REQUEST_TABLE, &req_info) < 0) {
        perror("SG_GET_REQUEST_TABLE ioctl error");
        return 1;
    }
    for(idx=0; idx < SG_MAX_QUEUE; idx++){
        if(req_info[idx].req_state == 0)
            continue;
        printf("req_info[%u]: req_state=%u, pack_id=%u, usr_ptr=%p,
duration=%u\n",
               idx, req_info[idx].req_state, req_info[idx].pack_id,
               req_info[idx].usr_ptr, req_info[idx].duration);
    }
    if (memunchr(fence, 0xFF, sizeof(fence)) != 0){
        hex_dump(fence, sizeof(fence), "Memory fence damaged:");
    }
    close(sg_fd);
    return 0;
}

static void hex_dump(const unsigned char *buf, int len, const char *str)
{
    printf("%s\n", str);
    int idx;
    for(idx=0; idx < len; idx++){
        if ((idx > 0) && ((idx & 0x0F) == 0)){
            printf("\n");
        }
        if ((idx & 0x0F) == 0){
            printf("%p:", &buf[idx]);
        }
        printf(" %02x", buf[idx]);
    }
    printf("\n");
    return;
}

static int memunchr(const void *s, int c, size_t n)
{
    unsigned char *ptr = (unsigned char *)s;
    for(; n > 0; n--){
        if (*ptr++ != c)
            return 1;
    }
    return 0;
}

-- 
Configure bugmail: https://bugzilla.kernel.org/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
You are watching the assignee of the bug.
--
To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Index of Archives]     [SCSI Target Devel]     [Linux SCSI Target Infrastructure]     [Kernel Newbies]     [IDE]     [Security]     [Git]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux ATA RAID]     [Linux IIO]     [Samba]     [Device Mapper]
  Powered by Linux