2

我正在尝试在我的 fuse 文件系统中使用ioctl来利用 LTO5 设备的硬件加密。应该很简单,用 cdb 设置一个 io_hdr:

0xB5, 0x20, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00

并根据所选算法提供关键页面。当我执行 SG_IO ioctl时,我返回 0 并且 SCSI 感觉全为 0 。

现在,这就是奇怪的地方。写入设备的数据永远不会加密。我将磁带切换到另一个驱动器并进行 SCSI 读取,数据都是明文形式。

因此,下一步是执行 SCSI SPIN 命令以查看 SPOUT 命令是否已执行,即使所有返回都表明已执行。在 SPOUT 之后,我立即为安全状态页面 (0x20) 发送一个 SPIN:

0xA2, 0x20, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x00

同样,从 SG_IO ioctl返回值 0和全零感。但是我返回的页面是我放入驱动器的 SPOUT 关键页面。我确信这不是来自驱动器,因为它具有我发送的密钥,这绝对是 SCSI 规范,不,不。顺便说一句,我对两个 SCSI 命令都使用了完全不同的缓冲区,并将 SPIN 页面 memset 为零只是为了更好地衡量。sg 驱动程序正在提供此数据以响应 SPIN。

任何人都可以阐明这种行为吗?

Linux archive.xxxxx.xxx 2.6.18-274.7.1.el5 #1 SMP Thu Oct 20 16:21:01 EDT 2011 x86_64 x86_64 x86_64 GNU/Linux

sg3_utils-libs-1.25-5.el5

sgpio-1.2.0_10-2.el5

mt-st-0.9b-2.2.2

我将ioctl命令发送到 /dev/sg5:

[root@archive bin]# sg_inq /dev/sg5
standard INQUIRY:
  PQual=0  Device_type=1  RMB=1  version=0x06  [SPC-4]
  [AERC=0]  [TrmTsk=0]  NormACA=0  HiSUP=0  Resp_data_format=2
  SCCS=0  ACC=0  TPGS=0  3PC=0  Protect=1  BQue=0
  EncServ=0  MultiP=1 (VS=0)  [MChngr=0]  [ACKREQQ=0]  Addr16=0
  [RelAdr=0]  WBus16=0  Sync=0  Linked=0  [TranDis=0]  CmdQue=1
  [SPI: Clocking=0x0  QAS=0  IUS=0]
    length=70 (0x46)   Peripheral device type: tape
 Vendor identification: IBM     
 Product identification: ULTRIUM-HH5     
 Product revision level: BAKG
 Unit serial number: 106xxxxxxxxxx

我发现 Linux ioctl 系统调用返回 SG_ERR_DID_ERROR [0x07] 在 sg_io_hdr_t 的 host_status 成员中的主机适配器中检测到内部错误。

setltokey.c 代码也在这里:http ://www.circlesoft.com/setltokey.c

/*
   setLTO4key: Set LTO4 Encryption Key

   Copyright (c) 2008  Andrew Schretter <schrett@math.duke.edu>
   Provided under GPL license

   added clear encryption,
     sense key and
     error printouts - Gerard J. Cerchio <gjpc@circlesoft.com>
*/

#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <scsi/sg.h>
#include <scsi/scsi.h>
#include <ctype.h>
#include <sys/ioctl.h>
#include <unistd.h>

#define SENSE_BUFF_LEN  96          /* from lto spec */

/*
 * here is a sample key - create a file with these HEX digits:
   4418AFCD046F2535B2E996123CE7DE3D418A15915A091C4BA12BDC85D4069A77
 */

/*
 * A good sg_io_hdr_t reference: http://tldp.org/HOWTO/SCSI-Generic-HOWTO/sg_io_hdr_t.html
 */

