开发者手机设置锁屏密码失败问题分析报告
1 关键字 锁屏密码;用户认证 2 问题描述 环境:开发板:开发者手机版本号:4.0.10.203 问题现象:打开 系统设置应用 -> 生物识别和密码 -> 锁屏密码,进入设置锁屏密码界面,根据界面提示输入要设置的密码,在第二遍密码(和第一遍的密码一致ÿ
1 关键字
锁屏密码;用户认证
2 问题描述
环境:
开发板:开发者手机
版本号:4.0.10.203
问题现象:
打开 系统设置应用 -> 生物识别和密码 -> 锁屏密码,进入设置锁屏密码界面,根据界面提示输入要设置的密码,在第二遍密码(和第一遍的密码一致)输完后界面无反应、锁屏密码设置失败。
3 问题原因
3.1 正常机制
可在设置锁屏密码界面成功设置锁屏密码,打印日志:
[Settings]: Settings PasswordInputController create password success
3.2 异常机制
在设置锁屏密码界面无法设置锁屏密码,打印日志:
[Settings]: Settings PasswordInputController create password failed
4 解决方案
在vendor/hys/laphone/hdf_config/uhdf/device_info.hcs文件内,修改服务pin_auth_interface_service、user_auth_interface_service的uid和gid为对应服务的hostName:
pin_auth :: host {
hostName = "pin_auth_host";
priority = 50;
- uid = "useriam";
- gid = ["useriam"];
+ uid = "pin_auth_host";
+ gid = ["pin_auth_host"];
...
user_auth :: host {
hostName = "user_auth_host";
priority = 50;
- uid = "useriam";
- gid = ["useriam"];
+ uid = "user_auth_host";
+ gid = ["user_auth_host"];
*注
hcs配置文件(HDF Configuration Source)是HDF驱动框架的配置描述语言,是为了实现配置代码与驱动代码解耦,以及便于配置的管理而设计的一种Key-Value为主体的文本格式。
hcs配置文件在OpenHarmony源码的vendor目录下,按照芯片厂商、开发板、配置的目录进行规划,HDF驱动的配置位于hdf_config目录下。根据硬件规格,此hdf_config目录下存放内核态配置信息或者分别内核态和用户态的配置信息。
hcs配置文件各字段含义以及配置方法参考:https://gitee.com/openharmony/docs/blob/master/zh-cn/device-dev/driver/driver-hdf-manage.md#%E9%85%8D%E7%BD%AE%E7%AE%A1%E7%90%86-1
5 定位过程
设置锁屏密码的关键调用链如下:
1、应用调用代码
addPinCredential(pinSubType: number, password: string, onResultCall: (result: number) => void): void {
try {
...
let credentialInfo = {
credType: AuthType.PIN, credSubType: pinSubType, token: token
}
let callback = {
onResult: (result, extraInfo) => {
LogUtil.info(`${this.TAG} Add pin credential, result: ${result}`);
onResultCall(result);
}
};
this.userIdentityManager.addCredential(credentialInfo, callback);
}
}
应用端收集credentialInfo参数(认证执行器类型、token),执行userIdentityManager.addCredential录入口令认证凭据(设置密码)
2、userIdentityManager.addCredential调用进入用户IAM子系统napi层流转到统一用户认证框架,在文件base/useriam/user_auth_framework/services/ipc/src/user_idm_service.cpp中的AddCredential函数中,先通过auto context = ContextFactory::CreateEnrollContext(para, contextCallback);
获取hdi实例创建context,调用 context->Start()
进入用户态驱动
3、执行文件base/useriam/user_auth_framework/services/context/src/enroll_context.cpp的OnStart
函数:经由enroll_->Start(scheduleList_, shared_from_this());
、drivers/peripheral/user_auth/hdi_service/service/user_auth_interface_service.cpp的UserAuthInterfaceService::BeginEnrollmentV1_1(
int32_t userId, const std::vector &authToken, const EnrollParam ¶m, ScheduleInfoV1_1 &info) 函数连接user_auth_host服务
4、执行文件base/useriam/user_auth_framework/frameworks/native/executors/src/async_command/enroll_command.cpp内 EnrollCommand::SendRequest函数通过IPC通信调用pin_auth_host服务
5、执行文件drivers/peripheral/pin_auth/hdi_service/service/src/executor_impl.cpp内的函数ExecutorImpl::Enroll(uint64_t scheduleId, const std::vector &extraInfo, const sptr &callbackObj),该函数调用NewSalt(salt) 获取包含'localDeviceId'的uint8_t数组:
uint32_t ExecutorImpl::NewSalt(std::vector<uint8_t> &salt)
{
IAM_LOGI("start");
constexpr uint32_t DEVICE_UUID_LENGTH = 65;
char localDeviceId[DEVICE_UUID_LENGTH] = {0};
if (GetDevUdid(localDeviceId, DEVICE_UUID_LENGTH) != EC_SUCCESS) { //调用GetDevUdid函数获取localDeviceId
IAM_LOGE("GetDevUdid failed");
return HDF_FAILURE;
}
...
for (uint32_t i = 0; i < size; i++) {
salt.push_back(result[i]);
}
return HDF_SUCCESS;
}
6、GetDevUdid最终执行文件base/startup/init/services/modules/udid/udid_comm.c内的INIT_LOCAL_API int GetUdidFromParam(char *udid, uint32_t size)
函数获取udid
INIT_LOCAL_API int GetUdidFromParam(char *udid, uint32_t size)
{
uint32_t len = size;
int ret = SystemGetParameter("const.product.udid", udid, &len); //获取系统参数const.product.udid
BEGET_CHECK(ret != 0, return ret);
len = size;
ret = SystemGetParameter("const.product.devUdid", udid, &len); //获取系统参数const.product.devUdid
BEGET_CHECK(ret != 0, return ret);
return ret;
}
7、SystemGetParameter获取系统参数之前调用文件base/startup/init/services/param/base/param_base.c内的DacCheckParamPermission函数检查DAC访问控制权限:
STATIC_INLINE int DacCheckParamPermission(const ParamLabelIndex *labelIndex,
const ParamSecurityLabel *srcLabel, const char *name, uint32_t mode)
{
/**
* DAC group
* user:group:read|write|watch
*/
******
// 2, check uid
******
// 3, check gid
******
// 4, check user in group
if (CheckUserInGroup(space, node->gid, srcLabel->cred.uid) == 0) {
localMode = (mode & (DAC_READ | DAC_WRITE | DAC_WATCH)) >> DAC_GROUP_START;
if ((node->mode & localMode) != 0) {
return DAC_RESULT_PERMISSION;
}
}
// forbid
PARAM_LOGW("Param '%s' label gid:%d uid:%d mode 0%x", name, srcLabel->cred.gid, srcLabel->cred.uid, mode);
PARAM_LOGW("Cfg label %u gid:%d uid:%d mode 0%x ", labelIndex->dacLabelIndex, node->gid, node->uid, node->mode);
int ret = DAC_RESULT_FORBIDED;
return ret;
}
依据以上调用链执行到DacCheckParamPermission函数时,对比rk3568功能正常下的日志,发现开发者手机多出了以下Warning日志:
pin_auth_host W [param_base.c:447]Param 'const.product.udid' label gid:1088 uid:1088 mode 0100
pin_auth_host W [param_base.c:448]Cfg label 57992 gid:1053 uid:0 mode 01e8
即开发者手机在执行DacCheckParamPermission函数时最终并没有返回 DAC_RESULT_PERMISSION,通过额外添加日志对比发现,函数体内第4步'检查用户是否在群组'CheckUserInGroup函数的执行结果,开发者手机与rk3568返回不一致:
static int CheckUserInGroup(WorkSpace *space, gid_t groupId, uid_t uid)
{
char buffer[USER_BUFFER_LEN] = {0};
int ret = PARAM_SPRINTF(buffer, sizeof(buffer), GROUP_FORMAT, groupId, uid);
PARAM_CHECK(ret >= 0, return -1, "Failed to format name for "GROUP_FORMAT, groupId, uid);
PARAM_LOGW("1 CheckUserInGroup gid is: %d,uid is:%d; buffer is:%s", groupId,uid,buffer); // 添加日志
ParamNode *node = GetParamNode(WORKSPACE_INDEX_BASE, buffer);
if (node != NULL) {
return 0;
}
return -1;
}
rk3568内添加的日志打印的buffer为 1053_1113,而开发者手机为1053_1088,进程uid不一致,一个为1113,一个是1088,查看进程的uid配置文件base/startup/init/services/etc/passwd,发现对应进程名为pin_auth_host、useriam:
useriam:x:1088:1088:::/bin/false
...
pin_auth_host:x:1113:1113:::/bin/false
再对比相应的hdf框架驱动设备描述配置文件,查看对应服务的配置: vendor/${product_company}${product_name}/hdf_config/uhdf/device_info.hcs
发现rk下pin_auth_host服务对应的uid设置的是pin_auth_host,开发者手机下uid则是useriam,
gid:1053对应的group为deviceprivate(gid配置文件base/startup/init/services/etc/group)
......
deviceprivate:x:1053:root,shell,system,samgr,hdf_devmgr,deviceinfo,dsoftbus,dms,account,pin_auth_host,access_token,device_manager,foundation,dbms,deviceauth,huks_server,dlp_credential,dsserver,edm,update,device_attest
可见deviceprivate组内配置的用户列表里并不包含uid useriam,致开发者手机在执行CheckUserInGroup权限检查时结果为无权限。
而在3.2Release deviceprivate组内配置的用户列表里包含了uid useriam:
https://gitee.com/openharmony/startup_init/blob/OpenHarmony-v3.2.4-Release/services/etc/group#L35
在项目升级到4.0Release时(deviceprivate组内配置的用户已经没有了useriam的uid,相关服务的gid和uid的配置及对应逻辑都做了变动),hcs配置文件却并没有升级,仍然保留了3.2Release的hcs配置文件,因此存在本案例所提到的问题。
6 知识分享
1:本案例针对"设置锁屏密码功能"所涉及用户IAM子系统、启动子系统简要示意图如下:
uid、gid等配置项是用户态驱动的启动配置,进程的uid在文件base/startup/init/services/etc/passwd中配置,进程的gid在文件base/startup/init/services/etc/group中配置,进程uid和gid配置参考:系统服务用户组添加方法。
更多推荐
所有评论(0)