Skip to content

Commit ae753ee

Browse files
committed
Merge tag 'afs-fixes-20171201' of git://git.kernel.org/pub/scm/linux/kernel/git/dhowells/linux-fs
Pull AFS fixes from David Howells: "Two fix patches for the AFS filesystem: - Fix the refcounting on permit caching. - AFS inode (afs_vnode) fields need resetting after allocation because they're only initialised when slab pages are obtained from the page allocator" * tag 'afs-fixes-20171201' of git://git.kernel.org/pub/scm/linux/kernel/git/dhowells/linux-fs: afs: Properly reset afs_vnode (inode) fields afs: Fix permit refcounting
2 parents 3c1c4dd + f8de483 commit ae753ee

File tree

3 files changed

+27
-10
lines changed

3 files changed

+27
-10
lines changed

fs/afs/internal.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -441,7 +441,10 @@ enum afs_lock_state {
441441
};
442442

443443
/*
444-
* AFS inode private data
444+
* AFS inode private data.
445+
*
446+
* Note that afs_alloc_inode() *must* reset anything that could incorrectly
447+
* leak from one inode to another.
445448
*/
446449
struct afs_vnode {
447450
struct inode vfs_inode; /* the VFS's inode record */

fs/afs/security.c

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,7 @@ static void afs_hash_permits(struct afs_permits *permits)
120120
void afs_cache_permit(struct afs_vnode *vnode, struct key *key,
121121
unsigned int cb_break)
122122
{
123-
struct afs_permits *permits, *xpermits, *replacement, *new = NULL;
123+
struct afs_permits *permits, *xpermits, *replacement, *zap, *new = NULL;
124124
afs_access_t caller_access = READ_ONCE(vnode->status.caller_access);
125125
size_t size = 0;
126126
bool changed = false;
@@ -204,7 +204,7 @@ void afs_cache_permit(struct afs_vnode *vnode, struct key *key,
204204
new = kzalloc(sizeof(struct afs_permits) +
205205
sizeof(struct afs_permit) * size, GFP_NOFS);
206206
if (!new)
207-
return;
207+
goto out_put;
208208

209209
refcount_set(&new->usage, 1);
210210
new->nr_permits = size;
@@ -229,8 +229,6 @@ void afs_cache_permit(struct afs_vnode *vnode, struct key *key,
229229

230230
afs_hash_permits(new);
231231

232-
afs_put_permits(permits);
233-
234232
/* Now see if the permit list we want is actually already available */
235233
spin_lock(&afs_permits_lock);
236234

@@ -262,11 +260,15 @@ void afs_cache_permit(struct afs_vnode *vnode, struct key *key,
262260
kfree(new);
263261

264262
spin_lock(&vnode->lock);
265-
if (cb_break != (vnode->cb_break + vnode->cb_interest->server->cb_s_break) ||
266-
permits != rcu_access_pointer(vnode->permit_cache))
267-
goto someone_else_changed_it_unlock;
268-
rcu_assign_pointer(vnode->permit_cache, replacement);
263+
zap = rcu_access_pointer(vnode->permit_cache);
264+
if (cb_break == (vnode->cb_break + vnode->cb_interest->server->cb_s_break) &&
265+
zap == permits)
266+
rcu_assign_pointer(vnode->permit_cache, replacement);
267+
else
268+
zap = replacement;
269269
spin_unlock(&vnode->lock);
270+
afs_put_permits(zap);
271+
out_put:
270272
afs_put_permits(permits);
271273
return;
272274

fs/afs/super.c

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -536,7 +536,9 @@ static void afs_kill_super(struct super_block *sb)
536536
}
537537

538538
/*
539-
* initialise an inode cache slab element prior to any use
539+
* Initialise an inode cache slab element prior to any use. Note that
540+
* afs_alloc_inode() *must* reset anything that could incorrectly leak from one
541+
* inode to another.
540542
*/
541543
static void afs_i_init_once(void *_vnode)
542544
{
@@ -568,11 +570,21 @@ static struct inode *afs_alloc_inode(struct super_block *sb)
568570

569571
atomic_inc(&afs_count_active_inodes);
570572

573+
/* Reset anything that shouldn't leak from one inode to the next. */
571574
memset(&vnode->fid, 0, sizeof(vnode->fid));
572575
memset(&vnode->status, 0, sizeof(vnode->status));
573576

574577
vnode->volume = NULL;
578+
vnode->lock_key = NULL;
579+
vnode->permit_cache = NULL;
580+
vnode->cb_interest = NULL;
581+
#ifdef CONFIG_AFS_FSCACHE
582+
vnode->cache = NULL;
583+
#endif
584+
575585
vnode->flags = 1 << AFS_VNODE_UNSET;
586+
vnode->cb_type = 0;
587+
vnode->lock_state = AFS_VNODE_LOCK_NONE;
576588

577589
_leave(" = %p", &vnode->vfs_inode);
578590
return &vnode->vfs_inode;

0 commit comments

Comments
 (0)