]>
Commit | Line | Data |
---|---|---|
0fd16957 HG |
1 | // SPDX-License-Identifier: MIT |
2 | /* | |
3 | * VirtualBox Guest Shared Folders support: Virtual File System. | |
4 | * | |
5 | * Module initialization/finalization | |
6 | * File system registration/deregistration | |
7 | * Superblock reading | |
8 | * Few utility functions | |
9 | * | |
10 | * Copyright (C) 2006-2018 Oracle Corporation | |
11 | */ | |
12 | ||
13 | #include <linux/idr.h> | |
14 | #include <linux/fs_parser.h> | |
15 | #include <linux/magic.h> | |
16 | #include <linux/module.h> | |
17 | #include <linux/nls.h> | |
18 | #include <linux/statfs.h> | |
19 | #include <linux/vbox_utils.h> | |
20 | #include "vfsmod.h" | |
21 | ||
22 | #define VBOXSF_SUPER_MAGIC 0x786f4256 /* 'VBox' little endian */ | |
23 | ||
9b3b353e | 24 | static const unsigned char VBSF_MOUNT_SIGNATURE[4] = "\000\377\376\375"; |
0fd16957 HG |
25 | |
26 | static int follow_symlinks; | |
27 | module_param(follow_symlinks, int, 0444); | |
28 | MODULE_PARM_DESC(follow_symlinks, | |
29 | "Let host resolve symlinks rather than showing them"); | |
30 | ||
31 | static DEFINE_IDA(vboxsf_bdi_ida); | |
32 | static DEFINE_MUTEX(vboxsf_setup_mutex); | |
33 | static bool vboxsf_setup_done; | |
34 | static struct super_operations vboxsf_super_ops; /* forward declaration */ | |
35 | static struct kmem_cache *vboxsf_inode_cachep; | |
36 | ||
37 | static char * const vboxsf_default_nls = CONFIG_NLS_DEFAULT; | |
38 | ||
39 | enum { opt_nls, opt_uid, opt_gid, opt_ttl, opt_dmode, opt_fmode, | |
40 | opt_dmask, opt_fmask }; | |
41 | ||
42 | static const struct fs_parameter_spec vboxsf_fs_parameters[] = { | |
43 | fsparam_string ("nls", opt_nls), | |
44 | fsparam_u32 ("uid", opt_uid), | |
45 | fsparam_u32 ("gid", opt_gid), | |
46 | fsparam_u32 ("ttl", opt_ttl), | |
47 | fsparam_u32oct ("dmode", opt_dmode), | |
48 | fsparam_u32oct ("fmode", opt_fmode), | |
49 | fsparam_u32oct ("dmask", opt_dmask), | |
50 | fsparam_u32oct ("fmask", opt_fmask), | |
51 | {} | |
52 | }; | |
53 | ||
54 | static int vboxsf_parse_param(struct fs_context *fc, struct fs_parameter *param) | |
55 | { | |
56 | struct vboxsf_fs_context *ctx = fc->fs_private; | |
57 | struct fs_parse_result result; | |
58 | kuid_t uid; | |
59 | kgid_t gid; | |
60 | int opt; | |
61 | ||
62 | opt = fs_parse(fc, vboxsf_fs_parameters, param, &result); | |
63 | if (opt < 0) | |
64 | return opt; | |
65 | ||
66 | switch (opt) { | |
67 | case opt_nls: | |
68 | if (ctx->nls_name || fc->purpose != FS_CONTEXT_FOR_MOUNT) { | |
69 | vbg_err("vboxsf: Cannot reconfigure nls option\n"); | |
70 | return -EINVAL; | |
71 | } | |
72 | ctx->nls_name = param->string; | |
73 | param->string = NULL; | |
74 | break; | |
75 | case opt_uid: | |
76 | uid = make_kuid(current_user_ns(), result.uint_32); | |
77 | if (!uid_valid(uid)) | |
78 | return -EINVAL; | |
79 | ctx->o.uid = uid; | |
80 | break; | |
81 | case opt_gid: | |
82 | gid = make_kgid(current_user_ns(), result.uint_32); | |
83 | if (!gid_valid(gid)) | |
84 | return -EINVAL; | |
85 | ctx->o.gid = gid; | |
86 | break; | |
87 | case opt_ttl: | |
88 | ctx->o.ttl = msecs_to_jiffies(result.uint_32); | |
89 | break; | |
90 | case opt_dmode: | |
91 | if (result.uint_32 & ~0777) | |
92 | return -EINVAL; | |
93 | ctx->o.dmode = result.uint_32; | |
94 | ctx->o.dmode_set = true; | |
95 | break; | |
96 | case opt_fmode: | |
97 | if (result.uint_32 & ~0777) | |
98 | return -EINVAL; | |
99 | ctx->o.fmode = result.uint_32; | |
100 | ctx->o.fmode_set = true; | |
101 | break; | |
102 | case opt_dmask: | |
103 | if (result.uint_32 & ~07777) | |
104 | return -EINVAL; | |
105 | ctx->o.dmask = result.uint_32; | |
106 | break; | |
107 | case opt_fmask: | |
108 | if (result.uint_32 & ~07777) | |
109 | return -EINVAL; | |
110 | ctx->o.fmask = result.uint_32; | |
111 | break; | |
112 | default: | |
113 | return -EINVAL; | |
114 | } | |
115 | ||
116 | return 0; | |
117 | } | |
118 | ||
119 | static int vboxsf_fill_super(struct super_block *sb, struct fs_context *fc) | |
120 | { | |
121 | struct vboxsf_fs_context *ctx = fc->fs_private; | |
122 | struct shfl_string *folder_name, root_path; | |
123 | struct vboxsf_sbi *sbi; | |
124 | struct dentry *droot; | |
125 | struct inode *iroot; | |
126 | char *nls_name; | |
127 | size_t size; | |
128 | int err; | |
129 | ||
130 | if (!fc->source) | |
131 | return -EINVAL; | |
132 | ||
133 | sbi = kzalloc(sizeof(*sbi), GFP_KERNEL); | |
134 | if (!sbi) | |
135 | return -ENOMEM; | |
136 | ||
137 | sbi->o = ctx->o; | |
138 | idr_init(&sbi->ino_idr); | |
139 | spin_lock_init(&sbi->ino_idr_lock); | |
140 | sbi->next_generation = 1; | |
141 | sbi->bdi_id = -1; | |
142 | ||
143 | /* Load nls if not utf8 */ | |
144 | nls_name = ctx->nls_name ? ctx->nls_name : vboxsf_default_nls; | |
145 | if (strcmp(nls_name, "utf8") != 0) { | |
146 | if (nls_name == vboxsf_default_nls) | |
147 | sbi->nls = load_nls_default(); | |
148 | else | |
149 | sbi->nls = load_nls(nls_name); | |
150 | ||
151 | if (!sbi->nls) { | |
152 | vbg_err("vboxsf: Count not load '%s' nls\n", nls_name); | |
153 | err = -EINVAL; | |
154 | goto fail_free; | |
155 | } | |
156 | } | |
157 | ||
158 | sbi->bdi_id = ida_simple_get(&vboxsf_bdi_ida, 0, 0, GFP_KERNEL); | |
159 | if (sbi->bdi_id < 0) { | |
160 | err = sbi->bdi_id; | |
161 | goto fail_free; | |
162 | } | |
163 | ||
156c7573 | 164 | err = super_setup_bdi_name(sb, "vboxsf-%d", sbi->bdi_id); |
0fd16957 HG |
165 | if (err) |
166 | goto fail_free; | |
55b2598e CH |
167 | sb->s_bdi->ra_pages = 0; |
168 | sb->s_bdi->io_pages = 0; | |
0fd16957 HG |
169 | |
170 | /* Turn source into a shfl_string and map the folder */ | |
171 | size = strlen(fc->source) + 1; | |
172 | folder_name = kmalloc(SHFLSTRING_HEADER_SIZE + size, GFP_KERNEL); | |
173 | if (!folder_name) { | |
174 | err = -ENOMEM; | |
175 | goto fail_free; | |
176 | } | |
177 | folder_name->size = size; | |
178 | folder_name->length = size - 1; | |
179 | strlcpy(folder_name->string.utf8, fc->source, size); | |
180 | err = vboxsf_map_folder(folder_name, &sbi->root); | |
181 | kfree(folder_name); | |
182 | if (err) { | |
183 | vbg_err("vboxsf: Host rejected mount of '%s' with error %d\n", | |
184 | fc->source, err); | |
185 | goto fail_free; | |
186 | } | |
187 | ||
188 | root_path.length = 1; | |
189 | root_path.size = 2; | |
190 | root_path.string.utf8[0] = '/'; | |
191 | root_path.string.utf8[1] = 0; | |
192 | err = vboxsf_stat(sbi, &root_path, &sbi->root_info); | |
193 | if (err) | |
194 | goto fail_unmap; | |
195 | ||
196 | sb->s_magic = VBOXSF_SUPER_MAGIC; | |
197 | sb->s_blocksize = 1024; | |
198 | sb->s_maxbytes = MAX_LFS_FILESIZE; | |
199 | sb->s_op = &vboxsf_super_ops; | |
200 | sb->s_d_op = &vboxsf_dentry_ops; | |
201 | ||
202 | iroot = iget_locked(sb, 0); | |
203 | if (!iroot) { | |
204 | err = -ENOMEM; | |
205 | goto fail_unmap; | |
206 | } | |
e98f93e7 | 207 | vboxsf_init_inode(sbi, iroot, &sbi->root_info, false); |
0fd16957 HG |
208 | unlock_new_inode(iroot); |
209 | ||
210 | droot = d_make_root(iroot); | |
211 | if (!droot) { | |
212 | err = -ENOMEM; | |
213 | goto fail_unmap; | |
214 | } | |
215 | ||
216 | sb->s_root = droot; | |
217 | sb->s_fs_info = sbi; | |
218 | return 0; | |
219 | ||
220 | fail_unmap: | |
221 | vboxsf_unmap_folder(sbi->root); | |
222 | fail_free: | |
223 | if (sbi->bdi_id >= 0) | |
224 | ida_simple_remove(&vboxsf_bdi_ida, sbi->bdi_id); | |
225 | if (sbi->nls) | |
226 | unload_nls(sbi->nls); | |
227 | idr_destroy(&sbi->ino_idr); | |
228 | kfree(sbi); | |
229 | return err; | |
230 | } | |
231 | ||
232 | static void vboxsf_inode_init_once(void *data) | |
233 | { | |
234 | struct vboxsf_inode *sf_i = data; | |
235 | ||
236 | mutex_init(&sf_i->handle_list_mutex); | |
237 | inode_init_once(&sf_i->vfs_inode); | |
238 | } | |
239 | ||
240 | static struct inode *vboxsf_alloc_inode(struct super_block *sb) | |
241 | { | |
242 | struct vboxsf_inode *sf_i; | |
243 | ||
fd60b288 | 244 | sf_i = alloc_inode_sb(sb, vboxsf_inode_cachep, GFP_NOFS); |
0fd16957 HG |
245 | if (!sf_i) |
246 | return NULL; | |
247 | ||
248 | sf_i->force_restat = 0; | |
249 | INIT_LIST_HEAD(&sf_i->handle_list); | |
250 | ||
251 | return &sf_i->vfs_inode; | |
252 | } | |
253 | ||
254 | static void vboxsf_free_inode(struct inode *inode) | |
255 | { | |
256 | struct vboxsf_sbi *sbi = VBOXSF_SBI(inode->i_sb); | |
257 | unsigned long flags; | |
258 | ||
259 | spin_lock_irqsave(&sbi->ino_idr_lock, flags); | |
260 | idr_remove(&sbi->ino_idr, inode->i_ino); | |
261 | spin_unlock_irqrestore(&sbi->ino_idr_lock, flags); | |
262 | kmem_cache_free(vboxsf_inode_cachep, VBOXSF_I(inode)); | |
263 | } | |
264 | ||
265 | static void vboxsf_put_super(struct super_block *sb) | |
266 | { | |
267 | struct vboxsf_sbi *sbi = VBOXSF_SBI(sb); | |
268 | ||
269 | vboxsf_unmap_folder(sbi->root); | |
270 | if (sbi->bdi_id >= 0) | |
271 | ida_simple_remove(&vboxsf_bdi_ida, sbi->bdi_id); | |
272 | if (sbi->nls) | |
273 | unload_nls(sbi->nls); | |
274 | ||
275 | /* | |
276 | * vboxsf_free_inode uses the idr, make sure all delayed rcu free | |
277 | * inodes are flushed. | |
278 | */ | |
279 | rcu_barrier(); | |
280 | idr_destroy(&sbi->ino_idr); | |
281 | kfree(sbi); | |
282 | } | |
283 | ||
284 | static int vboxsf_statfs(struct dentry *dentry, struct kstatfs *stat) | |
285 | { | |
286 | struct super_block *sb = dentry->d_sb; | |
287 | struct shfl_volinfo shfl_volinfo; | |
288 | struct vboxsf_sbi *sbi; | |
289 | u32 buf_len; | |
290 | int err; | |
291 | ||
292 | sbi = VBOXSF_SBI(sb); | |
293 | buf_len = sizeof(shfl_volinfo); | |
294 | err = vboxsf_fsinfo(sbi->root, 0, SHFL_INFO_GET | SHFL_INFO_VOLUME, | |
295 | &buf_len, &shfl_volinfo); | |
296 | if (err) | |
297 | return err; | |
298 | ||
299 | stat->f_type = VBOXSF_SUPER_MAGIC; | |
300 | stat->f_bsize = shfl_volinfo.bytes_per_allocation_unit; | |
301 | ||
302 | do_div(shfl_volinfo.total_allocation_bytes, | |
303 | shfl_volinfo.bytes_per_allocation_unit); | |
304 | stat->f_blocks = shfl_volinfo.total_allocation_bytes; | |
305 | ||
306 | do_div(shfl_volinfo.available_allocation_bytes, | |
307 | shfl_volinfo.bytes_per_allocation_unit); | |
308 | stat->f_bfree = shfl_volinfo.available_allocation_bytes; | |
309 | stat->f_bavail = shfl_volinfo.available_allocation_bytes; | |
310 | ||
311 | stat->f_files = 1000; | |
312 | /* | |
313 | * Don't return 0 here since the guest may then think that it is not | |
314 | * possible to create any more files. | |
315 | */ | |
316 | stat->f_ffree = 1000000; | |
317 | stat->f_fsid.val[0] = 0; | |
318 | stat->f_fsid.val[1] = 0; | |
319 | stat->f_namelen = 255; | |
320 | return 0; | |
321 | } | |
322 | ||
323 | static struct super_operations vboxsf_super_ops = { | |
324 | .alloc_inode = vboxsf_alloc_inode, | |
325 | .free_inode = vboxsf_free_inode, | |
326 | .put_super = vboxsf_put_super, | |
327 | .statfs = vboxsf_statfs, | |
328 | }; | |
329 | ||
330 | static int vboxsf_setup(void) | |
331 | { | |
332 | int err; | |
333 | ||
334 | mutex_lock(&vboxsf_setup_mutex); | |
335 | ||
336 | if (vboxsf_setup_done) | |
337 | goto success; | |
338 | ||
339 | vboxsf_inode_cachep = | |
340 | kmem_cache_create("vboxsf_inode_cache", | |
341 | sizeof(struct vboxsf_inode), 0, | |
342 | (SLAB_RECLAIM_ACCOUNT | SLAB_MEM_SPREAD | | |
343 | SLAB_ACCOUNT), | |
344 | vboxsf_inode_init_once); | |
345 | if (!vboxsf_inode_cachep) { | |
346 | err = -ENOMEM; | |
347 | goto fail_nomem; | |
348 | } | |
349 | ||
350 | err = vboxsf_connect(); | |
351 | if (err) { | |
352 | vbg_err("vboxsf: err %d connecting to guest PCI-device\n", err); | |
353 | vbg_err("vboxsf: make sure you are inside a VirtualBox VM\n"); | |
354 | vbg_err("vboxsf: and check dmesg for vboxguest errors\n"); | |
355 | goto fail_free_cache; | |
356 | } | |
357 | ||
358 | err = vboxsf_set_utf8(); | |
359 | if (err) { | |
360 | vbg_err("vboxsf_setutf8 error %d\n", err); | |
361 | goto fail_disconnect; | |
362 | } | |
363 | ||
364 | if (!follow_symlinks) { | |
365 | err = vboxsf_set_symlinks(); | |
366 | if (err) | |
367 | vbg_warn("vboxsf: Unable to show symlinks: %d\n", err); | |
368 | } | |
369 | ||
370 | vboxsf_setup_done = true; | |
371 | success: | |
372 | mutex_unlock(&vboxsf_setup_mutex); | |
373 | return 0; | |
374 | ||
375 | fail_disconnect: | |
376 | vboxsf_disconnect(); | |
377 | fail_free_cache: | |
378 | kmem_cache_destroy(vboxsf_inode_cachep); | |
379 | fail_nomem: | |
380 | mutex_unlock(&vboxsf_setup_mutex); | |
381 | return err; | |
382 | } | |
383 | ||
384 | static int vboxsf_parse_monolithic(struct fs_context *fc, void *data) | |
385 | { | |
9b3b353e | 386 | if (data && !memcmp(data, VBSF_MOUNT_SIGNATURE, 4)) { |
0fd16957 HG |
387 | vbg_err("vboxsf: Old binary mount data not supported, remove obsolete mount.vboxsf and/or update your VBoxService.\n"); |
388 | return -EINVAL; | |
389 | } | |
390 | ||
391 | return generic_parse_monolithic(fc, data); | |
392 | } | |
393 | ||
394 | static int vboxsf_get_tree(struct fs_context *fc) | |
395 | { | |
396 | int err; | |
397 | ||
398 | err = vboxsf_setup(); | |
399 | if (err) | |
400 | return err; | |
401 | ||
402 | return get_tree_nodev(fc, vboxsf_fill_super); | |
403 | } | |
404 | ||
405 | static int vboxsf_reconfigure(struct fs_context *fc) | |
406 | { | |
407 | struct vboxsf_sbi *sbi = VBOXSF_SBI(fc->root->d_sb); | |
408 | struct vboxsf_fs_context *ctx = fc->fs_private; | |
409 | struct inode *iroot = fc->root->d_sb->s_root->d_inode; | |
410 | ||
411 | /* Apply changed options to the root inode */ | |
412 | sbi->o = ctx->o; | |
e98f93e7 | 413 | vboxsf_init_inode(sbi, iroot, &sbi->root_info, true); |
0fd16957 HG |
414 | |
415 | return 0; | |
416 | } | |
417 | ||
418 | static void vboxsf_free_fc(struct fs_context *fc) | |
419 | { | |
420 | struct vboxsf_fs_context *ctx = fc->fs_private; | |
421 | ||
422 | kfree(ctx->nls_name); | |
423 | kfree(ctx); | |
424 | } | |
425 | ||
426 | static const struct fs_context_operations vboxsf_context_ops = { | |
427 | .free = vboxsf_free_fc, | |
428 | .parse_param = vboxsf_parse_param, | |
429 | .parse_monolithic = vboxsf_parse_monolithic, | |
430 | .get_tree = vboxsf_get_tree, | |
431 | .reconfigure = vboxsf_reconfigure, | |
432 | }; | |
433 | ||
434 | static int vboxsf_init_fs_context(struct fs_context *fc) | |
435 | { | |
436 | struct vboxsf_fs_context *ctx; | |
437 | ||
438 | ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); | |
439 | if (!ctx) | |
440 | return -ENOMEM; | |
441 | ||
442 | current_uid_gid(&ctx->o.uid, &ctx->o.gid); | |
443 | ||
444 | fc->fs_private = ctx; | |
445 | fc->ops = &vboxsf_context_ops; | |
446 | return 0; | |
447 | } | |
448 | ||
449 | static struct file_system_type vboxsf_fs_type = { | |
450 | .owner = THIS_MODULE, | |
451 | .name = "vboxsf", | |
452 | .init_fs_context = vboxsf_init_fs_context, | |
453 | .kill_sb = kill_anon_super | |
454 | }; | |
455 | ||
456 | /* Module initialization/finalization handlers */ | |
457 | static int __init vboxsf_init(void) | |
458 | { | |
459 | return register_filesystem(&vboxsf_fs_type); | |
460 | } | |
461 | ||
462 | static void __exit vboxsf_fini(void) | |
463 | { | |
464 | unregister_filesystem(&vboxsf_fs_type); | |
465 | ||
466 | mutex_lock(&vboxsf_setup_mutex); | |
467 | if (vboxsf_setup_done) { | |
468 | vboxsf_disconnect(); | |
469 | /* | |
470 | * Make sure all delayed rcu free inodes are flushed | |
471 | * before we destroy the cache. | |
472 | */ | |
473 | rcu_barrier(); | |
474 | kmem_cache_destroy(vboxsf_inode_cachep); | |
475 | } | |
476 | mutex_unlock(&vboxsf_setup_mutex); | |
477 | } | |
478 | ||
479 | module_init(vboxsf_init); | |
480 | module_exit(vboxsf_fini); | |
481 | ||
482 | MODULE_DESCRIPTION("Oracle VM VirtualBox Module for Host File System Access"); | |
483 | MODULE_AUTHOR("Oracle Corporation"); | |
484 | MODULE_LICENSE("GPL v2"); | |
485 | MODULE_ALIAS_FS("vboxsf"); |