Почему getpidcon() ошибка на AOSP 7.1.2?
Я работаю над созданием индивидуального BSP на основе последнего источника AOSP Nougat.
Сервисный процесс Android просит сервис-менеджера найти или добавить сервис. А менеджер сервисов пытается проверить разрешения Mac, вызывая svc_can_register () или svc_can_find (), который вызывает check_mac_perms (), который вызывает getpidcon ().
Давайте посмотрим svc_can_find ()
static int svc_can_find(const uint16_t *name, size_t name_len, pid_t spid, uid_t uid)
{
const char *perm = "find";
return check_mac_perms_from_lookup(spid, uid, perm, str8(name, name_len)) ? 1 : 0;
}
check_mac_perms_from_lookup () выглядит так:
static bool check_mac_perms_from_lookup(pid_t spid, uid_t uid, const char *perm, const char *name)
{
bool allowed;
char *tctx = NULL;
if (selinux_enabled <= 0) {
return true;
}
if (!sehandle) {
ALOGE("SELinux: Failed to find sehandle. Aborting service_manager.\n");
abort();
}
if (selabel_lookup(sehandle, &tctx, name, 0) != 0) {
ALOGE("SELinux: No match for %s in service_contexts.\n", name);
return false;
}
allowed = check_mac_perms(spid, uid, tctx, perm, name);
freecon(tctx);
return allowed;
}
Он вызывает check_mac_perms (). check_mac_perms () вот так:
static bool check_mac_perms(pid_t spid, uid_t uid, const char *tctx, const char *perm, const char *name)
{
char *sctx = NULL;
const char *class = "service_manager";
bool allowed;
struct audit_data ad;
if (getpidcon(spid, &sctx) < 0) {
ALOGE("SELinux: getpidcon(pid=%d) failed to retrieve pid context.\n", spid);
return false;
}
ad.pid = spid;
ad.uid = uid;
ad.name = name;
int result = selinux_check_access(sctx, tctx, class, perm, (void *) &ad);
allowed = (result == 0);
freecon(sctx);
return allowed;
}
Он вызывает getpidcon (). getpidcon () определяется во внешних / selinux / libselinux / src / procattr.c
getpidcon () определяется так:
#define getpidattr_def(fn, attr) \
int get##fn(pid_t pid, char **c) \
{ \
if (pid <= 0) { \
errno = EINVAL; \
return -1; \
} else { \
return getprocattrcon(c, pid, #attr); \
} \
}
...
...
getpidattr_def(pidcon, current)
"getpidattr_def (pidcon, current)" расширен до определения функции getpidcon () и вызывает getprocatrcon ()
getprocattrcon () выглядит так:
static int getprocattrcon(char ** context,
pid_t pid, const char *attr)
{
char *buf;
size_t size;
int fd;
ssize_t ret;
int errno_hold;
fd = openattr(pid, attr, O_RDONLY);
if (fd < 0)
return -1;
size = selinux_page_size;
buf = malloc(size);
if (!buf) {
ret = -1;
goto out;
}
memset(buf, 0, size);
do {
ret = read(fd, buf, size - 1);
} while (ret < 0 && errno == EINTR);
if (ret < 0)
goto out2;
if (ret == 0) {
*context = NULL;
goto out2;
}
*context = strdup(buf);
if (!(*context)) {
ret = -1;
goto out2;
}
ret = 0;
out2:
free(buf);
out:
errno_hold = errno;
close(fd);
errno = errno_hold;
return ret;
}
Довольно просто, а? Просто откройте несколько файлов и прочитайте содержимое и верните его по аргументу функции.
Это терпит неудачу в openattr (). Я подтвердил это, вставив некоторую функцию журнала в openattr (). openattr () также простая функция.
static int openattr(pid_t pid, const char *attr, int flags)
{
int fd, rc;
char *path;
pid_t tid;
if (pid > 0) {
rc = asprintf(&path, "/proc/%d/attr/%s", pid, attr);
} else if (pid == 0) {
rc = asprintf(&path, "/proc/thread-self/attr/%s", attr);
if (rc < 0)
return -1;
fd = open(path, flags | O_CLOEXEC);
if (fd >= 0 || errno != ENOENT)
goto out;
free(path);
tid = gettid();
rc = asprintf(&path, "/proc/self/task/%d/attr/%s", tid, attr);
} else {
errno = EINVAL;
return -1;
}
if (rc < 0)
return -1;
fd = open(path, flags | O_CLOEXEC);
out:
free(path);
return fd;
}
Точка сбоя: "fd = open(path, flags | O_CLOEXEC);"
Даже если файл существует, почти всегда происходит сбой открытия. Я не понимаю этого и хочу знать, что вызвало проблему. Я подтвердил ошибку, вставив некоторые коды печати журнала, проверив журнал Android (adb logcat) и прочитав файл из оболочки Android (оболочка adb), например, "cat /proc/412/attr/current". Чтение по 'cat...' успешно завершено, но журнал показывает, что открытие файла не удается. Странно то, что если 'pid' равен 0, то это успешно.
Если открытие не удается, службы не могут быть запущены, поэтому система не загружается должным образом. Если я игнорирую сбои и возвращаю успешный результат из getpidcon (), система загружается правильно, но это, очевидно, неправильно.
Я тестирую bsp как разрешительный режим selinux.
Может ли кто-нибудь иметь опыт, как я? Если кто-то, пожалуйста, поделитесь опытом и решением проблемы.
Спасибо. Sangyong Lee.