Branch data Line data Source code
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 : 0 : static ssize_t fscontext_read(struct file *file, 25 : : char __user *_buf, size_t len, loff_t *pos) 26 : : { 27 : 0 : struct fs_context *fc = file->private_data; 28 : 0 : struct fc_log *log = fc->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 : 0 : ret = mutex_lock_interruptible(&fc->uapi_mutex); 36 : 0 : if (ret < 0) 37 : : return ret; 38 : : 39 : 0 : if (log->head == log->tail) { 40 : 0 : mutex_unlock(&fc->uapi_mutex); 41 : 0 : return -ENODATA; 42 : : } 43 : : 44 : 0 : index = log->tail & (logsize - 1); 45 : 0 : p = log->buffer[index]; 46 : 0 : need_free = log->need_free & (1 << index); 47 : 0 : log->buffer[index] = NULL; 48 : 0 : log->need_free &= ~(1 << index); 49 : 0 : log->tail++; 50 : 0 : mutex_unlock(&fc->uapi_mutex); 51 : : 52 : : ret = -EMSGSIZE; 53 : 0 : n = strlen(p); 54 : 0 : if (n > len) 55 : : goto err_free; 56 : : ret = -EFAULT; 57 : 0 : if (copy_to_user(_buf, p, n) != 0) 58 : : goto err_free; 59 : : ret = n; 60 : : 61 : : err_free: 62 : 0 : if (need_free) 63 : 0 : kfree(p); 64 : 0 : return ret; 65 : : } 66 : : 67 : 0 : static int fscontext_release(struct inode *inode, struct file *file) 68 : : { 69 : 0 : struct fs_context *fc = file->private_data; 70 : : 71 : 0 : if (fc) { 72 : 0 : file->private_data = NULL; 73 : 0 : put_fs_context(fc); 74 : : } 75 : 0 : 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 : 0 : static int fscontext_create_fd(struct fs_context *fc, unsigned int o_flags) 88 : : { 89 : : int fd; 90 : : 91 : 0 : fd = anon_inode_getfd("[fscontext]", &fscontext_fops, fc, 92 : 0 : O_RDWR | o_flags); 93 : 0 : if (fd < 0) 94 : 0 : put_fs_context(fc); 95 : 0 : return fd; 96 : : } 97 : : 98 : 0 : static int fscontext_alloc_log(struct fs_context *fc) 99 : : { 100 : 0 : fc->log = kzalloc(sizeof(*fc->log), GFP_KERNEL); 101 : 0 : if (!fc->log) 102 : : return -ENOMEM; 103 : : refcount_set(&fc->log->usage, 1); 104 : 0 : fc->log->owner = fc->fs_type->owner; 105 : 0 : 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 : 0 : 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 : 0 : if (!ns_capable(current->nsproxy->mnt_ns->user_ns, CAP_SYS_ADMIN)) 123 : : return -EPERM; 124 : : 125 : 0 : if (flags & ~FSOPEN_CLOEXEC) 126 : : return -EINVAL; 127 : : 128 : 0 : fs_name = strndup_user(_fs_name, PAGE_SIZE); 129 : 0 : if (IS_ERR(fs_name)) 130 : 0 : return PTR_ERR(fs_name); 131 : : 132 : 0 : fs_type = get_fs_type(fs_name); 133 : 0 : kfree(fs_name); 134 : 0 : if (!fs_type) 135 : : return -ENODEV; 136 : : 137 : 0 : fc = fs_context_for_mount(fs_type, 0); 138 : 0 : put_filesystem(fs_type); 139 : 0 : if (IS_ERR(fc)) 140 : 0 : return PTR_ERR(fc); 141 : : 142 : 0 : fc->phase = FS_CONTEXT_CREATE_PARAMS; 143 : : 144 : 0 : ret = fscontext_alloc_log(fc); 145 : 0 : if (ret < 0) 146 : : goto err_fc; 147 : : 148 : 0 : return fscontext_create_fd(fc, flags & FSOPEN_CLOEXEC ? O_CLOEXEC : 0); 149 : : 150 : : err_fc: 151 : 0 : put_fs_context(fc); 152 : 0 : return ret; 153 : : } 154 : : 155 : : /* 156 : : * Pick a superblock into a context for reconfiguration. 157 : : */ 158 : 0 : 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 : 0 : if (!ns_capable(current->nsproxy->mnt_ns->user_ns, CAP_SYS_ADMIN)) 166 : : return -EPERM; 167 : : 168 : 0 : 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 : 0 : if (flags & FSPICK_SYMLINK_NOFOLLOW) 176 : : lookup_flags &= ~LOOKUP_FOLLOW; 177 : 0 : if (flags & FSPICK_NO_AUTOMOUNT) 178 : 0 : lookup_flags &= ~LOOKUP_AUTOMOUNT; 179 : 0 : if (flags & FSPICK_EMPTY_PATH) 180 : 0 : lookup_flags |= LOOKUP_EMPTY; 181 : : ret = user_path_at(dfd, path, lookup_flags, &target); 182 : 0 : if (ret < 0) 183 : : goto err; 184 : : 185 : : ret = -EINVAL; 186 : 0 : if (target.mnt->mnt_root != target.dentry) 187 : : goto err_path; 188 : : 189 : 0 : fc = fs_context_for_reconfigure(target.dentry, 0, 0); 190 : 0 : if (IS_ERR(fc)) { 191 : : ret = PTR_ERR(fc); 192 : 0 : goto err_path; 193 : : } 194 : : 195 : 0 : fc->phase = FS_CONTEXT_RECONF_PARAMS; 196 : : 197 : 0 : ret = fscontext_alloc_log(fc); 198 : 0 : if (ret < 0) 199 : : goto err_fc; 200 : : 201 : 0 : path_put(&target); 202 : 0 : return fscontext_create_fd(fc, flags & FSPICK_CLOEXEC ? O_CLOEXEC : 0); 203 : : 204 : : err_fc: 205 : 0 : put_fs_context(fc); 206 : : err_path: 207 : 0 : path_put(&target); 208 : : err: 209 : 0 : return ret; 210 : : } 211 : : 212 : : /* 213 : : * Check the state and apply the configuration. Note that this function is 214 : : * allowed to 'steal' the value by setting param->xxx to NULL before returning. 215 : : */ 216 : 0 : static int vfs_fsconfig_locked(struct fs_context *fc, int cmd, 217 : : struct fs_parameter *param) 218 : : { 219 : : struct super_block *sb; 220 : : int ret; 221 : : 222 : 0 : ret = finish_clean_context(fc); 223 : 0 : if (ret) 224 : : return ret; 225 : 0 : switch (cmd) { 226 : : case FSCONFIG_CMD_CREATE: 227 : 0 : if (fc->phase != FS_CONTEXT_CREATE_PARAMS) 228 : : return -EBUSY; 229 : 0 : if (!mount_capable(fc)) 230 : : return -EPERM; 231 : 0 : fc->phase = FS_CONTEXT_CREATING; 232 : 0 : ret = vfs_get_tree(fc); 233 : 0 : if (ret) 234 : : break; 235 : 0 : sb = fc->root->d_sb; 236 : 0 : ret = security_sb_kern_mount(sb); 237 : 0 : if (unlikely(ret)) { 238 : 0 : fc_drop_locked(fc); 239 : 0 : break; 240 : : } 241 : 0 : up_write(&sb->s_umount); 242 : 0 : fc->phase = FS_CONTEXT_AWAITING_MOUNT; 243 : 0 : return 0; 244 : : case FSCONFIG_CMD_RECONFIGURE: 245 : 0 : if (fc->phase != FS_CONTEXT_RECONF_PARAMS) 246 : : return -EBUSY; 247 : 0 : fc->phase = FS_CONTEXT_RECONFIGURING; 248 : 0 : sb = fc->root->d_sb; 249 : 0 : if (!ns_capable(sb->s_user_ns, CAP_SYS_ADMIN)) { 250 : : ret = -EPERM; 251 : : break; 252 : : } 253 : 0 : down_write(&sb->s_umount); 254 : 0 : ret = reconfigure_super(fc); 255 : 0 : up_write(&sb->s_umount); 256 : 0 : if (ret) 257 : : break; 258 : 0 : vfs_clean_context(fc); 259 : 0 : return 0; 260 : : default: 261 : 0 : if (fc->phase != FS_CONTEXT_CREATE_PARAMS && 262 : : fc->phase != FS_CONTEXT_RECONF_PARAMS) 263 : : return -EBUSY; 264 : : 265 : 0 : return vfs_parse_fs_param(fc, param); 266 : : } 267 : 0 : fc->phase = FS_CONTEXT_FAILED; 268 : 0 : return ret; 269 : : } 270 : : 271 : : /** 272 : : * sys_fsconfig - Set parameters and trigger actions on a context 273 : : * @fd: The filesystem context to act upon 274 : : * @cmd: The action to take 275 : : * @_key: Where appropriate, the parameter key to set 276 : : * @_value: Where appropriate, the parameter value to set 277 : : * @aux: Additional information for the value 278 : : * 279 : : * This system call is used to set parameters on a context, including 280 : : * superblock settings, data source and security labelling. 281 : : * 282 : : * Actions include triggering the creation of a superblock and the 283 : : * reconfiguration of the superblock attached to the specified context. 284 : : * 285 : : * When setting a parameter, @cmd indicates the type of value being proposed 286 : : * and @_key indicates the parameter to be altered. 287 : : * 288 : : * @_value and @aux are used to specify the value, should a value be required: 289 : : * 290 : : * (*) fsconfig_set_flag: No value is specified. The parameter must be boolean 291 : : * in nature. The key may be prefixed with "no" to invert the 292 : : * setting. @_value must be NULL and @aux must be 0. 293 : : * 294 : : * (*) fsconfig_set_string: A string value is specified. The parameter can be 295 : : * expecting boolean, integer, string or take a path. A conversion to an 296 : : * appropriate type will be attempted (which may include looking up as a 297 : : * path). @_value points to a NUL-terminated string and @aux must be 0. 298 : : * 299 : : * (*) fsconfig_set_binary: A binary blob is specified. @_value points to the 300 : : * blob and @aux indicates its size. The parameter must be expecting a 301 : : * blob. 302 : : * 303 : : * (*) fsconfig_set_path: A non-empty path is specified. The parameter must be 304 : : * expecting a path object. @_value points to a NUL-terminated string that 305 : : * is the path and @aux is a file descriptor at which to start a relative 306 : : * lookup or AT_FDCWD. 307 : : * 308 : : * (*) fsconfig_set_path_empty: As fsconfig_set_path, but with AT_EMPTY_PATH 309 : : * implied. 310 : : * 311 : : * (*) fsconfig_set_fd: An open file descriptor is specified. @_value must be 312 : : * NULL and @aux indicates the file descriptor. 313 : : */ 314 : 0 : SYSCALL_DEFINE5(fsconfig, 315 : : int, fd, 316 : : unsigned int, cmd, 317 : : const char __user *, _key, 318 : : const void __user *, _value, 319 : : int, aux) 320 : : { 321 : : struct fs_context *fc; 322 : : struct fd f; 323 : : int ret; 324 : : 325 : 0 : struct fs_parameter param = { 326 : : .type = fs_value_is_undefined, 327 : : }; 328 : : 329 : 0 : if (fd < 0) 330 : : return -EINVAL; 331 : : 332 : 0 : switch (cmd) { 333 : : case FSCONFIG_SET_FLAG: 334 : 0 : if (!_key || _value || aux) 335 : : return -EINVAL; 336 : : break; 337 : : case FSCONFIG_SET_STRING: 338 : 0 : if (!_key || !_value || aux) 339 : : return -EINVAL; 340 : : break; 341 : : case FSCONFIG_SET_BINARY: 342 : 0 : if (!_key || !_value || aux <= 0 || aux > 1024 * 1024) 343 : : return -EINVAL; 344 : : break; 345 : : case FSCONFIG_SET_PATH: 346 : : case FSCONFIG_SET_PATH_EMPTY: 347 : 0 : if (!_key || !_value || (aux != AT_FDCWD && aux < 0)) 348 : : return -EINVAL; 349 : : break; 350 : : case FSCONFIG_SET_FD: 351 : 0 : if (!_key || _value || aux < 0) 352 : : return -EINVAL; 353 : : break; 354 : : case FSCONFIG_CMD_CREATE: 355 : : case FSCONFIG_CMD_RECONFIGURE: 356 : 0 : if (_key || _value || aux) 357 : : return -EINVAL; 358 : : break; 359 : : default: 360 : : return -EOPNOTSUPP; 361 : : } 362 : : 363 : 0 : f = fdget(fd); 364 : 0 : if (!f.file) 365 : : return -EBADF; 366 : : ret = -EINVAL; 367 : 0 : if (f.file->f_op != &fscontext_fops) 368 : : goto out_f; 369 : : 370 : 0 : fc = f.file->private_data; 371 : 0 : if (fc->ops == &legacy_fs_context_ops) { 372 : 0 : switch (cmd) { 373 : : case FSCONFIG_SET_BINARY: 374 : : case FSCONFIG_SET_PATH: 375 : : case FSCONFIG_SET_PATH_EMPTY: 376 : : case FSCONFIG_SET_FD: 377 : : ret = -EOPNOTSUPP; 378 : : goto out_f; 379 : : } 380 : : } 381 : : 382 : 0 : if (_key) { 383 : 0 : param.key = strndup_user(_key, 256); 384 : 0 : if (IS_ERR(param.key)) { 385 : : ret = PTR_ERR(param.key); 386 : 0 : goto out_f; 387 : : } 388 : : } 389 : : 390 : 0 : switch (cmd) { 391 : : case FSCONFIG_SET_FLAG: 392 : 0 : param.type = fs_value_is_flag; 393 : 0 : break; 394 : : case FSCONFIG_SET_STRING: 395 : 0 : param.type = fs_value_is_string; 396 : 0 : param.string = strndup_user(_value, 256); 397 : 0 : if (IS_ERR(param.string)) { 398 : : ret = PTR_ERR(param.string); 399 : 0 : goto out_key; 400 : : } 401 : 0 : param.size = strlen(param.string); 402 : 0 : break; 403 : : case FSCONFIG_SET_BINARY: 404 : 0 : param.type = fs_value_is_blob; 405 : 0 : param.size = aux; 406 : 0 : param.blob = memdup_user_nul(_value, aux); 407 : 0 : if (IS_ERR(param.blob)) { 408 : : ret = PTR_ERR(param.blob); 409 : 0 : goto out_key; 410 : : } 411 : : break; 412 : : case FSCONFIG_SET_PATH: 413 : 0 : param.type = fs_value_is_filename; 414 : 0 : param.name = getname_flags(_value, 0, NULL); 415 : 0 : if (IS_ERR(param.name)) { 416 : : ret = PTR_ERR(param.name); 417 : 0 : goto out_key; 418 : : } 419 : 0 : param.dirfd = aux; 420 : 0 : param.size = strlen(param.name->name); 421 : 0 : break; 422 : : case FSCONFIG_SET_PATH_EMPTY: 423 : 0 : param.type = fs_value_is_filename_empty; 424 : 0 : param.name = getname_flags(_value, LOOKUP_EMPTY, NULL); 425 : 0 : if (IS_ERR(param.name)) { 426 : : ret = PTR_ERR(param.name); 427 : 0 : goto out_key; 428 : : } 429 : 0 : param.dirfd = aux; 430 : 0 : param.size = strlen(param.name->name); 431 : 0 : break; 432 : : case FSCONFIG_SET_FD: 433 : 0 : param.type = fs_value_is_file; 434 : : ret = -EBADF; 435 : 0 : param.file = fget(aux); 436 : 0 : if (!param.file) 437 : : goto out_key; 438 : : break; 439 : : default: 440 : : break; 441 : : } 442 : : 443 : 0 : ret = mutex_lock_interruptible(&fc->uapi_mutex); 444 : 0 : if (ret == 0) { 445 : 0 : ret = vfs_fsconfig_locked(fc, cmd, ¶m); 446 : 0 : mutex_unlock(&fc->uapi_mutex); 447 : : } 448 : : 449 : : /* Clean up the our record of any value that we obtained from 450 : : * userspace. Note that the value may have been stolen by the LSM or 451 : : * filesystem, in which case the value pointer will have been cleared. 452 : : */ 453 : 0 : switch (cmd) { 454 : : case FSCONFIG_SET_STRING: 455 : : case FSCONFIG_SET_BINARY: 456 : 0 : kfree(param.string); 457 : 0 : break; 458 : : case FSCONFIG_SET_PATH: 459 : : case FSCONFIG_SET_PATH_EMPTY: 460 : 0 : if (param.name) 461 : 0 : putname(param.name); 462 : : break; 463 : : case FSCONFIG_SET_FD: 464 : 0 : if (param.file) 465 : 0 : fput(param.file); 466 : : break; 467 : : default: 468 : : break; 469 : : } 470 : : out_key: 471 : 0 : kfree(param.key); 472 : : out_f: 473 : : fdput(f); 474 : 0 : return ret; 475 : : }