From 798434bda36e357af9ccaf68a7ba1129658c8332 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Thu, 24 Mar 2016 20:38:43 -0400 Subject: __d_alloc(): treat NULL name as QSTR("/", 1) Signed-off-by: Al Viro --- fs/dcache.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) (limited to 'fs') diff --git a/fs/dcache.c b/fs/dcache.c index 32ceae3e6112..3cb98dfd9f96 100644 --- a/fs/dcache.c +++ b/fs/dcache.c @@ -1558,7 +1558,11 @@ struct dentry *__d_alloc(struct super_block *sb, const struct qstr *name) * be overwriting an internal NUL character */ dentry->d_iname[DNAME_INLINE_LEN-1] = 0; - if (name->len > DNAME_INLINE_LEN-1) { + if (unlikely(!name)) { + static const struct qstr anon = QSTR_INIT("/", 1); + name = &anon; + dname = dentry->d_iname; + } else if (name->len > DNAME_INLINE_LEN-1) { size_t size = offsetof(struct external_name, name[1]); struct external_name *p = kmalloc(size + name->len, GFP_KERNEL_ACCOUNT); @@ -1812,9 +1816,7 @@ struct dentry *d_make_root(struct inode *root_inode) struct dentry *res = NULL; if (root_inode) { - static const struct qstr name = QSTR_INIT("/", 1); - - res = __d_alloc(root_inode->i_sb, &name); + res = __d_alloc(root_inode->i_sb, NULL); if (res) d_instantiate(res, root_inode); else @@ -1855,7 +1857,6 @@ EXPORT_SYMBOL(d_find_any_alias); static struct dentry *__d_obtain_alias(struct inode *inode, int disconnected) { - static const struct qstr anonstring = QSTR_INIT("/", 1); struct dentry *tmp; struct dentry *res; unsigned add_flags; @@ -1869,7 +1870,7 @@ static struct dentry *__d_obtain_alias(struct inode *inode, int disconnected) if (res) goto out_iput; - tmp = __d_alloc(inode->i_sb, &anonstring); + tmp = __d_alloc(inode->i_sb, NULL); if (!tmp) { res = ERR_PTR(-ENOMEM); goto out_iput; -- cgit v1.2.3 From b1168a928277149e1c606763d76ff5c728988755 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Mon, 28 Mar 2016 00:30:35 -0400 Subject: ecryptfs: avoid multiple aliases for directories ecryptfs_lookup_interpose should use d_splice_alias(), not d_add() (and return struct dentry * rather than int). Get rid of redundant dir_inode argument, while we are touching it... Signed-off-by: Al Viro --- fs/ecryptfs/inode.c | 40 ++++++++++++++++++++-------------------- 1 file changed, 20 insertions(+), 20 deletions(-) (limited to 'fs') diff --git a/fs/ecryptfs/inode.c b/fs/ecryptfs/inode.c index 121114e9a464..91ebc8f18e20 100644 --- a/fs/ecryptfs/inode.c +++ b/fs/ecryptfs/inode.c @@ -324,9 +324,8 @@ static int ecryptfs_i_size_read(struct dentry *dentry, struct inode *inode) /** * ecryptfs_lookup_interpose - Dentry interposition for a lookup */ -static int ecryptfs_lookup_interpose(struct dentry *dentry, - struct dentry *lower_dentry, - struct inode *dir_inode) +static struct dentry *ecryptfs_lookup_interpose(struct dentry *dentry, + struct dentry *lower_dentry) { struct inode *inode, *lower_inode = d_inode(lower_dentry); struct ecryptfs_dentry_info *dentry_info; @@ -339,11 +338,12 @@ static int ecryptfs_lookup_interpose(struct dentry *dentry, "to allocate ecryptfs_dentry_info struct\n", __func__); dput(lower_dentry); - return -ENOMEM; + return ERR_PTR(-ENOMEM); } lower_mnt = mntget(ecryptfs_dentry_to_lower_mnt(dentry->d_parent)); - fsstack_copy_attr_atime(dir_inode, d_inode(lower_dentry->d_parent)); + fsstack_copy_attr_atime(d_inode(dentry->d_parent), + d_inode(lower_dentry->d_parent)); BUG_ON(!d_count(lower_dentry)); ecryptfs_set_dentry_private(dentry, dentry_info); @@ -353,27 +353,25 @@ static int ecryptfs_lookup_interpose(struct dentry *dentry, if (d_really_is_negative(lower_dentry)) { /* We want to add because we couldn't find in lower */ d_add(dentry, NULL); - return 0; + return NULL; } - inode = __ecryptfs_get_inode(lower_inode, dir_inode->i_sb); + inode = __ecryptfs_get_inode(lower_inode, dentry->d_sb); if (IS_ERR(inode)) { printk(KERN_ERR "%s: Error interposing; rc = [%ld]\n", __func__, PTR_ERR(inode)); - return PTR_ERR(inode); + return ERR_CAST(inode); } if (S_ISREG(inode->i_mode)) { rc = ecryptfs_i_size_read(dentry, inode); if (rc) { make_bad_inode(inode); - return rc; + return ERR_PTR(rc); } } if (inode->i_state & I_NEW) unlock_new_inode(inode); - d_add(dentry, inode); - - return rc; + return d_splice_alias(inode, dentry); } /** @@ -393,6 +391,7 @@ static struct dentry *ecryptfs_lookup(struct inode *ecryptfs_dir_inode, size_t encrypted_and_encoded_name_size; struct ecryptfs_mount_crypt_stat *mount_crypt_stat = NULL; struct dentry *lower_dir_dentry, *lower_dentry; + struct dentry *res; int rc = 0; lower_dir_dentry = ecryptfs_dentry_to_lower(ecryptfs_dentry->d_parent); @@ -400,10 +399,10 @@ static struct dentry *ecryptfs_lookup(struct inode *ecryptfs_dir_inode, lower_dir_dentry, ecryptfs_dentry->d_name.len); if (IS_ERR(lower_dentry)) { - rc = PTR_ERR(lower_dentry); ecryptfs_printk(KERN_DEBUG, "%s: lookup_one_len() returned " - "[%d] on lower_dentry = [%pd]\n", __func__, rc, - ecryptfs_dentry); + "[%ld] on lower_dentry = [%pd]\n", __func__, + PTR_ERR(lower_dentry), ecryptfs_dentry); + res = ERR_CAST(lower_dentry); goto out; } if (d_really_is_positive(lower_dentry)) @@ -421,24 +420,25 @@ static struct dentry *ecryptfs_lookup(struct inode *ecryptfs_dir_inode, if (rc) { printk(KERN_ERR "%s: Error attempting to encrypt and encode " "filename; rc = [%d]\n", __func__, rc); + res = ERR_PTR(rc); goto out; } lower_dentry = lookup_one_len_unlocked(encrypted_and_encoded_name, lower_dir_dentry, encrypted_and_encoded_name_size); if (IS_ERR(lower_dentry)) { - rc = PTR_ERR(lower_dentry); ecryptfs_printk(KERN_DEBUG, "%s: lookup_one_len() returned " - "[%d] on lower_dentry = [%s]\n", __func__, rc, + "[%ld] on lower_dentry = [%s]\n", __func__, + PTR_ERR(lower_dentry), encrypted_and_encoded_name); + res = ERR_CAST(lower_dentry); goto out; } interpose: - rc = ecryptfs_lookup_interpose(ecryptfs_dentry, lower_dentry, - ecryptfs_dir_inode); + res = ecryptfs_lookup_interpose(ecryptfs_dentry, lower_dentry); out: kfree(encrypted_and_encoded_name); - return ERR_PTR(rc); + return res; } static int ecryptfs_link(struct dentry *old_dentry, struct inode *dir, -- cgit v1.2.3 From 88ae4ab9802eaa8e400e611f85883143d89d6b61 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Mon, 28 Mar 2016 00:43:29 -0400 Subject: ecryptfs_lookup(): try either only encrypted or plaintext name Signed-off-by: Al Viro --- fs/ecryptfs/inode.c | 55 +++++++++++++++++++---------------------------------- 1 file changed, 20 insertions(+), 35 deletions(-) (limited to 'fs') diff --git a/fs/ecryptfs/inode.c b/fs/ecryptfs/inode.c index 91ebc8f18e20..2b8fc9b6b570 100644 --- a/fs/ecryptfs/inode.c +++ b/fs/ecryptfs/inode.c @@ -388,55 +388,40 @@ static struct dentry *ecryptfs_lookup(struct inode *ecryptfs_dir_inode, unsigned int flags) { char *encrypted_and_encoded_name = NULL; - size_t encrypted_and_encoded_name_size; - struct ecryptfs_mount_crypt_stat *mount_crypt_stat = NULL; + struct ecryptfs_mount_crypt_stat *mount_crypt_stat; struct dentry *lower_dir_dentry, *lower_dentry; + const char *name = ecryptfs_dentry->d_name.name; + size_t len = ecryptfs_dentry->d_name.len; struct dentry *res; int rc = 0; lower_dir_dentry = ecryptfs_dentry_to_lower(ecryptfs_dentry->d_parent); - lower_dentry = lookup_one_len_unlocked(ecryptfs_dentry->d_name.name, - lower_dir_dentry, - ecryptfs_dentry->d_name.len); - if (IS_ERR(lower_dentry)) { - ecryptfs_printk(KERN_DEBUG, "%s: lookup_one_len() returned " - "[%ld] on lower_dentry = [%pd]\n", __func__, - PTR_ERR(lower_dentry), ecryptfs_dentry); - res = ERR_CAST(lower_dentry); - goto out; - } - if (d_really_is_positive(lower_dentry)) - goto interpose; + mount_crypt_stat = &ecryptfs_superblock_to_private( ecryptfs_dentry->d_sb)->mount_crypt_stat; - if (!(mount_crypt_stat - && (mount_crypt_stat->flags & ECRYPTFS_GLOBAL_ENCRYPT_FILENAMES))) - goto interpose; - dput(lower_dentry); - rc = ecryptfs_encrypt_and_encode_filename( - &encrypted_and_encoded_name, &encrypted_and_encoded_name_size, - mount_crypt_stat, ecryptfs_dentry->d_name.name, - ecryptfs_dentry->d_name.len); - if (rc) { - printk(KERN_ERR "%s: Error attempting to encrypt and encode " - "filename; rc = [%d]\n", __func__, rc); - res = ERR_PTR(rc); - goto out; + if (mount_crypt_stat + && (mount_crypt_stat->flags & ECRYPTFS_GLOBAL_ENCRYPT_FILENAMES)) { + rc = ecryptfs_encrypt_and_encode_filename( + &encrypted_and_encoded_name, &len, + mount_crypt_stat, name, len); + if (rc) { + printk(KERN_ERR "%s: Error attempting to encrypt and encode " + "filename; rc = [%d]\n", __func__, rc); + return ERR_PTR(rc); + } + name = encrypted_and_encoded_name; } - lower_dentry = lookup_one_len_unlocked(encrypted_and_encoded_name, - lower_dir_dentry, - encrypted_and_encoded_name_size); + + lower_dentry = lookup_one_len_unlocked(name, lower_dir_dentry, len); if (IS_ERR(lower_dentry)) { ecryptfs_printk(KERN_DEBUG, "%s: lookup_one_len() returned " "[%ld] on lower_dentry = [%s]\n", __func__, PTR_ERR(lower_dentry), - encrypted_and_encoded_name); + name); res = ERR_CAST(lower_dentry); - goto out; + } else { + res = ecryptfs_lookup_interpose(ecryptfs_dentry, lower_dentry); } -interpose: - res = ecryptfs_lookup_interpose(ecryptfs_dentry, lower_dentry); -out: kfree(encrypted_and_encoded_name); return res; } -- cgit v1.2.3 From a00839395103d5e2d132a6c4a9680256580ed3d1 Mon Sep 17 00:00:00 2001 From: Omar Sandoval Date: Wed, 11 May 2016 15:16:36 -0700 Subject: coredump: get rid of coredump_params->written cprm->written is redundant with cprm->file->f_pos, so use that instead. Signed-off-by: Omar Sandoval Signed-off-by: Al Viro --- arch/powerpc/platforms/cell/spufs/coredump.c | 5 +++-- fs/binfmt_elf.c | 2 +- fs/binfmt_elf_fdpic.c | 2 +- fs/coredump.c | 8 +++----- include/linux/binfmts.h | 1 - 5 files changed, 8 insertions(+), 10 deletions(-) (limited to 'fs') diff --git a/arch/powerpc/platforms/cell/spufs/coredump.c b/arch/powerpc/platforms/cell/spufs/coredump.c index be6212ddbf06..84fb984f29c1 100644 --- a/arch/powerpc/platforms/cell/spufs/coredump.c +++ b/arch/powerpc/platforms/cell/spufs/coredump.c @@ -137,6 +137,7 @@ static int spufs_arch_write_note(struct spu_context *ctx, int i, char *name; char fullname[80], *buf; struct elf_note en; + size_t skip; buf = (void *)get_zeroed_page(GFP_KERNEL); if (!buf) @@ -171,8 +172,8 @@ static int spufs_arch_write_note(struct spu_context *ctx, int i, if (rc < 0) goto out; - if (!dump_skip(cprm, - roundup(cprm->written - total + sz, 4) - cprm->written)) + skip = roundup(cprm->file->f_pos - total + sz, 4) - cprm->file->f_pos; + if (!dump_skip(cprm, skip)) goto Eio; out: free_page((unsigned long)buf); diff --git a/fs/binfmt_elf.c b/fs/binfmt_elf.c index 7d914c67a9d0..f5ce8f4e00b0 100644 --- a/fs/binfmt_elf.c +++ b/fs/binfmt_elf.c @@ -2273,7 +2273,7 @@ static int elf_core_dump(struct coredump_params *cprm) goto end_coredump; /* Align to page */ - if (!dump_skip(cprm, dataoff - cprm->written)) + if (!dump_skip(cprm, dataoff - cprm->file->f_pos)) goto end_coredump; for (i = 0, vma = first_vma(current, gate_vma); vma != NULL; diff --git a/fs/binfmt_elf_fdpic.c b/fs/binfmt_elf_fdpic.c index b1adb92e69de..8cfde2482468 100644 --- a/fs/binfmt_elf_fdpic.c +++ b/fs/binfmt_elf_fdpic.c @@ -1787,7 +1787,7 @@ static int elf_fdpic_core_dump(struct coredump_params *cprm) goto end_coredump; } - if (!dump_skip(cprm, dataoff - cprm->written)) + if (!dump_skip(cprm, dataoff - cprm->file->f_pos)) goto end_coredump; if (!elf_fdpic_dump_segments(cprm)) diff --git a/fs/coredump.c b/fs/coredump.c index 47c32c3bfa1d..9db0c514438e 100644 --- a/fs/coredump.c +++ b/fs/coredump.c @@ -782,7 +782,7 @@ int dump_emit(struct coredump_params *cprm, const void *addr, int nr) struct file *file = cprm->file; loff_t pos = file->f_pos; ssize_t n; - if (cprm->written + nr > cprm->limit) + if (pos + nr > cprm->limit) return 0; while (nr) { if (dump_interrupted()) @@ -791,7 +791,6 @@ int dump_emit(struct coredump_params *cprm, const void *addr, int nr) if (n <= 0) return 0; file->f_pos = pos; - cprm->written += n; nr -= n; } return 1; @@ -803,12 +802,11 @@ int dump_skip(struct coredump_params *cprm, size_t nr) static char zeroes[PAGE_SIZE]; struct file *file = cprm->file; if (file->f_op->llseek && file->f_op->llseek != no_llseek) { - if (cprm->written + nr > cprm->limit) + if (file->f_pos + nr > cprm->limit) return 0; if (dump_interrupted() || file->f_op->llseek(file, nr, SEEK_CUR) < 0) return 0; - cprm->written += nr; return 1; } else { while (nr > PAGE_SIZE) { @@ -823,7 +821,7 @@ EXPORT_SYMBOL(dump_skip); int dump_align(struct coredump_params *cprm, int align) { - unsigned mod = cprm->written & (align - 1); + unsigned mod = cprm->file->f_pos & (align - 1); if (align & (align - 1)) return 0; return mod ? dump_skip(cprm, align - mod) : 1; diff --git a/include/linux/binfmts.h b/include/linux/binfmts.h index 576e4639ca60..39c6d6e1234e 100644 --- a/include/linux/binfmts.h +++ b/include/linux/binfmts.h @@ -64,7 +64,6 @@ struct coredump_params { struct file *file; unsigned long limit; unsigned long mm_flags; - loff_t written; }; /* -- cgit v1.2.3 From 2c4cb04300fa160e9d78335c74184c4e66a56437 Mon Sep 17 00:00:00 2001 From: Omar Sandoval Date: Wed, 11 May 2016 15:16:37 -0700 Subject: coredump: only charge written data against RLIMIT_CORE Commit 9b56d54380ad ("dump_skip(): dump_seek() replacement taking coredump_params") introduced a regression with regard to RLIMIT_CORE. Previously, when a core dump was sparse, only the data that was actually written out would count against the limit. Now, the sparse ranges are also included, which leads to truncated core dumps when the actual disk usage is still well below the limit. Restore the old behavior by only counting what gets emitted and ignoring what gets skipped. Signed-off-by: Omar Sandoval Signed-off-by: Al Viro --- fs/coredump.c | 5 ++--- include/linux/binfmts.h | 1 + 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'fs') diff --git a/fs/coredump.c b/fs/coredump.c index 9db0c514438e..492c2db25dc9 100644 --- a/fs/coredump.c +++ b/fs/coredump.c @@ -782,7 +782,7 @@ int dump_emit(struct coredump_params *cprm, const void *addr, int nr) struct file *file = cprm->file; loff_t pos = file->f_pos; ssize_t n; - if (pos + nr > cprm->limit) + if (cprm->written + nr > cprm->limit) return 0; while (nr) { if (dump_interrupted()) @@ -791,6 +791,7 @@ int dump_emit(struct coredump_params *cprm, const void *addr, int nr) if (n <= 0) return 0; file->f_pos = pos; + cprm->written += n; nr -= n; } return 1; @@ -802,8 +803,6 @@ int dump_skip(struct coredump_params *cprm, size_t nr) static char zeroes[PAGE_SIZE]; struct file *file = cprm->file; if (file->f_op->llseek && file->f_op->llseek != no_llseek) { - if (file->f_pos + nr > cprm->limit) - return 0; if (dump_interrupted() || file->f_op->llseek(file, nr, SEEK_CUR) < 0) return 0; diff --git a/include/linux/binfmts.h b/include/linux/binfmts.h index 39c6d6e1234e..576e4639ca60 100644 --- a/include/linux/binfmts.h +++ b/include/linux/binfmts.h @@ -64,6 +64,7 @@ struct coredump_params { struct file *file; unsigned long limit; unsigned long mm_flags; + loff_t written; }; /* -- cgit v1.2.3