/* Print a hexadecimal dump of a block of data */
void hexdump(void *data, int size)
{
    unsigned char *p = data;
    unsigned char c;
    int n;
    char bytestr[4] = {0};
    char addrstr[10] = {0};
    char hexstr[ 16*3 + 5] = {0};
    char charstr[16*1 + 5] = {0};
    for(n=1;n<=size;n++) {
        if (n%16 == 1) {
            /* store address for this line */
            snprintf(addrstr, sizeof(addrstr), "%.4x",
               ((unsigned int)p-(unsigned int)data) );
        }

        c = *p;
        if (isalnum(c) == 0) {
            c = '.';
        }

        /* store hex str (for left side) */
        snprintf(bytestr, sizeof(bytestr), "%02X ", *p);
        strncat(hexstr, bytestr, sizeof(hexstr)-strlen(hexstr)-1);

        /* store char str (for right side) */
        snprintf(bytestr, sizeof(bytestr), "%c", c);
        strncat(charstr, bytestr, sizeof(charstr)-strlen(charstr)-1);

        if(n%16 == 0) {
            /* line completed */
            printf("  [%4.4s]  %-49.49s %s\n", addrstr, hexstr, charstr);
            hexstr[0] = 0;
            charstr[0] = 0;
        } else if(n%8 == 0) {
            /* half line: add whitespaces */
            strncat(hexstr, " ", sizeof(hexstr)-strlen(hexstr)-1);
        }
        p++; /* next byte */
    }

    if (strlen(hexstr) > 0) {
        /* print rest of buffer if not empty */
        printf("  [%4.4s]  %-49.49s %s\n", addrstr, hexstr, charstr);
    }
}

/* Send a SCSI command block and display the result. */
void do_read_command(int fd, char *desc, unsigned char *cmd, int len)
{
        unsigned char sense[SENSE_BUFF_LEN];
        memset( sense, 0, SENSE_BUFF_LEN );

        sg_io_hdr_t io;
        unsigned char buf[512];

        memset(buf, 0, sizeof(buf));

        memset(&io, 0, sizeof(io));
        io.interface_id = 'S';
        io.cmd_len = len;
        io.mx_sb_len = 0;
        io.dxfer_direction = SG_DXFER_FROM_DEV;
        io.dxfer_len = sizeof(buf);
        io.dxferp = buf;
        io.cmdp = cmd;

        printf("Command: %s\n", desc);
        hexdump(cmd, len);

        if (ioctl(fd, SG_IO, &io) < 0) {
                printf("Error: %s\n", strerror(errno));
                return;
        }

        if ( io.sb_len_wr ){
            printf("Sense\n");
            hexdump( sense, SENSE_BUFF_LEN );
        }
        else
            printf( "No Sense\n" );

        if ((io.info & SG_INFO_OK_MASK) != SG_INFO_OK) {
            printf("Failed with info 0x%02x  mask status 0x%02x  msg status 0x%02x  host status 0x%02x driver status 0x%02x\n", io.info, io.masked_status, io.msg_status, io.host_status, io.driver_status );
            return;
        }

        len = io.dxfer_len - io.resid;
        printf("Response: %d %s\n", len, (len == 1) ? "byte" : "bytes");
        hexdump(buf, len);
}

void do_write_command(int fd, char *desc, unsigned char *cmd, int len, char *data_desc, unsigned char *data, int datalen)
{
        unsigned char sense[SENSE_BUFF_LEN];
        memset( sense, 0, SENSE_BUFF_LEN );

        sg_io_hdr_t io;
        memset(&io, 0, sizeof(io));
        io.interface_id = 'S';
        io.cmd_len = len;
        io.mx_sb_len = SENSE_BUFF_LEN;
        io.dxfer_direction = SG_DXFER_TO_DEV;
        io.dxfer_len = datalen;
        io.dxferp = data;
        io.cmdp = cmd;
        io.sbp = sense;

        printf("Command: %s\n", desc);
        hexdump(cmd, len);
        printf("Data: %s\n", data_desc);
        hexdump(data, datalen);

        if (ioctl(fd, SG_IO, &io) < 0) {
                printf("Error: %s\n", strerror(errno));
                return;
        }

        if ( io.sb_len_wr ){
            printf("Sense\n");
            hexdump( sense, SENSE_BUFF_LEN );
        }
        else
            printf( "No Sense\n" );

        if ((io.info & SG_INFO_OK_MASK) != SG_INFO_OK) {
            printf("Failed with info 0x%02x  mask status 0x%02x  msg status 0x%02x  host status 0x%02x driver status 0x%02x\n", io.info, io.masked_status, io.msg_status, io.host_status, io.driver_status );
                return;
        }

        len = io.dxfer_len - io.resid;
        printf("Response: %d %s\n", len, (len == 1) ? "byte" : "bytes");

        //hexdump(buf, len);
}

