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 |
79 | veriexecattach(DEVPORT_DEVICE *parent, DEVPORT_DEVICE *self, void *aux) |
80 | { |
81 | veriexec_dev_usage = 0; |
82 | } |
83 | |
84 | static int |
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 |
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 |
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 |
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 |
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 | |