我正在根据AOSP Nougat最新消息制作定制的bsp。
Android服务流程要求服务管理员查找或添加服务。 服务管理器会尝试通过调用svc_can_register()或svc_can_find()来调用mac_perms()来检查mac权限。
让我们看看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(路径,标志| O_CLOEXEC);”
即使文件存在,几乎总是无法打开。我不明白,想知道是什么原因引起的。我已确认失败 通过插入一些日志打印代码,检查android log(adb logcat)并从android shell(adb shell)中读取文件,例如'cat / proc / 412 / attr / current'。成功读取“ cat ...”,但日志显示打开 文件失败。奇怪的是,如果'pid'为0,则表示成功。
如果打开失败,则无法启动服务,因此系统不会 正常启动。如果我忽略失败并从getpidcon()返回成功 系统可以正常启动,但这显然不是正确的事情。
我正在将bsp测试为selinux许可模式。
谁能像我一样经历?如果有人,请分享 经验和解决问题的方法。
谢谢。 李三gy。