Branch data Line data Source code
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 "services.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 : : */ 42 : 0 : struct page *selinux_kernel_status_page(struct selinux_state *state) 43 : : { 44 : 0 : struct selinux_kernel_status *status; 45 : 0 : struct page *result = NULL; 46 : : 47 : 0 : mutex_lock(&state->ss->status_lock); 48 [ # # ]: 0 : if (!state->ss->status_page) { 49 : 0 : state->ss->status_page = alloc_page(GFP_KERNEL|__GFP_ZERO); 50 : : 51 [ # # ]: 0 : if (state->ss->status_page) { 52 : 0 : status = page_address(state->ss->status_page); 53 : : 54 : 0 : status->version = SELINUX_KERNEL_STATUS_VERSION; 55 : 0 : status->sequence = 0; 56 : 0 : 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 : 0 : status->policyload = 0; 64 : 0 : status->deny_unknown = 65 : 0 : !security_get_allow_unknown(state); 66 : : } 67 : : } 68 : 0 : result = state->ss->status_page; 69 : 0 : mutex_unlock(&state->ss->status_lock); 70 : : 71 : 0 : return result; 72 : : } 73 : : 74 : : /* 75 : : * selinux_status_update_setenforce 76 : : * 77 : : * It updates status of the current enforcing/permissive mode. 78 : : */ 79 : 0 : void selinux_status_update_setenforce(struct selinux_state *state, 80 : : int enforcing) 81 : : { 82 : 0 : struct selinux_kernel_status *status; 83 : : 84 : 0 : mutex_lock(&state->ss->status_lock); 85 [ # # ]: 0 : if (state->ss->status_page) { 86 : 0 : status = page_address(state->ss->status_page); 87 : : 88 : 0 : status->sequence++; 89 : 0 : smp_wmb(); 90 : : 91 : 0 : status->enforcing = enforcing; 92 : : 93 : 0 : smp_wmb(); 94 : 0 : status->sequence++; 95 : : } 96 : 0 : mutex_unlock(&state->ss->status_lock); 97 : 0 : } 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 : : */ 105 : 0 : void selinux_status_update_policyload(struct selinux_state *state, 106 : : int seqno) 107 : : { 108 : 0 : struct selinux_kernel_status *status; 109 : : 110 : 0 : mutex_lock(&state->ss->status_lock); 111 [ # # ]: 0 : if (state->ss->status_page) { 112 : 0 : status = page_address(state->ss->status_page); 113 : : 114 : 0 : status->sequence++; 115 : 0 : smp_wmb(); 116 : : 117 : 0 : status->policyload = seqno; 118 : 0 : status->deny_unknown = !security_get_allow_unknown(state); 119 : : 120 : 0 : smp_wmb(); 121 : 0 : status->sequence++; 122 : : } 123 : 0 : mutex_unlock(&state->ss->status_lock); 124 : 0 : }