160 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*3 * eCryptfs: Linux filesystem encryption layer4 *5 * Copyright (C) 2008 International Business Machines Corp.6 * Author(s): Michael A. Halcrow <mahalcro@us.ibm.com>7 */8 9#include <linux/kthread.h>10#include <linux/freezer.h>11#include <linux/slab.h>12#include <linux/wait.h>13#include <linux/mount.h>14#include "ecryptfs_kernel.h"15 16struct ecryptfs_open_req {17 struct file **lower_file;18 struct path path;19 struct completion done;20 struct list_head kthread_ctl_list;21};22 23static struct ecryptfs_kthread_ctl {24#define ECRYPTFS_KTHREAD_ZOMBIE 0x0000000125 u32 flags;26 struct mutex mux;27 struct list_head req_list;28 wait_queue_head_t wait;29} ecryptfs_kthread_ctl;30 31static struct task_struct *ecryptfs_kthread;32 33/**34 * ecryptfs_threadfn35 * @ignored: ignored36 *37 * The eCryptfs kernel thread that has the responsibility of getting38 * the lower file with RW permissions.39 *40 * Returns zero on success; non-zero otherwise41 */42static int ecryptfs_threadfn(void *ignored)43{44 set_freezable();45 while (1) {46 struct ecryptfs_open_req *req;47 48 wait_event_freezable(49 ecryptfs_kthread_ctl.wait,50 (!list_empty(&ecryptfs_kthread_ctl.req_list)51 || kthread_should_stop()));52 mutex_lock(&ecryptfs_kthread_ctl.mux);53 if (ecryptfs_kthread_ctl.flags & ECRYPTFS_KTHREAD_ZOMBIE) {54 mutex_unlock(&ecryptfs_kthread_ctl.mux);55 goto out;56 }57 while (!list_empty(&ecryptfs_kthread_ctl.req_list)) {58 req = list_first_entry(&ecryptfs_kthread_ctl.req_list,59 struct ecryptfs_open_req,60 kthread_ctl_list);61 list_del(&req->kthread_ctl_list);62 *req->lower_file = dentry_open(&req->path,63 (O_RDWR | O_LARGEFILE), current_cred());64 complete(&req->done);65 }66 mutex_unlock(&ecryptfs_kthread_ctl.mux);67 }68out:69 return 0;70}71 72int __init ecryptfs_init_kthread(void)73{74 int rc = 0;75 76 mutex_init(&ecryptfs_kthread_ctl.mux);77 init_waitqueue_head(&ecryptfs_kthread_ctl.wait);78 INIT_LIST_HEAD(&ecryptfs_kthread_ctl.req_list);79 ecryptfs_kthread = kthread_run(&ecryptfs_threadfn, NULL,80 "ecryptfs-kthread");81 if (IS_ERR(ecryptfs_kthread)) {82 rc = PTR_ERR(ecryptfs_kthread);83 printk(KERN_ERR "%s: Failed to create kernel thread; rc = [%d]"84 "\n", __func__, rc);85 }86 return rc;87}88 89void ecryptfs_destroy_kthread(void)90{91 struct ecryptfs_open_req *req, *tmp;92 93 mutex_lock(&ecryptfs_kthread_ctl.mux);94 ecryptfs_kthread_ctl.flags |= ECRYPTFS_KTHREAD_ZOMBIE;95 list_for_each_entry_safe(req, tmp, &ecryptfs_kthread_ctl.req_list,96 kthread_ctl_list) {97 list_del(&req->kthread_ctl_list);98 *req->lower_file = ERR_PTR(-EIO);99 complete(&req->done);100 }101 mutex_unlock(&ecryptfs_kthread_ctl.mux);102 kthread_stop(ecryptfs_kthread);103 wake_up(&ecryptfs_kthread_ctl.wait);104}105 106/**107 * ecryptfs_privileged_open108 * @lower_file: Result of dentry_open by root on lower dentry109 * @lower_dentry: Lower dentry for file to open110 * @lower_mnt: Lower vfsmount for file to open111 * @cred: credential to use for this call112 *113 * This function gets a r/w file opened against the lower dentry.114 *115 * Returns zero on success; non-zero otherwise116 */117int ecryptfs_privileged_open(struct file **lower_file,118 struct dentry *lower_dentry,119 struct vfsmount *lower_mnt,120 const struct cred *cred)121{122 struct ecryptfs_open_req req;123 int flags = O_LARGEFILE;124 int rc = 0;125 126 init_completion(&req.done);127 req.lower_file = lower_file;128 req.path.dentry = lower_dentry;129 req.path.mnt = lower_mnt;130 131 /* Corresponding dput() and mntput() are done when the132 * lower file is fput() when all eCryptfs files for the inode are133 * released. */134 flags |= IS_RDONLY(d_inode(lower_dentry)) ? O_RDONLY : O_RDWR;135 (*lower_file) = dentry_open(&req.path, flags, cred);136 if (!IS_ERR(*lower_file))137 goto out;138 if ((flags & O_ACCMODE) == O_RDONLY) {139 rc = PTR_ERR((*lower_file));140 goto out;141 }142 mutex_lock(&ecryptfs_kthread_ctl.mux);143 if (ecryptfs_kthread_ctl.flags & ECRYPTFS_KTHREAD_ZOMBIE) {144 rc = -EIO;145 mutex_unlock(&ecryptfs_kthread_ctl.mux);146 printk(KERN_ERR "%s: We are in the middle of shutting down; "147 "aborting privileged request to open lower file\n",148 __func__);149 goto out;150 }151 list_add_tail(&req.kthread_ctl_list, &ecryptfs_kthread_ctl.req_list);152 mutex_unlock(&ecryptfs_kthread_ctl.mux);153 wake_up(&ecryptfs_kthread_ctl.wait);154 wait_for_completion(&req.done);155 if (IS_ERR(*lower_file))156 rc = PTR_ERR(*lower_file);157out:158 return rc;159}160