123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172 |
- /**
- * eCryptfs: Linux filesystem encryption layer
- *
- * Copyright (C) 2008 International Business Machines Corp.
- * Author(s): Michael A. Halcrow <mahalcro@us.ibm.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- * 02111-1307, USA.
- */
- #include <linux/kthread.h>
- #include <linux/freezer.h>
- #include <linux/slab.h>
- #include <linux/wait.h>
- #include <linux/mount.h>
- #include "ecryptfs_kernel.h"
- struct ecryptfs_open_req {
- struct file **lower_file;
- struct path path;
- struct completion done;
- struct list_head kthread_ctl_list;
- };
- static struct ecryptfs_kthread_ctl {
- #define ECRYPTFS_KTHREAD_ZOMBIE 0x00000001
- u32 flags;
- struct mutex mux;
- struct list_head req_list;
- wait_queue_head_t wait;
- } ecryptfs_kthread_ctl;
- static struct task_struct *ecryptfs_kthread;
- /**
- * ecryptfs_threadfn
- * @ignored: ignored
- *
- * The eCryptfs kernel thread that has the responsibility of getting
- * the lower file with RW permissions.
- *
- * Returns zero on success; non-zero otherwise
- */
- static int ecryptfs_threadfn(void *ignored)
- {
- set_freezable();
- while (1) {
- struct ecryptfs_open_req *req;
- wait_event_freezable(
- ecryptfs_kthread_ctl.wait,
- (!list_empty(&ecryptfs_kthread_ctl.req_list)
- || kthread_should_stop()));
- mutex_lock(&ecryptfs_kthread_ctl.mux);
- if (ecryptfs_kthread_ctl.flags & ECRYPTFS_KTHREAD_ZOMBIE) {
- mutex_unlock(&ecryptfs_kthread_ctl.mux);
- goto out;
- }
- while (!list_empty(&ecryptfs_kthread_ctl.req_list)) {
- req = list_first_entry(&ecryptfs_kthread_ctl.req_list,
- struct ecryptfs_open_req,
- kthread_ctl_list);
- list_del(&req->kthread_ctl_list);
- *req->lower_file = dentry_open(&req->path,
- (O_RDWR | O_LARGEFILE), current_cred());
- complete(&req->done);
- }
- mutex_unlock(&ecryptfs_kthread_ctl.mux);
- }
- out:
- return 0;
- }
- int __init ecryptfs_init_kthread(void)
- {
- int rc = 0;
- mutex_init(&ecryptfs_kthread_ctl.mux);
- init_waitqueue_head(&ecryptfs_kthread_ctl.wait);
- INIT_LIST_HEAD(&ecryptfs_kthread_ctl.req_list);
- ecryptfs_kthread = kthread_run(&ecryptfs_threadfn, NULL,
- "ecryptfs-kthread");
- if (IS_ERR(ecryptfs_kthread)) {
- rc = PTR_ERR(ecryptfs_kthread);
- printk(KERN_ERR "%s: Failed to create kernel thread; rc = [%d]"
- "\n", __func__, rc);
- }
- return rc;
- }
- void ecryptfs_destroy_kthread(void)
- {
- struct ecryptfs_open_req *req, *tmp;
- mutex_lock(&ecryptfs_kthread_ctl.mux);
- ecryptfs_kthread_ctl.flags |= ECRYPTFS_KTHREAD_ZOMBIE;
- list_for_each_entry_safe(req, tmp, &ecryptfs_kthread_ctl.req_list,
- kthread_ctl_list) {
- list_del(&req->kthread_ctl_list);
- *req->lower_file = ERR_PTR(-EIO);
- complete(&req->done);
- }
- mutex_unlock(&ecryptfs_kthread_ctl.mux);
- kthread_stop(ecryptfs_kthread);
- wake_up(&ecryptfs_kthread_ctl.wait);
- }
- /**
- * ecryptfs_privileged_open
- * @lower_file: Result of dentry_open by root on lower dentry
- * @lower_dentry: Lower dentry for file to open
- * @lower_mnt: Lower vfsmount for file to open
- *
- * This function gets a r/w file opened againt the lower dentry.
- *
- * Returns zero on success; non-zero otherwise
- */
- int ecryptfs_privileged_open(struct file **lower_file,
- struct dentry *lower_dentry,
- struct vfsmount *lower_mnt,
- const struct cred *cred)
- {
- struct ecryptfs_open_req req;
- int flags = O_LARGEFILE;
- int rc = 0;
- init_completion(&req.done);
- req.lower_file = lower_file;
- req.path.dentry = lower_dentry;
- req.path.mnt = lower_mnt;
- /* Corresponding dput() and mntput() are done when the
- * lower file is fput() when all eCryptfs files for the inode are
- * released. */
- flags |= IS_RDONLY(d_inode(lower_dentry)) ? O_RDONLY : O_RDWR;
- (*lower_file) = dentry_open(&req.path, flags, cred);
- if (!IS_ERR(*lower_file))
- goto out;
- if ((flags & O_ACCMODE) == O_RDONLY) {
- rc = PTR_ERR((*lower_file));
- goto out;
- }
- mutex_lock(&ecryptfs_kthread_ctl.mux);
- if (ecryptfs_kthread_ctl.flags & ECRYPTFS_KTHREAD_ZOMBIE) {
- rc = -EIO;
- mutex_unlock(&ecryptfs_kthread_ctl.mux);
- printk(KERN_ERR "%s: We are in the middle of shutting down; "
- "aborting privileged request to open lower file\n",
- __func__);
- goto out;
- }
- list_add_tail(&req.kthread_ctl_list, &ecryptfs_kthread_ctl.req_list);
- mutex_unlock(&ecryptfs_kthread_ctl.mux);
- wake_up(&ecryptfs_kthread_ctl.wait);
- wait_for_completion(&req.done);
- if (IS_ERR(*lower_file))
- rc = PTR_ERR(*lower_file);
- out:
- return rc;
- }
|