eCryptfs: Gracefully refuse miscdev file ops on inherited/passed files

File operations on /dev/ecryptfs would BUG() when the operations were
performed by processes other than the process that originally opened the
file. This could happen with open files inherited after fork() or file
descriptors passed through IPC mechanisms. Rather than calling BUG(), an
error code can be safely returned in most situations.

In ecryptfs_miscdev_release(), eCryptfs still needs to handle the
release even if the last file reference is being held by a process that
didn't originally open the file. ecryptfs_find_daemon_by_euid() will not
be successful, so a pointer to the daemon is stored in the file's
private_data. The private_data pointer is initialized when the miscdev
file is opened and only used when the file is released.

https://launchpad.net/bugs/994247

Signed-off-by: Tyler Hicks <tyhicks@canonical.com>
Reported-by: Sasha Levin <levinsasha928@gmail.com>
Tested-by: Sasha Levin <levinsasha928@gmail.com>

Changed files
+16 -7
fs
ecryptfs
+16 -7
fs/ecryptfs/miscdev.c
··· 49 49 mutex_lock(&ecryptfs_daemon_hash_mux); 50 50 /* TODO: Just use file->private_data? */ 51 51 rc = ecryptfs_find_daemon_by_euid(&daemon, euid, current_user_ns()); 52 - BUG_ON(rc || !daemon); 52 + if (rc || !daemon) { 53 + mutex_unlock(&ecryptfs_daemon_hash_mux); 54 + return -EINVAL; 55 + } 53 56 mutex_lock(&daemon->mux); 54 57 mutex_unlock(&ecryptfs_daemon_hash_mux); 55 58 if (daemon->flags & ECRYPTFS_DAEMON_ZOMBIE) { ··· 125 122 goto out_unlock_daemon; 126 123 } 127 124 daemon->flags |= ECRYPTFS_DAEMON_MISCDEV_OPEN; 125 + file->private_data = daemon; 128 126 atomic_inc(&ecryptfs_num_miscdev_opens); 129 127 out_unlock_daemon: 130 128 mutex_unlock(&daemon->mux); ··· 156 152 157 153 mutex_lock(&ecryptfs_daemon_hash_mux); 158 154 rc = ecryptfs_find_daemon_by_euid(&daemon, euid, current_user_ns()); 159 - BUG_ON(rc || !daemon); 155 + if (rc || !daemon) 156 + daemon = file->private_data; 160 157 mutex_lock(&daemon->mux); 161 - BUG_ON(daemon->pid != task_pid(current)); 162 158 BUG_ON(!(daemon->flags & ECRYPTFS_DAEMON_MISCDEV_OPEN)); 163 159 daemon->flags &= ~ECRYPTFS_DAEMON_MISCDEV_OPEN; 164 160 atomic_dec(&ecryptfs_num_miscdev_opens); ··· 274 270 mutex_lock(&ecryptfs_daemon_hash_mux); 275 271 /* TODO: Just use file->private_data? */ 276 272 rc = ecryptfs_find_daemon_by_euid(&daemon, euid, current_user_ns()); 277 - BUG_ON(rc || !daemon); 273 + if (rc || !daemon) { 274 + mutex_unlock(&ecryptfs_daemon_hash_mux); 275 + return -EINVAL; 276 + } 278 277 mutex_lock(&daemon->mux); 278 + if (task_pid(current) != daemon->pid) { 279 + mutex_unlock(&daemon->mux); 280 + mutex_unlock(&ecryptfs_daemon_hash_mux); 281 + return -EPERM; 282 + } 279 283 if (daemon->flags & ECRYPTFS_DAEMON_ZOMBIE) { 280 284 rc = 0; 281 285 mutex_unlock(&ecryptfs_daemon_hash_mux); ··· 320 308 * message from the queue; try again */ 321 309 goto check_list; 322 310 } 323 - BUG_ON(euid != daemon->euid); 324 - BUG_ON(current_user_ns() != daemon->user_ns); 325 - BUG_ON(task_pid(current) != daemon->pid); 326 311 msg_ctx = list_first_entry(&daemon->msg_ctx_out_queue, 327 312 struct ecryptfs_msg_ctx, daemon_out_list); 328 313 BUG_ON(!msg_ctx);