1 | /* $NetBSD: subr_kobj_vfs.c,v 1.10 2016/07/20 13:36:19 maxv Exp $ */ |
2 | |
3 | /*- |
4 | * Copyright (c) 2008 The NetBSD Foundation, Inc. |
5 | * All rights reserved. |
6 | * |
7 | * This code is derived from software developed for The NetBSD Foundation |
8 | * by Andrew Doran. |
9 | * |
10 | * Redistribution and use in source and binary forms, with or without |
11 | * modification, are permitted provided that the following conditions |
12 | * are met: |
13 | * 1. Redistributions of source code must retain the above copyright |
14 | * notice, this list of conditions and the following disclaimer. |
15 | * 2. Redistributions in binary form must reproduce the above copyright |
16 | * notice, this list of conditions and the following disclaimer in the |
17 | * documentation and/or other materials provided with the distribution. |
18 | * |
19 | * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS |
20 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED |
21 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
22 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS |
23 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
24 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
25 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
26 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
27 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
28 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
29 | * POSSIBILITY OF SUCH DAMAGE. |
30 | */ |
31 | |
32 | /*- |
33 | * Copyright (c) 1998-2000 Doug Rabson |
34 | * Copyright (c) 2004 Peter Wemm |
35 | * All rights reserved. |
36 | * |
37 | * Redistribution and use in source and binary forms, with or without |
38 | * modification, are permitted provided that the following conditions |
39 | * are met: |
40 | * 1. Redistributions of source code must retain the above copyright |
41 | * notice, this list of conditions and the following disclaimer. |
42 | * 2. Redistributions in binary form must reproduce the above copyright |
43 | * notice, this list of conditions and the following disclaimer in the |
44 | * documentation and/or other materials provided with the distribution. |
45 | * |
46 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND |
47 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
48 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
49 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE |
50 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
51 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
52 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
53 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
54 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
55 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
56 | * SUCH DAMAGE. |
57 | */ |
58 | |
59 | /* |
60 | * Kernel loader vfs routines. |
61 | */ |
62 | |
63 | #include <sys/kobj_impl.h> |
64 | |
65 | #ifdef _KERNEL_OPT |
66 | #include "opt_modular.h" |
67 | #endif |
68 | |
69 | #ifdef MODULAR |
70 | |
71 | #include <sys/param.h> |
72 | #include <sys/fcntl.h> |
73 | #include <sys/module.h> |
74 | #include <sys/namei.h> |
75 | #include <sys/vnode.h> |
76 | |
77 | #include <sys/cdefs.h> |
78 | __KERNEL_RCSID(0, "$NetBSD: subr_kobj_vfs.c,v 1.10 2016/07/20 13:36:19 maxv Exp $" ); |
79 | |
80 | static void |
81 | kobj_close_vfs(kobj_t ko) |
82 | { |
83 | |
84 | VOP_UNLOCK(ko->ko_source); |
85 | vn_close(ko->ko_source, FREAD, kauth_cred_get()); |
86 | } |
87 | |
88 | /* |
89 | * kobj_read: |
90 | * |
91 | * Utility function: read from the object. |
92 | */ |
93 | static int |
94 | kobj_read_vfs(kobj_t ko, void **basep, size_t size, off_t off, |
95 | bool allocate) |
96 | { |
97 | size_t resid; |
98 | void *base; |
99 | int error; |
100 | |
101 | KASSERT(ko->ko_source != NULL); |
102 | |
103 | if (allocate) { |
104 | base = kmem_alloc(size, KM_SLEEP); |
105 | } else { |
106 | base = *basep; |
107 | #ifdef DIAGNOSTIC |
108 | bool ok = false; |
109 | if ((uintptr_t)base >= (uintptr_t)ko->ko_text_address && |
110 | (uintptr_t)base + size <= |
111 | (uintptr_t)ko->ko_text_address + ko->ko_text_size) |
112 | ok = true; |
113 | if ((uintptr_t)base >= (uintptr_t)ko->ko_data_address && |
114 | (uintptr_t)base + size <= |
115 | (uintptr_t)ko->ko_data_address + ko->ko_data_size) |
116 | ok = true; |
117 | if ((uintptr_t)base >= (uintptr_t)ko->ko_rodata_address && |
118 | (uintptr_t)base + size <= |
119 | (uintptr_t)ko->ko_rodata_address + ko->ko_rodata_size) |
120 | ok = true; |
121 | if (!ok) |
122 | panic("kobj_read_vfs: not in a dedicated segment" ); |
123 | #endif |
124 | } |
125 | |
126 | error = vn_rdwr(UIO_READ, ko->ko_source, base, size, off, |
127 | UIO_SYSSPACE, IO_NODELOCKED, curlwp->l_cred, &resid, |
128 | curlwp); |
129 | |
130 | if (error == 0 && resid != 0) { |
131 | error = EINVAL; |
132 | } |
133 | |
134 | if (allocate && error != 0) { |
135 | kmem_free(base, size); |
136 | base = NULL; |
137 | } |
138 | |
139 | if (allocate) |
140 | *basep = base; |
141 | |
142 | return error; |
143 | } |
144 | |
145 | /* |
146 | * kobj_load_vfs: |
147 | * |
148 | * Load an object located in the file system. |
149 | */ |
150 | int |
151 | kobj_load_vfs(kobj_t *kop, const char *path, const bool nochroot) |
152 | { |
153 | struct nameidata nd; |
154 | struct pathbuf *pb; |
155 | int error; |
156 | kobj_t ko; |
157 | |
158 | KASSERT(path != NULL); |
159 | if (strchr(path, '/') == NULL) |
160 | return ENOENT; |
161 | |
162 | ko = kmem_zalloc(sizeof(*ko), KM_SLEEP); |
163 | if (ko == NULL) { |
164 | return ENOMEM; |
165 | } |
166 | |
167 | pb = pathbuf_create(path); |
168 | if (pb == NULL) { |
169 | kmem_free(ko, sizeof(*ko)); |
170 | return ENOMEM; |
171 | } |
172 | |
173 | NDINIT(&nd, LOOKUP, FOLLOW | (nochroot ? NOCHROOT : 0), pb); |
174 | error = vn_open(&nd, FREAD, 0); |
175 | |
176 | if (error != 0) { |
177 | pathbuf_destroy(pb); |
178 | kmem_free(ko, sizeof(*ko)); |
179 | return error; |
180 | } |
181 | |
182 | ko->ko_type = KT_VNODE; |
183 | kobj_setname(ko, path); |
184 | ko->ko_source = nd.ni_vp; |
185 | ko->ko_read = kobj_read_vfs; |
186 | ko->ko_close = kobj_close_vfs; |
187 | pathbuf_destroy(pb); |
188 | |
189 | *kop = ko; |
190 | return kobj_load(ko); |
191 | } |
192 | |
193 | #else /* MODULAR */ |
194 | |
195 | int |
196 | kobj_load_vfs(kobj_t *kop, const char *path, const bool nochroot) |
197 | { |
198 | |
199 | return ENOSYS; |
200 | } |
201 | |
202 | #endif |
203 | |