Stephen Smalley wrote: > On Mon, 2008-08-25 at 21:32 +0900, KaiGai Kohei wrote: >> The following patch is revised one for kernel. >> >> Updates: >> - This patch is rebased on James's security-testing-2.6 tree. >> - security_bounded_transition() is deployed just after read_unlock() >> within do_each_thread() { ... } while_each_thread() loop again. >> - The properties of type_datum are packed within the third word of >> type entries in the kernel policy. >> - Bounds checks on constraints are integrated within avc creation. >> Lazy bounds checks are invoked at the tail of context_struct_compute_av(), >> and it drops all of boundary violated permissions. It compares permissions >> of a bounded type based on both of TE and constraints by a bounds type in >> same time, so the bounded type always cannot have any wider permission than >> its parent. >> e.g) >> When a type of child_t is bounded by parent_t and has mcssetcats attribute, >> we cannot assign undominated categories because parent_t is not allowed to >> assign them and it bounds permissions of child_t. >> - Sanity checks for constraints are removed by the above reason. > > This looks good to me in terms of the functionality. > Have you run any benchmarks to assess the performance impact on AVC > misses? I measured it with attached program named as "avc_misses.c". It invokes lstat() for given files, and iterates it 1,000 times. The given files have inidividually different categories, so we can see the performance impact on AVC misses when the number of files is greater than /selinux/avc/cache_threshold . This program is executed in a domain with/without its boundary on pathed kernel, and did on vanilla kernel. The following result shows elapsed times of avc_misses on the second time scale. Because lstat() is invoked for all given files, we guess the result is basically proportional to number of files (= # of categories). | Number of | No bounds | Bounds | No bounds | | Files and | 2.6.27-rc4 | 2.6.27-rc4 | 2.6.27-rc4 | | Categories | patched | patched | vanilla | +------------+--------------+--------------+-------------+ | 100 | 2.338 | 2.372 | 2.216 | | 200 | 4.742 | 4.739 | 4.451 | | 300 | 7.275 | 7.116 | 6.844 | | 400 | 9.685 | 9.616 | 9.337 | | 500 | 12.509 | 12.187 | 12.049 |___ | 600 | 28.532 | 29.736 | 26.092 | | AVC misses for | 700 | 45.554 | 50.631 | 40.878 | | all lstat() | 800 | 59.908 | 72.730 | 54.208 | V +------------+--------------+--------------+-------------+ (*) /selinux/avc/cache_threshold is 512 (default) CPU: Pentium4 (3.20Ghz), single core When # of files is less than cache_threshold, it shows a little performance impact in both of Bounds/No-bounds cases. When # of files is greater than cache_threshold, it shows a significant performance impact. The difference between No-bounds ans Bounds cases got grown. However, it is extremely artifactual measurement result. In the typical case, the rate of AVC hits is greater than 99%. I don't think we don't need to worry about such level of performance impact. e.g) avcstat just after rawhide bootup. [kaigai@saba ~]$ /usr/sbin/avcstat lookups hits misses allocs reclaims frees 619277 614912 4365 4365 3840 3863 Thanks, -- OSS Platform Development Division, NEC KaiGai Kohei <kaigai@xxxxxxxxxxxxx>
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <errno.h> #include <unistd.h> #include <sys/time.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> int main(int argc, char *argv[]) { struct stat st_buf; struct timeval t1, t2; double delta; int nloops, rc, i, j; if (argc < 3) { fprintf(stderr, "usage: %s <# of loops> <files ...>\n", argv[0]); return 1; } nloops = atol(argv[1]); if (nloops < 1000) nloops = 1000; gettimeofday(&t1, NULL); for (i=0; i < nloops; i++) { for (j=2; argv[j]; j++) { rc = lstat(argv[j], &st_buf); if (rc < 0) { fprintf(stderr, "lstat(%s,...) : %s\n", argv[j], strerror(errno)); return 1; } } } gettimeofday(&t2, NULL); delta = (((double)(t2.tv_sec - t1.tv_sec)) * 1000000.0 + ((double)(t2.tv_usec - t1.tv_usec))) / 1000000.0; printf("result: %.3f [s] (%d of files, %d of loops)\n", delta, argc - 2, nloops); return 0; }