Android中SG_IO IOCTL触发sys_rawio AVC权限拒绝问题求助
问题背景
我正在开发Android原生HAL服务,提供从SCSI设备读取信息的接口。在用户空间通过带SG_IO请求的ioctl向/dev/block/sda设备发送命令时,触发了sys_rawio的AVC权限拒绝错误,但使用同一设备节点执行BLKDISCARD等其他ioctl命令时无此问题。此外,sys_rawio已被添加到private/domain.te的neverallow规则中,无法通过SEPolicy添加允许规则。
错误日志
01-01 00:57:50.227 1110 1110 I Diag@1.0-ser: type=1400 audit(0.0:332): avc: denied { sys_rawio } for capability=17 scontext=u:r:hal_Diag_default:s0 tcontext=u:r:hal_Diag_default:s0 tclass=capability permissive=1
触发权限拒绝的核心代码
执行SG_IO ioctl的关键调用:
ret = ioctl(fd, SG_IO, &io_hdr_v4);
完整的SCSI命令发送函数:
int32_t send_scsi_cmd_upiu (_Uint8t *cdb, _Uint8t cdb_len, int32_t fd, _Uint8t *data_ptr, int32_t data_len, int32_t timeout, _Uint8t write) { int k,ret=0; sg_io_hdr_t hp; unsigned char sense_buffer[32]={0}; timeout = 60000; memset(&hp,0,sizeof(sg_io_hdr_t)); hp.interface_id='S'; hp.cmd_len=cdb_len; hp.cmdp=cdb; hp.mx_sb_len=sizeof(sense_buffer); hp.dxfer_len=data_len; hp.timeout=60000; hp.sbp=sense_buffer; hp.iovec_count=0; hp.flags=0; hp.dxferp=data_ptr; hp.status=0; hp.masked_status=0; hp.msg_status=0; hp.sb_len_wr=0; hp.host_status=0; hp.driver_status=0; hp.resid=0; hp.duration=0; hp.info=0; if ( write ) { hp.dxfer_direction= SG_DXFER_TO_DEV; } else { hp.dxfer_direction= SG_DXFER_FROM_DEV; } if (ioctl(fd,SG_IO,&hp) == -1) { __android_log_print(ANDROID_LOG_ERROR,"\"DIAG\"","\"IOCTl SCSI Failed %s\n\"",strerror(errno)); ret=-1; } else { if (hp.info != 0) { ret = -1; if (hp.sb_len_wr > 0) { __android_log_print(ANDROID_LOG_INFO,"\"DIAG\"","\"INQUIRY sense data: \n \""); for (k = 0; k < hp.sb_len_wr; ++k) { if ((k > 0) && (0 == (k % 10))) __android_log_print(ANDROID_LOG_ERROR,"\"DIAG\"","\"\n \""); __android_log_print(ANDROID_LOG_ERROR,"\"DIAG\"","\"0x%02x \"", sense_buffer[k]); } __android_log_print(ANDROID_LOG_ERROR,"\"DIAG\"","\"\n\""); } if (hp.masked_status) __android_log_print(ANDROID_LOG_ERROR,"\"DIAG\"","\"INQUIRY SCSI status=0x%x\n\"", hp.status); if (hp.host_status) __android_log_print(ANDROID_LOG_ERROR,"\"DIAG\"","\"INQUIRY host_status=0x%x\n\"", hp.host_status); if (hp.driver_status) __android_log_print(ANDROID_LOG_ERROR,"\"DIAG\"","\"INQUIRY driver_status=0x%x\n\"", hp.driver_status); } } return ret; }
对比:无权限问题的ioctl代码
使用同一设备节点执行BLKDISCARD命令的代码,未触发权限拒绝:
int ret = 0 int fd; unsigned long long int range[2]; const char *device_path = "\"/dev/block/sda31\""; // Open the device file fd = open(device_path, O_RDWR); if (fd == -1) { ALOGD("\"Failed to open the device\""); } else { // Issue the BLKDISCARD ioctl command if (ioctl(fd, BLKDISCARD, &range) == -1) { ALOGD("\"BLKDISCARD ioctl failed\""); } else ALOGD("\"BLKDISCARD operation on %s successful.\n\"", device_path); // Close the device file close(fd); }
解决方案
1. 切换到sg设备节点而非块设备节点
/dev/block/sda是块设备节点,执行SG_IO需要sys_rawio权限;而/dev/sgX(比如/dev/sg0对应/dev/block/sda)是专门的SCSI通用设备节点,Android的SEPolicy通常对这类节点有更宽松的权限配置,无需sys_rawio能力。
- 可通过遍历
/sys/class/scsi_generic/找到对应设备的sg节点,比如:
找到指向目标块设备的ls -l /sys/class/scsi_generic/sgX节点,然后打开/dev/sgX替代/dev/block/sda。
2. 复用Android系统原生存储服务
如果你的功能属于存储操作范畴,可以直接复用Android原生的storaged服务或android.hardware.storage HAL接口,这类系统组件已经具备合法权限执行SCSI相关操作,无需自行处理权限问题。
3. 针对性调整SEPolicy(仅适用于定制ROM场景)
如果是定制ROM且有权修改SEPolicy,可尝试为hal_Diag_default域添加对sg_device类的ioctl权限:
allow hal_Diag_default sg_device:chr_file ioctl;
注意:此方法仅在使用sg节点时有效,因为操作sg节点不需要sys_rawio能力,不会触发neverallow规则限制。
内容的提问来源于stack exchange,提问作者Selva Kumar

