From 0060caec1aebd380198d9b131a18d77cae82d11d Mon Sep 17 00:00:00 2001 From: John Johansen Date: Fri, 23 Mar 2007 16:28:10 +0000 Subject: [PATCH] Fix a race between path lookup and removal of " (deleted)" that could result in incorrect removal of " (deleted)" from the pathname. The race is as follows: the path contains " (deleted)", which is unlikely but valid during path lookup the path is valid after path lookup before the deleted test the dentry is unhashed the deleted test now succeeds but the pathname never had " (deleted)" appended by d_path. The paths " (deleted)" string is removed and an incorrect path is returned --- module/apparmor/main.c | 23 +++++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/module/apparmor/main.c b/module/apparmor/main.c index 5459fdf66..d6cfb1370 100644 --- a/module/apparmor/main.c +++ b/module/apparmor/main.c @@ -779,6 +779,7 @@ out: char *aa_get_name(struct dentry *dentry, struct vfsmount *mnt) { char *page, *name; + int deleted = !IS_ROOT(dentry) && d_unhashed(dentry); page = (char *)__get_free_page(GFP_KERNEL); if (!page) { @@ -786,20 +787,30 @@ char *aa_get_name(struct dentry *dentry, struct vfsmount *mnt) goto out; } +retry: name = d_path(dentry, mnt, page, PAGE_SIZE); - /* check for (deleted) that d_path appends to pathnames if the dentry - * has been removed from the cache. - * The size > deleted_size and strcmp checks are redundant safe guards. - */ + if (IS_ERR(name)) { free_page((unsigned long)page); + } else if (!deleted && (!IS_ROOT(dentry) && d_unhashed(dentry))) { + /* test for race of name lookup against the dentry being + * deleted. If a race is detected then redo the lookup, + * so that the (deleted) suffix can be unambiguously removed + */ + deleted = 1; + goto retry; } else { const char deleted_str[] = " (deleted)"; const size_t deleted_size = sizeof(deleted_str) - 1; size_t size; size = strlen(name); - if (!IS_ROOT(dentry) && d_unhashed(dentry) && - size > deleted_size && + + /* check for (deleted) that d_path appends to pathnames if + * the dentry has been removed from the cache. + * The size > deleted_size and strcmp checks are redundant + * safe guards. + */ + if (deleted && size > deleted_size && strcmp(name + size - deleted_size, deleted_str) == 0) name[size - deleted_size] = '\0'; AA_DEBUG("%s: full_path=%s\n", __FUNCTION__, name);