systemd 上 emmc 上的 ioctl() 需要哪些功能?

Posted

技术标签:

【中文标题】systemd 上 emmc 上的 ioctl() 需要哪些功能?【英文标题】:What capabilities required for ioctl() on emmc on systemd? 【发布时间】:2020-02-28 17:35:24 【问题描述】:

我想以普通用户(非 root)使用 systemd 运行我的程序。该程序使用 ioctl() 系统调用来访问 emmc 寄存器。我想了解需要将哪些功能添加到我的 systemd 单元文件中。

我尝试使用以下单元文件:

[Unit]
Description=EMMC-LIFETIME UTILITY

[Service]
User=tron
Group=disk
ExecStart=/HARICI/emmc-lifetime /dev/mmcblk0 -v
CapabilityBoundingSet=CAP_SYS_ADMIN
DeviceAllow=/dev/mmcblk0 rw

[Install]
WantedBy=multi-user.target

这里是emmc-lifetime的代码:

int main(int argc, char **argv)


    if(argc < 2)
        printf("Usage: %s <mmcfilename> (-v)\n", argv[0]);
        printf("Example: %s /dev/mmcblk1 -v\n", argv[0]);
        return 1;
    

    char ext_csd[512], ext_csd_rev;
    int fd, ret;

    fd = open(argv[1], O_RDWR);
    if (fd < 0) 
        printf("Failed to open eMMC device, please check which path you have passed\n");
        return 1;
    

    struct mmc_ioc_cmd idata;
    memset(&idata, 0, sizeof(idata));
    memset(ext_csd, 0, sizeof(char) * 512);
    idata.write_flag = 0;
    idata.opcode = MMC_SEND_EXT_CSD;
    idata.arg = 0;
    idata.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_ADTC;
    idata.blksz = 512;
    idata.blocks = 1;
    mmc_ioc_cmd_set_data(idata, ext_csd);

    ret = ioctl(fd, MMC_IOC_CMD, &idata);
    if (ret)
        printf("ioctl failed, are you sure it is an MMC device???\n");
        return ret;
    


    ext_csd_rev = ext_csd[EXT_CSD_REV];

    if (ext_csd_rev >= 7) 

        if(argc==3 && !strcmp(argv[2],"-v"))
        printf("EXT_CSD_DEVICE_LIFE_TIME_EST_TYP_A: 0x%02x\n",
            ext_csd[EXT_CSD_DEVICE_LIFE_TIME_EST_TYP_A]);
        printf("EXT_CSD_DEVICE_LIFE_TIME_EST_TYP_B: 0x%02x\n",
            ext_csd[EXT_CSD_DEVICE_LIFE_TIME_EST_TYP_B]);
        printf("EXT_CSD_PRE_EOL_INFO: 0x%02x\n",
            ext_csd[EXT_CSD_PRE_EOL_INFO]);
        else
            printf("%d\n",ext_csd[EXT_CSD_DEVICE_LIFE_TIME_EST_TYP_B]*10);
        
    

    if(fd)
        close(fd);

    return ret;

如果我在单元文件中注释掉“User=tron”,一切正常:

Nov 03 01:17:03 tron systemd[1]: Started EMMC-LIFETIME UTILITY.
Nov 03 01:17:03 tron emmc-lifetime[28294]: EXT_CSD_DEVICE_LIFE_TIME_EST_TYP_A: 0x01 
Nov 03 01:17:03 tron emmc-lifetime[28294]: EXT_CSD_DEVICE_LIFE_TIME_EST_TYP_B: 0x01 
Nov 03 01:17:03 tron emmc-lifetime[28294]: EXT_CSD_PRE_EOL_INFO: 0x01 

但如果我取消注释“User=tron”,结果如下:

Nov 03 00:57:17 tron systemd[1]: Started EMMC-LIFETIME UTILITY. 
Nov 03 00:57:17 tron emmc-lifetime[27706]: ioctl failed, are you sure it is an MMC device??? 
Nov 03 00:57:17 tron systemd[1]: emmc-info.service: Main process exited, code=exited, status=255/n/a 
Nov 03 00:57:18 tron systemd[1]: emmc-info.service: Unit entered failed state. 
Nov 03 00:57:18 tron systemd[1]: emmc-info.service: Failed with result 'exit-code'.

我的单元文件中需要哪些功能才能以“tron”用户身份运行我的可执行文件?

【问题讨论】:

【参考方案1】:

解决了。对于功能方面,它必须具有 CAP_SYS_RAWIO。

我们可以使用:

setcap cap_sys_rawio=+eip /HARICI/emmc-lifetime

通过这种方式,我们可以使用非 root 用户运行“emmc-lifetime”二进制文件。请注意,此用户必须在“磁盘”组中才能打开“/dev/mmcblkX”

但不幸的是,这在 systemd 单元文件中不起作用。

在 systemd 单元文件中,如果你写:

User=some-non-root-user
CapabilityBoundingSet=SOME_CAPABILITY

不起作用。这就是为什么我上面的代码总是失败的原因。

我必须找到另一种方法来以非 root 权限运行我的二进制文件。

【讨论】:

以上是关于systemd 上 emmc 上的 ioctl() 需要哪些功能?的主要内容,如果未能解决你的问题,请参考以下文章

如何检查 ioctl 上的现有参数

如何使用Debian 8.2图像闪烁BeagleBone Black eMMC?

emmc是固态硬盘么

在 AIX 上使用 ioctl 的网络接口的硬件地址

EMMC是啥、啥是eMMC

eMMC 是什么