Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/sys/security/mac/mac_process.c
39530 views
1
/*-
2
* Copyright (c) 1999-2002, 2008-2009 Robert N. M. Watson
3
* Copyright (c) 2001 Ilmar S. Habibulin
4
* Copyright (c) 2001-2003 Networks Associates Technology, Inc.
5
* Copyright (c) 2006 SPARTA, Inc.
6
* Copyright (c) 2008 Apple Inc.
7
* All rights reserved.
8
*
9
* This software was developed by Robert Watson and Ilmar Habibulin for the
10
* TrustedBSD Project.
11
*
12
* This software was developed for the FreeBSD Project in part by Network
13
* Associates Laboratories, the Security Research Division of Network
14
* Associates, Inc. under DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"),
15
* as part of the DARPA CHATS research program.
16
*
17
* This software was enhanced by SPARTA ISSO under SPAWAR contract
18
* N66001-04-C-6019 ("SEFOS").
19
*
20
* This software was developed at the University of Cambridge Computer
21
* Laboratory with support from a grant from Google, Inc.
22
*
23
* Redistribution and use in source and binary forms, with or without
24
* modification, are permitted provided that the following conditions
25
* are met:
26
* 1. Redistributions of source code must retain the above copyright
27
* notice, this list of conditions and the following disclaimer.
28
* 2. Redistributions in binary form must reproduce the above copyright
29
* notice, this list of conditions and the following disclaimer in the
30
* documentation and/or other materials provided with the distribution.
31
*
32
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
33
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
34
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
35
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
36
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
37
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
38
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
39
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
40
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
41
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
42
* SUCH DAMAGE.
43
*/
44
45
#include <sys/cdefs.h>
46
#include "opt_mac.h"
47
48
#include <sys/param.h>
49
#include <sys/condvar.h>
50
#include <sys/imgact.h>
51
#include <sys/kernel.h>
52
#include <sys/lock.h>
53
#include <sys/malloc.h>
54
#include <sys/mac.h>
55
#include <sys/proc.h>
56
#include <sys/rwlock.h>
57
#include <sys/sbuf.h>
58
#include <sys/sdt.h>
59
#include <sys/systm.h>
60
#include <sys/vnode.h>
61
#include <sys/mount.h>
62
#include <sys/file.h>
63
#include <sys/namei.h>
64
#include <sys/sysctl.h>
65
66
#include <vm/vm.h>
67
#include <vm/pmap.h>
68
#include <vm/vm_map.h>
69
#include <vm/vm_object.h>
70
71
#include <security/mac/mac_framework.h>
72
#include <security/mac/mac_internal.h>
73
#include <security/mac/mac_policy.h>
74
75
static int mac_mmap_revocation = 1;
76
SYSCTL_INT(_security_mac, OID_AUTO, mmap_revocation, CTLFLAG_RW,
77
&mac_mmap_revocation, 0, "Revoke mmap access to files on subject "
78
"relabel");
79
80
static int mac_mmap_revocation_via_cow = 0;
81
SYSCTL_INT(_security_mac, OID_AUTO, mmap_revocation_via_cow, CTLFLAG_RW,
82
&mac_mmap_revocation_via_cow, 0, "Revoke mmap access to files via "
83
"copy-on-write semantics, or by removing all write access");
84
85
static void mac_proc_vm_revoke_recurse(struct thread *td,
86
struct ucred *cred, struct vm_map *map);
87
88
static struct label *
89
mac_proc_label_alloc(void)
90
{
91
struct label *label;
92
93
label = mac_labelzone_alloc(M_WAITOK);
94
MAC_POLICY_PERFORM(proc_init_label, label);
95
return (label);
96
}
97
98
void
99
mac_proc_init(struct proc *p)
100
{
101
102
if (mac_labeled & MPC_OBJECT_PROC)
103
p->p_label = mac_proc_label_alloc();
104
else
105
p->p_label = NULL;
106
}
107
108
static void
109
mac_proc_label_free(struct label *label)
110
{
111
112
MAC_POLICY_PERFORM_NOSLEEP(proc_destroy_label, label);
113
mac_labelzone_free(label);
114
}
115
116
void
117
mac_proc_destroy(struct proc *p)
118
{
119
120
if (p->p_label != NULL) {
121
mac_proc_label_free(p->p_label);
122
p->p_label = NULL;
123
}
124
}
125
126
void
127
mac_thread_userret(struct thread *td)
128
{
129
130
MAC_POLICY_PERFORM(thread_userret, td);
131
}
132
133
int
134
mac_execve_enter(struct image_params *imgp, struct mac *mac_p)
135
{
136
struct label *label;
137
struct mac mac;
138
char *buffer;
139
int error;
140
141
if (mac_p == NULL)
142
return (0);
143
144
if (!(mac_labeled & MPC_OBJECT_CRED))
145
return (EINVAL);
146
147
error = copyin(mac_p, &mac, sizeof(mac));
148
if (error)
149
return (error);
150
151
error = mac_check_structmac_consistent(&mac);
152
if (error)
153
return (error);
154
155
buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK);
156
error = copyinstr(mac.m_string, buffer, mac.m_buflen, NULL);
157
if (error) {
158
free(buffer, M_MACTEMP);
159
return (error);
160
}
161
162
label = mac_cred_label_alloc();
163
error = mac_cred_internalize_label(label, buffer);
164
free(buffer, M_MACTEMP);
165
if (error) {
166
mac_cred_label_free(label);
167
return (error);
168
}
169
imgp->execlabel = label;
170
return (0);
171
}
172
173
void
174
mac_execve_exit(struct image_params *imgp)
175
{
176
if (imgp->execlabel != NULL) {
177
mac_cred_label_free(imgp->execlabel);
178
imgp->execlabel = NULL;
179
}
180
}
181
182
void
183
mac_execve_interpreter_enter(struct vnode *interpvp,
184
struct label **interpvplabel)
185
{
186
187
if (mac_labeled & MPC_OBJECT_VNODE) {
188
*interpvplabel = mac_vnode_label_alloc();
189
mac_vnode_copy_label(interpvp->v_label, *interpvplabel);
190
} else
191
*interpvplabel = NULL;
192
}
193
194
void
195
mac_execve_interpreter_exit(struct label *interpvplabel)
196
{
197
198
if (interpvplabel != NULL)
199
mac_vnode_label_free(interpvplabel);
200
}
201
202
/*
203
* When relabeling a process, call out to the policies for the maximum
204
* permission allowed for each object type we know about in its memory space,
205
* and revoke access (in the least surprising ways we know) when necessary.
206
* The process lock is not held here.
207
*/
208
void
209
mac_proc_vm_revoke(struct thread *td)
210
{
211
struct ucred *cred;
212
213
PROC_LOCK(td->td_proc);
214
cred = crhold(td->td_proc->p_ucred);
215
PROC_UNLOCK(td->td_proc);
216
217
/* XXX freeze all other threads */
218
mac_proc_vm_revoke_recurse(td, cred,
219
&td->td_proc->p_vmspace->vm_map);
220
/* XXX allow other threads to continue */
221
222
crfree(cred);
223
}
224
225
static __inline const char *
226
prot2str(vm_prot_t prot)
227
{
228
229
switch (prot & VM_PROT_ALL) {
230
case VM_PROT_READ:
231
return ("r--");
232
case VM_PROT_READ | VM_PROT_WRITE:
233
return ("rw-");
234
case VM_PROT_READ | VM_PROT_EXECUTE:
235
return ("r-x");
236
case VM_PROT_READ | VM_PROT_WRITE | VM_PROT_EXECUTE:
237
return ("rwx");
238
case VM_PROT_WRITE:
239
return ("-w-");
240
case VM_PROT_EXECUTE:
241
return ("--x");
242
case VM_PROT_WRITE | VM_PROT_EXECUTE:
243
return ("-wx");
244
default:
245
return ("---");
246
}
247
}
248
249
static void
250
mac_proc_vm_revoke_recurse(struct thread *td, struct ucred *cred,
251
struct vm_map *map)
252
{
253
vm_map_entry_t prev, vme;
254
int result;
255
vm_prot_t revokeperms;
256
vm_object_t backing_object, object;
257
vm_ooffset_t offset;
258
struct vnode *vp;
259
struct mount *mp;
260
261
if (!mac_mmap_revocation)
262
return;
263
264
prev = &map->header;
265
vm_map_lock(map);
266
for (vme = vm_map_entry_first(map); vme != &map->header;
267
prev = vme, vme = vm_map_entry_succ(prev)) {
268
if (vme->eflags & MAP_ENTRY_IS_SUB_MAP) {
269
mac_proc_vm_revoke_recurse(td, cred,
270
vme->object.sub_map);
271
continue;
272
}
273
/*
274
* Skip over entries that obviously are not shared.
275
*/
276
if (vme->eflags & (MAP_ENTRY_COW | MAP_ENTRY_NOSYNC) ||
277
!vme->max_protection)
278
continue;
279
/*
280
* Drill down to the deepest backing object.
281
*/
282
offset = vme->offset;
283
object = vme->object.vm_object;
284
if (object == NULL)
285
continue;
286
VM_OBJECT_RLOCK(object);
287
while ((backing_object = object->backing_object) != NULL) {
288
VM_OBJECT_RLOCK(backing_object);
289
offset += object->backing_object_offset;
290
VM_OBJECT_RUNLOCK(object);
291
object = backing_object;
292
}
293
VM_OBJECT_RUNLOCK(object);
294
/*
295
* At the moment, vm_maps and objects aren't considered by
296
* the MAC system, so only things with backing by a normal
297
* object (read: vnodes) are checked.
298
*/
299
if (object->type != OBJT_VNODE)
300
continue;
301
vp = (struct vnode *)object->handle;
302
vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
303
result = vme->max_protection;
304
mac_vnode_check_mmap_downgrade(cred, vp, &result);
305
VOP_UNLOCK(vp);
306
/*
307
* Find out what maximum protection we may be allowing now
308
* but a policy needs to get removed.
309
*/
310
revokeperms = vme->max_protection & ~result;
311
if (!revokeperms)
312
continue;
313
printf("pid %ld: revoking %s perms from %#lx:%ld "
314
"(max %s/cur %s)\n", (long)td->td_proc->p_pid,
315
prot2str(revokeperms), (u_long)vme->start,
316
(long)(vme->end - vme->start),
317
prot2str(vme->max_protection), prot2str(vme->protection));
318
/*
319
* This is the really simple case: if a map has more
320
* max_protection than is allowed, but it's not being
321
* actually used (that is, the current protection is still
322
* allowed), we can just wipe it out and do nothing more.
323
*/
324
if ((vme->protection & revokeperms) == 0) {
325
vme->max_protection -= revokeperms;
326
} else {
327
if (revokeperms & VM_PROT_WRITE) {
328
/*
329
* In the more complicated case, flush out all
330
* pending changes to the object then turn it
331
* copy-on-write.
332
*/
333
vm_object_reference(object);
334
(void) vn_start_write(vp, &mp, V_WAIT);
335
vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
336
VM_OBJECT_WLOCK(object);
337
vm_object_page_clean(object, offset, offset +
338
vme->end - vme->start, OBJPC_SYNC);
339
VM_OBJECT_WUNLOCK(object);
340
VOP_UNLOCK(vp);
341
vn_finished_write(mp);
342
vm_object_deallocate(object);
343
/*
344
* Why bother if there's no read permissions
345
* anymore? For the rest, we need to leave
346
* the write permissions on for COW, or
347
* remove them entirely if configured to.
348
*/
349
if (!mac_mmap_revocation_via_cow) {
350
vme->max_protection &= ~VM_PROT_WRITE;
351
vme->protection &= ~VM_PROT_WRITE;
352
} if ((revokeperms & VM_PROT_READ) == 0)
353
vme->eflags |= MAP_ENTRY_COW |
354
MAP_ENTRY_NEEDS_COPY;
355
}
356
if (revokeperms & VM_PROT_EXECUTE) {
357
vme->max_protection &= ~VM_PROT_EXECUTE;
358
vme->protection &= ~VM_PROT_EXECUTE;
359
}
360
if (revokeperms & VM_PROT_READ) {
361
vme->max_protection = 0;
362
vme->protection = 0;
363
}
364
pmap_protect(map->pmap, vme->start, vme->end,
365
vme->protection & ~revokeperms);
366
vm_map_try_merge_entries(map, prev, vme);
367
}
368
}
369
vm_map_unlock(map);
370
}
371
372
MAC_CHECK_PROBE_DEFINE2(proc_check_debug, "struct ucred *", "struct proc *");
373
374
int
375
mac_proc_check_debug(struct ucred *cred, struct proc *p)
376
{
377
int error;
378
379
PROC_LOCK_ASSERT(p, MA_OWNED);
380
381
MAC_POLICY_CHECK_NOSLEEP(proc_check_debug, cred, p);
382
MAC_CHECK_PROBE2(proc_check_debug, error, cred, p);
383
384
return (error);
385
}
386
387
MAC_CHECK_PROBE_DEFINE2(proc_check_sched, "struct ucred *", "struct proc *");
388
389
int
390
mac_proc_check_sched(struct ucred *cred, struct proc *p)
391
{
392
int error;
393
394
PROC_LOCK_ASSERT(p, MA_OWNED);
395
396
MAC_POLICY_CHECK_NOSLEEP(proc_check_sched, cred, p);
397
MAC_CHECK_PROBE2(proc_check_sched, error, cred, p);
398
399
return (error);
400
}
401
402
MAC_CHECK_PROBE_DEFINE3(proc_check_signal, "struct ucred *", "struct proc *",
403
"int");
404
405
int
406
mac_proc_check_signal(struct ucred *cred, struct proc *p, int signum)
407
{
408
int error;
409
410
PROC_LOCK_ASSERT(p, MA_OWNED);
411
412
MAC_POLICY_CHECK_NOSLEEP(proc_check_signal, cred, p, signum);
413
MAC_CHECK_PROBE3(proc_check_signal, error, cred, p, signum);
414
415
return (error);
416
}
417
418
MAC_CHECK_PROBE_DEFINE2(proc_check_wait, "struct ucred *", "struct proc *");
419
420
int
421
mac_proc_check_wait(struct ucred *cred, struct proc *p)
422
{
423
int error;
424
425
PROC_LOCK_ASSERT(p, MA_OWNED);
426
427
MAC_POLICY_CHECK_NOSLEEP(proc_check_wait, cred, p);
428
MAC_CHECK_PROBE2(proc_check_wait, error, cred, p);
429
430
return (error);
431
}
432
433