Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * mmap based event notifications for SELinux
0004  *
0005  * Author: KaiGai Kohei <kaigai@ak.jp.nec.com>
0006  *
0007  * Copyright (C) 2010 NEC corporation
0008  */
0009 #include <linux/kernel.h>
0010 #include <linux/gfp.h>
0011 #include <linux/mm.h>
0012 #include <linux/mutex.h>
0013 #include "avc.h"
0014 #include "security.h"
0015 
0016 /*
0017  * The selinux_status_page shall be exposed to userspace applications
0018  * using mmap interface on /selinux/status.
0019  * It enables to notify applications a few events that will cause reset
0020  * of userspace access vector without context switching.
0021  *
0022  * The selinux_kernel_status structure on the head of status page is
0023  * protected from concurrent accesses using seqlock logic, so userspace
0024  * application should reference the status page according to the seqlock
0025  * logic.
0026  *
0027  * Typically, application checks status->sequence at the head of access
0028  * control routine. If it is odd-number, kernel is updating the status,
0029  * so please wait for a moment. If it is changed from the last sequence
0030  * number, it means something happen, so application will reset userspace
0031  * avc, if needed.
0032  * In most cases, application shall confirm the kernel status is not
0033  * changed without any system call invocations.
0034  */
0035 
0036 /*
0037  * selinux_kernel_status_page
0038  *
0039  * It returns a reference to selinux_status_page. If the status page is
0040  * not allocated yet, it also tries to allocate it at the first time.
0041  */
0042 struct page *selinux_kernel_status_page(struct selinux_state *state)
0043 {
0044     struct selinux_kernel_status   *status;
0045     struct page            *result = NULL;
0046 
0047     mutex_lock(&state->status_lock);
0048     if (!state->status_page) {
0049         state->status_page = alloc_page(GFP_KERNEL|__GFP_ZERO);
0050 
0051         if (state->status_page) {
0052             status = page_address(state->status_page);
0053 
0054             status->version = SELINUX_KERNEL_STATUS_VERSION;
0055             status->sequence = 0;
0056             status->enforcing = enforcing_enabled(state);
0057             /*
0058              * NOTE: the next policyload event shall set
0059              * a positive value on the status->policyload,
0060              * although it may not be 1, but never zero.
0061              * So, application can know it was updated.
0062              */
0063             status->policyload = 0;
0064             status->deny_unknown =
0065                 !security_get_allow_unknown(state);
0066         }
0067     }
0068     result = state->status_page;
0069     mutex_unlock(&state->status_lock);
0070 
0071     return result;
0072 }
0073 
0074 /*
0075  * selinux_status_update_setenforce
0076  *
0077  * It updates status of the current enforcing/permissive mode.
0078  */
0079 void selinux_status_update_setenforce(struct selinux_state *state,
0080                       int enforcing)
0081 {
0082     struct selinux_kernel_status   *status;
0083 
0084     mutex_lock(&state->status_lock);
0085     if (state->status_page) {
0086         status = page_address(state->status_page);
0087 
0088         status->sequence++;
0089         smp_wmb();
0090 
0091         status->enforcing = enforcing;
0092 
0093         smp_wmb();
0094         status->sequence++;
0095     }
0096     mutex_unlock(&state->status_lock);
0097 }
0098 
0099 /*
0100  * selinux_status_update_policyload
0101  *
0102  * It updates status of the times of policy reloaded, and current
0103  * setting of deny_unknown.
0104  */
0105 void selinux_status_update_policyload(struct selinux_state *state,
0106                       int seqno)
0107 {
0108     struct selinux_kernel_status   *status;
0109 
0110     mutex_lock(&state->status_lock);
0111     if (state->status_page) {
0112         status = page_address(state->status_page);
0113 
0114         status->sequence++;
0115         smp_wmb();
0116 
0117         status->policyload = seqno;
0118         status->deny_unknown = !security_get_allow_unknown(state);
0119 
0120         smp_wmb();
0121         status->sequence++;
0122     }
0123     mutex_unlock(&state->status_lock);
0124 }