xref: /openbsd-src/sys/kern/kern_subr.c (revision d62ebcb2023f9bedf18a9581f9e426635774d636)
1*d62ebcb2Sderaadt /*	$OpenBSD: kern_subr.c,v 1.52 2023/01/31 15:18:56 deraadt Exp $	*/
2d724e01aSderaadt /*	$NetBSD: kern_subr.c,v 1.15 1996/04/09 17:21:56 ragge Exp $	*/
3df930be7Sderaadt 
4df930be7Sderaadt /*
5df930be7Sderaadt  * Copyright (c) 1982, 1986, 1991, 1993
6df930be7Sderaadt  *	The Regents of the University of California.  All rights reserved.
7df930be7Sderaadt  * (c) UNIX System Laboratories, Inc.
8df930be7Sderaadt  * All or some portions of this file are derived from material licensed
9df930be7Sderaadt  * to the University of California by American Telephone and Telegraph
10df930be7Sderaadt  * Co. or Unix System Laboratories, Inc. and are reproduced herein with
11df930be7Sderaadt  * the permission of UNIX System Laboratories, Inc.
12df930be7Sderaadt  *
13df930be7Sderaadt  * Redistribution and use in source and binary forms, with or without
14df930be7Sderaadt  * modification, are permitted provided that the following conditions
15df930be7Sderaadt  * are met:
16df930be7Sderaadt  * 1. Redistributions of source code must retain the above copyright
17df930be7Sderaadt  *    notice, this list of conditions and the following disclaimer.
18df930be7Sderaadt  * 2. Redistributions in binary form must reproduce the above copyright
19df930be7Sderaadt  *    notice, this list of conditions and the following disclaimer in the
20df930be7Sderaadt  *    documentation and/or other materials provided with the distribution.
2129295d1cSmillert  * 3. Neither the name of the University nor the names of its contributors
22df930be7Sderaadt  *    may be used to endorse or promote products derived from this software
23df930be7Sderaadt  *    without specific prior written permission.
24df930be7Sderaadt  *
25df930be7Sderaadt  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
26df930be7Sderaadt  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27df930be7Sderaadt  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
28df930be7Sderaadt  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
29df930be7Sderaadt  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
30df930be7Sderaadt  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
31df930be7Sderaadt  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
32df930be7Sderaadt  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
33df930be7Sderaadt  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
34df930be7Sderaadt  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35df930be7Sderaadt  * SUCH DAMAGE.
36df930be7Sderaadt  *
37df930be7Sderaadt  *	@(#)kern_subr.c	8.3 (Berkeley) 1/21/94
38df930be7Sderaadt  */
39df930be7Sderaadt 
40df930be7Sderaadt #include <sys/param.h>
41df930be7Sderaadt #include <sys/systm.h>
42df930be7Sderaadt #include <sys/proc.h>
43012ea299Sniklas #include <sys/sched.h>
44df930be7Sderaadt #include <sys/malloc.h>
45df930be7Sderaadt #include <sys/queue.h>
46*d62ebcb2Sderaadt #include <uvm/uvm_extern.h>
47*d62ebcb2Sderaadt 
48*d62ebcb2Sderaadt #ifdef PMAP_CHECK_COPYIN
49*d62ebcb2Sderaadt 
50*d62ebcb2Sderaadt static inline int check_copyin(struct proc *, const void *, size_t);
51*d62ebcb2Sderaadt extern int _copyinstr(const void *, void *, size_t, size_t *);
52*d62ebcb2Sderaadt extern int _copyin(const void *uaddr, void *kaddr, size_t len);
53*d62ebcb2Sderaadt 
54*d62ebcb2Sderaadt /*
55*d62ebcb2Sderaadt  * If range overlaps an check_copyin region, return EFAULT
56*d62ebcb2Sderaadt  */
57*d62ebcb2Sderaadt static inline int
check_copyin(struct proc * p,const void * vstart,size_t len)58*d62ebcb2Sderaadt check_copyin(struct proc *p, const void *vstart, size_t len)
59*d62ebcb2Sderaadt {
60*d62ebcb2Sderaadt 	struct vm_map *map = &p->p_vmspace->vm_map;
61*d62ebcb2Sderaadt 	const vaddr_t start = (vaddr_t)vstart;
62*d62ebcb2Sderaadt 	const vaddr_t end = start + len;
63*d62ebcb2Sderaadt 	int i, max;
64*d62ebcb2Sderaadt 
65*d62ebcb2Sderaadt 	/* XXX if the array was sorted, we could shortcut */
66*d62ebcb2Sderaadt 	max = map->check_copyin_count;
67*d62ebcb2Sderaadt 	membar_consumer();
68*d62ebcb2Sderaadt 	for (i = 0; i < max; i++) {
69*d62ebcb2Sderaadt 		vaddr_t s = map->check_copyin[i].start;
70*d62ebcb2Sderaadt 		vaddr_t e = map->check_copyin[i].end;
71*d62ebcb2Sderaadt 		if ((start >= s && start < e) || (end > s && end < e))
72*d62ebcb2Sderaadt 			return EFAULT;
73*d62ebcb2Sderaadt 	}
74*d62ebcb2Sderaadt 	return (0);
75*d62ebcb2Sderaadt }
76*d62ebcb2Sderaadt 
77*d62ebcb2Sderaadt int
copyinstr(const void * uaddr,void * kaddr,size_t len,size_t * done)78*d62ebcb2Sderaadt copyinstr(const void *uaddr, void *kaddr, size_t len, size_t *done)
79*d62ebcb2Sderaadt {
80*d62ebcb2Sderaadt 	size_t alen;
81*d62ebcb2Sderaadt 	int error;
82*d62ebcb2Sderaadt 
83*d62ebcb2Sderaadt 	/*
84*d62ebcb2Sderaadt 	 * Must do the copyin checks after figuring out the string length,
85*d62ebcb2Sderaadt 	 * the buffer size length may cross into another ELF segment
86*d62ebcb2Sderaadt 	 */
87*d62ebcb2Sderaadt 	error = _copyinstr(uaddr, kaddr, len, &alen);
88*d62ebcb2Sderaadt 	if (PMAP_CHECK_COPYIN && error == 0)
89*d62ebcb2Sderaadt 		error = check_copyin(curproc, uaddr, alen);
90*d62ebcb2Sderaadt 	if (done)
91*d62ebcb2Sderaadt 		*done = alen;
92*d62ebcb2Sderaadt 	return (error);
93*d62ebcb2Sderaadt }
94*d62ebcb2Sderaadt 
95*d62ebcb2Sderaadt int
copyin(const void * uaddr,void * kaddr,size_t len)96*d62ebcb2Sderaadt copyin(const void *uaddr, void *kaddr, size_t len)
97*d62ebcb2Sderaadt {
98*d62ebcb2Sderaadt 	int error = 0;
99*d62ebcb2Sderaadt 
100*d62ebcb2Sderaadt 	if (PMAP_CHECK_COPYIN)
101*d62ebcb2Sderaadt 		error = check_copyin(curproc, uaddr, len);
102*d62ebcb2Sderaadt 	if (error == 0)
103*d62ebcb2Sderaadt 		error = _copyin(uaddr, kaddr, len);
104*d62ebcb2Sderaadt 	return (error);
105*d62ebcb2Sderaadt }
106*d62ebcb2Sderaadt #endif /* PMAP_CHECK_COPYIN */
107f7e5f6f6Sart 
108df930be7Sderaadt int
uiomove(void * cp,size_t n,struct uio * uio)109081bf720Smiod uiomove(void *cp, size_t n, struct uio *uio)
110df930be7Sderaadt {
111158fb4f9Sjsg 	struct iovec *iov;
112906c107fSguenther 	size_t cnt;
113df930be7Sderaadt 	int error = 0;
114df930be7Sderaadt 
115df930be7Sderaadt #ifdef DIAGNOSTIC
116df930be7Sderaadt 	if (uio->uio_rw != UIO_READ && uio->uio_rw != UIO_WRITE)
117df930be7Sderaadt 		panic("uiomove: mode");
118481e765dSstefan 	if (uio->uio_segflg == UIO_USERSPACE && uio->uio_procp != curproc)
119f7e5f6f6Sart 		panic("uiomove: proc");
120df930be7Sderaadt #endif
121481e765dSstefan 
122481e765dSstefan 	if (n > uio->uio_resid)
123481e765dSstefan 		n = uio->uio_resid;
124481e765dSstefan 
125481e765dSstefan 	while (n > 0) {
126df930be7Sderaadt 		iov = uio->uio_iov;
127df930be7Sderaadt 		cnt = iov->iov_len;
128df930be7Sderaadt 		if (cnt == 0) {
129481e765dSstefan 			KASSERT(uio->uio_iovcnt > 0);
130df930be7Sderaadt 			uio->uio_iov++;
131df930be7Sderaadt 			uio->uio_iovcnt--;
132df930be7Sderaadt 			continue;
133df930be7Sderaadt 		}
134df930be7Sderaadt 		if (cnt > n)
135df930be7Sderaadt 			cnt = n;
136906c107fSguenther 		switch (uio->uio_segflg) {
137df930be7Sderaadt 
138df930be7Sderaadt 		case UIO_USERSPACE:
1399b1ed563Smpi 			sched_pause(preempt);
140df930be7Sderaadt 			if (uio->uio_rw == UIO_READ)
141df930be7Sderaadt 				error = copyout(cp, iov->iov_base, cnt);
142df930be7Sderaadt 			else
143df930be7Sderaadt 				error = copyin(iov->iov_base, cp, cnt);
144df930be7Sderaadt 			if (error)
145df930be7Sderaadt 				return (error);
146df930be7Sderaadt 			break;
147df930be7Sderaadt 
148df930be7Sderaadt 		case UIO_SYSSPACE:
149a91606c1Sart 			if (uio->uio_rw == UIO_READ)
150a91606c1Sart 				error = kcopy(cp, iov->iov_base, cnt);
151a91606c1Sart 			else
152a91606c1Sart 				error = kcopy(iov->iov_base, cp, cnt);
153a91606c1Sart 			if (error)
154a91606c1Sart 				return(error);
155df930be7Sderaadt 		}
1567cdefcf6Saaron 		iov->iov_base = (caddr_t)iov->iov_base + cnt;
157df930be7Sderaadt 		iov->iov_len -= cnt;
158df930be7Sderaadt 		uio->uio_resid -= cnt;
159df930be7Sderaadt 		uio->uio_offset += cnt;
16027e97305Stedu 		cp = (caddr_t)cp + cnt;
161df930be7Sderaadt 		n -= cnt;
162df930be7Sderaadt 	}
163df930be7Sderaadt 	return (error);
164df930be7Sderaadt }
165df930be7Sderaadt 
166df930be7Sderaadt /*
167df930be7Sderaadt  * Give next character to user as result of read.
168df930be7Sderaadt  */
169df930be7Sderaadt int
ureadc(int c,struct uio * uio)170158fb4f9Sjsg ureadc(int c, struct uio *uio)
171df930be7Sderaadt {
172158fb4f9Sjsg 	struct iovec *iov;
173df930be7Sderaadt 
1749b355cb2Smillert 	if (uio->uio_resid == 0)
1759b355cb2Smillert #ifdef DIAGNOSTIC
1769b355cb2Smillert 		panic("ureadc: zero resid");
1779b355cb2Smillert #else
1789b355cb2Smillert 		return (EINVAL);
1799b355cb2Smillert #endif
180df930be7Sderaadt again:
181df930be7Sderaadt 	if (uio->uio_iovcnt <= 0)
1829b355cb2Smillert #ifdef DIAGNOSTIC
183df930be7Sderaadt 		panic("ureadc: non-positive iovcnt");
1849b355cb2Smillert #else
1859b355cb2Smillert 		return (EINVAL);
1869b355cb2Smillert #endif
187df930be7Sderaadt 	iov = uio->uio_iov;
188df930be7Sderaadt 	if (iov->iov_len <= 0) {
189df930be7Sderaadt 		uio->uio_iovcnt--;
190df930be7Sderaadt 		uio->uio_iov++;
191df930be7Sderaadt 		goto again;
192df930be7Sderaadt 	}
193906c107fSguenther 	switch (uio->uio_segflg) {
194df930be7Sderaadt 
195df930be7Sderaadt 	case UIO_USERSPACE:
1961de66d4eSmiod 	{
1971de66d4eSmiod 		char tmp = c;
1981de66d4eSmiod 
1991de66d4eSmiod 		if (copyout(&tmp, iov->iov_base, sizeof(char)) != 0)
200df930be7Sderaadt 			return (EFAULT);
2011de66d4eSmiod 	}
202df930be7Sderaadt 		break;
203df930be7Sderaadt 
204df930be7Sderaadt 	case UIO_SYSSPACE:
205f4e9f33fSderaadt 		*(char *)iov->iov_base = c;
206df930be7Sderaadt 		break;
207df930be7Sderaadt 	}
2087cdefcf6Saaron 	iov->iov_base = (caddr_t)iov->iov_base + 1;
209df930be7Sderaadt 	iov->iov_len--;
210df930be7Sderaadt 	uio->uio_resid--;
211df930be7Sderaadt 	uio->uio_offset++;
212df930be7Sderaadt 	return (0);
213df930be7Sderaadt }
214df930be7Sderaadt 
215df930be7Sderaadt /*
216df930be7Sderaadt  * General routine to allocate a hash table.
217df930be7Sderaadt  */
218df930be7Sderaadt void *
hashinit(int elements,int type,int flags,u_long * hashmask)219158fb4f9Sjsg hashinit(int elements, int type, int flags, u_long *hashmask)
22013049928Smillert {
221ffe9e374Smarkus 	u_long hashsize, i;
222df930be7Sderaadt 	LIST_HEAD(generic, generic) *hashtbl;
223df930be7Sderaadt 
224df930be7Sderaadt 	if (elements <= 0)
225df930be7Sderaadt 		panic("hashinit: bad cnt");
2268e8a4c44Santon 	if ((elements & (elements - 1)) == 0)
2278e8a4c44Santon 		hashsize = elements;
2288e8a4c44Santon 	else
229ffe9e374Smarkus 		for (hashsize = 1; hashsize < elements; hashsize <<= 1)
230df930be7Sderaadt 			continue;
23147e7ee29Stedu 	hashtbl = mallocarray(hashsize, sizeof(*hashtbl), type, flags);
232a950bd2dSart 	if (hashtbl == NULL)
233a950bd2dSart 		return NULL;
234df930be7Sderaadt 	for (i = 0; i < hashsize; i++)
235df930be7Sderaadt 		LIST_INIT(&hashtbl[i]);
236df930be7Sderaadt 	*hashmask = hashsize - 1;
237df930be7Sderaadt 	return (hashtbl);
238df930be7Sderaadt }
239df930be7Sderaadt 
24054f18723Stedu void
hashfree(void * hash,int elements,int type)24154f18723Stedu hashfree(void *hash, int elements, int type)
24254f18723Stedu {
24354f18723Stedu 	u_long hashsize;
24454f18723Stedu 	LIST_HEAD(generic, generic) *hashtbl = hash;
24554f18723Stedu 
24654f18723Stedu 	if (elements <= 0)
24754f18723Stedu 		panic("hashfree: bad cnt");
2488e8a4c44Santon 	if ((elements & (elements - 1)) == 0)
2498e8a4c44Santon 		hashsize = elements;
2508e8a4c44Santon 	else
25154f18723Stedu 		for (hashsize = 1; hashsize < elements; hashsize <<= 1)
25254f18723Stedu 			continue;
25354f18723Stedu 
25454f18723Stedu 	free(hashtbl, type, sizeof(*hashtbl) * hashsize);
25554f18723Stedu }
25654f18723Stedu 
257df930be7Sderaadt /*
258ef89f9e6Smpi  * "startup hook" types, functions, and variables.
259df930be7Sderaadt  */
260df930be7Sderaadt 
261ec1f6c03Sniklas struct hook_desc_head startuphook_list =
262ec1f6c03Sniklas     TAILQ_HEAD_INITIALIZER(startuphook_list);
263df930be7Sderaadt 
264df930be7Sderaadt void *
hook_establish(struct hook_desc_head * head,int tail,void (* fn)(void *),void * arg)265158fb4f9Sjsg hook_establish(struct hook_desc_head *head, int tail, void (*fn)(void *),
266158fb4f9Sjsg     void *arg)
267df930be7Sderaadt {
268ec1f6c03Sniklas 	struct hook_desc *hdp;
269df930be7Sderaadt 
27044f3212aStedu 	hdp = malloc(sizeof(*hdp), M_DEVBUF, M_NOWAIT);
271ec1f6c03Sniklas 	if (hdp == NULL)
272ec1f6c03Sniklas 		return (NULL);
273df930be7Sderaadt 
274ec1f6c03Sniklas 	hdp->hd_fn = fn;
275ec1f6c03Sniklas 	hdp->hd_arg = arg;
276ec1f6c03Sniklas 	if (tail)
277ec1f6c03Sniklas 		TAILQ_INSERT_TAIL(head, hdp, hd_list);
278ec1f6c03Sniklas 	else
279ec1f6c03Sniklas 		TAILQ_INSERT_HEAD(head, hdp, hd_list);
280df930be7Sderaadt 
281ec1f6c03Sniklas 	return (hdp);
282df930be7Sderaadt }
283df930be7Sderaadt 
284df930be7Sderaadt void
hook_disestablish(struct hook_desc_head * head,void * vhook)285158fb4f9Sjsg hook_disestablish(struct hook_desc_head *head, void *vhook)
286df930be7Sderaadt {
287ec1f6c03Sniklas 	struct hook_desc *hdp;
288df930be7Sderaadt 
28956133d81Sart #ifdef DIAGNOSTIC
290ec1f6c03Sniklas 	for (hdp = TAILQ_FIRST(head); hdp != NULL;
291ec1f6c03Sniklas 	    hdp = TAILQ_NEXT(hdp, hd_list))
292ec1f6c03Sniklas                 if (hdp == vhook)
293df930be7Sderaadt 			break;
294ec1f6c03Sniklas 	if (hdp == NULL)
295e7cd818eSmarco 		return;
296df930be7Sderaadt #endif
29756133d81Sart 	hdp = vhook;
29856133d81Sart 	TAILQ_REMOVE(head, hdp, hd_list);
299fc62de09Stedu 	free(hdp, M_DEVBUF, sizeof(*hdp));
300df930be7Sderaadt }
301df930be7Sderaadt 
302df930be7Sderaadt /*
303ec1f6c03Sniklas  * Run hooks.  Startup hooks are invoked right after scheduler_start but
304ec1f6c03Sniklas  * before root is mounted.  Shutdown hooks are invoked immediately before the
305df930be7Sderaadt  * system is halted or rebooted, i.e. after file systems unmounted,
306df930be7Sderaadt  * after crash dump done, etc.
307df930be7Sderaadt  */
308df930be7Sderaadt void
dohooks(struct hook_desc_head * head,int flags)30956133d81Sart dohooks(struct hook_desc_head *head, int flags)
310df930be7Sderaadt {
3117f06f937Sreyk 	struct hook_desc *hdp, *hdp_temp;
312df930be7Sderaadt 
31356133d81Sart 	if ((flags & HOOK_REMOVE) == 0) {
3147f06f937Sreyk 		TAILQ_FOREACH_SAFE(hdp, head, hd_list, hdp_temp) {
315ec1f6c03Sniklas 			(*hdp->hd_fn)(hdp->hd_arg);
316df930be7Sderaadt 		}
31756133d81Sart 	} else {
31856133d81Sart 		while ((hdp = TAILQ_FIRST(head)) != NULL) {
31956133d81Sart 			TAILQ_REMOVE(head, hdp, hd_list);
32056133d81Sart 			(*hdp->hd_fn)(hdp->hd_arg);
32156133d81Sart 			if ((flags & HOOK_FREE) != 0)
322fc62de09Stedu 				free(hdp, M_DEVBUF, sizeof(*hdp));
32356133d81Sart 		}
32456133d81Sart 	}
32556133d81Sart }
326