#include #include #include #include #include #include #include #include #include #include #include #include #define N_TRIAL 10000000 typedef struct { uint32_t version; uint32_t sequence; uint32_t enforcing; uint32_t policyload; uint32_t deny_unknown; } selinux_status_t; static uint32_t compat_seqno = 0; static int test_callback(int code) { compat_seqno++; return 0; } int main(int argc, const char *argv[]) { selinux_status_t *status; security_context_t scontext = "staff_u:staff_r:staff_t:s0"; security_context_t tcontext = "system_u:object_r:etc_t:s0"; security_id_t ssid, tsid; security_class_t tclass; struct av_decision avd; int compat, fd, i; if (argc < 2) { printf("usage: %s (1: compat| 0: mmap)\n", argv[0]); return 1; } compat = atoi(argv[1]); if (avc_open(NULL, 0) < 0) { printf("failed on avc_open() : %s\n", strerror(errno)); return 1; } /* * I think existing avc code is a bit rough, because it checks * netlink socket on the head of avc_has_perm_noaudit(), but * not on the tail of the function. It cannot ensure the kernel * status is not updated during the function. * So, we also need to check it after the avc lookups, then * it shall repeat from the head, if something updated. */ avc_netlink_acquire_fd(); if (compat) { union selinux_callback cb; /* * callback functions to update sequence number */ cb.func_setenforce = test_callback; selinux_set_callback(SELINUX_CB_SETENFORCE, cb); cb.func_policyload = test_callback; selinux_set_callback(SELINUX_CB_POLICYLOAD, cb); } else { /* * Open /selinux/status and mmap it. */ fd = open("/selinux/status", O_RDONLY); if (fd < 0) { printf("failed to open /selinux/status : %s\n", strerror(errno)); return 1; } status = mmap(NULL, sysconf(_SC_PAGESIZE), PROT_READ, MAP_SHARED, fd, 0); if (status == MAP_FAILED) { printf("failed to mmap : %s\n", strerror(errno)); return 1; } } /* * Start benchmarking */ for (i = 0; i < N_TRIAL; i++) { uint32_t seqno; repeat: if (compat) { avc_netlink_check_nb(); seqno = compat_seqno; } else { seqno = status->sequence; __sync_synchronize(); } tclass = string_to_security_class("file"); avc_context_to_sid_raw(scontext, &ssid); avc_context_to_sid_raw(tcontext, &tsid); avc_has_perm_noaudit(ssid, tsid, tclass, -1, NULL, &avd); if (compat) { avc_netlink_check_nb(); if (seqno != compat_seqno) goto repeat; } else { __sync_synchronize(); if (seqno != status->sequence) goto repeat; } } }