aboutsummaryrefslogtreecommitdiffstats
path: root/fs/ubifs
diff options
context:
space:
mode:
authorAdam Thomas <adamthomas1111@gmail.com>2013-02-02 17:35:08 -0500
committerArtem Bityutskiy <artem.bityutskiy@linux.intel.com>2013-02-04 05:31:48 -0500
commit8afd500cb52a5d00bab4525dd5a560d199f979b9 (patch)
tree91ee2f6917c1f84300308dc6e659865cae89a3cc /fs/ubifs
parent2928f0d0c5ebd6c9605c0d98207a44376387c298 (diff)
UBIFS: fix double free of ubifs_orphan objects
The last orphan in the dnext list has its dnext set to NULL. Because of that, ubifs_delete_orphan assumes that it is not on the dnext list and frees it immediately instead ignoring it as a second delete. The orphan is later freed again by erase_deleted. This change adds an explicit flag to ubifs_orphan indicating whether it is pending delete. Signed-off-by: Adam Thomas <adamthomas1111@gmail.com> Signed-off-by: Artem Bityutskiy <artem.bityutskiy@linux.intel.com> Cc: stable@vger.kernel.org
Diffstat (limited to 'fs/ubifs')
-rw-r--r--fs/ubifs/orphan.c5
-rw-r--r--fs/ubifs/ubifs.h2
2 files changed, 6 insertions, 1 deletions
diff --git a/fs/ubifs/orphan.c b/fs/ubifs/orphan.c
index 8534d9c6492f..ba32da3fe08a 100644
--- a/fs/ubifs/orphan.c
+++ b/fs/ubifs/orphan.c
@@ -126,13 +126,14 @@ void ubifs_delete_orphan(struct ubifs_info *c, ino_t inum)
126 else if (inum > o->inum) 126 else if (inum > o->inum)
127 p = p->rb_right; 127 p = p->rb_right;
128 else { 128 else {
129 if (o->dnext) { 129 if (o->del) {
130 spin_unlock(&c->orphan_lock); 130 spin_unlock(&c->orphan_lock);
131 dbg_gen("deleted twice ino %lu", 131 dbg_gen("deleted twice ino %lu",
132 (unsigned long)inum); 132 (unsigned long)inum);
133 return; 133 return;
134 } 134 }
135 if (o->cmt) { 135 if (o->cmt) {
136 o->del = 1;
136 o->dnext = c->orph_dnext; 137 o->dnext = c->orph_dnext;
137 c->orph_dnext = o; 138 c->orph_dnext = o;
138 spin_unlock(&c->orphan_lock); 139 spin_unlock(&c->orphan_lock);
@@ -447,6 +448,7 @@ static void erase_deleted(struct ubifs_info *c)
447 orphan = dnext; 448 orphan = dnext;
448 dnext = orphan->dnext; 449 dnext = orphan->dnext;
449 ubifs_assert(!orphan->new); 450 ubifs_assert(!orphan->new);
451 ubifs_assert(orphan->del);
450 rb_erase(&orphan->rb, &c->orph_tree); 452 rb_erase(&orphan->rb, &c->orph_tree);
451 list_del(&orphan->list); 453 list_del(&orphan->list);
452 c->tot_orphans -= 1; 454 c->tot_orphans -= 1;
@@ -536,6 +538,7 @@ static int insert_dead_orphan(struct ubifs_info *c, ino_t inum)
536 rb_link_node(&orphan->rb, parent, p); 538 rb_link_node(&orphan->rb, parent, p);
537 rb_insert_color(&orphan->rb, &c->orph_tree); 539 rb_insert_color(&orphan->rb, &c->orph_tree);
538 list_add_tail(&orphan->list, &c->orph_list); 540 list_add_tail(&orphan->list, &c->orph_list);
541 orphan->del = 1;
539 orphan->dnext = c->orph_dnext; 542 orphan->dnext = c->orph_dnext;
540 c->orph_dnext = orphan; 543 c->orph_dnext = orphan;
541 dbg_mnt("ino %lu, new %d, tot %d", (unsigned long)inum, 544 dbg_mnt("ino %lu, new %d, tot %d", (unsigned long)inum,
diff --git a/fs/ubifs/ubifs.h b/fs/ubifs/ubifs.h
index c16fff7271d3..b2babce4d70f 100644
--- a/fs/ubifs/ubifs.h
+++ b/fs/ubifs/ubifs.h
@@ -905,6 +905,7 @@ struct ubifs_budget_req {
905 * @inum: inode number 905 * @inum: inode number
906 * @new: %1 => added since the last commit, otherwise %0 906 * @new: %1 => added since the last commit, otherwise %0
907 * @cmt: %1 => commit pending, otherwise %0 907 * @cmt: %1 => commit pending, otherwise %0
908 * @del: %1 => delete pending, otherwise %0
908 */ 909 */
909struct ubifs_orphan { 910struct ubifs_orphan {
910 struct rb_node rb; 911 struct rb_node rb;
@@ -915,6 +916,7 @@ struct ubifs_orphan {
915 ino_t inum; 916 ino_t inum;
916 unsigned new:1; 917 unsigned new:1;
917 unsigned cmt:1; 918 unsigned cmt:1;
919 unsigned del:1;
918}; 920};
919 921
920/** 922/**