hbsd_pax_hardening.c 8.12 KB
Newer Older
1
/*-
Shawn Webb's avatar
Shawn Webb committed
2
 * Copyright (c) 2014, by Shawn Webb <shawn.webb at hardenedbsd.org>
3
 * Copyright (c) 2014, by Oliver Pinter <oliver.pinter@hardenedbsd.org>
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * $FreeBSD$
 */

#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");

#include "opt_compat.h"
#include "opt_pax.h"

#include <sys/param.h>
#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/imgact.h>
#include <sys/imgact_elf.h>
#include <sys/lock.h>
#include <sys/mutex.h>
#include <sys/sysent.h>
45
#include <sys/syslimits.h>
46
#include <sys/stat.h>
47
#include <sys/pax.h>
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
#include <sys/proc.h>
#include <sys/elf_common.h>
#include <sys/mount.h>
#include <sys/sysctl.h>
#include <sys/vnode.h>
#include <sys/queue.h>
#include <sys/libkern.h>
#include <sys/jail.h>
#include <sys/mman.h>
#include <sys/libkern.h>
#include <sys/exec.h>
#include <sys/kthread.h>

#include <vm/pmap.h>
#include <vm/vm_map.h>
#include <vm/vm_extern.h>

#include <machine/elf.h>

67
68
69
70
#if __FreeBSD_version < 1100000
#define	kern_unsetenv	unsetenv
#endif

Oliver Pinter's avatar
Oliver Pinter committed
71
#ifdef PAX_HARDENING
72
73
static int pax_map32_enabled_global = PAX_FEATURE_SIMPLE_DISABLED;
static int pax_procfs_harden_global = PAX_FEATURE_SIMPLE_ENABLED;
74
static int pax_randomize_pids_global = PAX_FEATURE_SIMPLE_ENABLED;
75
static int pax_init_hardening_global = PAX_FEATURE_SIMPLE_ENABLED;
Oliver Pinter's avatar
Oliver Pinter committed
76
#else
77
78
static int pax_map32_enabled_global = PAX_FEATURE_SIMPLE_ENABLED;
static int pax_procfs_harden_global = PAX_FEATURE_SIMPLE_DISABLED;
79
static int pax_randomize_pids_global = PAX_FEATURE_SIMPLE_DISABLED;
80
static int pax_init_hardening_global = PAX_FEATURE_SIMPLE_DISABLED;
Oliver Pinter's avatar
Oliver Pinter committed
81
#endif
82

Oliver Pinter's avatar
Oliver Pinter committed
83
static int sysctl_pax_allow_map32(SYSCTL_HANDLER_ARGS);
84
static int sysctl_pax_procfs(SYSCTL_HANDLER_ARGS);
85

Oliver Pinter's avatar
Oliver Pinter committed
86
#ifdef PAX_SYSCTLS
87
SYSCTL_PROC(_hardening, OID_AUTO, allow_map32bit,
88
    CTLTYPE_INT|CTLFLAG_RWTUN|CTLFLAG_PRISON|CTLFLAG_SECURE,
89
    NULL, 0, sysctl_pax_allow_map32, "I",
90
    "mmap MAP_32BIT support. "
91
92
    "0 - disabled, "
    "1 - enabled.");
Shawn Webb's avatar
Shawn Webb committed
93
94
SYSCTL_PROC(_hardening, OID_AUTO, procfs_harden,
    CTLTYPE_INT|CTLFLAG_RWTUN|CTLFLAG_SECURE,
95
    NULL, 0, sysctl_pax_procfs, "I",
Shawn Webb's avatar
Shawn Webb committed
96
97
98
    "Harden procfs, disabling write of /proc/pid/mem. "
    "0 - disabled, "
    "1 - enabled.");
Oliver Pinter's avatar
Oliver Pinter committed
99
100
101
#endif

