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