1 // SPDX-License-Identifier: GPL-2.0-or-later 2 /* Filesystem access-by-fd. 3 * 4 * Copyright (C) 2017 Red Hat, Inc. All Rights Reserved. 5 * Written by David Howells (dhowells@redhat.com) 6 */ 7 8 #include <linux/fs_context.h> 9 #include <linux/fs_parser.h> 10 #include <linux/slab.h> 11 #include <linux/uaccess.h> 12 #include <linux/syscalls.h> 13 #include <linux/security.h> 14 #include <linux/anon_inodes.h> 15 #include <linux/namei.h> 16 #include <linux/file.h> 17 #include <uapi/linux/mount.h> 18 #include "internal.h" 19 #include "mount.h" 20 21 /* 22 * Allow the user to read back any error, warning or informational messages. 23 */ 24 static ssize_t fscontext_read(struct file *file, 25 char __user *_buf, size_t len, loff_t *pos) 26 { 27 struct fs_context *fc = file->private_data; 28 struct fc_log *log = fc->log.log; 29 unsigned int logsize = ARRAY_SIZE(log->buffer); 30 ssize_t ret; 31 char *p; 32 bool need_free; 33 int index, n; 34 35 ret = mutex_lock_interruptible(&fc->uapi_mutex); 36 if (ret < 0) 37 return ret; 38 39 if (log->head == log->tail) { 40 mutex_unlock(&fc->uapi_mutex); 41 return -ENODATA; 42 } 43 44 index = log->tail & (logsize - 1); 45 p = log->buffer[index]; 46 need_free = log->need_free & (1 << index); 47 log->buffer[index] = NULL; 48 log->need_free &= ~(1 << index); 49 log->tail++; 50 mutex_unlock(&fc->uapi_mutex); 51 52 ret = -EMSGSIZE; 53 n = strlen(p); 54 if (n > len) 55 goto err_free; 56 ret = -EFAULT; 57 if (copy_to_user(_buf, p, n) != 0) 58 goto err_free; 59 ret = n; 60 61 err_free: 62 if (need_free) 63 kfree(p); 64 return ret; 65 } 66 67 static int fscontext_release(struct inode *inode, struct file *file) 68 { 69 struct fs_context *fc = file->private_data; 70 71 if (fc) { 72 file->private_data = NULL; 73 put_fs_context(fc); 74 } 75 return 0; 76 } 77 78 const struct file_operations fscontext_fops = { 79 .read = fscontext_read, 80 .release = fscontext_release, 81 .llseek = no_llseek, 82 }; 83 84 /* 85 * Attach a filesystem context to a file and an fd. 86 */ 87 static int fscontext_create_fd(struct fs_context *fc, unsigned int o_flags) 88 { 89 int fd; 90 91 fd = anon_inode_getfd("[fscontext]", &fscontext_fops, fc, 92 O_RDWR | o_flags); 93 if (fd < 0) 94 put_fs_context(fc); 95 return fd; 96 } 97 98 static int fscontext_alloc_log(struct fs_context *fc) 99 { 100 fc->log.log = kzalloc(sizeof(*fc->log.log), GFP_KERNEL); 101 if (!fc->log.log) 102 return -ENOMEM; 103 refcount_set(&fc->log.log->usage, 1); 104 fc->log.log->owner = fc->fs_type->owner; 105 return 0; 106 } 107 108 /* 109 * Open a filesystem by name so that it can be configured for mounting. 110 * 111 * We are allowed to specify a container in which the filesystem will be 112 * opened, thereby indicating which namespaces will be used (notably, which 113 * network namespace will be used for network filesystems). 114 */ 115 SYSCALL_DEFINE2(fsopen, const char __user *, _fs_name, unsigned int, flags) 116 { 117 struct file_system_type *fs_type; 118 struct fs_context *fc; 119 const char *fs_name; 120 int ret; 121 122 if (!may_mount()) 123 return -EPERM; 124 125 if (flags & ~FSOPEN_CLOEXEC) 126 return -EINVAL; 127 128 fs_name = strndup_user(_fs_name, PAGE_SIZE); 129 if (IS_ERR(fs_name)) 130 return PTR_ERR(fs_name); 131 132 fs_type = get_fs_type(fs_name); 133 kfree(fs_name); 134 if (!fs_type) 135 return -ENODEV; 136 137 fc = fs_context_for_mount(fs_type, 0); 138 put_filesystem(fs_type); 139 if (IS_ERR(fc)) 140 return PTR_ERR(fc); 141 142 fc->phase = FS_CONTEXT_CREATE_PARAMS; 143 144 ret = fscontext_alloc_log(fc); 145 if (ret < 0) 146 goto err_fc; 147 148 return fscontext_create_fd(fc, flags & FSOPEN_CLOEXEC ? O_CLOEXEC : 0); 149 150 err_fc: 151 put_fs_context(fc); 152 return ret; 153 } 154 155 /* 156 * Pick a superblock into a context for reconfiguration. 157 */ 158 SYSCALL_DEFINE3(fspick, int, dfd, const char __user *, path, unsigned int, flags) 159 { 160 struct fs_context *fc; 161 struct path target; 162 unsigned int lookup_flags; 163 int ret; 164 165 if (!may_mount()) 166 return -EPERM; 167 168 if ((flags & ~(FSPICK_CLOEXEC | 169 FSPICK_SYMLINK_NOFOLLOW | 170 FSPICK_NO_AUTOMOUNT | 171 FSPICK_EMPTY_PATH)) != 0) 172 return -EINVAL; 173 174 lookup_flags = LOOKUP_FOLLOW | LOOKUP_AUTOMOUNT; 175 if (flags & FSPICK_SYMLINK_NOFOLLOW) 176 lookup_flags &= ~LOOKUP_FOLLOW; 177 if (flags & FSPICK_NO_AUTOMOUNT) 178 lookup_flags &= ~LOOKUP_AUTOMOUNT; 179 if (flags & FSPICK_EMPTY_PATH) 180 lookup_flags |= LOOKUP_EMPTY; 181 ret = user_path_at(dfd, path, lookup_flags, &target); 182 if (ret < 0) 183 goto err; 184 185 ret = -EINVAL; 186 if (target.mnt->mnt_root != target.dentry) 187 goto err_path; 188 189 fc = fs_context_for_reconfigure(target.dentry, 0, 0); 190 if (IS_ERR(fc)) { 191 ret = PTR_ERR(fc); 192 goto err_path; 193 } 194 195 fc->phase = FS_CONTEXT_RECONF_PARAMS; 196 197 ret = fscontext_alloc_log(fc); 198 if (ret < 0) 199 goto err_fc; 200 201 path_put(&target); 202 return fscontext_create_fd(fc, flags & FSPICK_CLOEXEC ? O_CLOEXEC : 0); 203 204 err_fc: 205 put_fs_context(fc); 206 err_path: 207 path_put(&target); 208 err: 209 return ret; 210 } 211 212 static int vfs_cmd_create(struct fs_context *fc, bool exclusive) 213 { 214 struct super_block *sb; 215 int ret; 216 217 if (fc->phase != FS_CONTEXT_CREATE_PARAMS) 218 return -EBUSY; 219 220 if (!mount_capable(fc)) 221 return -EPERM; 222 223 fc->phase = FS_CONTEXT_CREATING; 224 fc->exclusive = exclusive; 225 226 ret = vfs_get_tree(fc); 227 if (ret) { 228 fc->phase = FS_CONTEXT_FAILED; 229 return ret; 230 } 231 232 sb = fc->root->d_sb; 233 ret = security_sb_kern_mount(sb); 234 if (unlikely(ret)) { 235 fc_drop_locked(fc); 236 fc->phase = FS_CONTEXT_FAILED; 237 return ret; 238 } 239 240 /* vfs_get_tree() callchains will have grabbed @s_umount */ 241 up_write(&sb->s_umount); 242 fc->phase = FS_CONTEXT_AWAITING_MOUNT; 243 return 0; 244 } 245 246 static int vfs_cmd_reconfigure(struct fs_context *fc) 247 { 248 struct super_block *sb; 249 int ret; 250 251 if (fc->phase != FS_CONTEXT_RECONF_PARAMS) 252 return -EBUSY; 253 254 fc->phase = FS_CONTEXT_RECONFIGURING; 255 256 sb = fc->root->d_sb; 257 if (!ns_capable(sb->s_user_ns, CAP_SYS_ADMIN)) { 258 fc->phase = FS_CONTEXT_FAILED; 259 return -EPERM; 260 } 261 262 down_write(&sb->s_umount); 263 ret = reconfigure_super(fc); 264 up_write(&sb->s_umount); 265 if (ret) { 266 fc->phase = FS_CONTEXT_FAILED; 267 return ret; 268 } 269 270 vfs_clean_context(fc); 271 return 0; 272 } 273 274 /* 275 * Check the state and apply the configuration. Note that this function is 276 * allowed to 'steal' the value by setting param->xxx to NULL before returning. 277 */ 278 static int vfs_fsconfig_locked(struct fs_context *fc, int cmd, 279 struct fs_parameter *param) 280 { 281 int ret; 282 283 ret = finish_clean_context(fc); 284 if (ret) 285 return ret; 286 switch (cmd) { 287 case FSCONFIG_CMD_CREATE: 288 return vfs_cmd_create(fc, false); 289 case FSCONFIG_CMD_CREATE_EXCL: 290 return vfs_cmd_create(fc, true); 291 case FSCONFIG_CMD_RECONFIGURE: 292 return vfs_cmd_reconfigure(fc); 293 default: 294 if (fc->phase != FS_CONTEXT_CREATE_PARAMS && 295 fc->phase != FS_CONTEXT_RECONF_PARAMS) 296 return -EBUSY; 297 298 return vfs_parse_fs_param(fc, param); 299 } 300 } 301 302 /** 303 * sys_fsconfig - Set parameters and trigger actions on a context 304 * @fd: The filesystem context to act upon 305 * @cmd: The action to take 306 * @_key: Where appropriate, the parameter key to set 307 * @_value: Where appropriate, the parameter value to set 308 * @aux: Additional information for the value 309 * 310 * This system call is used to set parameters on a context, including 311 * superblock settings, data source and security labelling. 312 * 313 * Actions include triggering the creation of a superblock and the 314 * reconfiguration of the superblock attached to the specified context. 315 * 316 * When setting a parameter, @cmd indicates the type of value being proposed 317 * and @_key indicates the parameter to be altered. 318 * 319 * @_value and @aux are used to specify the value, should a value be required: 320 * 321 * (*) fsconfig_set_flag: No value is specified. The parameter must be boolean 322 * in nature. The key may be prefixed with "no" to invert the 323 * setting. @_value must be NULL and @aux must be 0. 324 * 325 * (*) fsconfig_set_string: A string value is specified. The parameter can be 326 * expecting boolean, integer, string or take a path. A conversion to an 327 * appropriate type will be attempted (which may include looking up as a 328 * path). @_value points to a NUL-terminated string and @aux must be 0. 329 * 330 * (*) fsconfig_set_binary: A binary blob is specified. @_value points to the 331 * blob and @aux indicates its size. The parameter must be expecting a 332 * blob. 333 * 334 * (*) fsconfig_set_path: A non-empty path is specified. The parameter must be 335 * expecting a path object. @_value points to a NUL-terminated string that 336 * is the path and @aux is a file descriptor at which to start a relative 337 * lookup or AT_FDCWD. 338 * 339 * (*) fsconfig_set_path_empty: As fsconfig_set_path, but with AT_EMPTY_PATH 340 * implied. 341 * 342 * (*) fsconfig_set_fd: An open file descriptor is specified. @_value must be 343 * NULL and @aux indicates the file descriptor. 344 */ 345 SYSCALL_DEFINE5(fsconfig, 346 int, fd, 347 unsigned int, cmd, 348 const char __user *, _key, 349 const void __user *, _value, 350 int, aux) 351 { 352 struct fs_context *fc; 353 struct fd f; 354 int ret; 355 int lookup_flags = 0; 356 357 struct fs_parameter param = { 358 .type = fs_value_is_undefined, 359 }; 360 361 if (fd < 0) 362 return -EINVAL; 363 364 switch (cmd) { 365 case FSCONFIG_SET_FLAG: 366 if (!_key || _value || aux) 367 return -EINVAL; 368 break; 369 case FSCONFIG_SET_STRING: 370 if (!_key || !_value || aux) 371 return -EINVAL; 372 break; 373 case FSCONFIG_SET_BINARY: 374 if (!_key || !_value || aux <= 0 || aux > 1024 * 1024) 375 return -EINVAL; 376 break; 377 case FSCONFIG_SET_PATH: 378 case FSCONFIG_SET_PATH_EMPTY: 379 if (!_key || !_value || (aux != AT_FDCWD && aux < 0)) 380 return -EINVAL; 381 break; 382 case FSCONFIG_SET_FD: 383 if (!_key || _value || aux < 0) 384 return -EINVAL; 385 break; 386 case FSCONFIG_CMD_CREATE: 387 case FSCONFIG_CMD_CREATE_EXCL: 388 case FSCONFIG_CMD_RECONFIGURE: 389 if (_key || _value || aux) 390 return -EINVAL; 391 break; 392 default: 393 return -EOPNOTSUPP; 394 } 395 396 f = fdget(fd); 397 if (!f.file) 398 return -EBADF; 399 ret = -EINVAL; 400 if (f.file->f_op != &fscontext_fops) 401 goto out_f; 402 403 fc = f.file->private_data; 404 if (fc->ops == &legacy_fs_context_ops) { 405 switch (cmd) { 406 case FSCONFIG_SET_BINARY: 407 case FSCONFIG_SET_PATH: 408 case FSCONFIG_SET_PATH_EMPTY: 409 case FSCONFIG_SET_FD: 410 case FSCONFIG_CMD_CREATE_EXCL: 411 ret = -EOPNOTSUPP; 412 goto out_f; 413 } 414 } 415 416 if (_key) { 417 param.key = strndup_user(_key, 256); 418 if (IS_ERR(param.key)) { 419 ret = PTR_ERR(param.key); 420 goto out_f; 421 } 422 } 423 424 switch (cmd) { 425 case FSCONFIG_SET_FLAG: 426 param.type = fs_value_is_flag; 427 break; 428 case FSCONFIG_SET_STRING: 429 param.type = fs_value_is_string; 430 param.string = strndup_user(_value, 256); 431 if (IS_ERR(param.string)) { 432 ret = PTR_ERR(param.string); 433 goto out_key; 434 } 435 param.size = strlen(param.string); 436 break; 437 case FSCONFIG_SET_BINARY: 438 param.type = fs_value_is_blob; 439 param.size = aux; 440 param.blob = memdup_user_nul(_value, aux); 441 if (IS_ERR(param.blob)) { 442 ret = PTR_ERR(param.blob); 443 goto out_key; 444 } 445 break; 446 case FSCONFIG_SET_PATH_EMPTY: 447 lookup_flags = LOOKUP_EMPTY; 448 fallthrough; 449 case FSCONFIG_SET_PATH: 450 param.type = fs_value_is_filename; 451 param.name = getname_flags(_value, lookup_flags); 452 if (IS_ERR(param.name)) { 453 ret = PTR_ERR(param.name); 454 goto out_key; 455 } 456 param.dirfd = aux; 457 param.size = strlen(param.name->name); 458 break; 459 case FSCONFIG_SET_FD: 460 param.type = fs_value_is_file; 461 ret = -EBADF; 462 param.file = fget(aux); 463 if (!param.file) 464 goto out_key; 465 param.dirfd = aux; 466 break; 467 default: 468 break; 469 } 470 471 ret = mutex_lock_interruptible(&fc->uapi_mutex); 472 if (ret == 0) { 473 ret = vfs_fsconfig_locked(fc, cmd, ¶m); 474 mutex_unlock(&fc->uapi_mutex); 475 } 476 477 /* Clean up the our record of any value that we obtained from 478 * userspace. Note that the value may have been stolen by the LSM or 479 * filesystem, in which case the value pointer will have been cleared. 480 */ 481 switch (cmd) { 482 case FSCONFIG_SET_STRING: 483 case FSCONFIG_SET_BINARY: 484 kfree(param.string); 485 break; 486 case FSCONFIG_SET_PATH: 487 case FSCONFIG_SET_PATH_EMPTY: 488 if (param.name) 489 putname(param.name); 490 break; 491 case FSCONFIG_SET_FD: 492 if (param.file) 493 fput(param.file); 494 break; 495 default: 496 break; 497 } 498 out_key: 499 kfree(param.key); 500 out_f: 501 fdput(f); 502 return ret; 503 } 504
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.