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
51void veriexecattach(device_t, device_t, void *);
52static dev_type_open(veriexecopen);
53static dev_type_close(veriexecclose);
54static dev_type_ioctl(veriexecioctl);
55
56struct veriexec_softc {
57 DEVPORT_DEVICE veriexec_dev;
58};
59
60const 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) */
76static unsigned int veriexec_dev_usage = 0;
77
78void
79veriexecattach(DEVPORT_DEVICE *parent, DEVPORT_DEVICE *self, void *aux)
80{
81 veriexec_dev_usage = 0;
82}
83
84static int
85veriexecopen(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
98static int
99veriexecclose(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
106static int
107veriexec_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
131static int
132veriexec_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
152int
153veriexecioctl(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