TUNABLE_INT("hardening.allow_map32bit", &pax_map32_enabled_global);
102
TUNABLE_INT("hardening.procfs_harden", &pax_procfs_harden_global);
103
TUNABLE_INT("hardening.randomize_pids", &pax_randomize_pids_global);
104

105
106
107
static void
pax_hardening_sysinit(void)
{
108
109
110
111
112
113
	switch (pax_map32_enabled_global) {
	case PAX_FEATURE_SIMPLE_DISABLED:
	case PAX_FEATURE_SIMPLE_ENABLED:
		break;
	default:
		printf("[PAX HARDENING] WARNING, invalid settings in loader.conf!"
114
115
		    " (hardening.allow_map32bit = %d)\n",
		    pax_map32_enabled_global);
116
		pax_map32_enabled_global = PAX_FEATURE_SIMPLE_DISABLED;
117
	}
118
119
	printf("[PAX HARDENING] mmap MAP32_bit support: %s\n",
	    pax_status_simple_str[pax_map32_enabled_global]);
120

121
	switch (pax_procfs_harden_global) {
Shawn Webb's avatar
Shawn Webb committed
122
123
124
125
126
	case PAX_FEATURE_SIMPLE_DISABLED:
	case PAX_FEATURE_SIMPLE_ENABLED:
		break;
	default:
		printf("[PAX HARDENING] WARNING, invalid settings in loader.conf!"
127
		    " (hardening.procfs_harden = %d)\n", pax_procfs_harden_global);
128
		pax_procfs_harden_global = PAX_FEATURE_SIMPLE_ENABLED;
Shawn Webb's avatar
Shawn Webb committed
129
130
	}
	printf("[PAX HARDENING] procfs hardening: %s\n",
131
	    pax_status_simple_str[pax_procfs_harden_global]);
132
133
134
135
136
137
138
139
140
141
142
143

	switch (pax_randomize_pids_global) {
	case PAX_FEATURE_SIMPLE_DISABLED:
	case PAX_FEATURE_SIMPLE_ENABLED:
		break;
	default:
		printf("[PAX HARDENING] WARNING, invalid settings in loader.conf!"
		    " (hardening.randomize_pids = %d)\n", pax_randomize_pids_global);
		pax_randomize_pids_global = PAX_FEATURE_SIMPLE_ENABLED;
	}
	printf("[PAX HARDENING] randomize pids: %s\n",
	    pax_status_simple_str[pax_randomize_pids_global]);
144
145
146
147
148
149
150
151
152
153

	switch (pax_init_hardening_global) {
	case PAX_FEATURE_SIMPLE_DISABLED:
	case PAX_FEATURE_SIMPLE_ENABLED:
		break;
	default:
		pax_init_hardening_global = PAX_FEATURE_SIMPLE_ENABLED;
	}
	printf("[PAX HARDENING] unset unsecure init variables: %s\n",
	    pax_status_simple_str[pax_init_hardening_global]);
154
}
155
SYSINIT(pax_hardening, SI_SUB_PAX, SI_ORDER_SECOND, pax_hardening_sysinit, NULL);
156

Oliver Pinter's avatar
Oliver Pinter committed
157
#ifdef PAX_SYSCTLS
158
static int
Oliver Pinter's avatar
Oliver Pinter committed
159
sysctl_pax_allow_map32(SYSCTL_HANDLER_ARGS)
160
161
162
163
{
	struct prison *pr;
	int err, val;

164
	pr = pax_get_prison_td(req->td);
165

166
	val = pr->pr_hardening.hr_pax_map32_enabled;
167
168
169
170
171
172
173
174
175
176
	err = sysctl_handle_int(oidp, &val, sizeof(int), req);
	if (err || (req->newptr == NULL))
		return (err);

	if (val > 1 || val < -1)
		return (EINVAL);

	if ((pr == NULL) || (pr == &prison0))
		pax_map32_enabled_global = val;

177
	pr->pr_hardening.hr_pax_map32_enabled = val;
178
179
180

	return (0);
}
181

