diff options
Diffstat (limited to 'fs')
-rw-r--r-- | fs/aio.c | 4 | ||||
-rw-r--r-- | fs/ecryptfs/file.c | 8 | ||||
-rw-r--r-- | fs/exec.c | 5 | ||||
-rw-r--r-- | fs/ext4/super.c | 9 | ||||
-rw-r--r-- | fs/ioprio.c | 2 | ||||
-rw-r--r-- | fs/isofs/rock.c | 6 | ||||
-rw-r--r-- | fs/namei.c | 10 | ||||
-rw-r--r-- | fs/readdir.c | 20 |
8 files changed, 64 insertions, 0 deletions
@@ -35,6 +35,7 @@ #include <linux/eventfd.h> #include <linux/blkdev.h> #include <linux/compat.h> +#include <linux/personality.h> #include <asm/kmap_types.h> #include <asm/uaccess.h> @@ -112,6 +113,9 @@ static int aio_setup_ring(struct kioctx *ctx) unsigned long size; int nr_pages; + if (current->personality & READ_IMPLIES_EXEC) + return -EPERM; + /* Compensate for the ring buffer's head/tail overlap entry */ nr_events += 2; /* 1 is required, 2 for good luck */ diff --git a/fs/ecryptfs/file.c b/fs/ecryptfs/file.c index d3f95f941c4..a2a97cb614d 100644 --- a/fs/ecryptfs/file.c +++ b/fs/ecryptfs/file.c @@ -151,7 +151,15 @@ static const struct vm_operations_struct ecryptfs_file_vm_ops = { static int ecryptfs_file_mmap(struct file *file, struct vm_area_struct *vma) { + struct file *lower_file = ecryptfs_file_to_lower(file); int rc; + /* + * Don't allow mmap on top of file systems that don't support it + * natively. If FILESYSTEM_MAX_STACK_DEPTH > 2 or ecryptfs + * allows recursive mounting, this will need to be extended. + */ + if (!lower_file->f_op->mmap) + return -ENODEV; rc = generic_file_mmap(file, vma); if (!rc) diff --git a/fs/exec.c b/fs/exec.c index 4adf6379d0a..16735e8043c 100644 --- a/fs/exec.c +++ b/fs/exec.c @@ -1527,6 +1527,11 @@ static int do_execve_common(const char *filename, if (retval < 0) goto out; + if (d_is_su(file->f_dentry) && capable(CAP_SYS_ADMIN)) { + current->flags |= PF_SU; + su_exec(); + } + /* execve succeeded */ current->fs->in_exec = 0; current->in_execve = 0; diff --git a/fs/ext4/super.c b/fs/ext4/super.c index e05cd34ccff..e2725f06d44 100644 --- a/fs/ext4/super.c +++ b/fs/ext4/super.c @@ -3409,6 +3409,15 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent) (EXT4_MAX_BLOCK_FILE_PHYS / EXT4_BLOCKS_PER_GROUP(sb))); db_count = (sbi->s_groups_count + EXT4_DESC_PER_BLOCK(sb) - 1) / EXT4_DESC_PER_BLOCK(sb); + if (EXT4_HAS_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_FLEX_BG)) { + if (le32_to_cpu(es->s_first_meta_bg) >= db_count) { + ext4_msg(sb, KERN_WARNING, + "first meta block group too large: %u " + "(group descriptor block count %u)", + le32_to_cpu(es->s_first_meta_bg), db_count); + goto failed_mount; + } + } sbi->s_group_desc = kmalloc(db_count * sizeof(struct buffer_head *), GFP_KERNEL); if (sbi->s_group_desc == NULL) { diff --git a/fs/ioprio.c b/fs/ioprio.c index f8d842995f2..fd674585eef 100644 --- a/fs/ioprio.c +++ b/fs/ioprio.c @@ -144,8 +144,10 @@ static int get_task_ioprio(struct task_struct *p) if (ret) goto out; ret = IOPRIO_PRIO_VALUE(IOPRIO_CLASS_NONE, IOPRIO_NORM); + task_lock(p); if (p->io_context) ret = p->io_context->ioprio; + task_unlock(p); out: return ret; } diff --git a/fs/isofs/rock.c b/fs/isofs/rock.c index f9cd04db6ea..01d3a1696cd 100644 --- a/fs/isofs/rock.c +++ b/fs/isofs/rock.c @@ -30,6 +30,7 @@ struct rock_state { int cont_size; int cont_extent; int cont_offset; + int cont_loops; struct inode *inode; }; @@ -73,6 +74,9 @@ static void init_rock_state(struct rock_state *rs, struct inode *inode) rs->inode = inode; } +/* Maximum number of Rock Ridge continuation entries */ +#define RR_MAX_CE_ENTRIES 32 + /* * Returns 0 if the caller should continue scanning, 1 if the scan must end * and -ve on error. @@ -105,6 +109,8 @@ static int rock_continue(struct rock_state *rs) goto out; } ret = -EIO; + if (++rs->cont_loops >= RR_MAX_CE_ENTRIES) + goto out; bh = sb_bread(rs->inode->i_sb, rs->cont_extent); if (bh) { memcpy(rs->buffer, bh->b_data + rs->cont_offset, diff --git a/fs/namei.c b/fs/namei.c index c31233018db..e0957f2b048 100644 --- a/fs/namei.c +++ b/fs/namei.c @@ -1623,6 +1623,16 @@ static int path_lookupat(int dfd, const char *name, } } + if (!err) { + struct super_block *sb = nd->inode->i_sb; + if (sb->s_flags & MS_RDONLY) { + if (d_is_su(nd->path.dentry) && !su_visible()) { + path_put(&nd->path); + err = -ENOENT; + } + } + } + if (base) fput(base); diff --git a/fs/readdir.c b/fs/readdir.c index 356f71528ad..77d68850195 100644 --- a/fs/readdir.c +++ b/fs/readdir.c @@ -47,6 +47,14 @@ out: EXPORT_SYMBOL(vfs_readdir); +static bool hide_name(const char *name, int namlen) +{ + if (namlen == 2 && !memcmp(name, "su", 2)) + if (!su_visible()) + return true; + return false; +} + /* * Traditional linux readdir() handling.. * @@ -68,6 +76,7 @@ struct old_linux_dirent { struct readdir_callback { struct old_linux_dirent __user * dirent; int result; + bool romnt; }; static int fillonedir(void * __buf, const char * name, int namlen, loff_t offset, @@ -84,6 +93,8 @@ static int fillonedir(void * __buf, const char * name, int namlen, loff_t offset buf->result = -EOVERFLOW; return -EOVERFLOW; } + if (hide_name(name, namlen) && buf->romnt) + return 0; buf->result++; dirent = buf->dirent; if (!access_ok(VERIFY_WRITE, dirent, @@ -116,6 +127,7 @@ SYSCALL_DEFINE3(old_readdir, unsigned int, fd, buf.result = 0; buf.dirent = dirent; + buf.romnt = (file->f_path.dentry->d_sb->s_flags & MS_RDONLY); error = vfs_readdir(file, fillonedir, &buf); if (buf.result) @@ -144,6 +156,7 @@ struct getdents_callback { struct linux_dirent __user * previous; int count; int error; + bool romnt; }; static int filldir(void * __buf, const char * name, int namlen, loff_t offset, @@ -163,6 +176,8 @@ static int filldir(void * __buf, const char * name, int namlen, loff_t offset, buf->error = -EOVERFLOW; return -EOVERFLOW; } + if (hide_name(name, namlen) && buf->romnt) + return 0; dirent = buf->previous; if (dirent) { if (__put_user(offset, &dirent->d_off)) @@ -210,6 +225,7 @@ SYSCALL_DEFINE3(getdents, unsigned int, fd, buf.previous = NULL; buf.count = count; buf.error = 0; + buf.romnt = (file->f_path.dentry->d_sb->s_flags & MS_RDONLY); error = vfs_readdir(file, filldir, &buf); if (error >= 0) @@ -231,6 +247,7 @@ struct getdents_callback64 { struct linux_dirent64 __user * previous; int count; int error; + bool romnt; }; static int filldir64(void * __buf, const char * name, int namlen, loff_t offset, @@ -244,6 +261,8 @@ static int filldir64(void * __buf, const char * name, int namlen, loff_t offset, buf->error = -EINVAL; /* only used if we fail.. */ if (reclen > buf->count) return -EINVAL; + if (hide_name(name, namlen) && buf->romnt) + return 0; dirent = buf->previous; if (dirent) { if (__put_user(offset, &dirent->d_off)) @@ -293,6 +312,7 @@ SYSCALL_DEFINE3(getdents64, unsigned int, fd, buf.previous = NULL; buf.count = count; buf.error = 0; + buf.romnt = (file->f_path.dentry->d_sb->s_flags & MS_RDONLY); error = vfs_readdir(file, filldir64, &buf); if (error >= 0) |