1 /*	$NetBSD: veriexec.c,v 1.1 2015/12/09 18:25:32 maxv Exp $	*/
2 
3 /*-
4  * Copyright (c) 2005, 2006 Elad Efrat <elad@NetBSD.org>
5  * Copyright (c) 2005, 2006 Brett Lymn <blymn@NetBSD.org>
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  * 3. The name of the authors may not be used to endorse or promote products
17  *    derived from this software without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
20  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
21  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
22  * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT,
23  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
24  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
28  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29  */
30 
31 #include <sys/cdefs.h>
32 __KERNEL_RCSID(0, "$NetBSD: veriexec.c,v 1.1 2015/12/09 18:25:32 maxv Exp $");
33 
34 #include <sys/param.h>
35 #include <sys/errno.h>
36 #include <sys/conf.h>
37 #include <sys/vnode.h>
38 #include <sys/fcntl.h>
39 #include <sys/namei.h>
40 #include <sys/verified_exec.h>
41 #include <sys/kauth.h>
42 #include <sys/syslog.h>
43 #include <sys/proc.h>
44 
45 #include <sys/ioctl.h>
46 #include <sys/device.h>
47 #define DEVPORT_DEVICE struct device
48 
49 #include <prop/proplib.h>
50 
51 void veriexecattach(device_t, device_t, void *);
52 static dev_type_open(veriexecopen);
53 static dev_type_close(veriexecclose);
54 static dev_type_ioctl(veriexecioctl);
55 
56 struct veriexec_softc {
57 	DEVPORT_DEVICE veriexec_dev;
58 };
59 
60 const struct cdevsw veriexec_cdevsw = {
61 	.d_open = veriexecopen,
62 	.d_close = veriexecclose,
63 	.d_read = noread,
64 	.d_write = nowrite,
65 	.d_ioctl = veriexecioctl,
66 	.d_stop = nostop,
67 	.d_tty = notty,
68 	.d_poll = nopoll,
69 	.d_mmap = nommap,
70 	.d_discard = nodiscard,
71 	.d_kqfilter = nokqfilter,
72 	.d_flag = D_OTHER,
73 };
74 
75 /* count of number of times device is open (we really only allow one open) */
76 static unsigned int veriexec_dev_usage = 0;
77 
78 void
veriexecattach(DEVPORT_DEVICE * parent,DEVPORT_DEVICE * self,void * aux)79 veriexecattach(DEVPORT_DEVICE *parent, DEVPORT_DEVICE *self, void *aux)
80 {
81 	veriexec_dev_usage = 0;
82 }
83 
84 static int
veriexecopen(dev_t dev,int flags,int fmt,struct lwp * l)85 veriexecopen(dev_t dev, int flags, int fmt, struct lwp *l)
86 {
87 	if (kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_VERIEXEC,
88 	    KAUTH_REQ_SYSTEM_VERIEXEC_ACCESS, NULL, NULL, NULL))
89 		return (EPERM);
90 
91 	if (veriexec_dev_usage > 0)
92 		return(EBUSY);
93 
94 	veriexec_dev_usage++;
95 	return (0);
96 }
97 
98 static int
veriexecclose(dev_t dev,int flags,int fmt,struct lwp * l)99 veriexecclose(dev_t dev, int flags, int fmt, struct lwp *l)
100 {
101 	if (veriexec_dev_usage > 0)
102 		veriexec_dev_usage--;
103 	return (0);
104 }
105 
106 static int
veriexec_delete(prop_dictionary_t dict,struct lwp * l)107 veriexec_delete(prop_dictionary_t dict, struct lwp *l)
108 {
109 	struct vnode *vp;
110 	const char *file;
111 	int error;
112 
113 	if (!prop_dictionary_get_cstring_nocopy(dict, "file", &file))
114 		return (EINVAL);
115 
116 	error = namei_simple_kernel(file, NSM_FOLLOW_NOEMULROOT, &vp);
117 	if (error)
118 		return (error);
119 
120 	/* XXX this should be done differently... */
121 	if (vp->v_type == VREG)
122 		error = veriexec_file_delete(l, vp);
123 	else if (vp->v_type == VDIR)
124 		error = veriexec_table_delete(l, vp->v_mount);
125 
126 	vrele(vp);
127 
128 	return (error);
129 }
130 
131 static int
veriexec_query(prop_dictionary_t dict,prop_dictionary_t rdict,struct lwp * l)132 veriexec_query(prop_dictionary_t dict, prop_dictionary_t rdict, struct lwp *l)
133 {
134 	struct vnode *vp;
135 	const char *file;
136 	int error;
137 
138 	if (!prop_dictionary_get_cstring_nocopy(dict, "file", &file))
139 		return (EINVAL);
140 
141 	error = namei_simple_kernel(file, NSM_FOLLOW_NOEMULROOT, &vp);
142 	if (error)
143 		return (error);
144 
145 	error = veriexec_convert(vp, rdict);
146 
147 	vrele(vp);
148 
149 	return (error);
150 }
151 
152 int
veriexecioctl(dev_t dev,u_long cmd,void * data,int flags,struct lwp * l)153 veriexecioctl(dev_t dev, u_long cmd, void *data, int flags, struct lwp *l)
154 {
155 	struct plistref *plistref;
156 	prop_dictionary_t dict;
157 	int error = 0;
158 
159 	switch (cmd) {
160 	case VERIEXEC_TABLESIZE:
161 	case VERIEXEC_LOAD:
162 	case VERIEXEC_DELETE:
163 	case VERIEXEC_FLUSH:
164 		if (!(flags & FWRITE))
165 			return (EPERM);
166 
167 		error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_VERIEXEC,
168 		    KAUTH_REQ_SYSTEM_VERIEXEC_MODIFY, KAUTH_ARG(cmd), NULL,
169 		    NULL);
170 		if (error)
171 			return error;
172 
173 		break;
174 
175 	case VERIEXEC_QUERY:
176 	case VERIEXEC_DUMP:
177 		if (!(flags & FREAD))
178 			return (EPERM);
179 
180 		break;
181 
182 	default:
183 		/* Invalid operation. */
184 		return (ENODEV);
185 	}
186 
187 	plistref = (struct plistref *)data;
188 
189 	switch (cmd) {
190 	case VERIEXEC_TABLESIZE:
191 		/* Do nothing. Kept for binary compatibility. */
192 		break;
193 
194 	case VERIEXEC_LOAD:
195 		error = prop_dictionary_copyin_ioctl(plistref, cmd, &dict);
196 		if (error)
197 			break;
198 
199 		error = veriexec_file_add(l, dict);
200 		prop_object_release(dict);
201 		break;
202 
203 	case VERIEXEC_DELETE:
204 		error = prop_dictionary_copyin_ioctl(plistref, cmd, &dict);
205 		if (error)
206 			break;
207 
208 		error = veriexec_delete(dict, l);
209 		prop_object_release(dict);
210 		break;
211 
212 	case VERIEXEC_QUERY: {
213 		prop_dictionary_t rdict;
214 
215 		error = prop_dictionary_copyin_ioctl(plistref, cmd, &dict);
216 		if (error)
217 			return (error);
218 
219 		rdict = prop_dictionary_create();
220 		if (rdict == NULL) {
221 			prop_object_release(dict);
222 			error = ENOMEM;
223 			break;
224 		}
225 
226 		error = veriexec_query(dict, rdict, l);
227 		if (error == 0) {
228 			error = prop_dictionary_copyout_ioctl(plistref, cmd,
229 			    rdict);
230 		}
231 
232 		prop_object_release(rdict);
233 		prop_object_release(dict);
234 
235 		break;
236 		}
237 
238 	case VERIEXEC_DUMP: {
239 		prop_array_t rarray;
240 
241 		rarray = prop_array_create();
242 		if (rarray == NULL) {
243 			error = ENOMEM;
244 			break;
245 		}
246 
247 		error = veriexec_dump(l, rarray);
248 		if (error == 0) {
249 			error = prop_array_copyout_ioctl(plistref, cmd,
250 			    rarray);
251 		}
252 
253 		prop_object_release(rarray);
254 
255 		break;
256 		}
257 
258 	case VERIEXEC_FLUSH:
259 		error = veriexec_flush(l);
260 		break;
261 
262 	default:
263 		/* Invalid operation. */
264 		error = ENODEV;
265 		break;
266 	}
267 
268 	return (error);
269 }
270 
271