diff options
Diffstat (limited to 'fs')
| -rw-r--r-- | fs/9p/acl.c | 40 | ||||
| -rw-r--r-- | fs/btrfs/acl.c | 4 | ||||
| -rw-r--r-- | fs/ecryptfs/file.c | 9 | ||||
| -rw-r--r-- | fs/ecryptfs/main.c | 7 | ||||
| -rw-r--r-- | fs/exec.c | 5 | ||||
| -rw-r--r-- | fs/ext2/acl.c | 12 | ||||
| -rw-r--r-- | fs/ext3/acl.c | 12 | ||||
| -rw-r--r-- | fs/ext4/acl.c | 12 | ||||
| -rw-r--r-- | fs/f2fs/acl.c | 4 | ||||
| -rw-r--r-- | fs/generic_acl.c | 8 | ||||
| -rw-r--r-- | fs/gfs2/acl.c | 11 | ||||
| -rw-r--r-- | fs/jffs2/acl.c | 9 | ||||
| -rw-r--r-- | fs/jfs/xattr.c | 6 | ||||
| -rw-r--r-- | fs/namei.c | 10 | ||||
| -rw-r--r-- | fs/ocfs2/acl.c | 18 | ||||
| -rw-r--r-- | fs/posix_acl.c | 29 | ||||
| -rw-r--r-- | fs/proc/array.c | 10 | ||||
| -rw-r--r-- | fs/readdir.c | 20 | ||||
| -rw-r--r-- | fs/reiserfs/xattr_acl.c | 8 | ||||
| -rw-r--r-- | fs/sdcardfs/main.c | 7 | ||||
| -rw-r--r-- | fs/xfs/xfs_acl.c | 13 |
21 files changed, 148 insertions, 106 deletions
diff --git a/fs/9p/acl.c b/fs/9p/acl.c index 9a1d4263075..a4188cfcc9f 100644 --- a/fs/9p/acl.c +++ b/fs/9p/acl.c @@ -319,32 +319,26 @@ static int v9fs_xattr_set_acl(struct dentry *dentry, const char *name, case ACL_TYPE_ACCESS: name = POSIX_ACL_XATTR_ACCESS; if (acl) { - umode_t mode = inode->i_mode; - retval = posix_acl_equiv_mode(acl, &mode); - if (retval < 0) + struct iattr iattr; + + retval = posix_acl_update_mode(inode, &iattr.ia_mode, &acl); + if (retval) goto err_out; - else { - struct iattr iattr; - if (retval == 0) { - /* - * ACL can be represented - * by the mode bits. So don't - * update ACL. - */ - acl = NULL; - value = NULL; - size = 0; - } - /* Updte the mode bits */ - iattr.ia_mode = ((mode & S_IALLUGO) | - (inode->i_mode & ~S_IALLUGO)); - iattr.ia_valid = ATTR_MODE; - /* FIXME should we update ctime ? - * What is the following setxattr update the - * mode ? + if (!acl) { + /* + * ACL can be represented + * by the mode bits. So don't + * update ACL. */ - v9fs_vfs_setattr_dotl(dentry, &iattr); + value = NULL; + size = 0; } + iattr.ia_valid = ATTR_MODE; + /* FIXME should we update ctime ? + * What is the following setxattr update the + * mode ? + */ + v9fs_vfs_setattr_dotl(dentry, &iattr); } break; case ACL_TYPE_DEFAULT: diff --git a/fs/btrfs/acl.c b/fs/btrfs/acl.c index 89b156d85d6..9f55b545ea4 100644 --- a/fs/btrfs/acl.c +++ b/fs/btrfs/acl.c @@ -118,8 +118,8 @@ static int btrfs_set_acl(struct btrfs_trans_handle *trans, case ACL_TYPE_ACCESS: name = POSIX_ACL_XATTR_ACCESS; if (acl) { - ret = posix_acl_equiv_mode(acl, &inode->i_mode); - if (ret < 0) + ret = posix_acl_update_mode(inode, &inode->i_mode, &acl); + if (ret) return ret; } ret = 0; diff --git a/fs/ecryptfs/file.c b/fs/ecryptfs/file.c index 805be43324a..ef830491326 100644 --- a/fs/ecryptfs/file.c +++ b/fs/ecryptfs/file.c @@ -146,6 +146,15 @@ static int read_or_initialize_metadata(struct dentry *dentry) struct ecryptfs_mount_crypt_stat *mount_crypt_stat; struct ecryptfs_crypt_stat *crypt_stat; int rc; + struct file *lower_file = ecryptfs_file_to_lower(file); + + /* + * 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; crypt_stat = &ecryptfs_inode_to_private(inode)->crypt_stat; mount_crypt_stat = &ecryptfs_superblock_to_private( diff --git a/fs/ecryptfs/main.c b/fs/ecryptfs/main.c index 93b7bec021b..81e69c7a74b 100644 --- a/fs/ecryptfs/main.c +++ b/fs/ecryptfs/main.c @@ -576,6 +576,13 @@ static struct dentry *ecryptfs_mount(struct file_system_type *fs_type, int flags s->s_maxbytes = path.dentry->d_sb->s_maxbytes; s->s_blocksize = path.dentry->d_sb->s_blocksize; s->s_magic = ECRYPTFS_SUPER_MAGIC; + s->s_stack_depth = path.dentry->d_sb->s_stack_depth + 1; + + rc = -EINVAL; + if (s->s_stack_depth > FILESYSTEM_MAX_STACK_DEPTH) { + pr_err("eCryptfs: maximum fs stacking depth exceeded\n"); + goto out_free; + } inode = ecryptfs_get_inode(path.dentry->d_inode, s); rc = PTR_ERR(inode); diff --git a/fs/exec.c b/fs/exec.c index a4d05ce9248..73e9bd4d46e 100644 --- a/fs/exec.c +++ b/fs/exec.c @@ -1591,6 +1591,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/ext2/acl.c b/fs/ext2/acl.c index 35d6a3cfd9f..e38a9b61af3 100644 --- a/fs/ext2/acl.c +++ b/fs/ext2/acl.c @@ -194,15 +194,11 @@ ext2_set_acl(struct inode *inode, int type, struct posix_acl *acl) case ACL_TYPE_ACCESS: name_index = EXT2_XATTR_INDEX_POSIX_ACL_ACCESS; if (acl) { - error = posix_acl_equiv_mode(acl, &inode->i_mode); - if (error < 0) + error = posix_acl_update_mode(inode, &inode->i_mode, &acl); + if (error) return error; - else { - inode->i_ctime = CURRENT_TIME_SEC; - mark_inode_dirty(inode); - if (error == 0) - acl = NULL; - } + inode->i_ctime = CURRENT_TIME_SEC; + mark_inode_dirty(inode); } break; diff --git a/fs/ext3/acl.c b/fs/ext3/acl.c index c76832c8d19..f3326ca3415 100644 --- a/fs/ext3/acl.c +++ b/fs/ext3/acl.c @@ -193,15 +193,11 @@ ext3_set_acl(handle_t *handle, struct inode *inode, int type, case ACL_TYPE_ACCESS: name_index = EXT3_XATTR_INDEX_POSIX_ACL_ACCESS; if (acl) { - error = posix_acl_equiv_mode(acl, &inode->i_mode); - if (error < 0) + error = posix_acl_update_mode(inode, &inode->i_mode, &acl); + if (error) return error; - else { - inode->i_ctime = CURRENT_TIME_SEC; - ext3_mark_inode_dirty(handle, inode); - if (error == 0) - acl = NULL; - } + inode->i_ctime = CURRENT_TIME_SEC; + ext3_mark_inode_dirty(handle, inode); } break; diff --git a/fs/ext4/acl.c b/fs/ext4/acl.c index 8535c45dfce..5d419a496d9 100644 --- a/fs/ext4/acl.c +++ b/fs/ext4/acl.c @@ -198,15 +198,11 @@ ext4_set_acl(handle_t *handle, struct inode *inode, int type, case ACL_TYPE_ACCESS: name_index = EXT4_XATTR_INDEX_POSIX_ACL_ACCESS; if (acl) { - error = posix_acl_equiv_mode(acl, &inode->i_mode); - if (error < 0) + error = posix_acl_update_mode(inode, &inode->i_mode, &acl); + if (error) return error; - else { - inode->i_ctime = ext4_current_time(inode); - ext4_mark_inode_dirty(handle, inode); - if (error == 0) - acl = NULL; - } + inode->i_ctime = ext4_current_time(inode); + ext4_mark_inode_dirty(handle, inode); } break; diff --git a/fs/f2fs/acl.c b/fs/f2fs/acl.c index f431f992555..962e4e98e8a 100644 --- a/fs/f2fs/acl.c +++ b/fs/f2fs/acl.c @@ -211,8 +211,8 @@ static int f2fs_set_acl(struct inode *inode, int type, case ACL_TYPE_ACCESS: name_index = F2FS_XATTR_INDEX_POSIX_ACL_ACCESS; if (acl) { - error = posix_acl_equiv_mode(acl, &inode->i_mode); - if (error < 0) + error = posix_acl_update_mode(inode, &inode->i_mode, &acl); + if (error) return error; set_acl_inode(inode, inode->i_mode); if (error == 0) diff --git a/fs/generic_acl.c b/fs/generic_acl.c index d0dddaceac5..e9c0746e820 100644 --- a/fs/generic_acl.c +++ b/fs/generic_acl.c @@ -87,14 +87,10 @@ generic_acl_set(struct dentry *dentry, const char *name, const void *value, goto failed; switch (type) { case ACL_TYPE_ACCESS: - error = posix_acl_equiv_mode(acl, &inode->i_mode); - if (error < 0) + error = posix_acl_update_mode(inode, &inode->i_mode, &acl); + if (error) goto failed; inode->i_ctime = CURRENT_TIME; - if (error == 0) { - posix_acl_release(acl); - acl = NULL; - } break; case ACL_TYPE_DEFAULT: if (!S_ISDIR(inode->i_mode)) { diff --git a/fs/gfs2/acl.c b/fs/gfs2/acl.c index 230eb0f005b..846611f2e41 100644 --- a/fs/gfs2/acl.c +++ b/fs/gfs2/acl.c @@ -274,15 +274,10 @@ static int gfs2_xattr_system_set(struct dentry *dentry, const char *name, if (type == ACL_TYPE_ACCESS) { umode_t mode = inode->i_mode; - error = posix_acl_equiv_mode(acl, &mode); + error = posix_acl_update_mode(inode, &inode->i_mode, &acl); - if (error <= 0) { - posix_acl_release(acl); - acl = NULL; - - if (error < 0) - return error; - } + if (error) + goto out_release; error = gfs2_set_mode(inode, mode); if (error) diff --git a/fs/jffs2/acl.c b/fs/jffs2/acl.c index 922f146e423..398e5c71c50 100644 --- a/fs/jffs2/acl.c +++ b/fs/jffs2/acl.c @@ -229,9 +229,10 @@ static int jffs2_set_acl(struct inode *inode, int type, struct posix_acl *acl) case ACL_TYPE_ACCESS: xprefix = JFFS2_XPREFIX_ACL_ACCESS; if (acl) { - umode_t mode = inode->i_mode; - rc = posix_acl_equiv_mode(acl, &mode); - if (rc < 0) + umode_t mode; + + rc = posix_acl_update_mode(inode, &mode, &acl); + if (rc) return rc; if (inode->i_mode != mode) { struct iattr attr; @@ -243,8 +244,6 @@ static int jffs2_set_acl(struct inode *inode, int type, struct posix_acl *acl) if (rc < 0) return rc; } - if (rc == 0) - acl = NULL; } break; case ACL_TYPE_DEFAULT: diff --git a/fs/jfs/xattr.c b/fs/jfs/xattr.c index 26683e15b3a..41a0735314f 100644 --- a/fs/jfs/xattr.c +++ b/fs/jfs/xattr.c @@ -693,11 +693,11 @@ static int can_set_system_xattr(struct inode *inode, const char *name, return rc; } if (acl) { - rc = posix_acl_equiv_mode(acl, &inode->i_mode); + rc = posix_acl_update_mode(inode, &inode->i_mode, &acl); posix_acl_release(acl); - if (rc < 0) { + if (rc) { printk(KERN_ERR - "posix_acl_equiv_mode returned %d\n", + "posix_acl_update_mode returned %d\n", rc); return rc; } diff --git a/fs/namei.c b/fs/namei.c index df12b576c21..689339e3e7e 100644 --- a/fs/namei.c +++ b/fs/namei.c @@ -1800,6 +1800,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/ocfs2/acl.c b/fs/ocfs2/acl.c index a7219075b4d..eed868e9a89 100644 --- a/fs/ocfs2/acl.c +++ b/fs/ocfs2/acl.c @@ -248,19 +248,13 @@ static int ocfs2_set_acl(handle_t *handle, name_index = OCFS2_XATTR_INDEX_POSIX_ACL_ACCESS; if (acl) { umode_t mode = inode->i_mode; - ret = posix_acl_equiv_mode(acl, &mode); - if (ret < 0) + ret = posix_acl_update_mode(inode, &mode, &acl); + if (ret) + return ret; + ret = ocfs2_acl_set_mode(inode, di_bh, + handle, mode); + if (ret) return ret; - else { - if (ret == 0) - acl = NULL; - - ret = ocfs2_acl_set_mode(inode, di_bh, - handle, mode); - if (ret) - return ret; - - } } break; case ACL_TYPE_DEFAULT: diff --git a/fs/posix_acl.c b/fs/posix_acl.c index 64496020bf1..9607a1df282 100644 --- a/fs/posix_acl.c +++ b/fs/posix_acl.c @@ -341,6 +341,35 @@ static int posix_acl_create_masq(struct posix_acl *acl, umode_t *mode_p) return not_equiv; } +/** + * posix_acl_update_mode - update mode in set_acl + * + * Update the file mode when setting an ACL: compute the new file permission + * bits based on the ACL. In addition, if the ACL is equivalent to the new + * file mode, set *acl to NULL to indicate that no ACL should be set. + * + * As with chmod, clear the setgit bit if the caller is not in the owning group + * or capable of CAP_FSETID (see inode_change_ok). + * + * Called from set_acl inode operations. + */ +int posix_acl_update_mode(struct inode *inode, umode_t *mode_p, + struct posix_acl **acl) +{ + umode_t mode = inode->i_mode; + int error; + + error = posix_acl_update_mode(inode, &inode->i_mode, acl); + if (error) + return error; + if (!in_group_p(inode->i_gid) && + !capable(CAP_FSETID)) + mode &= ~S_ISGID; + *mode_p = mode; + return 0; +} +EXPORT_SYMBOL(posix_acl_update_mode); + /* * Modify the ACL for the chmod syscall. */ diff --git a/fs/proc/array.c b/fs/proc/array.c index e7bb0fed720..607f80c8d50 100644 --- a/fs/proc/array.c +++ b/fs/proc/array.c @@ -166,16 +166,16 @@ static inline void task_state(struct seq_file *m, struct pid_namespace *ns, int g; struct fdtable *fdt = NULL; const struct cred *cred; - pid_t ppid, tpid; + pid_t ppid = 0, tpid = 0; + struct task_struct *leader = NULL; rcu_read_lock(); - ppid = pid_alive(p) ? - task_tgid_nr_ns(rcu_dereference(p->real_parent), ns) : 0; - tpid = 0; if (pid_alive(p)) { struct task_struct *tracer = ptrace_parent(p); if (tracer) tpid = task_pid_nr_ns(tracer, ns); + ppid = task_tgid_nr_ns(rcu_dereference(p->real_parent), ns); + leader = p->group_leader; } cred = get_task_cred(p); seq_printf(m, @@ -187,7 +187,7 @@ static inline void task_state(struct seq_file *m, struct pid_namespace *ns, "Uid:\t%d\t%d\t%d\t%d\n" "Gid:\t%d\t%d\t%d\t%d\n", get_task_state(p), - task_tgid_nr_ns(p, ns), + leader ? task_pid_nr_ns(leader, ns) : 0, pid_nr_ns(pid, ns), ppid, tpid, cred->uid, cred->euid, cred->suid, cred->fsuid, diff --git a/fs/readdir.c b/fs/readdir.c index cc0a8227cdd..536054080bc 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) diff --git a/fs/reiserfs/xattr_acl.c b/fs/reiserfs/xattr_acl.c index 44474f9b990..502254b6432 100644 --- a/fs/reiserfs/xattr_acl.c +++ b/fs/reiserfs/xattr_acl.c @@ -272,13 +272,9 @@ reiserfs_set_acl(struct reiserfs_transaction_handle *th, struct inode *inode, case ACL_TYPE_ACCESS: name = POSIX_ACL_XATTR_ACCESS; if (acl) { - error = posix_acl_equiv_mode(acl, &inode->i_mode); - if (error < 0) + error = posix_acl_update_mode(inode, &inode->i_mode, &acl); + if (error) return error; - else { - if (error == 0) - acl = NULL; - } } break; case ACL_TYPE_DEFAULT: diff --git a/fs/sdcardfs/main.c b/fs/sdcardfs/main.c index d46970095cb..97375a13ba1 100644 --- a/fs/sdcardfs/main.c +++ b/fs/sdcardfs/main.c @@ -223,6 +223,13 @@ static int sdcardfs_read_super(struct super_block *sb, const char *dev_name, atomic_inc(&lower_sb->s_active); sdcardfs_set_lower_super(sb, lower_sb); + sb->s_stack_depth = lower_sb->s_stack_depth + 1; + if (sb->s_stack_depth > FILESYSTEM_MAX_STACK_DEPTH) { + pr_err("sdcardfs: maximum fs stacking depth exceeded\n"); + err = -EINVAL; + goto out_sput; + } + /* inherit maxbytes from lower file system */ sb->s_maxbytes = lower_sb->s_maxbytes; diff --git a/fs/xfs/xfs_acl.c b/fs/xfs/xfs_acl.c index ac702a6eab9..c0f97c319b7 100644 --- a/fs/xfs/xfs_acl.c +++ b/fs/xfs/xfs_acl.c @@ -384,16 +384,9 @@ xfs_xattr_acl_set(struct dentry *dentry, const char *name, if (type == ACL_TYPE_ACCESS) { umode_t mode = inode->i_mode; - error = posix_acl_equiv_mode(acl, &mode); - - if (error <= 0) { - posix_acl_release(acl); - acl = NULL; - - if (error < 0) - return error; - } - + error = posix_acl_update_mode(inode, &mode, &acl); + if (error) + goto out_release; error = xfs_set_mode(inode, mode); if (error) goto out_release; |
