Blame view
fs/autofs4/dev-ioctl.c
18.1 KB
8d7b48e0b autofs4: add misc... |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
/* * Copyright 2008 Red Hat, Inc. All rights reserved. * Copyright 2008 Ian Kent <raven@themaw.net> * * This file is part of the Linux kernel and is made available under * the terms of the GNU General Public License, version 2, or at your * option, any later version, incorporated herein by reference. */ #include <linux/module.h> #include <linux/vmalloc.h> #include <linux/miscdevice.h> #include <linux/init.h> #include <linux/wait.h> #include <linux/namei.h> #include <linux/fcntl.h> #include <linux/file.h> #include <linux/fdtable.h> #include <linux/sched.h> |
5b825c3af sched/headers: Pr... |
20 |
#include <linux/cred.h> |
8d7b48e0b autofs4: add misc... |
21 22 |
#include <linux/compat.h> #include <linux/syscalls.h> |
8d7b48e0b autofs4: add misc... |
23 24 25 |
#include <linux/magic.h> #include <linux/dcache.h> #include <linux/uaccess.h> |
5a0e3ad6a include cleanup: ... |
26 |
#include <linux/slab.h> |
8d7b48e0b autofs4: add misc... |
27 28 29 30 31 32 33 34 35 36 37 38 39 40 |
#include "autofs_i.h" /* * This module implements an interface for routing autofs ioctl control * commands via a miscellaneous device file. * * The alternate interface is needed because we need to be able open * an ioctl file descriptor on an autofs mount that may be covered by * another mount. This situation arises when starting automount(8) * or other user space daemon which uses direct mounts or offset * mounts (used for autofs lazy mount/umount of nested mount trees), * which have been left busy at at service shutdown. */ |
8d7b48e0b autofs4: add misc... |
41 42 43 44 45 46 47 48 49 50 51 52 53 54 |
typedef int (*ioctl_fn)(struct file *, struct autofs_sb_info *, struct autofs_dev_ioctl *); static int check_name(const char *name) { if (!strchr(name, '/')) return -EINVAL; return 0; } /* * Check a string doesn't overrun the chunk of * memory we copied from user land. */ |
3eac8778a autofs4: use memc... |
55 |
static int invalid_str(char *str, size_t size) |
8d7b48e0b autofs4: add misc... |
56 |
{ |
3eac8778a autofs4: use memc... |
57 58 |
if (memchr(str, 0, size)) return 0; |
8d7b48e0b autofs4: add misc... |
59 60 61 62 63 64 65 66 67 68 69 70 71 |
return -EINVAL; } /* * Check that the user compiled against correct version of autofs * misc device code. * * As well as checking the version compatibility this always copies * the kernel interface version out. */ static int check_dev_ioctl_version(int cmd, struct autofs_dev_ioctl *param) { int err = 0; |
e9a7c2f1a autofs4: coding s... |
72 73 |
if ((param->ver_major != AUTOFS_DEV_IOCTL_VERSION_MAJOR) || (param->ver_minor > AUTOFS_DEV_IOCTL_VERSION_MINOR)) { |
8a78d5930 autofs4: use pr_x... |
74 |
pr_warn("ioctl control interface version mismatch: " |
390855547 autofs: fix print... |
75 76 |
"kernel(%u.%u), user(%u.%u), cmd(0x%08x) ", |
8a78d5930 autofs4: use pr_x... |
77 78 79 |
AUTOFS_DEV_IOCTL_VERSION_MAJOR, AUTOFS_DEV_IOCTL_VERSION_MINOR, param->ver_major, param->ver_minor, cmd); |
8d7b48e0b autofs4: add misc... |
80 81 82 83 84 85 86 87 88 89 90 91 92 93 |
err = -EINVAL; } /* Fill in the kernel version. */ param->ver_major = AUTOFS_DEV_IOCTL_VERSION_MAJOR; param->ver_minor = AUTOFS_DEV_IOCTL_VERSION_MINOR; return err; } /* * Copy parameter control struct, including a possible path allocated * at the end of the struct. */ |
e9a7c2f1a autofs4: coding s... |
94 |
static struct autofs_dev_ioctl * |
b9fa2ad1e autofs: use unsig... |
95 |
copy_dev_ioctl(struct autofs_dev_ioctl __user *in) |
8d7b48e0b autofs4: add misc... |
96 |
{ |
0a280962d autofs4 copy_dev_... |
97 |
struct autofs_dev_ioctl tmp, *res; |
8d7b48e0b autofs4: add misc... |
98 |
|
718b303b4 autofs: use AUTOF... |
99 |
if (copy_from_user(&tmp, in, AUTOFS_DEV_IOCTL_SIZE)) |
8d7b48e0b autofs4: add misc... |
100 |
return ERR_PTR(-EFAULT); |
718b303b4 autofs: use AUTOF... |
101 |
if (tmp.size < AUTOFS_DEV_IOCTL_SIZE) |
8d7b48e0b autofs4: add misc... |
102 |
return ERR_PTR(-EINVAL); |
718b303b4 autofs: use AUTOF... |
103 |
if (tmp.size > AUTOFS_DEV_IOCTL_SIZE + PATH_MAX) |
e53d77eb8 autofs4: check de... |
104 |
return ERR_PTR(-ENAMETOOLONG); |
0a280962d autofs4 copy_dev_... |
105 106 107 108 109 |
res = memdup_user(in, tmp.size); if (!IS_ERR(res)) res->size = tmp.size; return res; |
8d7b48e0b autofs4: add misc... |
110 111 112 113 114 |
} static inline void free_dev_ioctl(struct autofs_dev_ioctl *param) { kfree(param); |
8d7b48e0b autofs4: add misc... |
115 116 117 118 |
} /* * Check sanity of parameter control fields and if a path is present |
bae8ec665 autofs4: fix stri... |
119 |
* check that it is terminated and contains at least one "/". |
8d7b48e0b autofs4: add misc... |
120 121 122 |
*/ static int validate_dev_ioctl(int cmd, struct autofs_dev_ioctl *param) { |
96b031790 autofs4: collect ... |
123 |
int err; |
8d7b48e0b autofs4: add misc... |
124 |
|
96b031790 autofs4: collect ... |
125 126 |
err = check_dev_ioctl_version(cmd, param); if (err) { |
8a78d5930 autofs4: use pr_x... |
127 128 129 |
pr_warn("invalid device control module version " "supplied for cmd(0x%08x) ", cmd); |
8d7b48e0b autofs4: add misc... |
130 131 |
goto out; } |
718b303b4 autofs: use AUTOF... |
132 133 |
if (param->size > AUTOFS_DEV_IOCTL_SIZE) { err = invalid_str(param->path, param->size - AUTOFS_DEV_IOCTL_SIZE); |
8d7b48e0b autofs4: add misc... |
134 |
if (err) { |
8a78d5930 autofs4: use pr_x... |
135 |
pr_warn( |
90967c87e autofs4: change l... |
136 137 |
"path string terminator missing for cmd(0x%08x) ", |
bae8ec665 autofs4: fix stri... |
138 |
cmd); |
8d7b48e0b autofs4: add misc... |
139 140 |
goto out; } |
bae8ec665 autofs4: fix stri... |
141 |
err = check_name(param->path); |
8d7b48e0b autofs4: add misc... |
142 |
if (err) { |
8a78d5930 autofs4: use pr_x... |
143 144 145 |
pr_warn("invalid path supplied for cmd(0x%08x) ", cmd); |
8d7b48e0b autofs4: add misc... |
146 147 |
goto out; } |
00235ab80 autofs: fix slab ... |
148 149 150 151 152 153 154 155 156 |
} else { unsigned int inr = _IOC_NR(cmd); if (inr == AUTOFS_DEV_IOCTL_OPENMOUNT_CMD || inr == AUTOFS_DEV_IOCTL_REQUESTER_CMD || inr == AUTOFS_DEV_IOCTL_ISMOUNTPOINT_CMD) { err = -EINVAL; goto out; } |
8d7b48e0b autofs4: add misc... |
157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 |
} err = 0; out: return err; } /* * Get the autofs super block info struct from the file opened on * the autofs mount point. */ static struct autofs_sb_info *autofs_dev_ioctl_sbi(struct file *f) { struct autofs_sb_info *sbi = NULL; struct inode *inode; if (f) { |
496ad9aa8 new helper: file_... |
174 |
inode = file_inode(f); |
8d7b48e0b autofs4: add misc... |
175 176 177 178 |
sbi = autofs4_sbi(inode->i_sb); } return sbi; } |
d9e192320 autofs: add autof... |
179 180 181 182 183 184 185 186 187 188 |
/* Return autofs dev ioctl version */ static int autofs_dev_ioctl_version(struct file *fp, struct autofs_sb_info *sbi, struct autofs_dev_ioctl *param) { /* This should have already been set. */ param->ver_major = AUTOFS_DEV_IOCTL_VERSION_MAJOR; param->ver_minor = AUTOFS_DEV_IOCTL_VERSION_MINOR; return 0; } |
8d7b48e0b autofs4: add misc... |
189 190 191 192 193 |
/* Return autofs module protocol version */ static int autofs_dev_ioctl_protover(struct file *fp, struct autofs_sb_info *sbi, struct autofs_dev_ioctl *param) { |
730c9eeca autofs4: improve ... |
194 |
param->protover.version = sbi->version; |
8d7b48e0b autofs4: add misc... |
195 196 197 198 199 200 201 202 |
return 0; } /* Return autofs module protocol sub version */ static int autofs_dev_ioctl_protosubver(struct file *fp, struct autofs_sb_info *sbi, struct autofs_dev_ioctl *param) { |
730c9eeca autofs4: improve ... |
203 |
param->protosubver.sub_version = sbi->sub_version; |
8d7b48e0b autofs4: add misc... |
204 205 |
return 0; } |
ac8387199 autofs4 - fix dev... |
206 |
/* Find the topmost mount satisfying test() */ |
4e44b6852 Get rid of path_l... |
207 208 |
static int find_autofs_mount(const char *pathname, struct path *res, |
5b5577e4e autofs: constify ... |
209 |
int test(const struct path *path, void *data), |
4e44b6852 Get rid of path_l... |
210 |
void *data) |
8d7b48e0b autofs4: add misc... |
211 |
{ |
4e44b6852 Get rid of path_l... |
212 |
struct path path; |
e9a7c2f1a autofs4: coding s... |
213 214 215 |
int err; err = kern_path_mountpoint(AT_FDCWD, pathname, &path, 0); |
4e44b6852 Get rid of path_l... |
216 217 |
if (err) return err; |
8d7b48e0b autofs4: add misc... |
218 |
err = -ENOENT; |
4e44b6852 Get rid of path_l... |
219 |
while (path.dentry == path.mnt->mnt_root) { |
d8c9584ea vfs: prefer ->den... |
220 |
if (path.dentry->d_sb->s_magic == AUTOFS_SUPER_MAGIC) { |
4e44b6852 Get rid of path_l... |
221 222 |
if (test(&path, data)) { path_get(&path); |
4e44b6852 Get rid of path_l... |
223 |
*res = path; |
8d7b48e0b autofs4: add misc... |
224 |
err = 0; |
ac8387199 autofs4 - fix dev... |
225 |
break; |
8d7b48e0b autofs4: add misc... |
226 227 |
} } |
bab77ebf5 switch follow_up(... |
228 |
if (!follow_up(&path)) |
4e44b6852 Get rid of path_l... |
229 |
break; |
8d7b48e0b autofs4: add misc... |
230 |
} |
4e44b6852 Get rid of path_l... |
231 |
path_put(&path); |
8d7b48e0b autofs4: add misc... |
232 233 |
return err; } |
5b5577e4e autofs: constify ... |
234 |
static int test_by_dev(const struct path *path, void *p) |
8d7b48e0b autofs4: add misc... |
235 |
{ |
d8c9584ea vfs: prefer ->den... |
236 |
return path->dentry->d_sb->s_dev == *(dev_t *)p; |
4e44b6852 Get rid of path_l... |
237 |
} |
8d7b48e0b autofs4: add misc... |
238 |
|
5b5577e4e autofs: constify ... |
239 |
static int test_by_type(const struct path *path, void *p) |
4e44b6852 Get rid of path_l... |
240 241 |
{ struct autofs_info *ino = autofs4_dentry_ino(path->dentry); |
e9a7c2f1a autofs4: coding s... |
242 |
|
4e44b6852 Get rid of path_l... |
243 |
return ino && ino->sbi->type & *(unsigned *)p; |
8d7b48e0b autofs4: add misc... |
244 |
} |
8d7b48e0b autofs4: add misc... |
245 246 247 248 |
/* * Open a file descriptor on the autofs mount point corresponding * to the given path and device number (aka. new_encode_dev(sb->s_dev)). */ |
4e44b6852 Get rid of path_l... |
249 |
static int autofs_dev_ioctl_open_mountpoint(const char *name, dev_t devid) |
8d7b48e0b autofs4: add misc... |
250 |
{ |
8d7b48e0b autofs4: add misc... |
251 |
int err, fd; |
c921b40d6 autofs4: don't op... |
252 |
fd = get_unused_fd_flags(O_CLOEXEC); |
8d7b48e0b autofs4: add misc... |
253 |
if (likely(fd >= 0)) { |
4e44b6852 Get rid of path_l... |
254 255 256 257 |
struct file *filp; struct path path; err = find_autofs_mount(name, &path, test_by_dev, &devid); |
8d7b48e0b autofs4: add misc... |
258 259 |
if (err) goto out; |
765927b2d switch dentry_ope... |
260 261 |
filp = dentry_open(&path, O_RDONLY, current_cred()); path_put(&path); |
8d7b48e0b autofs4: add misc... |
262 263 264 265 |
if (IS_ERR(filp)) { err = PTR_ERR(filp); goto out; } |
c921b40d6 autofs4: don't op... |
266 |
fd_install(fd, filp); |
8d7b48e0b autofs4: add misc... |
267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 |
} return fd; out: put_unused_fd(fd); return err; } /* Open a file descriptor on an autofs mount point */ static int autofs_dev_ioctl_openmount(struct file *fp, struct autofs_sb_info *sbi, struct autofs_dev_ioctl *param) { const char *path; dev_t devid; int err, fd; |
00235ab80 autofs: fix slab ... |
284 |
/* param->path has been checked in validate_dev_ioctl() */ |
730c9eeca autofs4: improve ... |
285 |
if (!param->openmount.devid) |
8d7b48e0b autofs4: add misc... |
286 287 288 289 290 |
return -EINVAL; param->ioctlfd = -1; path = param->path; |
4e44b6852 Get rid of path_l... |
291 |
devid = new_decode_dev(param->openmount.devid); |
8d7b48e0b autofs4: add misc... |
292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 |
err = 0; fd = autofs_dev_ioctl_open_mountpoint(path, devid); if (unlikely(fd < 0)) { err = fd; goto out; } param->ioctlfd = fd; out: return err; } /* Close file descriptor allocated above (user can also use close(2)). */ static int autofs_dev_ioctl_closemount(struct file *fp, struct autofs_sb_info *sbi, struct autofs_dev_ioctl *param) { return sys_close(param->ioctlfd); } /* * Send "ready" status for an existing wait (either a mount or an expire * request). */ static int autofs_dev_ioctl_ready(struct file *fp, struct autofs_sb_info *sbi, struct autofs_dev_ioctl *param) { autofs_wqt_t token; |
730c9eeca autofs4: improve ... |
322 |
token = (autofs_wqt_t) param->ready.token; |
8d7b48e0b autofs4: add misc... |
323 324 325 326 327 328 329 330 331 332 333 334 335 |
return autofs4_wait_release(sbi, token, 0); } /* * Send "fail" status for an existing wait (either a mount or an expire * request). */ static int autofs_dev_ioctl_fail(struct file *fp, struct autofs_sb_info *sbi, struct autofs_dev_ioctl *param) { autofs_wqt_t token; int status; |
730c9eeca autofs4: improve ... |
336 |
token = (autofs_wqt_t) param->fail.token; |
9fa4eb8e4 autofs: sanity ch... |
337 |
status = param->fail.status < 0 ? param->fail.status : -ENOENT; |
8d7b48e0b autofs4: add misc... |
338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 |
return autofs4_wait_release(sbi, token, status); } /* * Set the pipe fd for kernel communication to the daemon. * * Normally this is set at mount using an option but if we * are reconnecting to a busy mount then we need to use this * to tell the autofs mount about the new kernel pipe fd. In * order to protect mounts against incorrectly setting the * pipefd we also require that the autofs mount be catatonic. * * This also sets the process group id used to identify the * controlling process (eg. the owning automount(8) daemon). */ static int autofs_dev_ioctl_setpipefd(struct file *fp, struct autofs_sb_info *sbi, struct autofs_dev_ioctl *param) { int pipefd; int err = 0; |
6eaba35b4 autofs4: allow au... |
359 |
struct pid *new_pid = NULL; |
8d7b48e0b autofs4: add misc... |
360 |
|
730c9eeca autofs4: improve ... |
361 |
if (param->setpipefd.pipefd == -1) |
8d7b48e0b autofs4: add misc... |
362 |
return -EINVAL; |
730c9eeca autofs4: improve ... |
363 |
pipefd = param->setpipefd.pipefd; |
8d7b48e0b autofs4: add misc... |
364 365 366 367 368 369 |
mutex_lock(&sbi->wq_mutex); if (!sbi->catatonic) { mutex_unlock(&sbi->wq_mutex); return -EBUSY; } else { |
6eaba35b4 autofs4: allow au... |
370 371 372 373 374 |
struct file *pipe; new_pid = get_task_pid(current, PIDTYPE_PGID); if (ns_of_pid(new_pid) != ns_of_pid(sbi->oz_pgrp)) { |
8a78d5930 autofs4: use pr_x... |
375 376 |
pr_warn("not allowed to change PID namespace "); |
6eaba35b4 autofs4: allow au... |
377 378 379 380 381 |
err = -EINVAL; goto out; } pipe = fget(pipefd); |
3dc8fe4dc autofs4: Do not p... |
382 383 384 385 |
if (!pipe) { err = -EBADF; goto out; } |
64f371bc3 autofs: make the ... |
386 |
if (autofs_prepare_pipe(pipe) < 0) { |
8d7b48e0b autofs4: add misc... |
387 388 389 390 |
err = -EPIPE; fput(pipe); goto out; } |
6eaba35b4 autofs4: allow au... |
391 |
swap(sbi->oz_pgrp, new_pid); |
8d7b48e0b autofs4: add misc... |
392 393 394 395 396 |
sbi->pipefd = pipefd; sbi->pipe = pipe; sbi->catatonic = 0; } out: |
6eaba35b4 autofs4: allow au... |
397 |
put_pid(new_pid); |
8d7b48e0b autofs4: add misc... |
398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 |
mutex_unlock(&sbi->wq_mutex); return err; } /* * Make the autofs mount point catatonic, no longer responsive to * mount requests. Also closes the kernel pipe file descriptor. */ static int autofs_dev_ioctl_catatonic(struct file *fp, struct autofs_sb_info *sbi, struct autofs_dev_ioctl *param) { autofs4_catatonic_mode(sbi); return 0; } /* Set the autofs mount timeout */ static int autofs_dev_ioctl_timeout(struct file *fp, struct autofs_sb_info *sbi, struct autofs_dev_ioctl *param) { unsigned long timeout; |
730c9eeca autofs4: improve ... |
420 421 |
timeout = param->timeout.timeout; param->timeout.timeout = sbi->exp_timeout / HZ; |
8d7b48e0b autofs4: add misc... |
422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 |
sbi->exp_timeout = timeout * HZ; return 0; } /* * Return the uid and gid of the last request for the mount * * When reconstructing an autofs mount tree with active mounts * we need to re-connect to mounts that may have used the original * process uid and gid (or string variations of them) for mount * lookups within the map entry. */ static int autofs_dev_ioctl_requester(struct file *fp, struct autofs_sb_info *sbi, struct autofs_dev_ioctl *param) { struct autofs_info *ino; |
4e44b6852 Get rid of path_l... |
439 |
struct path path; |
8d7b48e0b autofs4: add misc... |
440 441 |
dev_t devid; int err = -ENOENT; |
00235ab80 autofs: fix slab ... |
442 |
/* param->path has been checked in validate_dev_ioctl() */ |
8d7b48e0b autofs4: add misc... |
443 |
|
4e44b6852 Get rid of path_l... |
444 |
devid = sbi->sb->s_dev; |
8d7b48e0b autofs4: add misc... |
445 |
|
730c9eeca autofs4: improve ... |
446 |
param->requester.uid = param->requester.gid = -1; |
8d7b48e0b autofs4: add misc... |
447 |
|
4e44b6852 Get rid of path_l... |
448 |
err = find_autofs_mount(param->path, &path, test_by_dev, &devid); |
8d7b48e0b autofs4: add misc... |
449 450 |
if (err) goto out; |
4e44b6852 Get rid of path_l... |
451 |
ino = autofs4_dentry_ino(path.dentry); |
8d7b48e0b autofs4: add misc... |
452 453 |
if (ino) { err = 0; |
74f504cff autofs: change au... |
454 |
autofs4_expire_wait(&path, 0); |
8d7b48e0b autofs4: add misc... |
455 |
spin_lock(&sbi->fs_lock); |
e9a7c2f1a autofs4: coding s... |
456 457 458 459 |
param->requester.uid = from_kuid_munged(current_user_ns(), ino->uid); param->requester.gid = from_kgid_munged(current_user_ns(), ino->gid); |
8d7b48e0b autofs4: add misc... |
460 461 |
spin_unlock(&sbi->fs_lock); } |
4e44b6852 Get rid of path_l... |
462 |
path_put(&path); |
8d7b48e0b autofs4: add misc... |
463 464 465 466 467 468 469 470 471 472 473 474 |
out: return err; } /* * Call repeatedly until it returns -EAGAIN, meaning there's nothing * more that can be done. */ static int autofs_dev_ioctl_expire(struct file *fp, struct autofs_sb_info *sbi, struct autofs_dev_ioctl *param) { |
8d7b48e0b autofs4: add misc... |
475 |
struct vfsmount *mnt; |
8d7b48e0b autofs4: add misc... |
476 |
int how; |
730c9eeca autofs4: improve ... |
477 |
how = param->expire.how; |
8d7b48e0b autofs4: add misc... |
478 |
mnt = fp->f_path.mnt; |
56fcef751 autofs4: cleanup ... |
479 |
return autofs4_do_expire_multi(sbi->sb, mnt, sbi, how); |
8d7b48e0b autofs4: add misc... |
480 481 482 483 484 485 486 |
} /* Check if autofs mount point is in use */ static int autofs_dev_ioctl_askumount(struct file *fp, struct autofs_sb_info *sbi, struct autofs_dev_ioctl *param) { |
730c9eeca autofs4: improve ... |
487 |
param->askumount.may_umount = 0; |
8d7b48e0b autofs4: add misc... |
488 |
if (may_umount(fp->f_path.mnt)) |
730c9eeca autofs4: improve ... |
489 |
param->askumount.may_umount = 1; |
8d7b48e0b autofs4: add misc... |
490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 |
return 0; } /* * Check if the given path is a mountpoint. * * If we are supplied with the file descriptor of an autofs * mount we're looking for a specific mount. In this case * the path is considered a mountpoint if it is itself a * mountpoint or contains a mount, such as a multi-mount * without a root mount. In this case we return 1 if the * path is a mount point and the super magic of the covering * mount if there is one or 0 if it isn't a mountpoint. * * If we aren't supplied with a file descriptor then we |
ac8387199 autofs4 - fix dev... |
505 506 507 508 509 |
* lookup the path and check if it is the root of a mount. * If a type is given we are looking for a particular autofs * mount and if we don't find a match we return fail. If the * located path is the root of a mount we return 1 along with * the super magic of the mount or 0 otherwise. |
8d7b48e0b autofs4: add misc... |
510 511 512 513 514 515 516 517 |
* * In both cases the the device number (as returned by * new_encode_dev()) is also returned. */ static int autofs_dev_ioctl_ismountpoint(struct file *fp, struct autofs_sb_info *sbi, struct autofs_dev_ioctl *param) { |
4e44b6852 Get rid of path_l... |
518 519 |
struct path path; const char *name; |
8d7b48e0b autofs4: add misc... |
520 |
unsigned int type; |
730c9eeca autofs4: improve ... |
521 |
unsigned int devid, magic; |
8d7b48e0b autofs4: add misc... |
522 |
int err = -ENOENT; |
00235ab80 autofs: fix slab ... |
523 |
/* param->path has been checked in validate_dev_ioctl() */ |
8d7b48e0b autofs4: add misc... |
524 |
|
4e44b6852 Get rid of path_l... |
525 |
name = param->path; |
730c9eeca autofs4: improve ... |
526 |
type = param->ismountpoint.in.type; |
8d7b48e0b autofs4: add misc... |
527 |
|
730c9eeca autofs4: improve ... |
528 529 |
param->ismountpoint.out.devid = devid = 0; param->ismountpoint.out.magic = magic = 0; |
8d7b48e0b autofs4: add misc... |
530 531 |
if (!fp || param->ioctlfd == -1) { |
4e44b6852 Get rid of path_l... |
532 |
if (autofs_type_any(type)) |
ac8387199 autofs4 - fix dev... |
533 534 |
err = kern_path_mountpoint(AT_FDCWD, name, &path, LOOKUP_FOLLOW); |
4e44b6852 Get rid of path_l... |
535 |
else |
ac8387199 autofs4 - fix dev... |
536 537 |
err = find_autofs_mount(name, &path, test_by_type, &type); |
4e44b6852 Get rid of path_l... |
538 539 |
if (err) goto out; |
d8c9584ea vfs: prefer ->den... |
540 |
devid = new_encode_dev(path.dentry->d_sb->s_dev); |
8d7b48e0b autofs4: add misc... |
541 |
err = 0; |
f598f9f12 Sanitize autofs_d... |
542 |
if (path.mnt->mnt_root == path.dentry) { |
8d7b48e0b autofs4: add misc... |
543 |
err = 1; |
d8c9584ea vfs: prefer ->den... |
544 |
magic = path.dentry->d_sb->s_magic; |
8d7b48e0b autofs4: add misc... |
545 546 |
} } else { |
4e44b6852 Get rid of path_l... |
547 |
dev_t dev = sbi->sb->s_dev; |
8d7b48e0b autofs4: add misc... |
548 |
|
4e44b6852 Get rid of path_l... |
549 |
err = find_autofs_mount(name, &path, test_by_dev, &dev); |
8d7b48e0b autofs4: add misc... |
550 551 |
if (err) goto out; |
4e44b6852 Get rid of path_l... |
552 |
devid = new_encode_dev(dev); |
8d7b48e0b autofs4: add misc... |
553 |
|
603597414 autofs: use path_... |
554 |
err = path_has_submounts(&path); |
8d7b48e0b autofs4: add misc... |
555 |
|
cc53ce53c Add a dentry op t... |
556 |
if (follow_down_one(&path)) |
d8c9584ea vfs: prefer ->den... |
557 |
magic = path.dentry->d_sb->s_magic; |
8d7b48e0b autofs4: add misc... |
558 |
} |
730c9eeca autofs4: improve ... |
559 560 |
param->ismountpoint.out.devid = devid; param->ismountpoint.out.magic = magic; |
4e44b6852 Get rid of path_l... |
561 |
path_put(&path); |
8d7b48e0b autofs4: add misc... |
562 563 564 565 566 567 568 569 570 571 572 573 574 |
out: return err; } /* * Our range of ioctl numbers isn't 0 based so we need to shift * the array index by _IOC_NR(AUTOFS_CTL_IOC_FIRST) for the table * lookup. */ #define cmd_idx(cmd) (cmd - _IOC_NR(AUTOFS_DEV_IOCTL_IOC_FIRST)) static ioctl_fn lookup_dev_ioctl(unsigned int cmd) { |
fcc24534b autofs: refactor ... |
575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 |
static ioctl_fn _ioctls[] = { autofs_dev_ioctl_version, autofs_dev_ioctl_protover, autofs_dev_ioctl_protosubver, autofs_dev_ioctl_openmount, autofs_dev_ioctl_closemount, autofs_dev_ioctl_ready, autofs_dev_ioctl_fail, autofs_dev_ioctl_setpipefd, autofs_dev_ioctl_catatonic, autofs_dev_ioctl_timeout, autofs_dev_ioctl_requester, autofs_dev_ioctl_expire, autofs_dev_ioctl_askumount, autofs_dev_ioctl_ismountpoint, |
8d7b48e0b autofs4: add misc... |
590 591 |
}; unsigned int idx = cmd_idx(cmd); |
fcc24534b autofs: refactor ... |
592 |
return (idx >= ARRAY_SIZE(_ioctls)) ? NULL : _ioctls[idx]; |
8d7b48e0b autofs4: add misc... |
593 594 595 |
} /* ioctl dispatcher */ |
e9a7c2f1a autofs4: coding s... |
596 597 |
static int _autofs_dev_ioctl(unsigned int command, struct autofs_dev_ioctl __user *user) |
8d7b48e0b autofs4: add misc... |
598 599 600 601 602 603 604 |
{ struct autofs_dev_ioctl *param; struct file *fp; struct autofs_sb_info *sbi; unsigned int cmd_first, cmd; ioctl_fn fn = NULL; int err = 0; |
8d7b48e0b autofs4: add misc... |
605 606 607 608 |
cmd_first = _IOC_NR(AUTOFS_DEV_IOCTL_IOC_FIRST); cmd = _IOC_NR(command); if (_IOC_TYPE(command) != _IOC_TYPE(AUTOFS_DEV_IOCTL_IOC_FIRST) || |
aa8419367 autofs: fix dev i... |
609 |
cmd - cmd_first > AUTOFS_DEV_IOCTL_IOC_COUNT) { |
8d7b48e0b autofs4: add misc... |
610 611 |
return -ENOTTY; } |
3dd8f7c3b autofs: make dev ... |
612 613 614 615 616 617 618 |
/* Only root can use ioctls other than AUTOFS_DEV_IOCTL_VERSION_CMD * and AUTOFS_DEV_IOCTL_ISMOUNTPOINT_CMD */ if (cmd != AUTOFS_DEV_IOCTL_VERSION_CMD && cmd != AUTOFS_DEV_IOCTL_ISMOUNTPOINT_CMD && !capable(CAP_SYS_ADMIN)) return -EPERM; |
8d7b48e0b autofs4: add misc... |
619 620 621 622 623 624 625 626 |
/* Copy the parameters into kernel space. */ param = copy_dev_ioctl(user); if (IS_ERR(param)) return PTR_ERR(param); err = validate_dev_ioctl(command, param); if (err) goto out; |
8d7b48e0b autofs4: add misc... |
627 628 |
fn = lookup_dev_ioctl(cmd); if (!fn) { |
8a78d5930 autofs4: use pr_x... |
629 630 |
pr_warn("unknown command 0x%08x ", command); |
41a4497a4 autofs: don't fai... |
631 632 |
err = -ENOTTY; goto out; |
8d7b48e0b autofs4: add misc... |
633 634 635 636 637 638 639 640 |
} fp = NULL; sbi = NULL; /* * For obvious reasons the openmount can't have a file * descriptor yet. We don't take a reference to the |
d9e192320 autofs: add autof... |
641 642 |
* file during close to allow for immediate release, * and the same for retrieving ioctl version. |
8d7b48e0b autofs4: add misc... |
643 |
*/ |
d9e192320 autofs: add autof... |
644 645 |
if (cmd != AUTOFS_DEV_IOCTL_VERSION_CMD && cmd != AUTOFS_DEV_IOCTL_OPENMOUNT_CMD && |
8d7b48e0b autofs4: add misc... |
646 647 648 649 650 651 652 653 |
cmd != AUTOFS_DEV_IOCTL_CLOSEMOUNT_CMD) { fp = fget(param->ioctlfd); if (!fp) { if (cmd == AUTOFS_DEV_IOCTL_ISMOUNTPOINT_CMD) goto cont; err = -EBADF; goto out; } |
8d7b48e0b autofs4: add misc... |
654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 |
sbi = autofs_dev_ioctl_sbi(fp); if (!sbi || sbi->magic != AUTOFS_SBI_MAGIC) { err = -EINVAL; fput(fp); goto out; } /* * Admin needs to be able to set the mount catatonic in * order to be able to perform the re-open. */ if (!autofs4_oz_mode(sbi) && cmd != AUTOFS_DEV_IOCTL_CATATONIC_CMD) { err = -EACCES; fput(fp); goto out; } } cont: err = fn(fp, sbi, param); if (fp) fput(fp); |
8d7b48e0b autofs4: add misc... |
677 678 679 680 681 682 |
if (err >= 0 && copy_to_user(user, param, AUTOFS_DEV_IOCTL_SIZE)) err = -EFAULT; out: free_dev_ioctl(param); return err; } |
b9fa2ad1e autofs: use unsig... |
683 684 |
static long autofs_dev_ioctl(struct file *file, unsigned int command, unsigned long u) |
8d7b48e0b autofs4: add misc... |
685 686 |
{ int err; |
e9a7c2f1a autofs4: coding s... |
687 |
|
8d7b48e0b autofs4: add misc... |
688 689 690 691 692 |
err = _autofs_dev_ioctl(command, (struct autofs_dev_ioctl __user *) u); return (long) err; } #ifdef CONFIG_COMPAT |
b9fa2ad1e autofs: use unsig... |
693 694 |
static long autofs_dev_ioctl_compat(struct file *file, unsigned int command, unsigned long u) |
8d7b48e0b autofs4: add misc... |
695 |
{ |
b9fa2ad1e autofs: use unsig... |
696 |
return autofs_dev_ioctl(file, command, (unsigned long) compat_ptr(u)); |
8d7b48e0b autofs4: add misc... |
697 698 699 700 701 702 703 704 705 |
} #else #define autofs_dev_ioctl_compat NULL #endif static const struct file_operations _dev_ioctl_fops = { .unlocked_ioctl = autofs_dev_ioctl, .compat_ioctl = autofs_dev_ioctl_compat, .owner = THIS_MODULE, |
6038f373a llseek: automatic... |
706 |
.llseek = noop_llseek, |
8d7b48e0b autofs4: add misc... |
707 708 709 |
}; static struct miscdevice _autofs_dev_ioctl_misc = { |
578454ff7 driver core: add ... |
710 |
.minor = AUTOFS_MINOR, |
e9a7c2f1a autofs4: coding s... |
711 |
.name = AUTOFS_DEVICE_NAME, |
e54c7bcbf autofs: make disc... |
712 713 |
.fops = &_dev_ioctl_fops, .mode = 0644, |
8d7b48e0b autofs4: add misc... |
714 |
}; |
578454ff7 driver core: add ... |
715 716 |
MODULE_ALIAS_MISCDEV(AUTOFS_MINOR); MODULE_ALIAS("devname:autofs"); |
8d7b48e0b autofs4: add misc... |
717 |
/* Register/deregister misc character device */ |
3ff6db328 fs/autofs4/dev-io... |
718 |
int __init autofs_dev_ioctl_init(void) |
8d7b48e0b autofs4: add misc... |
719 720 721 722 723 |
{ int r; r = misc_register(&_autofs_dev_ioctl_misc); if (r) { |
8a78d5930 autofs4: use pr_x... |
724 725 |
pr_err("misc_register failed for control device "); |
8d7b48e0b autofs4: add misc... |
726 727 728 729 730 731 732 733 734 |
return r; } return 0; } void autofs_dev_ioctl_exit(void) { misc_deregister(&_autofs_dev_ioctl_misc); |
8d7b48e0b autofs4: add misc... |
735 |
} |