#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <pthread.h>
#include <selinux/flask.h>
#include <selinux/selinux.h>
#include <selinux/avc.h>
#include <selinux/av_permissions.h>
/* ---------- auditing callbacks ---------- */
void audit_print(const char *fmt, ...)
{
/* we use stdout instead of the default stderr */
va_list ap;
va_start(ap, fmt);
vprintf(fmt, ap);
va_end(ap);
}
void audit_interp(void *data, security_class_t class,
char *buf, size_t buflen)
{
/* data is a filename */
snprintf(buf, buflen, (char*)data);
}
/* ---------- threading callbacks ---------- */
void* create_thread_helper(void *arg)
{
/* arg is the function we need to run */
void (*run)(void) = (void (*)(void))arg;
/* set ourself to immediate cancel mode */
pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
/* go do our work */
run();
/* should never get here */
return NULL;
}
void* create_thread(void (*run)(void))
{
int rc;
pthread_t *t = (pthread_t*)malloc(sizeof(pthread_t));
if (!t) {
puts("create_thread: out of memory");
exit(99);
}
/* have the new thread run the helper function above */
rc = pthread_create(t, NULL, create_thread_helper, (void*)run);
if (rc) {
puts("create_thread failed");
exit(2);
}
return t;
}
void stop_thread(void *thread)
{
int rc = pthread_cancel(*((pthread_t*)thread));
if (rc) {
puts("trouble stopping thread");
exit(2);
}
free(thread);
}
/* ---------- locking callbacks ---------- */
void* alloc_lock(void)
{
int rc;
pthread_mutexattr_t pma;
pthread_mutex_t *m = (pthread_mutex_t*)malloc(sizeof(pthread_mutex_t));
if (!m) {
puts("alloc_lock: out of memory");
exit(99);
}
/* set the lock to error checking mode for debugging purposes */
rc = pthread_mutexattr_init(&pma);
rc |= pthread_mutexattr_settype(&pma, PTHREAD_MUTEX_ERRORCHECK_NP);
rc |= pthread_mutex_init(m, &pma);
rc |= pthread_mutexattr_destroy(&pma);
if (rc) {
puts("trouble initializing lock");
exit(3);
}
return m;
}
void get_lock(void *lock)
{
int rc = pthread_mutex_lock((pthread_mutex_t*)lock);
if (rc) {
puts("trouble obtaining lock");
exit(3);
}
}
void release_lock(void *lock)
{
int rc = pthread_mutex_unlock((pthread_mutex_t*)lock);
if (rc) {
puts("trouble releasing lock");
exit(3);
}
}
void free_lock(void *lock)
{
int rc = pthread_mutex_destroy((pthread_mutex_t*)lock);
if (rc) {
puts("trouble destroying lock");
exit(3);
}
free(lock);
}
/* ---------- main routine ---------- */
int main (int argc, char **argv) {
security_context_t scon, fcon;
security_id_t ssid, fsid;
char buf[1024];
struct avc_entry_ref aeref;
struct avc_cache_stats acs;
int rc, short_of_memory = 0;
/* logging callbacks */
struct avc_log_callback alc = {
audit_print,
audit_interp
};
/* thread callbacks */
struct avc_thread_callback atc = {
create_thread,
stop_thread
};
/* locking callbacks */
struct avc_lock_callback akc = {
alloc_lock,
get_lock,
release_lock,
free_lock
};
avc_entry_ref_init(&aeref);
/* use standard malloc/free for the memory callbacks */
if (avc_init("myprog", NULL, &alc, &atc, &akc) < 0) {
puts("could not initialize avc");
exit(1);
}
/* get our process security context and a SID for it */
if (getcon(&scon) < 0) {
puts("could not get self context");
exit(5);
}
if (avc_context_to_sid(scon, &ssid) < 0) {
puts("could not get self sid");
exit(5);
}
/* read filenames from stdin */
while (scanf("%s", buf) != EOF)
{
/* force unused cache entries to be freed if necessary */
if (short_of_memory)
avc_cleanup();
/* get security context and SID for file */
if (getfilecon(buf, &fcon) < 0) {
printf("couldn't get file context for '%s'\n", buf);
continue;
}
if (avc_context_to_sid(fcon, &fsid) < 0) {
printf("could not get file sid for '%s'\n", buf);
exit(5);
}
/* see if we can do some things to file */
errno = 0;
rc = avc_has_perm(ssid, fsid, SECCLASS_FILE,
FILE__READ | FILE__WRITE | FILE__UNLINK,
&aeref, buf);
if (rc == 0)
printf("%s: granted\n", buf);
else if (errno == EACCES)
printf("%s: denied\n", buf);
else
printf("%s: unexpected error: %s\n", buf, strerror(errno));
}
/* print out statistics */
avc_av_stats();
avc_sid_stats();
avc_cache_stats(&acs);
printf("entry_lookups:\t%d\n", acs.entry_lookups);
printf("entry_hits:\t%d\n", acs.entry_hits);
printf("entry_misses:\t%d\n", acs.entry_misses);
printf("entry_discards:\t%d\n", acs.entry_discards);
printf("cav_lookups:\t%d\n", acs.cav_lookups);
printf("cav_hits:\t%d\n", acs.cav_hits);
printf("cav_probes:\t%d\n", acs.cav_probes);
printf("cav_misses:\t%d\n", acs.cav_misses);
/* free all AVC resources */
avc_destroy();
return 0;
} |