kern_environment.c revision 221597
1229997Sken/*-
2229997Sken * Copyright (c) 1998 Michael Smith
3229997Sken * All rights reserved.
4229997Sken *
5229997Sken * Redistribution and use in source and binary forms, with or without
6229997Sken * modification, are permitted provided that the following conditions
7229997Sken * are met:
8229997Sken * 1. Redistributions of source code must retain the above copyright
9229997Sken *    notice, this list of conditions and the following disclaimer.
10229997Sken * 2. Redistributions in binary form must reproduce the above copyright
11229997Sken *    notice, this list of conditions and the following disclaimer in the
12229997Sken *    documentation and/or other materials provided with the distribution.
13229997Sken *
14229997Sken * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15229997Sken * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16229997Sken * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17229997Sken * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18229997Sken * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19229997Sken * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20229997Sken * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21229997Sken * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22229997Sken * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23229997Sken * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24229997Sken * SUCH DAMAGE.
25229997Sken */
26229997Sken
27229997Sken/*
28229997Sken * The unified bootloader passes us a pointer to a preserved copy of
29229997Sken * bootstrap/kernel environment variables.  We convert them to a
30229997Sken * dynamic array of strings later when the VM subsystem is up.
31229997Sken *
32229997Sken * We make these available through the kenv(2) syscall for userland
33229997Sken * and through getenv()/freeenv() setenv() unsetenv() testenv() for
34229997Sken * the kernel.
35229997Sken */
36229997Sken
37229997Sken#include <sys/cdefs.h>
38229997Sken__FBSDID("$FreeBSD: head/sys/kern/kern_environment.c 221597 2011-05-07 11:10:58Z jh $");
39229997Sken
40229997Sken#include <sys/types.h>
41229997Sken#include <sys/param.h>
42229997Sken#include <sys/proc.h>
43229997Sken#include <sys/queue.h>
44229997Sken#include <sys/lock.h>
45229997Sken#include <sys/malloc.h>
46229997Sken#include <sys/mutex.h>
47229997Sken#include <sys/priv.h>
48229997Sken#include <sys/kernel.h>
49229997Sken#include <sys/systm.h>
50229997Sken#include <sys/sysent.h>
51229997Sken#include <sys/sysproto.h>
52229997Sken#include <sys/libkern.h>
53229997Sken#include <sys/kenv.h>
54229997Sken
55229997Sken#include <security/mac/mac_framework.h>
56229997Sken
57229997Skenstatic MALLOC_DEFINE(M_KENV, "kenv", "kernel environment");
58229997Sken
59229997Sken#define KENV_SIZE	512	/* Maximum number of environment strings */
60229997Sken
61229997Sken/* pointer to the static environment */
62229997Skenchar		*kern_envp;
63229997Skenstatic int	env_len;
64229997Skenstatic int	env_pos;
65229997Skenstatic char	*kernenv_next(char *);
66229997Sken
67229997Sken/* dynamic environment variables */
68229997Skenchar		**kenvp;
69229997Skenstruct mtx	kenv_lock;
70229997Sken
71229997Sken/*
72229997Sken * No need to protect this with a mutex since SYSINITS are single threaded.
73229997Sken */
74229997Skenint	dynamic_kenv = 0;
75229997Sken
76229997Sken#define KENV_CHECK	if (!dynamic_kenv) \
77229997Sken			    panic("%s: called before SI_SUB_KMEM", __func__)
78229997Sken
79229997Skenint
80229997Skenkenv(td, uap)
81229997Sken	struct thread *td;
82229997Sken	struct kenv_args /* {
83229997Sken		int what;
84229997Sken		const char *name;
85229997Sken		char *value;
86229997Sken		int len;
87229997Sken	} */ *uap;
88229997Sken{
89229997Sken	char *name, *value, *buffer = NULL;
90229997Sken	size_t len, done, needed, buflen;
91229997Sken	int error, i;
92229997Sken
93229997Sken	KASSERT(dynamic_kenv, ("kenv: dynamic_kenv = 0"));
94229997Sken
95229997Sken	error = 0;
96229997Sken	if (uap->what == KENV_DUMP) {
97229997Sken#ifdef MAC
98229997Sken		error = mac_kenv_check_dump(td->td_ucred);
99229997Sken		if (error)
100229997Sken			return (error);
101229997Sken#endif
102229997Sken		done = needed = 0;
103229997Sken		buflen = uap->len;
104229997Sken		if (buflen > KENV_SIZE * (KENV_MNAMELEN + KENV_MVALLEN + 2))
105229997Sken			buflen = KENV_SIZE * (KENV_MNAMELEN +
106229997Sken			    KENV_MVALLEN + 2);
107229997Sken		if (uap->len > 0 && uap->value != NULL)
108229997Sken			buffer = malloc(buflen, M_TEMP, M_WAITOK|M_ZERO);
109229997Sken		mtx_lock(&kenv_lock);
110229997Sken		for (i = 0; kenvp[i] != NULL; i++) {
111229997Sken			len = strlen(kenvp[i]) + 1;
112229997Sken			needed += len;
113229997Sken			len = min(len, buflen - done);
114229997Sken			/*
115229997Sken			 * If called with a NULL or insufficiently large
116229997Sken			 * buffer, just keep computing the required size.
117229997Sken			 */
118229997Sken			if (uap->value != NULL && buffer != NULL && len > 0) {
119229997Sken				bcopy(kenvp[i], buffer + done, len);
120229997Sken				done += len;
121229997Sken			}
122229997Sken		}
123229997Sken		mtx_unlock(&kenv_lock);
124229997Sken		if (buffer != NULL) {
125229997Sken			error = copyout(buffer, uap->value, done);
126229997Sken			free(buffer, M_TEMP);
127229997Sken		}
128229997Sken		td->td_retval[0] = ((done == needed) ? 0 : needed);
129229997Sken		return (error);
130229997Sken	}
131229997Sken
132229997Sken	switch (uap->what) {
133229997Sken	case KENV_SET:
134229997Sken		error = priv_check(td, PRIV_KENV_SET);
135229997Sken		if (error)
136229997Sken			return (error);
137229997Sken		break;
138229997Sken
139229997Sken	case KENV_UNSET:
140229997Sken		error = priv_check(td, PRIV_KENV_UNSET);
141229997Sken		if (error)
142229997Sken			return (error);
143229997Sken		break;
144229997Sken	}
145229997Sken
146229997Sken	name = malloc(KENV_MNAMELEN, M_TEMP, M_WAITOK);
147229997Sken
148229997Sken	error = copyinstr(uap->name, name, KENV_MNAMELEN, NULL);
149229997Sken	if (error)
150229997Sken		goto done;
151229997Sken
152229997Sken	switch (uap->what) {
153229997Sken	case KENV_GET:
154229997Sken#ifdef MAC
155229997Sken		error = mac_kenv_check_get(td->td_ucred, name);
156229997Sken		if (error)
157229997Sken			goto done;
158229997Sken#endif
159229997Sken		value = getenv(name);
160229997Sken		if (value == NULL) {
161229997Sken			error = ENOENT;
162229997Sken			goto done;
163229997Sken		}
164229997Sken		len = strlen(value) + 1;
165229997Sken		if (len > uap->len)
166229997Sken			len = uap->len;
167229997Sken		error = copyout(value, uap->value, len);
168229997Sken		freeenv(value);
169229997Sken		if (error)
170229997Sken			goto done;
171229997Sken		td->td_retval[0] = len;
172229997Sken		break;
173229997Sken	case KENV_SET:
174229997Sken		len = uap->len;
175229997Sken		if (len < 1) {
176254759Strasz			error = EINVAL;
177254759Strasz			goto done;
178254759Strasz		}
179254759Strasz		if (len > KENV_MVALLEN)
180254759Strasz			len = KENV_MVALLEN;
181254759Strasz		value = malloc(len, M_TEMP, M_WAITOK);
182229997Sken		error = copyinstr(uap->value, value, len, NULL);
183229997Sken		if (error) {
184229997Sken			free(value, M_TEMP);
185229997Sken			goto done;
186229997Sken		}
187229997Sken#ifdef MAC
188229997Sken		error = mac_kenv_check_set(td->td_ucred, name, value);
189229997Sken		if (error == 0)
190229997Sken#endif
191229997Sken			setenv(name, value);
192229997Sken		free(value, M_TEMP);
193229997Sken		break;
194229997Sken	case KENV_UNSET:
195229997Sken#ifdef MAC
196254759Strasz		error = mac_kenv_check_unset(td->td_ucred, name);
197229997Sken		if (error)
198229997Sken			goto done;
199229997Sken#endif
200229997Sken		error = unsetenv(name);
201229997Sken		if (error)
202229997Sken			error = ENOENT;
203229997Sken		break;
204229997Sken	default:
205229997Sken		error = EINVAL;
206229997Sken		break;
207229997Sken	}
208229997Skendone:
209229997Sken	free(name, M_TEMP);
210229997Sken	return (error);
211229997Sken}
212229997Sken
213229997Skenvoid
214229997Skeninit_static_kenv(char *buf, size_t len)
215229997Sken{
216229997Sken	kern_envp = buf;
217229997Sken	env_len = len;
218229997Sken	env_pos = 0;
219229997Sken}
220229997Sken
221229997Sken/*
222229997Sken * Setup the dynamic kernel environment.
223229997Sken */
224229997Skenstatic void
225229997Skeninit_dynamic_kenv(void *data __unused)
226229997Sken{
227229997Sken	char *cp;
228229997Sken	int len, i;
229229997Sken
230229997Sken	kenvp = malloc((KENV_SIZE + 1) * sizeof(char *), M_KENV,
231229997Sken		M_WAITOK | M_ZERO);
232229997Sken	i = 0;
233229997Sken	for (cp = kern_envp; cp != NULL; cp = kernenv_next(cp)) {
234229997Sken		len = strlen(cp) + 1;
235229997Sken		if (i < KENV_SIZE) {
236229997Sken			kenvp[i] = malloc(len, M_KENV, M_WAITOK);
237229997Sken			strcpy(kenvp[i++], cp);
238229997Sken		} else
239229997Sken			printf(
240229997Sken			    "WARNING: too many kenv strings, ignoring %s\n",
241229997Sken			    cp);
242229997Sken	}
243229997Sken	kenvp[i] = NULL;
244229997Sken
245229997Sken	mtx_init(&kenv_lock, "kernel environment", NULL, MTX_DEF);
246229997Sken	dynamic_kenv = 1;
247229997Sken}
248229997SkenSYSINIT(kenv, SI_SUB_KMEM, SI_ORDER_ANY, init_dynamic_kenv, NULL);
249229997Sken
250229997Skenvoid
251229997Skenfreeenv(char *env)
252229997Sken{
253229997Sken
254229997Sken	if (dynamic_kenv)
255229997Sken		free(env, M_KENV);
256229997Sken}
257229997Sken
258229997Sken/*
259229997Sken * Internal functions for string lookup.
260229997Sken */
261229997Skenstatic char *
262229997Sken_getenv_dynamic(const char *name, int *idx)
263229997Sken{
264229997Sken	char *cp;
265229997Sken	int len, i;
266229997Sken
267229997Sken	mtx_assert(&kenv_lock, MA_OWNED);
268229997Sken	len = strlen(name);
269229997Sken	for (cp = kenvp[0], i = 0; cp != NULL; cp = kenvp[++i]) {
270229997Sken		if ((strncmp(cp, name, len) == 0) &&
271229997Sken		    (cp[len] == '=')) {
272229997Sken			if (idx != NULL)
273229997Sken				*idx = i;
274229997Sken			return (cp + len + 1);
275229997Sken		}
276229997Sken	}
277229997Sken	return (NULL);
278229997Sken}
279229997Sken
280229997Skenstatic char *
281229997Sken_getenv_static(const char *name)
282229997Sken{
283229997Sken	char *cp, *ep;
284229997Sken	int len;
285229997Sken
286229997Sken	for (cp = kern_envp; cp != NULL; cp = kernenv_next(cp)) {
287229997Sken		for (ep = cp; (*ep != '=') && (*ep != 0); ep++)
288229997Sken			;
289229997Sken		if (*ep != '=')
290232604Strasz			continue;
291232604Strasz		len = ep - cp;
292232604Strasz		ep++;
293232604Strasz		if (!strncmp(name, cp, len) && name[len] == 0)
294232604Strasz			return (ep);
295229997Sken	}
296229997Sken	return (NULL);
297229997Sken}
298229997Sken
299229997Sken/*
300229997Sken * Look up an environment variable by name.
301 * Return a pointer to the string if found.
302 * The pointer has to be freed with freeenv()
303 * after use.
304 */
305char *
306getenv(const char *name)
307{
308	char buf[KENV_MNAMELEN + 1 + KENV_MVALLEN + 1];
309	char *ret, *cp;
310	int len;
311
312	if (dynamic_kenv) {
313		WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, NULL, "getenv");
314		mtx_lock(&kenv_lock);
315		cp = _getenv_dynamic(name, NULL);
316		if (cp != NULL) {
317			strcpy(buf, cp);
318			mtx_unlock(&kenv_lock);
319			len = strlen(buf) + 1;
320			ret = malloc(len, M_KENV, M_WAITOK);
321			strcpy(ret, buf);
322		} else {
323			mtx_unlock(&kenv_lock);
324			ret = NULL;
325		}
326	} else
327		ret = _getenv_static(name);
328	return (ret);
329}
330
331/*
332 * Test if an environment variable is defined.
333 */
334int
335testenv(const char *name)
336{
337	char *cp;
338
339	if (dynamic_kenv) {
340		mtx_lock(&kenv_lock);
341		cp = _getenv_dynamic(name, NULL);
342		mtx_unlock(&kenv_lock);
343	} else
344		cp = _getenv_static(name);
345	if (cp != NULL)
346		return (1);
347	return (0);
348}
349
350static int
351setenv_static(const char *name, const char *value)
352{
353	int len;
354
355	if (env_pos >= env_len)
356		return (-1);
357
358	/* Check space for x=y and two nuls */
359	len = strlen(name) + strlen(value);
360	if (len + 3 < env_len - env_pos) {
361		len = sprintf(&kern_envp[env_pos], "%s=%s", name, value);
362		env_pos += len+1;
363		kern_envp[env_pos] = '\0';
364		return (0);
365	} else
366		return (-1);
367
368}
369
370/*
371 * Set an environment variable by name.
372 */
373int
374setenv(const char *name, const char *value)
375{
376	char *buf, *cp, *oldenv;
377	int namelen, vallen, i;
378
379	if (dynamic_kenv == 0 && env_len > 0)
380		return (setenv_static(name, value));
381
382	KENV_CHECK;
383
384	namelen = strlen(name) + 1;
385	if (namelen > KENV_MNAMELEN)
386		return (-1);
387	vallen = strlen(value) + 1;
388	if (vallen > KENV_MVALLEN)
389		return (-1);
390	buf = malloc(namelen + vallen, M_KENV, M_WAITOK);
391	sprintf(buf, "%s=%s", name, value);
392
393	mtx_lock(&kenv_lock);
394	cp = _getenv_dynamic(name, &i);
395	if (cp != NULL) {
396		oldenv = kenvp[i];
397		kenvp[i] = buf;
398		mtx_unlock(&kenv_lock);
399		free(oldenv, M_KENV);
400	} else {
401		/* We add the option if it wasn't found */
402		for (i = 0; (cp = kenvp[i]) != NULL; i++)
403			;
404
405		/* Bounds checking */
406		if (i < 0 || i >= KENV_SIZE) {
407			free(buf, M_KENV);
408			mtx_unlock(&kenv_lock);
409			return (-1);
410		}
411
412		kenvp[i] = buf;
413		kenvp[i + 1] = NULL;
414		mtx_unlock(&kenv_lock);
415	}
416	return (0);
417}
418
419/*
420 * Unset an environment variable string.
421 */
422int
423unsetenv(const char *name)
424{
425	char *cp, *oldenv;
426	int i, j;
427
428	KENV_CHECK;
429
430	mtx_lock(&kenv_lock);
431	cp = _getenv_dynamic(name, &i);
432	if (cp != NULL) {
433		oldenv = kenvp[i];
434		for (j = i + 1; kenvp[j] != NULL; j++)
435			kenvp[i++] = kenvp[j];
436		kenvp[i] = NULL;
437		mtx_unlock(&kenv_lock);
438		free(oldenv, M_KENV);
439		return (0);
440	}
441	mtx_unlock(&kenv_lock);
442	return (-1);
443}
444
445/*
446 * Return a string value from an environment variable.
447 */
448int
449getenv_string(const char *name, char *data, int size)
450{
451	char *tmp;
452
453	tmp = getenv(name);
454	if (tmp != NULL) {
455		strlcpy(data, tmp, size);
456		freeenv(tmp);
457		return (1);
458	} else
459		return (0);
460}
461
462/*
463 * Return an integer value from an environment variable.
464 */
465int
466getenv_int(const char *name, int *data)
467{
468	quad_t tmp;
469	int rval;
470
471	rval = getenv_quad(name, &tmp);
472	if (rval)
473		*data = (int) tmp;
474	return (rval);
475}
476
477/*
478 * Return an unsigned integer value from an environment variable.
479 */
480int
481getenv_uint(const char *name, unsigned int *data)
482{
483	quad_t tmp;
484	int rval;
485
486	rval = getenv_quad(name, &tmp);
487	if (rval)
488		*data = (unsigned int) tmp;
489	return (rval);
490}
491
492/*
493 * Return a long value from an environment variable.
494 */
495int
496getenv_long(const char *name, long *data)
497{
498	quad_t tmp;
499	int rval;
500
501	rval = getenv_quad(name, &tmp);
502	if (rval)
503		*data = (long) tmp;
504	return (rval);
505}
506
507/*
508 * Return an unsigned long value from an environment variable.
509 */
510int
511getenv_ulong(const char *name, unsigned long *data)
512{
513	quad_t tmp;
514	int rval;
515
516	rval = getenv_quad(name, &tmp);
517	if (rval)
518		*data = (unsigned long) tmp;
519	return (rval);
520}
521
522/*
523 * Return a quad_t value from an environment variable.
524 */
525int
526getenv_quad(const char *name, quad_t *data)
527{
528	char	*value;
529	char	*vtp;
530	quad_t	iv;
531
532	value = getenv(name);
533	if (value == NULL)
534		return (0);
535	iv = strtoq(value, &vtp, 0);
536	if (vtp == value || (vtp[0] != '\0' && vtp[1] != '\0')) {
537		freeenv(value);
538		return (0);
539	}
540	switch (vtp[0]) {
541	case 't': case 'T':
542		iv *= 1024;
543	case 'g': case 'G':
544		iv *= 1024;
545	case 'm': case 'M':
546		iv *= 1024;
547	case 'k': case 'K':
548		iv *= 1024;
549	case '\0':
550		break;
551	default:
552		freeenv(value);
553		return (0);
554	}
555	*data = iv;
556	freeenv(value);
557	return (1);
558}
559
560/*
561 * Find the next entry after the one which (cp) falls within, return a
562 * pointer to its start or NULL if there are no more.
563 */
564static char *
565kernenv_next(char *cp)
566{
567
568	if (cp != NULL) {
569		while (*cp != 0)
570			cp++;
571		cp++;
572		if (*cp == 0)
573			cp = NULL;
574	}
575	return (cp);
576}
577
578void
579tunable_int_init(void *data)
580{
581	struct tunable_int *d = (struct tunable_int *)data;
582
583	TUNABLE_INT_FETCH(d->path, d->var);
584}
585
586void
587tunable_long_init(void *data)
588{
589	struct tunable_long *d = (struct tunable_long *)data;
590
591	TUNABLE_LONG_FETCH(d->path, d->var);
592}
593
594void
595tunable_ulong_init(void *data)
596{
597	struct tunable_ulong *d = (struct tunable_ulong *)data;
598
599	TUNABLE_ULONG_FETCH(d->path, d->var);
600}
601
602void
603tunable_quad_init(void *data)
604{
605	struct tunable_quad *d = (struct tunable_quad *)data;
606
607	TUNABLE_QUAD_FETCH(d->path, d->var);
608}
609
610void
611tunable_str_init(void *data)
612{
613	struct tunable_str *d = (struct tunable_str *)data;
614
615	TUNABLE_STR_FETCH(d->path, d->var, d->size);
616}
617