One theory:

Android uses prctl(PR_SET_NO_NEW_PRIVS) to prevent gaining additional
privileges across an exec. See

Android L: https://android-review.googlesource.com/92350
Prior versions: https://android.googlesource.com/platform/dalvik/+/b64e9cb

For SELinux, this inhibits domain transitions, as an exec domain transition
could cause an app to gain privileges, similar to a setuid root program.

-- Nick

On Thu, Oct 23, 2014 at 6:29 PM, Chris Stone <
[email protected]> wrote:

> 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].
>



-- 
Nick Kralevich | Android Security | [email protected] | 650.214.4037
_______________________________________________
Seandroid-list mailing list
[email protected]
To unsubscribe, send email to [email protected].
To get help, send an email containing "help" to 
[email protected].

Reply via email to