Print this page
Plug sharefs zone-shutdown leaks
| Split |
Close |
| Expand all |
| Collapse all |
--- old/usr/src/uts/common/fs/sharefs/sharetab.c
+++ new/usr/src/uts/common/fs/sharefs/sharetab.c
1 1 /*
2 2 * CDDL HEADER START
3 3 *
4 4 * The contents of this file are subject to the terms of the
5 5 * Common Development and Distribution License (the "License").
6 6 * You may not use this file except in compliance with the License.
7 7 *
8 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 9 * or http://www.opensolaris.org/os/licensing.
10 10 * See the License for the specific language governing permissions
11 11 * and limitations under the License.
12 12 *
13 13 * When distributing Covered Code, include this CDDL HEADER in each
14 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 15 * If applicable, add the following below this CDDL HEADER, with the
16 16 * fields enclosed by brackets "[]" replaced with your own identifying
17 17 * information: Portions Copyright [yyyy] [name of copyright owner]
|
↓ open down ↓ |
17 lines elided |
↑ open up ↑ |
18 18 *
19 19 * CDDL HEADER END
20 20 */
21 21
22 22 /*
23 23 * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
24 24 */
25 25
26 26 /*
27 27 * Copyright 2018 Nexenta Systems, Inc.
28 + * Copyright 2019 Joyent, Inc.
28 29 */
29 30
30 31 #include <sys/types.h>
31 32 #include <sys/types32.h>
32 33 #include <sys/param.h>
33 34 #include <sys/systm.h>
34 35 #include <rpc/types.h>
35 36 #include <sys/vfs.h>
36 37 #include <sys/siginfo.h>
37 38 #include <sys/proc.h> /* for exit() declaration */
38 39 #include <sys/kmem.h>
39 40 #include <sys/pathname.h>
40 41 #include <sys/debug.h>
41 42 #include <sys/vtrace.h>
42 43 #include <sys/cmn_err.h>
43 44 #include <sys/atomic.h>
44 45 #include <sys/policy.h>
45 46
46 47 #include <sharefs/sharefs.h>
47 48
48 49 /*
49 50 * A macro to avoid cut-and-paste errors on getting a string field
50 51 * from user-land.
51 52 */
52 53 #define SHARETAB_COPYIN(field) \
53 54 if (copyinstr(STRUCT_FGETP(u_sh, sh_##field), \
54 55 buf, \
55 56 bufsz + 1, /* Add one for extra NUL */ \
56 57 &len)) { \
57 58 error = EFAULT; \
58 59 goto cleanup; \
59 60 } \
60 61 /* Need to remove 1 because copyinstr() counts the NUL */ \
61 62 len--; \
62 63 sh->sh_##field = kmem_alloc(len + 1, KM_SLEEP); \
63 64 bcopy(buf, sh->sh_##field, len); \
64 65 sh->sh_##field[len] = '\0'; \
65 66 shl.shl_##field = (int)len; \
66 67 sh->sh_size += shl.shl_##field; /* Debug counting */
67 68
68 69 #define SHARETAB_DELETE_FIELD(field) \
69 70 if (sh->sh_##field != NULL) { \
70 71 kmem_free(sh->sh_##field, \
71 72 shl ? shl->shl_##field + 1 : \
72 73 strlen(sh->sh_##field) + 1); \
73 74 }
74 75
75 76 static zone_key_t sharetab_zone_key;
76 77
77 78 /*
78 79 * Take care of cleaning up a share.
79 80 * If passed in a length array, use it to determine how much
80 81 * space to clean up. Else, figure that out.
81 82 */
82 83 static void
83 84 sharefree(share_t *sh, sharefs_lens_t *shl)
84 85 {
85 86 if (sh == NULL)
86 87 return;
87 88
88 89 SHARETAB_DELETE_FIELD(path);
89 90 SHARETAB_DELETE_FIELD(res);
90 91 SHARETAB_DELETE_FIELD(fstype);
91 92 SHARETAB_DELETE_FIELD(opts);
92 93 SHARETAB_DELETE_FIELD(descr);
93 94
94 95 kmem_free(sh, sizeof (*sh));
95 96 }
96 97
97 98 /*
98 99 * If there is no error, then this function is responsible for
99 100 * cleaning up the memory associated with the share argument.
100 101 */
101 102 static int
102 103 sharefs_remove(sharetab_globals_t *sg, share_t *sh, sharefs_lens_t *shl)
103 104 {
104 105 int iHash;
105 106 sharetab_t *sht;
106 107 share_t *s, *p;
107 108 int iPath;
108 109
109 110 if (!sh)
110 111 return (ENOENT);
111 112
112 113 rw_enter(&sg->sharetab_lock, RW_WRITER);
113 114 for (sht = sg->sharefs_sharetab; sht != NULL; sht = sht->s_next) {
114 115 if (strcmp(sh->sh_fstype, sht->s_fstype) == 0)
115 116 break;
116 117 }
117 118
118 119 /*
119 120 * There does not exist a fstype in memory which
120 121 * matches the share passed in.
121 122 */
122 123 if (sht == NULL) {
123 124 rw_exit(&sg->sharetab_lock);
124 125 return (ENOENT);
125 126 }
126 127
127 128 iPath = shl != NULL ? shl->shl_path : strlen(sh->sh_path);
128 129 iHash = pkp_tab_hash(sh->sh_path, strlen(sh->sh_path));
129 130
130 131 /*
131 132 * Now walk down the hash table and find the entry to free!
132 133 */
133 134 for (p = NULL, s = sht->s_buckets[iHash].ssh_sh;
134 135 s != NULL; s = s->sh_next) {
135 136 /*
136 137 * We need exact matches.
137 138 */
138 139 if (strcmp(sh->sh_path, s->sh_path) == 0 &&
139 140 strlen(s->sh_path) == iPath) {
140 141 if (p != NULL)
141 142 p->sh_next = s->sh_next;
142 143 else
143 144 sht->s_buckets[iHash].ssh_sh = s->sh_next;
144 145
145 146 ASSERT(sht->s_buckets[iHash].ssh_count != 0);
146 147 atomic_dec_32(&sht->s_buckets[iHash].ssh_count);
147 148 atomic_dec_32(&sht->s_count);
148 149 atomic_dec_32(&sg->sharetab_count);
149 150
150 151 ASSERT(sg->sharetab_size >= s->sh_size);
151 152 sg->sharetab_size -= s->sh_size;
152 153
153 154 gethrestime(&sg->sharetab_mtime);
154 155 atomic_inc_32(&sg->sharetab_generation);
155 156
156 157 break;
157 158 }
158 159
159 160 p = s;
160 161 }
161 162
162 163 rw_exit(&sg->sharetab_lock);
163 164
164 165 if (s == NULL)
165 166 return (ENOENT);
166 167
167 168 s->sh_next = NULL;
168 169 sharefree(s, NULL);
169 170
170 171 /* We need to free the share for the caller */
171 172 sharefree(sh, shl);
172 173
173 174 return (0);
174 175 }
175 176
176 177 /*
177 178 * The caller must have allocated memory for us to use.
178 179 */
179 180 static int
180 181 sharefs_add(sharetab_globals_t *sg, share_t *sh, sharefs_lens_t *shl)
181 182 {
182 183 int iHash;
183 184 sharetab_t *sht;
184 185 share_t *s, *p;
185 186 int iPath;
186 187 int n;
187 188
188 189 if (sh == NULL)
189 190 return (ENOENT);
190 191
191 192 /* We need to find the hash buckets for the fstype */
192 193 rw_enter(&sg->sharetab_lock, RW_WRITER);
193 194 for (sht = sg->sharefs_sharetab; sht != NULL; sht = sht->s_next) {
194 195 if (strcmp(sh->sh_fstype, sht->s_fstype) == 0)
195 196 break;
196 197 }
197 198
198 199 /* Did not exist, so allocate one and add it to the sharetab */
199 200 if (sht == NULL) {
200 201 sht = kmem_zalloc(sizeof (*sht), KM_SLEEP);
201 202 n = strlen(sh->sh_fstype);
202 203 sht->s_fstype = kmem_zalloc(n + 1, KM_SLEEP);
203 204 (void) strncpy(sht->s_fstype, sh->sh_fstype, n);
204 205
205 206 sht->s_next = sg->sharefs_sharetab;
206 207 sg->sharefs_sharetab = sht;
207 208 }
208 209
209 210 /* Now we need to find where we have to add the entry */
210 211 iPath = shl != NULL ? shl->shl_path : strlen(sh->sh_path);
211 212 iHash = pkp_tab_hash(sh->sh_path, strlen(sh->sh_path));
212 213
213 214 if (shl) {
214 215 sh->sh_size = shl->shl_path + shl->shl_res +
215 216 shl->shl_fstype + shl->shl_opts + shl->shl_descr;
216 217 } else {
217 218 sh->sh_size = strlen(sh->sh_path) +
218 219 strlen(sh->sh_res) + strlen(sh->sh_fstype) +
219 220 strlen(sh->sh_opts) + strlen(sh->sh_descr);
220 221 }
221 222
222 223 /* We need to account for field seperators and the EOL */
223 224 sh->sh_size += 5;
224 225
225 226 /* Now walk down the hash table and add the new entry */
226 227 for (p = NULL, s = sht->s_buckets[iHash].ssh_sh;
227 228 s != NULL; s = s->sh_next) {
228 229 /*
229 230 * We need exact matches.
230 231 *
231 232 * We found a matching path. Either we have a
232 233 * duplicate path in a share command or we are
233 234 * being asked to replace an existing entry.
234 235 */
235 236 if (strcmp(sh->sh_path, s->sh_path) == 0 &&
236 237 strlen(s->sh_path) == iPath) {
237 238 if (p != NULL)
238 239 p->sh_next = sh;
239 240 else
240 241 sht->s_buckets[iHash].ssh_sh = sh;
241 242
242 243 sh->sh_next = s->sh_next;
243 244
244 245 ASSERT(sg->sharetab_size >= s->sh_size);
245 246 sg->sharetab_size -= s->sh_size;
246 247 sg->sharetab_size += sh->sh_size;
247 248
248 249 /* Get rid of the old node */
249 250 sharefree(s, NULL);
250 251
251 252 gethrestime(&sg->sharetab_mtime);
252 253 atomic_inc_32(&sg->sharetab_generation);
253 254
254 255 ASSERT(sht->s_buckets[iHash].ssh_count != 0);
255 256 rw_exit(&sg->sharetab_lock);
256 257
257 258 return (0);
258 259 }
259 260
260 261 p = s;
261 262 }
262 263
263 264 /*
264 265 * Okay, we have gone through the entire hash chain and not
265 266 * found a match. We just need to add this node.
266 267 */
267 268 sh->sh_next = sht->s_buckets[iHash].ssh_sh;
268 269 sht->s_buckets[iHash].ssh_sh = sh;
269 270 atomic_inc_32(&sht->s_buckets[iHash].ssh_count);
270 271 atomic_inc_32(&sht->s_count);
271 272 atomic_inc_32(&sg->sharetab_count);
272 273 sg->sharetab_size += sh->sh_size;
273 274
274 275 gethrestime(&sg->sharetab_mtime);
275 276 atomic_inc_32(&sg->sharetab_generation);
276 277
277 278 rw_exit(&sg->sharetab_lock);
278 279
279 280 return (0);
280 281 }
281 282
282 283 /* ARGSUSED */
283 284 static void *
284 285 sharetab_zone_init(zoneid_t zoneid)
285 286 {
286 287 sharetab_globals_t *sg;
287 288
288 289 sg = kmem_zalloc(sizeof (*sg), KM_SLEEP);
289 290
290 291 rw_init(&sg->sharetab_lock, NULL, RW_DEFAULT, NULL);
291 292 rw_init(&sg->sharefs_lock, NULL, RW_DEFAULT, NULL);
292 293
293 294 sg->sharetab_size = 0;
294 295 sg->sharetab_count = 0;
295 296 sg->sharetab_generation = 1;
296 297
297 298 gethrestime(&sg->sharetab_mtime);
298 299 gethrestime(&sg->sharetab_snap_time);
299 300
300 301 return (sg);
301 302 }
|
↓ open down ↓ |
264 lines elided |
↑ open up ↑ |
302 303
303 304 /* ARGSUSED */
304 305 static void
305 306 sharetab_zone_fini(zoneid_t zoneid, void *data)
306 307 {
307 308 sharetab_globals_t *sg = data;
308 309
309 310 rw_destroy(&sg->sharefs_lock);
310 311 rw_destroy(&sg->sharetab_lock);
311 312
313 + /* ALL of the allocated things must be cleaned before we free sg. */
314 + while (sg->sharefs_sharetab != NULL) {
315 + int i;
316 + sharetab_t *freeing = sg->sharefs_sharetab;
317 +
318 + sg->sharefs_sharetab = freeing->s_next;
319 + kmem_free(freeing->s_fstype, strlen(freeing->s_fstype) + 1);
320 + for (i = 0; i < PKP_HASH_SIZE; i++) {
321 + sharefs_hash_head_t *bucket;
322 +
323 + bucket = &(freeing->s_buckets[i]);
324 + while (bucket->ssh_sh != NULL) {
325 + share_t *share = bucket->ssh_sh;
326 +
327 + bucket->ssh_sh = share->sh_next;
328 + sharefree(share, NULL);
329 + }
330 + }
331 + kmem_free(freeing, sizeof (*freeing));
332 + }
333 +
312 334 kmem_free(sg, sizeof (*sg));
313 335 }
314 336
315 337 void
316 338 sharefs_sharetab_init(void)
317 339 {
318 340 zone_key_create(&sharetab_zone_key, sharetab_zone_init,
319 341 NULL, sharetab_zone_fini);
320 342 }
321 343
322 344 sharetab_globals_t *
323 345 sharetab_get_globals(zone_t *zone)
324 346 {
325 347 return (zone_getspecific(sharetab_zone_key, zone));
326 348 }
327 349
328 350 int
329 351 sharefs_impl(enum sharefs_sys_op opcode, share_t *sh_in, uint32_t iMaxLen)
330 352 {
331 353 int error = 0;
332 354 size_t len;
333 355 size_t bufsz;
334 356 share_t *sh;
335 357 sharefs_lens_t shl;
336 358 model_t model;
337 359 char *buf = NULL;
338 360 sharetab_globals_t *sg = sharetab_get_globals(curzone);
339 361
340 362 STRUCT_DECL(share, u_sh);
341 363
342 364 bufsz = iMaxLen;
343 365
344 366 /*
345 367 * Before we do anything, lets make sure we have
346 368 * a sharetab in memory if we need one.
347 369 */
348 370 rw_enter(&sg->sharetab_lock, RW_READER);
349 371 switch (opcode) {
350 372 case SHAREFS_REMOVE:
351 373 case SHAREFS_REPLACE:
352 374 if (!sg->sharefs_sharetab) {
353 375 rw_exit(&sg->sharetab_lock);
354 376 return (set_errno(ENOENT));
355 377 }
356 378 break;
357 379 case SHAREFS_ADD:
358 380 default:
359 381 break;
360 382 }
361 383 rw_exit(&sg->sharetab_lock);
362 384
363 385 model = get_udatamodel();
364 386
365 387 /*
366 388 * Initialize the data pointers.
367 389 */
368 390 STRUCT_INIT(u_sh, model);
369 391 if (copyin(sh_in, STRUCT_BUF(u_sh), STRUCT_SIZE(u_sh)))
370 392 return (set_errno(EFAULT));
371 393
372 394 /* Get the share */
373 395 sh = kmem_zalloc(sizeof (share_t), KM_SLEEP);
374 396
375 397 /* Get some storage for copying in the strings */
376 398 buf = kmem_zalloc(bufsz + 1, KM_SLEEP);
377 399 bzero(&shl, sizeof (sharefs_lens_t));
378 400
379 401 /* Only grab these two until we know what we want */
380 402 SHARETAB_COPYIN(path);
381 403 SHARETAB_COPYIN(fstype);
382 404
383 405 switch (opcode) {
384 406 case SHAREFS_ADD:
385 407 case SHAREFS_REPLACE:
386 408 SHARETAB_COPYIN(res);
387 409 SHARETAB_COPYIN(opts);
388 410 SHARETAB_COPYIN(descr);
389 411 error = sharefs_add(sg, sh, &shl);
390 412 break;
391 413 case SHAREFS_REMOVE:
392 414 error = sharefs_remove(sg, sh, &shl);
393 415 break;
394 416 default:
395 417 error = EINVAL;
396 418 break;
397 419 }
398 420
399 421 cleanup:
400 422 /*
401 423 * If there is no error, then we have stashed the structure
402 424 * away in the sharetab hash table or have deleted it.
403 425 *
404 426 * Either way, the only reason to blow away the data is if
405 427 * there was an error.
406 428 */
407 429 if (error != 0)
408 430 sharefree(sh, &shl);
409 431
410 432 if (buf != NULL)
411 433 kmem_free(buf, bufsz + 1);
412 434
413 435 return (error != 0 ? set_errno(error) : 0);
414 436 }
415 437
416 438 int
417 439 sharefs(enum sharefs_sys_op opcode, share_t *sh_in, uint32_t iMaxLen)
418 440 {
419 441 /*
420 442 * If we're in the global zone PRIV_SYS_CONFIG gives us the
421 443 * priviledges needed to act on sharetab. However if we're in
422 444 * a non-global zone PRIV_SYS_CONFIG is not allowed. To work
423 445 * around this issue PRIV_SYS_NFS is used in this case.
424 446 *
425 447 * TODO: This basically overloads the definition/use of
426 448 * PRIV_SYS_NFS to work around the limitation of PRIV_SYS_CONFIG
427 449 * in a zone. Solaris 11 solved this by implementing a PRIV_SYS_SHARE
428 450 * we should do the same and replace the use of PRIV_SYS_NFS here and
429 451 * in zfs_secpolicy_share.
430 452 */
431 453 if (INGLOBALZONE(curproc)) {
432 454 if (secpolicy_sys_config(CRED(), B_FALSE) != 0)
433 455 return (set_errno(EPERM));
434 456 } else {
435 457 /* behave like zfs_secpolicy_share() */
436 458 if (secpolicy_nfs(CRED()) != 0)
437 459 return (set_errno(EPERM));
438 460
439 461 }
440 462 return (sharefs_impl(opcode, sh_in, iMaxLen));
441 463 }
|
↓ open down ↓ |
120 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX