禁止非法root的设备OTA升级

一、问题描述:
    常常跟OTA打交道的朋友可能会经常遇到客户root后的手机OTA升级失败的问题,如果用户取得root权限,手误破坏了system分区数据,是很有可能导致OTA升级失败的,甚至导致手机无法正常开机,因此为了避免取得root权限的手机ota升级失败导致无法开机的情况,我们在OTA升级前对设备进行root检测,如果发现设备已经root,则禁止手机安装更新。

二、实现方案:

1.修改update_script打包脚本:
/* /bootable/recovery/ota_from_target_files.py */

def WriteIncrementalOTAPackage(target_zip, source_zip, output_zip):
......
  script.AssertRootCheck()
  script.AssertSomeFingerprint(source_fp, target_fp)
......

/* Edify_generator.py */
  def AssertRootCheck(self):
    cmd = ('root_check() ||abort("This phone has been root or an error occurred, can not upgrade.");')
    self.script.append(cmd)

下面是升级过程中recovery相关log:
====== Updater-Script:
mount("ext4", "EMMC", "/dev/block/mmcblk0p6", "/system");
root_check() ||abort("This phone has been root or an error occurred, can not upgrade.");
file_getprop("/system/build.prop", "ro.build.fingerprint") == "***" || file_getprop("/system/build.prop", "ro.build.fingerprint") == "***" || abort("Package expects build fingerprint of *** or ***; this device has " + getprop("ro.build.fingerprint") + ".");
getprop("ro.product.device") == "***" || abort("This package is for \"***\" devices; this is a \"" + getprop("ro.product.device") + "\".");
ui_print("Verifying current system...");
......
    如上,脚本第一句是挂载system分区,这是升级前必须要做的动作。之后,在校验fingerprint之前增加了root_check()的动作。这里root_check()是一个接口,该函数的函数体以二进制代码的形式也保存在HOTA包中,供升级时调用。

2.修改安装更新时对应root检测接口root_check()函数:

#define ROOT_SAVE_MAGIC  0x00071029
#define ROOT_UNIT_MAGIC  0x00071029
#define ROOT_MAX_RECORD  1024
#define MAX_TIME_LEN    32
#define MAX_ACTION_LEN  32
#define TASK_COMM_LEN   16


struct root_save_head{
     int           magic;
     int           count;
     char          reserved[512-8];
};

struct root_save_unit{
     int             magic;
     pid_t          ppid;
     pid_t          pid;
     pid_t          tid;
     int             cap;
     int             fork_by_sh;  
     char           parent_name[TASK_COMM_LEN];
     char           process_name[TASK_COMM_LEN];
     char           thread_name[TASK_COMM_LEN];
        char           action[MAX_ACTION_LEN];
     char             time[MAX_TIME_LEN];
     char            reserved[512-136];
};

static struct root_save_head  save_head_tmp;
static struct root_save_unit  save_unit_tmp;
static const char *ROOTM_PATCH = "/dev/rootm";


Value* RootCheckFN(const char* name, State* state, int argc, Expr* argv[]) {
    if (argc != 0) {
        return ErrorAbort(state, "%s() expects no args, got %d", name, argc);
    }

    int result = 1;
    int fd;
    int magic = 0;
    int count = 0;
    int index = 0;
    int result_check=1;

    fd = open(ROOTM_PATCH, O_RDONLY, 0);

    if(fd == -1){
        fprintf(stderr, "Can not open %s, errno=%d\n", ROOTM_PATCH, errno);
        result = 1;
        return StringValue(strdup(result == 0 ? "t" : ""));
    }

    if(sizeof(struct root_save_head) != read(fd, &save_head_tmp, sizeof(struct root_save_head))){
        fprintf(stderr, "Can not read the header of records\n");
        close(fd);
        result = 1;
        return StringValue(strdup(result == 0 ? "t" : ""));
    }

    magic = save_head_tmp.magic;
    count = save_head_tmp.count;

    if(magic != ROOT_SAVE_MAGIC || count > ROOT_MAX_RECORD || count <= 0){
        close(fd);
        fprintf(stderr, "System partition check Pass!\n");
     result = 0;
     return StringValue(strdup(result == 0 ? "t" : ""));
    }else{
        fprintf(stderr,"System partition check Fail!\n");
        fprintf(stderr, "System have been Root.\n");
        result = 1;
        return StringValue(strdup(result == 0 ? "t" : ""));
    }
    return StringValue(strdup(result == 0 ? "t" : ""));
}


void RegisterInstallFunctions() {
    RegisterFunction("root_check", RootCheckFN);
    这部分代码逻辑在项目的updater/install.c中,增加了一个root_check()的函数,该函数主要用来进行root检测。之后在/tools/releasetools/edify_generator.py脚本中增加对root_check()的调用。这个脚本的作用就是在制作升级包时生成升级包中的updater-script脚本。上述修改都是在该项目的代码中修改,专门用于制作升级包时生成脚本文件使用的,并不参与实际的软件版本编译,所以对这部分的修改只在生成HOTA升级包时生效,最终在HOTA包中的脚本updater-script中添加了root检测的逻辑调用。 而对已经发布的版本没有任何影响。

经过修改后,用户在进行HOTA升级时,实际的流程是:
    主系统下获取升级包 (差分包)---> 进行HOTA升级 ---> 手机重启后进入recovery模式 ---> 在recovery下解析HOTA升级包中的updater-script脚本 ---> 调用root_chek()函数检查root标志是否存在 ----> 如果存在,则执行“abort”退出升级流程并给出手机被root的提示语。 如果不存在,继续执行脚本的下一行,直到脚本执行完毕,开始对版本进行差分升级。【如果root检查没有通过,升级流程abort,那么手机停止在recovery模式,用户点击power键后选中reboot选项,手机重启回到正常模式。】

下面是root过的设备禁止OTA所记录的日志片段:
mount /system /dev/block/platform/mtk-msdc.0/by-name/system
System partition check Fail!
System have been Root.
script aborted: This phone has been root or an error occurred, can not upgrade.
This phone has been root or an error occurred, can not upgrade.
E:Error in /sdcard/dload/update.zip
(Status 7)
Installation aborted.

I:no boot messages recovery
I:[1]check the otaupdate is done!
factory_poweroff_flag=0
demo_mode_flag=0
  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

高桐@BILL

分享快乐,快乐分享...

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值