Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

fs, proc: fix ABBA deadlock in case of execution attempt of map_files…

…/ entries

map_files/ entries are never supposed to be executed, still curious
minds might try to run them, which leads to the following deadlock

  ======================================================
  [ INFO: possible circular locking dependency detected ]
  3.4.0-rc4-24406-g841e6a6 #121 Not tainted
  -------------------------------------------------------
  bash/1556 is trying to acquire lock:
   (&sb->s_type->i_mutex_key#8){+.+.+.}, at: do_lookup+0x267/0x2b1

  but task is already holding lock:
   (&sig->cred_guard_mutex){+.+.+.}, at: prepare_bprm_creds+0x2d/0x69

  which lock already depends on the new lock.

  the existing dependency chain (in reverse order) is:

  -> #1 (&sig->cred_guard_mutex){+.+.+.}:
         validate_chain+0x444/0x4f4
         __lock_acquire+0x387/0x3f8
         lock_acquire+0x12b/0x158
         __mutex_lock_common+0x56/0x3a9
         mutex_lock_killable_nested+0x40/0x45
         lock_trace+0x24/0x59
         proc_map_files_lookup+0x5a/0x165
         __lookup_hash+0x52/0x73
         do_lookup+0x276/0x2b1
         walk_component+0x3d/0x114
         do_last+0xfc/0x540
         path_openat+0xd3/0x306
         do_filp_open+0x3d/0x89
         do_sys_open+0x74/0x106
         sys_open+0x21/0x23
         tracesys+0xdd/0xe2

  -> #0 (&sb->s_type->i_mutex_key#8){+.+.+.}:
         check_prev_add+0x6a/0x1ef
         validate_chain+0x444/0x4f4
         __lock_acquire+0x387/0x3f8
         lock_acquire+0x12b/0x158
         __mutex_lock_common+0x56/0x3a9
         mutex_lock_nested+0x40/0x45
         do_lookup+0x267/0x2b1
         walk_component+0x3d/0x114
         link_path_walk+0x1f9/0x48f
         path_openat+0xb6/0x306
         do_filp_open+0x3d/0x89
         open_exec+0x25/0xa0
         do_execve_common+0xea/0x2f9
         do_execve+0x43/0x45
         sys_execve+0x43/0x5a
         stub_execve+0x6c/0xc0

This is because prepare_bprm_creds grabs task->signal->cred_guard_mutex
and when do_lookup happens we try to grab task->signal->cred_guard_mutex
again in lock_trace.

Fix it using plain ptrace_may_access() helper in proc_map_files_lookup()
and in proc_map_files_readdir() instead of lock_trace(), the caller must
be CAP_SYS_ADMIN granted anyway.

Signed-off-by: Cyrill Gorcunov <gorcunov@openvz.org>
Reported-by: Sasha Levin <levinsasha928@gmail.com>
Cc: Konstantin Khlebnikov <khlebnikov@openvz.org>
Cc: Pavel Emelyanov <xemul@openvz.org>
Cc: Dave Jones <davej@redhat.com>
Cc: Vasiliy Kulikov <segoon@openwall.com>
Cc: Oleg Nesterov <oleg@redhat.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
  • Loading branch information...
commit eb94cd96e05d6c65a07937e66a04ea265c1b767d 1 parent c0a5f4a
Cyrill Gorcunov authored May 17, 2012 torvalds committed May 17, 2012

Showing 1 changed file with 8 additions and 12 deletions. Show diff stats Hide diff stats

  1. 20  fs/proc/base.c
20  fs/proc/base.c
@@ -2177,16 +2177,16 @@ static struct dentry *proc_map_files_lookup(struct inode *dir,
2177 2177
 		goto out;
2178 2178
 
2179 2179
 	result = ERR_PTR(-EACCES);
2180  
-	if (lock_trace(task))
  2180
+	if (!ptrace_may_access(task, PTRACE_MODE_READ))
2181 2181
 		goto out_put_task;
2182 2182
 
2183 2183
 	result = ERR_PTR(-ENOENT);
2184 2184
 	if (dname_to_vma_addr(dentry, &vm_start, &vm_end))
2185  
-		goto out_unlock;
  2185
+		goto out_put_task;
2186 2186
 
2187 2187
 	mm = get_task_mm(task);
2188 2188
 	if (!mm)
2189  
-		goto out_unlock;
  2189
+		goto out_put_task;
2190 2190
 
2191 2191
 	down_read(&mm->mmap_sem);
2192 2192
 	vma = find_exact_vma(mm, vm_start, vm_end);
@@ -2198,8 +2198,6 @@ static struct dentry *proc_map_files_lookup(struct inode *dir,
2198 2198
 out_no_vma:
2199 2199
 	up_read(&mm->mmap_sem);
2200 2200
 	mmput(mm);
2201  
-out_unlock:
2202  
-	unlock_trace(task);
2203 2201
 out_put_task:
2204 2202
 	put_task_struct(task);
2205 2203
 out:
@@ -2233,7 +2231,7 @@ proc_map_files_readdir(struct file *filp, void *dirent, filldir_t filldir)
2233 2231
 		goto out;
2234 2232
 
2235 2233
 	ret = -EACCES;
2236  
-	if (lock_trace(task))
  2234
+	if (!ptrace_may_access(task, PTRACE_MODE_READ))
2237 2235
 		goto out_put_task;
2238 2236
 
2239 2237
 	ret = 0;
@@ -2241,12 +2239,12 @@ proc_map_files_readdir(struct file *filp, void *dirent, filldir_t filldir)
2241 2239
 	case 0:
2242 2240
 		ino = inode->i_ino;
2243 2241
 		if (filldir(dirent, ".", 1, 0, ino, DT_DIR) < 0)
2244  
-			goto out_unlock;
  2242
+			goto out_put_task;
2245 2243
 		filp->f_pos++;
2246 2244
 	case 1:
2247 2245
 		ino = parent_ino(dentry);
2248 2246
 		if (filldir(dirent, "..", 2, 1, ino, DT_DIR) < 0)
2249  
-			goto out_unlock;
  2247
+			goto out_put_task;
2250 2248
 		filp->f_pos++;
2251 2249
 	default:
2252 2250
 	{
@@ -2257,7 +2255,7 @@ proc_map_files_readdir(struct file *filp, void *dirent, filldir_t filldir)
2257 2255
 
2258 2256
 		mm = get_task_mm(task);
2259 2257
 		if (!mm)
2260  
-			goto out_unlock;
  2258
+			goto out_put_task;
2261 2259
 		down_read(&mm->mmap_sem);
2262 2260
 
2263 2261
 		nr_files = 0;
@@ -2287,7 +2285,7 @@ proc_map_files_readdir(struct file *filp, void *dirent, filldir_t filldir)
2287 2285
 					flex_array_free(fa);
2288 2286
 				up_read(&mm->mmap_sem);
2289 2287
 				mmput(mm);
2290  
-				goto out_unlock;
  2288
+				goto out_put_task;
2291 2289
 			}
2292 2290
 			for (i = 0, vma = mm->mmap, pos = 2; vma;
2293 2291
 					vma = vma->vm_next) {
@@ -2332,8 +2330,6 @@ proc_map_files_readdir(struct file *filp, void *dirent, filldir_t filldir)
2332 2330
 	}
2333 2331
 	}
2334 2332
 
2335  
-out_unlock:
2336  
-	unlock_trace(task);
2337 2333
 out_put_task:
2338 2334
 	put_task_struct(task);
2339 2335
 out:

0 notes on commit eb94cd9

Please sign in to comment.
Something went wrong with that request. Please try again.