I have written a new daemon for Android that gets started by zygote. It is
actually part of our namespaces security extensions, and the daemon is the
init process for each namespace. So, when zygote is launching an app, it
decides if a new namespace needs to be created, and if so, it execve's the
init process for that namespace, then adds the app to it. Up to now, to
keep things simple, this init process runs in the zygote seandroid domain,
because zygote starts it. However, as I continue to enhance this work, I am
now trying to change this so the init process runs in it's own selinux
domain, so we don't have to give unneeded permissions to zygote.
The namespaceinit domain is defined as follows:
# namespace init process
type namespaceinit, domain;
type namespaceinit_exec, exec_type, file_type;
typeattribute namespaceinit mlstrustedsubject;
net_domain(namespaceinit)
domain_auto_trans(zygote, namespaceinit_exec, namespaceinit)
tmpfs_domain(namespaceinit)
type_transition namespaceinit socket_device:sock_file namespace_socket;
allow namespaceinit self:capability { net_admin net_raw };
I have also added the following to the file_contexts file:
/system/bin/namespaceInit u:object_r:namespaceinit_exec:s0
And this to file.te:
type namespace_socket, file_type;
The function that creates a namespace, and launches the
/system/bin/namespaceInit process is as follows (note that this function is
invoked in the zygote domain from the dalvik vm):
static int create_namespace(userid_t uid)
{
pid_t initPid, ppid;
char socketName[UNIX_PATH_MAX];
char indexNum[12];
char *argv[4] = {"/system/bin/namespaceInit", socketName,
indexNum, NULL};
int retries=0, tfd, i;
struct timespec req;
char *environ[] = { NULL };
req.tv_sec = MALLOC_DELAY_SECS;
req.tv_nsec = MALLOC_DELAY_NSECS;
// remember the parent pid so we can move original pid back to parent
pid namespace
ppid = getppid();
while (retries++ < MALLOC_RETRIES) {
// Move into a new pid namespace
if (unshare(CLONE_NEWPID) == -1) {
ALOG(LOG_ERROR, logCatTag, "%s:%d Error creating init process -
%s.\n", __FUNCTION__, __LINE__, strerror(errno));
return -1 * errno;
}
initPid = fork();
if (initPid == 0) {
// Set a new session leader
if (setsid() < 0) {
ALOG(LOG_ERROR, logCatTag, "%s:%d Error setting new session
id - %s.\n", __FUNCTION__, __LINE__, strerror(errno));
}
// Move child into new mount namespace
if (unshare(CLONE_NEWNS) == -1) {
ALOG(LOG_ERROR, logCatTag, "%s:%d Error creating init
process mount namespace - %s.\n", __FUNCTION__, __LINE__, strerror(errno));
} else {
// mount a new /proc filesystem
if (mount("none", "/proc", "proc", 0, NULL) == -1) {
ALOG(LOG_ERROR, logCatTag, "%s:%d Error %s mounting
/proc filesystem.\n", __FUNCTION__, __LINE__, strerror(errno));
}
// mount emulated storage
if (uid == 2)
mountEmulatedStorage(0);
else
mountEmulatedStorage(uid);
}
// Move child into new net namespace
if (!namespaceData->netdisabled) {
if (unshare(CLONE_NEWNET) == -1) {
ALOG(LOG_ERROR, logCatTag, "%s:%d Error creating init
process net namespace - %s.\n", __FUNCTION__, __LINE__, strerror(errno));
}
}
// Now that we are in a new pid and mount namespace, exec the
actual init process
// This gets rid of all the overhead of zygote in the init
process, and leaves a very
// lean and mean process running.
snprintf(socketName, UNIX_PATH_MAX, "%s/namespaceInit%d",
socketDir, uid);
snprintf(indexNum, 12, "%d", uid);
execve(argv[0], argv, environ);
// It is an error if we get here.
ALOG(LOG_ERROR, logCatTag, "%s:%d namespaceInit process
terminated.\n", __FUNCTION__, __LINE__);
return -1;
} else {
// Move parent back to original parent pid namespace
unset_namespace(ppid, NAMESPACE_TYPE_PID);
if (initPid == -1) {
if (((errno == ENOMEM) && (retries == MALLOC_RETRIES)) ||
(errno != ENOMEM)) {
ALOG(LOG_ERROR, logCatTag, "%s:%d Error creating init
process - %s.\n", __FUNCTION__, __LINE__, strerror(errno));
return errno;
} else {
// Give Android a chance to release some memory
while ((nanosleep(&req, &req) == -1) && (errno ==
EINTR));
}
} else {
namespaceData->namespaceTable[uid].pid = initPid;
namespaceData->namespaceTable[uid].id = uid;
snprintf(socketName, UNIX_PATH_MAX, "%s/namespaceInit%d",
socketDir, uid);
memset(&namespaceData->namespaceTable[uid].initServiceAddr,
0, sizeof(namespaceData->namespaceTable[uid].initServiceAddr));
namespaceData->namespaceTable[uid].initServiceAddr.sun_family = AF_UNIX;
strcpy(namespaceData->namespaceTable[uid].initServiceAddr.sun_path,
socketName);
// Wait for init process to be ready
if (sem_wait(&namespaceData->clone_sem) == -1) {
ALOG(LOG_ERROR, logCatTag, "%s:%d Error waiting on
namespace semaphore - %s.\n", __FUNCTION__, __LINE__, strerror(errno));
return -1 * errno;
}
ALOG(LOG_INFO, logCatTag, "%s:%d Namespace init process
gets pid=%d\n", __FUNCTION__, __LINE__,
namespaceData->namespaceTable[uid].pid);
// Configure ethernet access in network namespace
if (!namespaceData->netdisabled) {
mntbndnet_uid(initPid, uid);
return netns_connect_setup(uid);
}
return 0;
}
}
}
return 0;
}
But, the /system/bin/namespaceInit process remains in the zygote domain.
When I run the audit.log through audit2allow, I get the following:
allow zygote namespaceinit_exec:file execute_no_trans;
This seems to indicate that zygote wants to execute without transitioning,
but I thought I explicitly allowed transitioning with the
domain_auto_trans(zygote, namespaceinit_exec, namespaceinit) statement.
What am I missing? How come the /system/bin/namespaceInit process is not
transitioning into the namespaceinit domain?
Cheers,
Chris
_______________________________________________
Seandroid-list mailing list
[email protected]
To unsubscribe, send email to [email protected].
To get help, send an email containing "help" to
[email protected].