]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/kern/kern_priv.c
ping: fix data type of a variable for a packet sequence number
[FreeBSD/FreeBSD.git] / sys / kern / kern_priv.c
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3  *
4  * Copyright (c) 2006 nCircle Network Security, Inc.
5  * Copyright (c) 2009 Robert N. M. Watson
6  * All rights reserved.
7  *
8  * This software was developed by Robert N. M. Watson for the TrustedBSD
9  * Project under contract to nCircle Network Security, Inc.
10  *
11  * Redistribution and use in source and binary forms, with or without
12  * modification, are permitted provided that the following conditions
13  * are met:
14  * 1. Redistributions of source code must retain the above copyright
15  *    notice, this list of conditions and the following disclaimer.
16  * 2. Redistributions in binary form must reproduce the above copyright
17  *    notice, this list of conditions and the following disclaimer in the
18  *    documentation and/or other materials provided with the distribution.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
21  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR, NCIRCLE NETWORK SECURITY,
24  * INC., OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
26  * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
27  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
28  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
29  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
30  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31  */
32
33 #include <sys/cdefs.h>
34 __FBSDID("$FreeBSD$");
35
36 #include <sys/param.h>
37 #include <sys/jail.h>
38 #include <sys/kernel.h>
39 #include <sys/priv.h>
40 #include <sys/proc.h>
41 #include <sys/sdt.h>
42 #include <sys/sysctl.h>
43 #include <sys/systm.h>
44
45 #include <security/mac/mac_framework.h>
46
47 /*
48  * `suser_enabled' (which can be set by the security.bsd.suser_enabled
49  * sysctl) determines whether the system 'super-user' policy is in effect.  If
50  * it is nonzero, an effective uid of 0 connotes special privilege,
51  * overriding many mandatory and discretionary protections.  If it is zero,
52  * uid 0 is offered no special privilege in the kernel security policy.
53  * Setting it to zero may seriously impact the functionality of many existing
54  * userland programs, and should not be done without careful consideration of
55  * the consequences.
56  */
57 static int      suser_enabled = 1;
58 SYSCTL_INT(_security_bsd, OID_AUTO, suser_enabled, CTLFLAG_RWTUN,
59     &suser_enabled, 0, "processes with uid 0 have privilege");
60
61 static int      unprivileged_mlock = 1;
62 SYSCTL_INT(_security_bsd, OID_AUTO, unprivileged_mlock, CTLFLAG_RWTUN,
63     &unprivileged_mlock, 0, "Allow non-root users to call mlock(2)");
64
65 static int      unprivileged_read_msgbuf = 1;
66 SYSCTL_INT(_security_bsd, OID_AUTO, unprivileged_read_msgbuf,
67     CTLFLAG_RW, &unprivileged_read_msgbuf, 0,
68     "Unprivileged processes may read the kernel message buffer");
69
70 SDT_PROVIDER_DEFINE(priv);
71 SDT_PROBE_DEFINE1(priv, kernel, priv_check, priv__ok, "int");
72 SDT_PROBE_DEFINE1(priv, kernel, priv_check, priv__err, "int");
73
74 /*
75  * Check a credential for privilege.  Lots of good reasons to deny privilege;
76  * only a few to grant it.
77  */
78 int
79 priv_check_cred(struct ucred *cred, int priv)
80 {
81         int error;
82
83         KASSERT(PRIV_VALID(priv), ("priv_check_cred: invalid privilege %d",
84             priv));
85
86         /*
87          * We first evaluate policies that may deny the granting of
88          * privilege unilaterally.
89          */
90 #ifdef MAC
91         error = mac_priv_check(cred, priv);
92         if (error)
93                 goto out;
94 #endif
95
96         /*
97          * Jail policy will restrict certain privileges that may otherwise be
98          * be granted.
99          */
100         error = prison_priv_check(cred, priv);
101         if (error)
102                 goto out;
103
104         if (unprivileged_mlock) {
105                 /*
106                  * Allow unprivileged users to call mlock(2)/munlock(2) and
107                  * mlockall(2)/munlockall(2).
108                  */
109                 switch (priv) {
110                 case PRIV_VM_MLOCK:
111                 case PRIV_VM_MUNLOCK:
112                         error = 0;
113                         goto out;
114                 }
115         }
116
117         if (unprivileged_read_msgbuf) {
118                 /*
119                  * Allow an unprivileged user to read the kernel message
120                  * buffer.
121                  */
122                 if (priv == PRIV_MSGBUF) {
123                         error = 0;
124                         goto out;
125                 }
126         }
127
128         /*
129          * Having determined if privilege is restricted by various policies,
130          * now determine if privilege is granted.  At this point, any policy
131          * may grant privilege.  For now, we allow short-circuit boolean
132          * evaluation, so may not call all policies.  Perhaps we should.
133          *
134          * Superuser policy grants privilege based on the effective (or in
135          * the case of specific privileges, real) uid being 0.  We allow the
136          * superuser policy to be globally disabled, although this is
137          * currenty of limited utility.
138          */
139         if (suser_enabled) {
140                 switch (priv) {
141                 case PRIV_MAXFILES:
142                 case PRIV_MAXPROC:
143                 case PRIV_PROC_LIMIT:
144                         if (cred->cr_ruid == 0) {
145                                 error = 0;
146                                 goto out;
147                         }
148                         break;
149                 default:
150                         if (cred->cr_uid == 0) {
151                                 error = 0;
152                                 goto out;
153                         }
154                         break;
155                 }
156         }
157
158         /*
159          * Writes to kernel/physical memory are a typical root-only operation,
160          * but non-root users are expected to be able to read it (provided they
161          * have permission to access /dev/[k]mem).
162          */
163         if (priv == PRIV_KMEM_READ) {
164                 error = 0;
165                 goto out;
166         }
167
168         /*
169          * Allow unprivileged process debugging on a per-jail basis.
170          * Do this here instead of prison_priv_check(), so it can also
171          * apply to prison0.
172          */
173         if (priv == PRIV_DEBUG_UNPRIV) {
174                 if (prison_allow(cred, PR_ALLOW_UNPRIV_DEBUG)) {
175                         error = 0;
176                         goto out;
177                 }
178         }
179
180         /*
181          * Now check with MAC, if enabled, to see if a policy module grants
182          * privilege.
183          */
184 #ifdef MAC
185         if (mac_priv_grant(cred, priv) == 0) {
186                 error = 0;
187                 goto out;
188         }
189 #endif
190
191         /*
192          * The default is deny, so if no policies have granted it, reject
193          * with a privilege error here.
194          */
195         error = EPERM;
196 out:
197         if (SDT_PROBES_ENABLED()) {
198                 if (error)
199                         SDT_PROBE1(priv, kernel, priv_check, priv__err, priv);
200                 else
201                         SDT_PROBE1(priv, kernel, priv_check, priv__ok, priv);
202         }
203         return (error);
204 }
205
206 int
207 priv_check(struct thread *td, int priv)
208 {
209
210         KASSERT(td == curthread, ("priv_check: td != curthread"));
211
212         return (priv_check_cred(td->td_ucred, priv));
213 }