Shawn Webb's avatar
Shawn Webb committed
182
static int
183
sysctl_pax_procfs(SYSCTL_HANDLER_ARGS)
Shawn Webb's avatar
Shawn Webb committed
184
185
186
187
{
	struct prison *pr;
	int err, val;

188
	pr = pax_get_prison_td(req->td);
Shawn Webb's avatar
Shawn Webb committed
189

190
	val = pr->pr_hardening.hr_pax_procfs_harden;
Shawn Webb's avatar
Shawn Webb committed
191
192
193
194
195
196
197
	err = sysctl_handle_int(oidp, &val, sizeof(int), req);
	if (err || (req->newptr == NULL))
		return (err);

	if (val > 1 || val < -1)
		return (EINVAL);

198
	if (pr == &prison0)
199
		pax_procfs_harden_global = val;
Shawn Webb's avatar
Shawn Webb committed
200

201
	pr->pr_hardening.hr_pax_procfs_harden = val;
Shawn Webb's avatar
Shawn Webb committed
202
203
204

	return (0);
}
Oliver Pinter's avatar
Oliver Pinter committed
205
#endif
206

207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
void
pax_hardening_init_prison(struct prison *pr)
{
	struct prison *pr_p;

	CTR2(KTR_PAX, "%s: Setting prison %s PaX variables\n",
	    __func__, pr->pr_name);

	if (pr == &prison0) {
		/* prison0 has no parent, use globals */
#ifdef MAP_32BIT
		pr->pr_hardening.hr_pax_map32_enabled =
		    pax_map32_enabled_global;
#endif
		pr->pr_hardening.hr_pax_procfs_harden =
		    pax_procfs_harden_global;
	} else {
		KASSERT(pr->pr_parent != NULL,
		   ("%s: pr->pr_parent == NULL", __func__));
		pr_p = pr->pr_parent;

#ifdef MAP_32BIT
		pr->pr_hardening.hr_pax_map32_enabled =
		    pr_p->pr_hardening.hr_pax_map32_enabled;
#endif
		pr->pr_hardening.hr_pax_procfs_harden =
		    pr_p->pr_hardening.hr_pax_procfs_harden;
	}
}

237
238
239
240
241
int
pax_map32_enabled(struct thread *td)
{
	struct prison *pr;

242
	pr = pax_get_prison_td(td);
243

244
	return (pr->pr_hardening.hr_pax_map32_enabled);
245
}
246

Shawn Webb's avatar
Shawn Webb committed
247
248
249
250
251
int
pax_procfs_harden(struct thread *td)
{
	struct prison *pr;

252
	pr = pax_get_prison_td(td);
Shawn Webb's avatar
Shawn Webb committed
253

254
	return (pr->pr_hardening.hr_pax_procfs_harden ? EPERM : 0);
Shawn Webb's avatar
Shawn Webb committed
255
}
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274

extern int randompid;

static void
pax_randomize_pids(void *dummy __unused)
{
	int modulus;

	if (pax_randomize_pids_global == PAX_FEATURE_SIMPLE_DISABLED)
		return;

	modulus = pid_max - 200;

	sx_xlock(&allproc_lock);
	randompid = arc4random() % modulus + 100;
	sx_xunlock(&allproc_lock);
}
SYSINIT(pax_randomize_pids, SI_SUB_KTHREAD_INIT, SI_ORDER_MIDDLE+1,
    pax_randomize_pids, NULL);
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292

static void
pax_init_hardening(void *dummy __unused)
{
	/*
	 * Never should be made available from the loader / outside
	 * the pax_init_hardening_global variable.
	 */
	if (pax_init_hardening_global == PAX_FEATURE_SIMPLE_DISABLED)
		return;

	kern_unsetenv("init_chroot");
	kern_unsetenv("init_path");
	kern_unsetenv("init_script");
	kern_unsetenv("init_shell");
}
SYSINIT(pax_init_hardening, SI_SUB_PAX, SI_ORDER_ANY,
    pax_init_hardening, NULL);
293