From 1ef45eb31cacd58c4c62e1fd26aa63a1f3d031a7 Mon Sep 17 00:00:00 2001
From: Zygmunt Krynicki <zygmunt.krynicki@canonical.com>
Date: Thu, 29 Sep 2016 15:11:15 +0200
Subject: [PATCH] Add printk-based debugging to pivot_root

This patch changes pivot_root to make it obvious which error exit path
was taken. It might be useful to apply to debug and investigate how
undocumented requirements of pivot_root are not met.

Signed-off-by: Zygmunt Krynicki <zygmunt.krynicki@canonical.com>
---
 fs/namespace.c | 70 ++++++++++++++++++++++++++++++++++++++++++++--------------
 1 file changed, 53 insertions(+), 17 deletions(-)

diff --git a/fs/namespace.c b/fs/namespace.c
index 877fc2c..6e15d1d 100644
--- a/fs/namespace.c
+++ b/fs/namespace.c
@@ -2993,57 +2993,93 @@ SYSCALL_DEFINE2(pivot_root, const char __user *, new_root,
 		return -EPERM;
 
 	error = user_path_dir(new_root, &new);
-	if (error)
+	if (error) {
+		printk(KERN_ERR "user_path_dir(new_root, &new) returned an error\n");
 		goto out0;
+	}
 
 	error = user_path_dir(put_old, &old);
-	if (error)
+	if (error) {
+		printk(KERN_ERR "user_path_dir(put_old, &old) returned an error\n");
 		goto out1;
+	}
 
 	error = security_sb_pivotroot(&old, &new);
-	if (error)
+	if (error) {
+		printk(KERN_ERR "security_sb_pivotroot(&old, &new) returned an error\n");
 		goto out2;
+	}
 
 	get_fs_root(current->fs, &root);
 	old_mp = lock_mount(&old);
 	error = PTR_ERR(old_mp);
-	if (IS_ERR(old_mp))
+	if (IS_ERR(old_mp)) {
+		printk(KERN_ERR "IS_ERR(old_mp)\n");
 		goto out3;
+	}
 
 	error = -EINVAL;
 	new_mnt = real_mount(new.mnt);
 	root_mnt = real_mount(root.mnt);
 	old_mnt = real_mount(old.mnt);
-	if (IS_MNT_SHARED(old_mnt) ||
-		IS_MNT_SHARED(new_mnt->mnt_parent) ||
-		IS_MNT_SHARED(root_mnt->mnt_parent))
+	if (IS_MNT_SHARED(old_mnt)) {
+		printk(KERN_ERR "IS_MNT_SHARED(old_mnt)\n");
+		goto out4;
+	}
+	if (IS_MNT_SHARED(new_mnt->mnt_parent)) {
+		printk(KERN_ERR "IS_MNT_SHARED(new_mnt->mnt_parent)\n");
 		goto out4;
-	if (!check_mnt(root_mnt) || !check_mnt(new_mnt))
+	}
+	if (IS_MNT_SHARED(root_mnt->mnt_parent)) {
+		printk(KERN_ERR "IS_MNT_SHARED(root_mnt->mnt_parent)\n");
 		goto out4;
-	if (new_mnt->mnt.mnt_flags & MNT_LOCKED)
+	}
+	if (!check_mnt(root_mnt) || !check_mnt(new_mnt)) {
+		printk(KERN_ERR "!check_mnt(root_mnt) || !check_mnt(new_mnt)\n");
+		goto out4;
+	}
+	if (new_mnt->mnt.mnt_flags & MNT_LOCKED) {
+		printk(KERN_ERR "new_mnt->mnt.mnt_flags & MNT_LOCKED\n");
 		goto out4;
+	}
 	error = -ENOENT;
-	if (d_unlinked(new.dentry))
+	if (d_unlinked(new.dentry)) {
+		printk(KERN_ERR "d_unlinked(new.dentry)\n");
 		goto out4;
+	}
 	error = -EBUSY;
-	if (new_mnt == root_mnt || old_mnt == root_mnt)
+	if (new_mnt == root_mnt || old_mnt == root_mnt) {
+		printk(KERN_ERR "new_mnt == root_mnt || old_mnt == root_mnt\n");
 		goto out4; /* loop, on the same file system  */
+	}
 	error = -EINVAL;
-	if (root.mnt->mnt_root != root.dentry)
+	if (root.mnt->mnt_root != root.dentry) {
+		printk(KERN_ERR "root.mnt->mnt_root != root.dentry\n");
 		goto out4; /* not a mountpoint */
-	if (!mnt_has_parent(root_mnt))
+	}
+	if (!mnt_has_parent(root_mnt)) {
+		printk(KERN_ERR "!mnt_has_parent(root_mnt)\n");
 		goto out4; /* not attached */
+	}
 	root_mp = root_mnt->mnt_mp;
-	if (new.mnt->mnt_root != new.dentry)
+	if (new.mnt->mnt_root != new.dentry) {
+		printk(KERN_ERR "new.mnt->mnt_root != new.dentry\n");
 		goto out4; /* not a mountpoint */
-	if (!mnt_has_parent(new_mnt))
+	}
+	if (!mnt_has_parent(new_mnt)) {
+		printk(KERN_ERR "!mnt_has_parent(new_mnt)\n");
 		goto out4; /* not attached */
+	}
 	/* make sure we can reach put_old from new_root */
-	if (!is_path_reachable(old_mnt, old.dentry, &new))
+	if (!is_path_reachable(old_mnt, old.dentry, &new)) {
+		printk(KERN_ERR "!is_path_reachable(old_mnt, old.dentry, &new)\n");
 		goto out4;
+	}
 	/* make certain new is below the root */
-	if (!is_path_reachable(new_mnt, new.dentry, &root))
+	if (!is_path_reachable(new_mnt, new.dentry, &root)) {
+		printk(KERN_ERR "!is_path_reachable(new_mnt, new.dentry, &root)\n");
 		goto out4;
+	}
 	root_mp->m_count++; /* pin it so it won't go away */
 	lock_mount_hash();
 	detach_mnt(new_mnt, &parent_path);
-- 
2.7.4