struct {
        char *description;
        int len;
        unsigned char cmd[16];
} commands[] = {
        { "SCSI Inquiry", 6,
          { 0x12, 0x00, 0x00, 0x00, 0xFF, 0x00 } },
        { "SCSI SPOUT Set Encryption Key", 12,
          { 0xb5, 0x20, 0x00, 0x10, 0x00, 0x00,
            0x00, 0x00, 0x00, 0x34, 0x00, 0x00 } },
        { "SCSI SPIN Read Status", 12,
          { 0xa2, 0x20, 0x00, 0x20, 0x00, 0x00,
            0xff, 0xff, 0xff, 0xff, 0x00, 0x00 } },
        { NULL, 0, { 0 } },
};

struct {
        char *description;
        int len;
        unsigned char cmd[64];
} data[] = {
        { "SCSI SPOUT Send Encryption Key Page", 52,
          { 0x00, 0x10, 0x00, 0x30, 0x40, 0x00,
            0x02, 0x03, 0x01, 0x00,
            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
            0x00, 0x20,
          } },
        { "SCSI SPOUT Clear Encryption Mode Page", 52,
          { 0x00, 0x10, 0x00, 0x30, 0x40, 0x00,
            0x00, 0x00, 0x01, 0x00,
            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
            0x00, 0x20,
          } },
        { NULL, 0, { 0 } },
};

int main(int argc, char **argv)
{
        FILE *fd2;
        int fd;
        int i = 0;

        if (argc < 2) {
                fprintf(stderr, "usage: %s /dev/sda < <keyfile.txt> | clear >\n", *argv);
                return 1;
        }

        if ((fd = open(argv[1], O_RDWR)) < 0) {
                perror(argv[1]);
                return 1;
        }

        if ((ioctl(fd, SG_GET_VERSION_NUM, &i) < 0) || (i < 30000)) {
                fprintf(stderr,"%s is not a sg device\n", argv[1]);
                close(fd);
                return 1;
        }

        printf("Opened %s\n", argv[1]);
        /* Send query command */
        do_read_command(fd, commands[0].description, commands[0].cmd, commands[0].len);

        if(argc > 2) {

        if ( strcasecmp( argv[2], "clear" ) == 0 ) {
            do_write_command(fd, commands[1].description, commands[1].cmd, commands[1].len, data[1].description, data[1].cmd, data[1].len);

        }
        else
        {
            if ((fd2 = fopen(argv[2], "r")) < 0) {
                perror(argv[2]);
                return 1;
                }

            for (i = 0; i < 32; i++) {
                if( fscanf(fd2, "%2x ", (unsigned int *) &data[0].cmd[i + 20]) != 1 ) {
                    fprintf(stderr, "Keyfile Error reading %s\n", argv[2]);
                    return 1;
                    }
                }
            fclose(fd2);
            /* Set Encryption key*/
            do_write_command(fd, commands[1].description, commands[1].cmd, commands[1].len, data[0].description, data[0].cmd, data[0].len);
            }
        }

        /* Query encryption status */
        do_read_command(fd, commands[2].description, commands[2].cmd, commands[2].len);
        close(fd);
        return 0;
}
4

2 回答 2

1

gjpc 我正在尝试完成同样的事情,您在这个问题上取得了任何进展吗?

更新:我刚刚发现您的程序正在运行。我使用 HP 驱动器对其进行了测试,它正确上传了密钥(蓝色指示灯亮起)。我能够写磁带,上传另一个密钥,但我无法读取磁带,更改为正确的密钥后,我可以再次从磁带读取数据。感谢您分享您的代码。

于 2012-01-22T11:53:56.160 回答
1

我发现了问题。Dell PowerEdge R410 中内置的 LSI 6Gb SAS SCSI HBA 与 IBM 的 ULTRIUM-HH5 LTO5 磁带机不兼容。

The HBA was failing on the both the SPIN and SPOUT commands. We assumed it was the version of RedHat we were using, which is older than Paul's Ubuntu 10.04. We performed the cryptography using our file system's built in facility and decided to re-visit the problem when we were able to upgrade to a newer RedHat.

The show stopper incompatibility was discovered during validation. The LSI HBA was generating extra SCSI MOVE MEDIA commands to the Qualstar RLS-8560 library when we loaded an expired cleaning cartridge into any of the drives. This error presented as an occasional sense key 2 ASC 3B ASQ 90 return to the host's single SCSI MOVE MEDIA command.

The solution is to install a ATTO ExpressSAS H680 6Gb/s SAS/SATA HBA, PCIe 2.0, 8 Port External SCSI adapter which is certified compatible with the IBM drives.

于 2012-04-04T16:08:31.427 回答