Hello. Currently, we have to use execve() in order to trigger TOMOYO's domain transition. Therefore, we cannot divide permissions given to Apache's CGI programs which are executed without execve(). But, user's desire to divide permissions given to Apache's CGI programs is increasing. Thus, I'm considering implementing a mechanism for triggering TOMOYO's domain transition without execve().
Implementation approach: (1) Perform domain transition by an atomic write operation. Apache runs as an unprivileged user. Therefore, we need to allow all users to perform domain transition without execve(). To perform a domain transition, the kernel has to receive string parameter which specifies the name of domain to transit to. If we allow users to pass string parameter with multiple write operations, the kernel has to allocate kernel's memory for holding incomplete string parameter. It will allow malicious users to consume all of kernel memory by intentionally issuing many requests with incomplete string parameter. In order to avoid such attacks, I'll force users to pass string parameter with single write operation. The usage will be to pass "string parameter" + '\0' by single write() system call. What I worry is that some buffering functionalities provided libraries (e.g. fprintf()) may divide single write operation from user into multiple write() system calls. It will be no problem if all programs can call write() system call directly. But there will be programming languages (e.g. Java) which don't allow programmers to call write() system call directly. Maybe I should not use write() system call for passing "string parameter" + '\0' from user to kernel atomically. (2) Automatically append // prefix to given string parameter due to security reasons. If we grant /bin/bash process to transit to /usr/bin/passwd domain without transferring control, /bin/bash process will be able to access /etc/shadow . We don't want to grant such dangerous transition, do we? Therefore, I think that we should be able to tell "domain transitions with execve()" (which transfers control) and "domain transitions without execve()" (which doesn't transfer control) apart. In particular, the kernel will automatically append // prefix to the string parameter for domain transitions without execve(). Since domain transitions with execve() use canonicalized pathnames, the string parameter does not have // prefix, unless we map canonicalized pathnames to names starting with // using "aggregator" directive. (3) Don't apply "keep_domain" directive nor "initialize_domain" directive. It makes no sense if domain transition without execve() is suppressed by "keep_domain" directive, for the purpose of domain transition without execve() is to divide permissions by triggering domain transition. Also, so far I don't see advantages of applying "initialize_domain" directive for domain transition without execve(), I won't apply "initialize_domain" directive for domain transition without execve() for now. How to try this mechanism: A kernel patch against ccs-patch-1.7.1-20100214.tar.gz is available at http://sourceforge.jp/projects/tomoyo/svn/view/branches/transit3.diff?root=tomoyo&revision=3463 . You can simply apply using "patch -p0" and recompile. KaiGai Kohei (a SELinux developer in Japan) developed mod_selinux package and mod_selinux package is available since Fedora 11. In mod_selinux, a disposable thread is created for each request. The disposable thread changes to different security context and performs the request. The original process simply waits for the disposable thread to finish. In this way, it can process Apache's CGI programs which are executed without execve() with different security contexts, without having a mechanism for returning to previous security context. This one-way security context change well suits for TOMOYO's domain tree model. Thus, I'm developing mod_ccs package based on mod_selinux package. Now, mod_ccs package is ready for usability testing. If you use mod_ccs , you can divide permissions based on Apache's virtual host's name and location of requested files. Screenshots are available at http://sourceforge.jp/projects/tomoyo/svn/view/branches/apache-1.png?root=tomoyo&revision=3463 and http://sourceforge.jp/projects/tomoyo/svn/view/branches/apache-2.png?root=tomoyo&revision=3463 . To install mod_ccs package, do # wget -O mod_ccs.c 'http://sourceforge.jp/projects/tomoyo/svn/view/branches/mod_ccs.c?root=tomoyo&revision=3463' # apxs -c mod_ccs.c # apxs -i -a mod_ccs.la You may need to use "apxs2" rather than "apxs". To configure mod_ccs , create /etc/apache_domain_map.conf which contains list of "requested pathname's pattern" and "domainname to transit to". An example content of /etc/apache_domain_map.conf is shown below. /usr/share/horde3/\* appname=horde /usr/share/horde3/\{\*\}/\* appname=horde /var/www/cgi-bin/main.cgi /var/www/cgi-bin/main.cgi /var/www/cgi-bin/\* appname=cgi-bin /var/www/cgi-bin/\{\*\}/\* appname=cgi-bin /\{\*\}/\*.pl appname=perl-programs /\{\*\}/\*.php appname=php-programs /\{\*\}/\* default /\* default Above example tells mod_ccs to transit to "appname=horde" domain if /usr/share/horde3/\* or /usr/share/horde3/\{\*\}/\* is requested, "/var/www/cgi-bin/main.cgi" domain if /var/www/cgi-bin/main.cgi is requested, "appname=cgi-bin" domain if /var/www/cgi-bin/\* or /var/www/cgi-bin/\{\*\}/\* is requested, "appname=perl-programs" domain if "/\{\*\}/\*.pl" is requested, "appname=php-programs" domain if /\{\*\}/\*.php is requested, "default" domain otherwise. Note that prefix // is automatically appended by kernel. Thus, specifying "default" will transit to "//default" domain. If you apply below patch for Android, --- mydroid.orig/dalvik/vm/native/dalvik_system_Zygote.c +++ mydroid/dalvik/vm/native/dalvik_system_Zygote.c @@ -25,6 +25,8 @@ #include <sys/wait.h> #include <grp.h> #include <errno.h> +#include <fcntl.h> /* open() */ +#include <sys/stat.h> /* open() */ #if defined(HAVE_PRCTL) # include <sys/prctl.h> @@ -358,6 +360,16 @@ static pid_t forkAndSpecializeCommon(con LOGW("cannot setuid(%d) errno: %d", uid, errno); } + { + const int fd = open("/proc/ccs/.transition", O_WRONLY); + if (fd >= 0) { + char buffer[128]; + memset(buffer, 0, sizeof(buffer)); + snprintf(buffer, sizeof(buffer) - 1, "uid=%d/gid=%d", uid, gid); + write(fd, buffer, strlen(buffer) + 1); + close(fd); + } + } /* * Our system thread ID has changed. Get the new one. */ each Java application running on Dalvik VM will run with different domains divided by UID and GID of that application. Screenshots are available at http://sourceforge.jp/projects/tomoyo/svn/view/branches/android-1.png?root=tomoyo&revision=3463 and http://sourceforge.jp/projects/tomoyo/svn/view/branches/android-2.png?root=tomoyo&revision=3463 . Currently, dividing domains by application's name (e.g. com.android.browser) is not supported because above function does not receive the application's name as parameter. But it will be possible to divide by application's name if we can insert a hook into functions where the application's name is available. Questions/opinions?: (1) Do you think that TOMOYO wants a mechanism for returning to previous domain like AppArmor? If programmers can use clone() + wait() like mod_ccs does, a mechanism for returning to previous domain will be unneeded. If we don't transfer control to other code (whereas mod_ccs transfers control to other code such as perl scripts), having a mechanism to return to previous domain would be convenient. But if we allow returning to previous domain, some protection is needed for preventing other code from illegally returning to previous domain. AppArmor uses a 64bits random number as a magic token. But TOMOYO 1.x does not have space for holding such token. (2) Do you think that TOMOYO should support domain transition to parent and/or specified domain in addition to domain transition to child domain? I think TOMOYO should not support domain transition to parent and/or specified domain because it is dangerous. But please let me know if you know a use case where domain transition to parent and/or specified domain is useful. I'll consider implementing. (3) Regarding mod_ccs package, how should domain transition based on virtual host's name performed? Is it OK to use virtual host's name as domainname? Or, we want to use an external mapping table for controlling virtual host's name and domainname? If virtual host's name is automatically used as domainname, it will be fine when there are only 2 or 3 virtual hosts. But it may be annoying if mapping table is not used when there are 100 or 1000 virtual hosts. (4) Anything else? Regards. _______________________________________________ tomoyo-users-en mailing list [email protected] http://lists.sourceforge.jp/mailman/listinfo/tomoyo-users-en
