linux/security/selinux/ss/status.c
<<
>>
Prefs
   1/*
   2 * mmap based event notifications for SELinux
   3 *
   4 * Author: KaiGai Kohei <kaigai@ak.jp.nec.com>
   5 *
   6 * Copyright (C) 2010 NEC corporation
   7 *
   8 * This program is free software; you can redistribute it and/or modify
   9 * it under the terms of the GNU General Public License version 2,
  10 * as published by the Free Software Foundation.
  11 */
  12#include <linux/kernel.h>
  13#include <linux/gfp.h>
  14#include <linux/mm.h>
  15#include <linux/mutex.h>
  16#include "avc.h"
  17#include "services.h"
  18
  19/*
  20 * The selinux_status_page shall be exposed to userspace applications
  21 * using mmap interface on /selinux/status.
  22 * It enables to notify applications a few events that will cause reset
  23 * of userspace access vector without context switching.
  24 *
  25 * The selinux_kernel_status structure on the head of status page is
  26 * protected from concurrent accesses using seqlock logic, so userspace
  27 * application should reference the status page according to the seqlock
  28 * logic.
  29 *
  30 * Typically, application checks status->sequence at the head of access
  31 * control routine. If it is odd-number, kernel is updating the status,
  32 * so please wait for a moment. If it is changed from the last sequence
  33 * number, it means something happen, so application will reset userspace
  34 * avc, if needed.
  35 * In most cases, application shall confirm the kernel status is not
  36 * changed without any system call invocations.
  37 */
  38static struct page *selinux_status_page;
  39static DEFINE_MUTEX(selinux_status_lock);
  40
  41/*
  42 * selinux_kernel_status_page
  43 *
  44 * It returns a reference to selinux_status_page. If the status page is
  45 * not allocated yet, it also tries to allocate it at the first time.
  46 */
  47struct page *selinux_kernel_status_page(void)
  48{
  49        struct selinux_kernel_status   *status;
  50        struct page                    *result = NULL;
  51
  52        mutex_lock(&selinux_status_lock);
  53        if (!selinux_status_page) {
  54                selinux_status_page = alloc_page(GFP_KERNEL|__GFP_ZERO);
  55
  56                if (selinux_status_page) {
  57                        status = page_address(selinux_status_page);
  58
  59                        status->version = SELINUX_KERNEL_STATUS_VERSION;
  60                        status->sequence = 0;
  61                        status->enforcing = selinux_enforcing;
  62                        /*
  63                         * NOTE: the next policyload event shall set
  64                         * a positive value on the status->policyload,
  65                         * although it may not be 1, but never zero.
  66                         * So, application can know it was updated.
  67                         */
  68                        status->policyload = 0;
  69                        status->deny_unknown = !security_get_allow_unknown();
  70                }
  71        }
  72        result = selinux_status_page;
  73        mutex_unlock(&selinux_status_lock);
  74
  75        return result;
  76}
  77
  78/*
  79 * selinux_status_update_setenforce
  80 *
  81 * It updates status of the current enforcing/permissive mode.
  82 */
  83void selinux_status_update_setenforce(int enforcing)
  84{
  85        struct selinux_kernel_status   *status;
  86
  87        mutex_lock(&selinux_status_lock);
  88        if (selinux_status_page) {
  89                status = page_address(selinux_status_page);
  90
  91                status->sequence++;
  92                smp_wmb();
  93
  94                status->enforcing = enforcing;
  95
  96                smp_wmb();
  97                status->sequence++;
  98        }
  99        mutex_unlock(&selinux_status_lock);
 100}
 101
 102/*
 103 * selinux_status_update_policyload
 104 *
 105 * It updates status of the times of policy reloaded, and current
 106 * setting of deny_unknown.
 107 */
 108void selinux_status_update_policyload(int seqno)
 109{
 110        struct selinux_kernel_status   *status;
 111
 112        mutex_lock(&selinux_status_lock);
 113        if (selinux_status_page) {
 114                status = page_address(selinux_status_page);
 115
 116                status->sequence++;
 117                smp_wmb();
 118
 119                status->policyload = seqno;
 120                status->deny_unknown = !security_get_allow_unknown();
 121
 122                smp_wmb();
 123                status->sequence++;
 124        }
 125        mutex_unlock(&selinux_status_lock);
 126}
 127