diff options
| author | Srinivasarao P <spathi@codeaurora.org> | 2018-09-28 12:05:13 +0530 |
|---|---|---|
| committer | Srinivasarao P <spathi@codeaurora.org> | 2018-09-28 12:05:58 +0530 |
| commit | 0280dd7aee45ec2a4cfce936f61ba619af9288ab (patch) | |
| tree | cc796c490fb43512281c6fd994b603e2af19ebe8 /fs/overlayfs/readdir.c | |
| parent | 7c445f53749dc7347dcbb8e1cee28f2a3faa8896 (diff) | |
| parent | 7eb7037bb3fdb271ca6d593b6897b0575093795e (diff) | |
Merge android-4.4.156 (7eb7037) into msm-4.4
* refs/heads/tmp-7eb7037
Linux 4.4.156
btrfs: use correct compare function of dirty_metadata_bytes
ASoC: wm8994: Fix missing break in switch
s390/lib: use expoline for all bcr instructions
mei: me: allow runtime pm for platform with D0i3
sch_tbf: fix two null pointer dereferences on init failure
sch_netem: avoid null pointer deref on init failure
sch_hhf: fix null pointer dereference on init failure
sch_multiq: fix double free on init failure
sch_htb: fix crash on init failure
ovl: proper cleanup of workdir
ovl: override creds with the ones from the superblock mounter
ovl: rename is_merge to is_lowest
irqchip/gic: Make interrupt ID 1020 invalid
irqchip/gic-v3: Add missing barrier to 32bit version of gic_read_iar()
irqchip/gicv3-its: Avoid cache flush beyond ITS_BASERn memory size
irqchip/gicv3-its: Fix memory leak in its_free_tables()
irqchip/gic-v3-its: Recompute the number of pages on page size change
genirq: Delay incrementing interrupt count if it's disabled/pending
Fixes: Commit cdbf92675fad ("mm: numa: avoid waiting on freed migrated pages")
enic: do not call enic_change_mtu in enic_probe
Revert "ARM: imx_v6_v7_defconfig: Select ULPI support"
irda: Only insert new objects into the global database via setsockopt
irda: Fix memory leak caused by repeated binds of irda socket
kbuild: make missing $DEPMOD a Warning instead of an Error
x86/pae: use 64 bit atomic xchg function in native_ptep_get_and_clear
debugobjects: Make stack check warning more informative
btrfs: Don't remove block group that still has pinned down bytes
btrfs: relocation: Only remove reloc rb_trees if reloc control has been initialized
btrfs: replace: Reset on-disk dev stats value after replace
powerpc/pseries: Avoid using the size greater than RTAS_ERROR_LOG_MAX.
SMB3: Number of requests sent should be displayed for SMB3 not just CIFS
smb3: fix reset of bytes read and written stats
selftests/powerpc: Kill child processes on SIGINT
staging: comedi: ni_mio_common: fix subdevice flags for PFI subdevice
dm kcopyd: avoid softlockup in run_complete_job
PCI: mvebu: Fix I/O space end address calculation
scsi: aic94xx: fix an error code in aic94xx_init()
s390/dasd: fix hanging offline processing due to canceled worker
powerpc: Fix size calculation using resource_size()
net/9p: fix error path of p9_virtio_probe
irqchip/bcm7038-l1: Hide cpu offline callback when building for !SMP
platform/x86: asus-nb-wmi: Add keymap entry for lid flip action on UX360
mfd: sm501: Set coherent_dma_mask when creating subdevices
ipvs: fix race between ip_vs_conn_new() and ip_vs_del_dest()
fs/dcache.c: fix kmemcheck splat at take_dentry_name_snapshot()
mm/fadvise.c: fix signed overflow UBSAN complaint
scripts: modpost: check memory allocation results
fat: validate ->i_start before using
hfsplus: fix NULL dereference in hfsplus_lookup()
reiserfs: change j_timestamp type to time64_t
fork: don't copy inconsistent signal handler state to child
hfs: prevent crash on exit from failed search
hfsplus: don't return 0 when fill_super() failed
cifs: check if SMB2 PDU size has been padded and suppress the warning
vti6: remove !skb->ignore_df check from vti6_xmit()
tcp: do not restart timewait timer on rst reception
qlge: Fix netdev features configuration.
net: bcmgenet: use MAC link status for fixed phy
staging: android: ion: fix ION_IOC_{MAP,SHARE} use-after-free
x86/speculation/l1tf: Fix up pte->pfn conversion for PAE
Conflicts:
drivers/staging/android/ion/ion.c
Change-Id: I7153f61c3a676a788f64eeb8bab13e840bbbf985
[readded the function ion_handle_get_by_id() which got deleted with
commit 'staging: android: ion: fix ION_IOC_{MAP,SHARE} use-after-free'
since it is used in msm/msm_ion.c]
Signed-off-by: Srinivasarao P <spathi@codeaurora.org>
Diffstat (limited to 'fs/overlayfs/readdir.c')
| -rw-r--r-- | fs/overlayfs/readdir.c | 93 |
1 files changed, 73 insertions, 20 deletions
diff --git a/fs/overlayfs/readdir.c b/fs/overlayfs/readdir.c index 0c59955c4653..da999e73c97a 100644 --- a/fs/overlayfs/readdir.c +++ b/fs/overlayfs/readdir.c @@ -36,7 +36,8 @@ struct ovl_dir_cache { struct ovl_readdir_data { struct dir_context ctx; - bool is_merge; + struct dentry *dentry; + bool is_lowest; struct rb_root root; struct list_head *list; struct list_head middle; @@ -140,9 +141,9 @@ static int ovl_cache_entry_add_rb(struct ovl_readdir_data *rdd, return 0; } -static int ovl_fill_lower(struct ovl_readdir_data *rdd, - const char *name, int namelen, - loff_t offset, u64 ino, unsigned int d_type) +static int ovl_fill_lowest(struct ovl_readdir_data *rdd, + const char *name, int namelen, + loff_t offset, u64 ino, unsigned int d_type) { struct ovl_cache_entry *p; @@ -194,10 +195,10 @@ static int ovl_fill_merge(struct dir_context *ctx, const char *name, container_of(ctx, struct ovl_readdir_data, ctx); rdd->count++; - if (!rdd->is_merge) + if (!rdd->is_lowest) return ovl_cache_entry_add_rb(rdd, name, namelen, ino, d_type); else - return ovl_fill_lower(rdd, name, namelen, offset, ino, d_type); + return ovl_fill_lowest(rdd, name, namelen, offset, ino, d_type); } static int ovl_check_whiteouts(struct dentry *dir, struct ovl_readdir_data *rdd) @@ -206,17 +207,8 @@ static int ovl_check_whiteouts(struct dentry *dir, struct ovl_readdir_data *rdd) struct ovl_cache_entry *p; struct dentry *dentry; const struct cred *old_cred; - struct cred *override_cred; - - override_cred = prepare_creds(); - if (!override_cred) - return -ENOMEM; - /* - * CAP_DAC_OVERRIDE for lookup - */ - cap_raise(override_cred->cap_effective, CAP_DAC_OVERRIDE); - old_cred = override_creds(override_cred); + old_cred = ovl_override_creds(rdd->dentry->d_sb); err = mutex_lock_killable(&dir->d_inode->i_mutex); if (!err) { @@ -232,7 +224,6 @@ static int ovl_check_whiteouts(struct dentry *dir, struct ovl_readdir_data *rdd) mutex_unlock(&dir->d_inode->i_mutex); } revert_creds(old_cred); - put_cred(override_cred); return err; } @@ -257,7 +248,7 @@ static inline int ovl_dir_read(struct path *realpath, err = rdd->err; } while (!err && rdd->count); - if (!err && rdd->first_maybe_whiteout) + if (!err && rdd->first_maybe_whiteout && rdd->dentry) err = ovl_check_whiteouts(realpath->dentry, rdd); fput(realfile); @@ -288,9 +279,10 @@ static int ovl_dir_read_merged(struct dentry *dentry, struct list_head *list) struct path realpath; struct ovl_readdir_data rdd = { .ctx.actor = ovl_fill_merge, + .dentry = dentry, .list = list, .root = RB_ROOT, - .is_merge = false, + .is_lowest = false, }; int idx, next; @@ -307,7 +299,7 @@ static int ovl_dir_read_merged(struct dentry *dentry, struct list_head *list) * allows offsets to be reasonably constant */ list_add(&rdd.middle, rdd.list); - rdd.is_merge = true; + rdd.is_lowest = true; err = ovl_dir_read(&realpath, &rdd); list_del(&rdd.middle); } @@ -618,3 +610,64 @@ int ovl_check_d_type_supported(struct path *realpath) return rdd.d_type_supported; } + +static void ovl_workdir_cleanup_recurse(struct path *path, int level) +{ + int err; + struct inode *dir = path->dentry->d_inode; + LIST_HEAD(list); + struct ovl_cache_entry *p; + struct ovl_readdir_data rdd = { + .ctx.actor = ovl_fill_merge, + .dentry = NULL, + .list = &list, + .root = RB_ROOT, + .is_lowest = false, + }; + + err = ovl_dir_read(path, &rdd); + if (err) + goto out; + + inode_lock_nested(dir, I_MUTEX_PARENT); + list_for_each_entry(p, &list, l_node) { + struct dentry *dentry; + + if (p->name[0] == '.') { + if (p->len == 1) + continue; + if (p->len == 2 && p->name[1] == '.') + continue; + } + dentry = lookup_one_len(p->name, path->dentry, p->len); + if (IS_ERR(dentry)) + continue; + if (dentry->d_inode) + ovl_workdir_cleanup(dir, path->mnt, dentry, level); + dput(dentry); + } + inode_unlock(dir); +out: + ovl_cache_free(&list); +} + +void ovl_workdir_cleanup(struct inode *dir, struct vfsmount *mnt, + struct dentry *dentry, int level) +{ + int err; + + if (!d_is_dir(dentry) || level > 1) { + ovl_cleanup(dir, dentry); + return; + } + + err = ovl_do_rmdir(dir, dentry); + if (err) { + struct path path = { .mnt = mnt, .dentry = dentry }; + + inode_unlock(dir); + ovl_workdir_cleanup_recurse(&path, level + 1); + inode_lock_nested(dir, I_MUTEX_PARENT); + ovl_cleanup(dir, dentry); + } +} |
