aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
Diffstat (limited to 'fs')
-rw-r--r--fs/aio.c4
-rw-r--r--fs/ecryptfs/file.c8
-rw-r--r--fs/exec.c5
-rw-r--r--fs/ext4/super.c9
-rw-r--r--fs/ioprio.c2
-rw-r--r--fs/isofs/rock.c6
-rw-r--r--fs/namei.c10
-rw-r--r--fs/readdir.c20
8 files changed, 64 insertions, 0 deletions
diff --git a/fs/aio.c b/fs/aio.c
index 278ed7dc71b..cde2b5f5637 100644
--- a/fs/aio.c
+++ b/fs/aio.c
@@ -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)