您的位置:首页 > 其它

禁止非法root的设备OTA升级

2015-08-20 13:36 351 查看
一、问题描述:
    常常跟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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: