Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

orangefs: posix open permission checking...

Orangefs has no open, and orangefs checks file permissions
on each file access. Posix requires that file permissions
be checked on open and nowhere else. Orangefs-through-the-kernel
needs to seem posix compliant.

The VFS opens files, even if the filesystem provides no
method. We can see if a file was successfully opened for
read and or for write by looking at file->f_mode.

When writes are flowing from the page cache, file is no
longer available. We can trust the VFS to have checked
file->f_mode before writing to the page cache.

The mode of a file might change between when it is opened
and IO commences, or it might be created with an arbitrary mode.

We'll make sure we don't hit EACCES during the IO stage by
using UID 0. Some of the time we have access without changing
to UID 0 - how to check?

Signed-off-by: Mike Marshall <hubcap@omnibond.com>

+43 -7
+37 -2
fs/orangefs/file.c
··· 46 46 * Post and wait for the I/O upcall to finish 47 47 */ 48 48 ssize_t wait_for_direct_io(enum ORANGEFS_io_type type, struct inode *inode, 49 - loff_t *offset, struct iov_iter *iter, size_t total_size, 50 - loff_t readahead_size, struct orangefs_write_range *wr, int *index_return) 49 + loff_t *offset, struct iov_iter *iter, size_t total_size, 50 + loff_t readahead_size, struct orangefs_write_range *wr, 51 + int *index_return, struct file *file) 51 52 { 52 53 struct orangefs_inode_s *orangefs_inode = ORANGEFS_I(inode); 53 54 struct orangefs_khandle *handle = &orangefs_inode->refn.khandle; ··· 56 55 int buffer_index; 57 56 ssize_t ret; 58 57 size_t copy_amount; 58 + int open_for_read; 59 + int open_for_write; 59 60 60 61 new_op = op_alloc(ORANGEFS_VFS_OP_FILE_IO); 61 62 if (!new_op) ··· 93 90 new_op->upcall.uid = from_kuid(&init_user_ns, wr->uid); 94 91 new_op->upcall.gid = from_kgid(&init_user_ns, wr->gid); 95 92 } 93 + /* 94 + * Orangefs has no open, and orangefs checks file permissions 95 + * on each file access. Posix requires that file permissions 96 + * be checked on open and nowhere else. Orangefs-through-the-kernel 97 + * needs to seem posix compliant. 98 + * 99 + * The VFS opens files, even if the filesystem provides no 100 + * method. We can see if a file was successfully opened for 101 + * read and or for write by looking at file->f_mode. 102 + * 103 + * When writes are flowing from the page cache, file is no 104 + * longer available. We can trust the VFS to have checked 105 + * file->f_mode before writing to the page cache. 106 + * 107 + * The mode of a file might change between when it is opened 108 + * and IO commences, or it might be created with an arbitrary mode. 109 + * 110 + * We'll make sure we don't hit EACCES during the IO stage by 111 + * using UID 0. Some of the time we have access without changing 112 + * to UID 0 - how to check? 113 + */ 114 + if (file) { 115 + open_for_write = file->f_mode & FMODE_WRITE; 116 + open_for_read = file->f_mode & FMODE_READ; 117 + } else { 118 + open_for_write = 1; 119 + open_for_read = 0; /* not relevant? */ 120 + } 121 + if ((type == ORANGEFS_IO_WRITE) && open_for_write) 122 + new_op->upcall.uid = 0; 123 + if ((type == ORANGEFS_IO_READ) && open_for_read) 124 + new_op->upcall.uid = 0; 96 125 97 126 gossip_debug(GOSSIP_FILE_DEBUG, 98 127 "%s(%pU): offset: %llu total_size: %zd\n",
+4 -4
fs/orangefs/inode.c
··· 55 55 iov_iter_bvec(&iter, WRITE, &bv, 1, wlen); 56 56 57 57 ret = wait_for_direct_io(ORANGEFS_IO_WRITE, inode, &off, &iter, wlen, 58 - len, wr, NULL); 58 + len, wr, NULL, NULL); 59 59 if (ret < 0) { 60 60 SetPageError(page); 61 61 mapping_set_error(page->mapping, ret); ··· 126 126 wr.uid = ow->uid; 127 127 wr.gid = ow->gid; 128 128 ret = wait_for_direct_io(ORANGEFS_IO_WRITE, inode, &off, &iter, ow->len, 129 - 0, &wr, NULL); 129 + 0, &wr, NULL, NULL); 130 130 if (ret < 0) { 131 131 for (i = 0; i < ow->npages; i++) { 132 132 SetPageError(ow->pages[i]); ··· 311 311 iov_iter_bvec(&iter, READ, &bv, 1, PAGE_SIZE); 312 312 313 313 ret = wait_for_direct_io(ORANGEFS_IO_READ, inode, &off, &iter, 314 - read_size, inode->i_size, NULL, &buffer_index); 314 + read_size, inode->i_size, NULL, &buffer_index, file); 315 315 remaining = ret; 316 316 /* this will only zero remaining unread portions of the page data */ 317 317 iov_iter_zero(~0U, &iter); ··· 651 651 (int)*offset); 652 652 653 653 ret = wait_for_direct_io(type, inode, offset, iter, 654 - each_count, 0, NULL, NULL); 654 + each_count, 0, NULL, NULL, file); 655 655 gossip_debug(GOSSIP_FILE_DEBUG, 656 656 "%s(%pU): return from wait_for_io:%d\n", 657 657 __func__,
+2 -1
fs/orangefs/orangefs-kernel.h
··· 398 398 */ 399 399 int orangefs_revalidate_mapping(struct inode *); 400 400 ssize_t wait_for_direct_io(enum ORANGEFS_io_type, struct inode *, loff_t *, 401 - struct iov_iter *, size_t, loff_t, struct orangefs_write_range *, int *); 401 + struct iov_iter *, size_t, loff_t, struct orangefs_write_range *, int *, 402 + struct file *); 402 403 ssize_t do_readv_writev(enum ORANGEFS_io_type, struct file *, loff_t *, 403 404 struct iov_iter *); 404 405