Fix su_info cache yet again...

This commit is contained in:
topjohnwu 2019-09-13 14:05:28 -04:00
parent f109038d12
commit 6e46d394b1

View File

@ -83,56 +83,50 @@ static void database_check(const shared_ptr<su_info> &info) {
validate_manager(info->str[SU_MANAGER], uid / 100000, &info->mgr_st); validate_manager(info->str[SU_MANAGER], uid / 100000, &info->mgr_st);
} }
static void update_su_info(unsigned uid) { static shared_ptr<su_info> get_su_info(unsigned uid) {
LOGD("su: request from uid=[%d]\n", uid); LOGD("su: request from uid=[%d]\n", uid);
RunFinally refresh([] { shared_ptr<su_info> info;
cached->refresh();
});
// Get from cache or new instance
{ {
MutexGuard lock(cache_lock); MutexGuard lock(cache_lock);
if (!cached || cached->uid != uid || !cached->is_fresh()) if (!cached || cached->uid != uid || !cached->is_fresh())
cached = make_shared<su_info>(uid); cached = make_shared<su_info>(uid);
else cached->refresh();
return; info = cached;
} }
// Lock before the policy is determined info->lock();
cached->lock();
RunFinally unlock([&] { RunFinally unlock([&] {
cached->unlock(); info->unlock();
}); });
if (cached->access.policy == QUERY) { if (info->access.policy == QUERY) {
// Not cached, get data from database // Not cached, get data from database
database_check(cached); database_check(info);
// If it's root or the manager, allow it silently // If it's root or the manager, allow it silently
if (cached->uid == UID_ROOT || (cached->uid % 100000) == (cached->mgr_st.st_uid % 100000)) { if (info->uid == UID_ROOT || (info->uid % 100000) == (info->mgr_st.st_uid % 100000)) {
cached->access = SILENT_SU_ACCESS; info->access = SILENT_SU_ACCESS;
return; return info;
} }
// Check su access settings // Check su access settings
switch (cached->cfg[ROOT_ACCESS]) { switch (info->cfg[ROOT_ACCESS]) {
case ROOT_ACCESS_DISABLED: case ROOT_ACCESS_DISABLED:
LOGW("Root access is disabled!\n"); LOGW("Root access is disabled!\n");
cached->access = NO_SU_ACCESS; info->access = NO_SU_ACCESS;
return; break;
case ROOT_ACCESS_ADB_ONLY: case ROOT_ACCESS_ADB_ONLY:
if (cached->uid != UID_SHELL) { if (info->uid != UID_SHELL) {
LOGW("Root access limited to ADB only!\n"); LOGW("Root access limited to ADB only!\n");
cached->access = NO_SU_ACCESS; info->access = NO_SU_ACCESS;
return;
} }
break; break;
case ROOT_ACCESS_APPS_ONLY: case ROOT_ACCESS_APPS_ONLY:
if (cached->uid == UID_SHELL) { if (info->uid == UID_SHELL) {
LOGW("Root access is disabled for ADB!\n"); LOGW("Root access is disabled for ADB!\n");
cached->access = NO_SU_ACCESS; info->access = NO_SU_ACCESS;
return;
} }
break; break;
case ROOT_ACCESS_APPS_AND_ADB: case ROOT_ACCESS_APPS_AND_ADB:
@ -140,14 +134,16 @@ static void update_su_info(unsigned uid) {
break; break;
} }
if (cached->access.policy != QUERY) if (info->access.policy != QUERY)
return; return info;
// If still not determined, check if manager exists // If still not determined, check if manager exists
if (cached->str[SU_MANAGER][0] == '\0') { if (info->str[SU_MANAGER][0] == '\0') {
cached->access = NO_SU_ACCESS; info->access = NO_SU_ACCESS;
return; return info;
} }
} else {
return info;
} }
// If still not determined, ask manager // If still not determined, ask manager
@ -155,17 +151,19 @@ static void update_su_info(unsigned uid) {
int sockfd = create_rand_socket(&addr); int sockfd = create_rand_socket(&addr);
// Connect manager // Connect manager
app_connect(addr.sun_path + 1, cached); app_connect(addr.sun_path + 1, info);
int fd = socket_accept(sockfd, 60); int fd = socket_accept(sockfd, 60);
if (fd < 0) { if (fd < 0) {
cached->access.policy = DENY; info->access.policy = DENY;
} else { } else {
socket_send_request(fd, cached); socket_send_request(fd, info);
int ret = read_int_be(fd); int ret = read_int_be(fd);
cached->access.policy = ret < 0 ? DENY : static_cast<policy_t>(ret); info->access.policy = ret < 0 ? DENY : static_cast<policy_t>(ret);
close(fd); close(fd);
} }
close(sockfd); close(sockfd);
return info;
} }
static void set_identity(unsigned uid) { static void set_identity(unsigned uid) {
@ -187,9 +185,8 @@ static void set_identity(unsigned uid) {
void su_daemon_handler(int client, struct ucred *credential) { void su_daemon_handler(int client, struct ucred *credential) {
LOGD("su: request from pid=[%d], client=[%d]\n", credential->pid, client); LOGD("su: request from pid=[%d], client=[%d]\n", credential->pid, client);
update_su_info(credential->uid);
su_context ctx = { su_context ctx = {
.info = cached, .info = get_su_info(credential->uid),
.req = su_request(true), .req = su_request(true),
.pid = credential->pid .pid = credential->pid
}; };