145051539SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
2*65bbb7b8SLee Jones /*
38bf2debdSMichael Halcrow * eCryptfs: Linux filesystem encryption layer
48bf2debdSMichael Halcrow *
58bf2debdSMichael Halcrow * Copyright (C) 2008 International Business Machines Corp.
68bf2debdSMichael Halcrow * Author(s): Michael A. Halcrow <mhalcrow@us.ibm.com>
78bf2debdSMichael Halcrow */
88bf2debdSMichael Halcrow
98bf2debdSMichael Halcrow #include <linux/fs.h>
108bf2debdSMichael Halcrow #include <linux/hash.h>
118bf2debdSMichael Halcrow #include <linux/random.h>
128bf2debdSMichael Halcrow #include <linux/miscdevice.h>
138bf2debdSMichael Halcrow #include <linux/poll.h>
145a0e3ad6STejun Heo #include <linux/slab.h>
158bf2debdSMichael Halcrow #include <linux/wait.h>
168bf2debdSMichael Halcrow #include <linux/module.h>
178bf2debdSMichael Halcrow #include "ecryptfs_kernel.h"
188bf2debdSMichael Halcrow
198bf2debdSMichael Halcrow static atomic_t ecryptfs_num_miscdev_opens;
208bf2debdSMichael Halcrow
218bf2debdSMichael Halcrow /**
228bf2debdSMichael Halcrow * ecryptfs_miscdev_poll
232ecaf55dSTyler Hicks * @file: dev file
248bf2debdSMichael Halcrow * @pt: dev poll table (ignored)
258bf2debdSMichael Halcrow *
268bf2debdSMichael Halcrow * Returns the poll mask
278bf2debdSMichael Halcrow */
28076ccb76SAl Viro static __poll_t
ecryptfs_miscdev_poll(struct file * file,poll_table * pt)298bf2debdSMichael Halcrow ecryptfs_miscdev_poll(struct file *file, poll_table *pt)
308bf2debdSMichael Halcrow {
312ecaf55dSTyler Hicks struct ecryptfs_daemon *daemon = file->private_data;
32076ccb76SAl Viro __poll_t mask = 0;
338bf2debdSMichael Halcrow
348bf2debdSMichael Halcrow mutex_lock(&daemon->mux);
358bf2debdSMichael Halcrow if (daemon->flags & ECRYPTFS_DAEMON_ZOMBIE) {
368bf2debdSMichael Halcrow printk(KERN_WARNING "%s: Attempt to poll on zombified "
378bf2debdSMichael Halcrow "daemon\n", __func__);
388bf2debdSMichael Halcrow goto out_unlock_daemon;
398bf2debdSMichael Halcrow }
408bf2debdSMichael Halcrow if (daemon->flags & ECRYPTFS_DAEMON_IN_READ)
418bf2debdSMichael Halcrow goto out_unlock_daemon;
428bf2debdSMichael Halcrow if (daemon->flags & ECRYPTFS_DAEMON_IN_POLL)
438bf2debdSMichael Halcrow goto out_unlock_daemon;
448bf2debdSMichael Halcrow daemon->flags |= ECRYPTFS_DAEMON_IN_POLL;
458bf2debdSMichael Halcrow mutex_unlock(&daemon->mux);
468bf2debdSMichael Halcrow poll_wait(file, &daemon->wait, pt);
478bf2debdSMichael Halcrow mutex_lock(&daemon->mux);
488bf2debdSMichael Halcrow if (!list_empty(&daemon->msg_ctx_out_queue))
49a9a08845SLinus Torvalds mask |= EPOLLIN | EPOLLRDNORM;
508bf2debdSMichael Halcrow out_unlock_daemon:
518bf2debdSMichael Halcrow daemon->flags &= ~ECRYPTFS_DAEMON_IN_POLL;
528bf2debdSMichael Halcrow mutex_unlock(&daemon->mux);
538bf2debdSMichael Halcrow return mask;
548bf2debdSMichael Halcrow }
558bf2debdSMichael Halcrow
568bf2debdSMichael Halcrow /**
578bf2debdSMichael Halcrow * ecryptfs_miscdev_open
588bf2debdSMichael Halcrow * @inode: inode of miscdev handle (ignored)
592ecaf55dSTyler Hicks * @file: file for miscdev handle
608bf2debdSMichael Halcrow *
618bf2debdSMichael Halcrow * Returns zero on success; non-zero otherwise
628bf2debdSMichael Halcrow */
638bf2debdSMichael Halcrow static int
ecryptfs_miscdev_open(struct inode * inode,struct file * file)648bf2debdSMichael Halcrow ecryptfs_miscdev_open(struct inode *inode, struct file *file)
658bf2debdSMichael Halcrow {
668bf2debdSMichael Halcrow struct ecryptfs_daemon *daemon = NULL;
678bf2debdSMichael Halcrow int rc;
688bf2debdSMichael Halcrow
698bf2debdSMichael Halcrow mutex_lock(&ecryptfs_daemon_hash_mux);
702ecaf55dSTyler Hicks rc = ecryptfs_find_daemon_by_euid(&daemon);
712ecaf55dSTyler Hicks if (!rc) {
722ecaf55dSTyler Hicks rc = -EINVAL;
732ecaf55dSTyler Hicks goto out_unlock_daemon_list;
742ecaf55dSTyler Hicks }
752ecaf55dSTyler Hicks rc = ecryptfs_spawn_daemon(&daemon, file);
768bf2debdSMichael Halcrow if (rc) {
778bf2debdSMichael Halcrow printk(KERN_ERR "%s: Error attempting to spawn daemon; "
788bf2debdSMichael Halcrow "rc = [%d]\n", __func__, rc);
7952f21999SAl Viro goto out_unlock_daemon_list;
808bf2debdSMichael Halcrow }
818bf2debdSMichael Halcrow mutex_lock(&daemon->mux);
828bf2debdSMichael Halcrow if (daemon->flags & ECRYPTFS_DAEMON_MISCDEV_OPEN) {
838bf2debdSMichael Halcrow rc = -EBUSY;
848bf2debdSMichael Halcrow goto out_unlock_daemon;
858bf2debdSMichael Halcrow }
868bf2debdSMichael Halcrow daemon->flags |= ECRYPTFS_DAEMON_MISCDEV_OPEN;
878dc67805STyler Hicks file->private_data = daemon;
888bf2debdSMichael Halcrow atomic_inc(&ecryptfs_num_miscdev_opens);
898bf2debdSMichael Halcrow out_unlock_daemon:
908bf2debdSMichael Halcrow mutex_unlock(&daemon->mux);
918bf2debdSMichael Halcrow out_unlock_daemon_list:
928bf2debdSMichael Halcrow mutex_unlock(&ecryptfs_daemon_hash_mux);
938bf2debdSMichael Halcrow return rc;
948bf2debdSMichael Halcrow }
958bf2debdSMichael Halcrow
968bf2debdSMichael Halcrow /**
978bf2debdSMichael Halcrow * ecryptfs_miscdev_release
988bf2debdSMichael Halcrow * @inode: inode of fs/ecryptfs/euid handle (ignored)
992ecaf55dSTyler Hicks * @file: file for fs/ecryptfs/euid handle
1008bf2debdSMichael Halcrow *
1018bf2debdSMichael Halcrow * This keeps the daemon registered until the daemon sends another
1028bf2debdSMichael Halcrow * ioctl to fs/ecryptfs/ctl or until the kernel module unregisters.
1038bf2debdSMichael Halcrow *
1048bf2debdSMichael Halcrow * Returns zero on success; non-zero otherwise
1058bf2debdSMichael Halcrow */
1068bf2debdSMichael Halcrow static int
ecryptfs_miscdev_release(struct inode * inode,struct file * file)1078bf2debdSMichael Halcrow ecryptfs_miscdev_release(struct inode *inode, struct file *file)
1088bf2debdSMichael Halcrow {
1092ecaf55dSTyler Hicks struct ecryptfs_daemon *daemon = file->private_data;
1108bf2debdSMichael Halcrow int rc;
1118bf2debdSMichael Halcrow
1128bf2debdSMichael Halcrow mutex_lock(&daemon->mux);
1138bf2debdSMichael Halcrow BUG_ON(!(daemon->flags & ECRYPTFS_DAEMON_MISCDEV_OPEN));
1148bf2debdSMichael Halcrow daemon->flags &= ~ECRYPTFS_DAEMON_MISCDEV_OPEN;
1158bf2debdSMichael Halcrow atomic_dec(&ecryptfs_num_miscdev_opens);
1168bf2debdSMichael Halcrow mutex_unlock(&daemon->mux);
1172ecaf55dSTyler Hicks
1182ecaf55dSTyler Hicks mutex_lock(&ecryptfs_daemon_hash_mux);
1198bf2debdSMichael Halcrow rc = ecryptfs_exorcise_daemon(daemon);
1202ecaf55dSTyler Hicks mutex_unlock(&ecryptfs_daemon_hash_mux);
1218bf2debdSMichael Halcrow if (rc) {
1228bf2debdSMichael Halcrow printk(KERN_CRIT "%s: Fatal error whilst attempting to "
1238bf2debdSMichael Halcrow "shut down daemon; rc = [%d]. Please report this "
1248bf2debdSMichael Halcrow "bug.\n", __func__, rc);
1258bf2debdSMichael Halcrow BUG();
1268bf2debdSMichael Halcrow }
1278bf2debdSMichael Halcrow return rc;
1288bf2debdSMichael Halcrow }
1298bf2debdSMichael Halcrow
1308bf2debdSMichael Halcrow /**
1318bf2debdSMichael Halcrow * ecryptfs_send_miscdev
1328bf2debdSMichael Halcrow * @data: Data to send to daemon; may be NULL
1338bf2debdSMichael Halcrow * @data_size: Amount of data to send to daemon
1348bf2debdSMichael Halcrow * @msg_ctx: Message context, which is used to handle the reply. If
1358bf2debdSMichael Halcrow * this is NULL, then we do not expect a reply.
1368bf2debdSMichael Halcrow * @msg_type: Type of message
1378bf2debdSMichael Halcrow * @msg_flags: Flags for message
1388bf2debdSMichael Halcrow * @daemon: eCryptfs daemon object
1398bf2debdSMichael Halcrow *
1408bf2debdSMichael Halcrow * Add msg_ctx to queue and then, if it exists, notify the blocked
1418bf2debdSMichael Halcrow * miscdevess about the data being available. Must be called with
1428bf2debdSMichael Halcrow * ecryptfs_daemon_hash_mux held.
1438bf2debdSMichael Halcrow *
1448bf2debdSMichael Halcrow * Returns zero on success; non-zero otherwise
1458bf2debdSMichael Halcrow */
ecryptfs_send_miscdev(char * data,size_t data_size,struct ecryptfs_msg_ctx * msg_ctx,u8 msg_type,u16 msg_flags,struct ecryptfs_daemon * daemon)1468bf2debdSMichael Halcrow int ecryptfs_send_miscdev(char *data, size_t data_size,
1478bf2debdSMichael Halcrow struct ecryptfs_msg_ctx *msg_ctx, u8 msg_type,
1488bf2debdSMichael Halcrow u16 msg_flags, struct ecryptfs_daemon *daemon)
1498bf2debdSMichael Halcrow {
15060d65f1fSTyler Hicks struct ecryptfs_message *msg;
1518bf2debdSMichael Halcrow
15260d65f1fSTyler Hicks msg = kmalloc((sizeof(*msg) + data_size), GFP_KERNEL);
1531a0bba4fSMarkus Elfring if (!msg)
15460d65f1fSTyler Hicks return -ENOMEM;
15560d65f1fSTyler Hicks
15660d65f1fSTyler Hicks mutex_lock(&msg_ctx->mux);
15760d65f1fSTyler Hicks msg_ctx->msg = msg;
1588bf2debdSMichael Halcrow msg_ctx->msg->index = msg_ctx->index;
1598bf2debdSMichael Halcrow msg_ctx->msg->data_len = data_size;
1608bf2debdSMichael Halcrow msg_ctx->type = msg_type;
1618bf2debdSMichael Halcrow memcpy(msg_ctx->msg->data, data, data_size);
1628bf2debdSMichael Halcrow msg_ctx->msg_size = (sizeof(*msg_ctx->msg) + data_size);
1638bf2debdSMichael Halcrow list_add_tail(&msg_ctx->daemon_out_list, &daemon->msg_ctx_out_queue);
16460d65f1fSTyler Hicks mutex_unlock(&msg_ctx->mux);
16560d65f1fSTyler Hicks
16660d65f1fSTyler Hicks mutex_lock(&daemon->mux);
1678bf2debdSMichael Halcrow daemon->num_queued_msg_ctx++;
1688bf2debdSMichael Halcrow wake_up_interruptible(&daemon->wait);
1698bf2debdSMichael Halcrow mutex_unlock(&daemon->mux);
17060d65f1fSTyler Hicks
17160d65f1fSTyler Hicks return 0;
1728bf2debdSMichael Halcrow }
1738bf2debdSMichael Halcrow
17448399c0bSTyler Hicks /*
17548399c0bSTyler Hicks * miscdevfs packet format:
17648399c0bSTyler Hicks * Octet 0: Type
17748399c0bSTyler Hicks * Octets 1-4: network byte order msg_ctx->counter
17848399c0bSTyler Hicks * Octets 5-N0: Size of struct ecryptfs_message to follow
17948399c0bSTyler Hicks * Octets N0-N1: struct ecryptfs_message (including data)
18048399c0bSTyler Hicks *
18148399c0bSTyler Hicks * Octets 5-N1 not written if the packet type does not include a message
18248399c0bSTyler Hicks */
18348399c0bSTyler Hicks #define PKT_TYPE_SIZE 1
18448399c0bSTyler Hicks #define PKT_CTR_SIZE 4
18548399c0bSTyler Hicks #define MIN_NON_MSG_PKT_SIZE (PKT_TYPE_SIZE + PKT_CTR_SIZE)
18648399c0bSTyler Hicks #define MIN_MSG_PKT_SIZE (PKT_TYPE_SIZE + PKT_CTR_SIZE \
18748399c0bSTyler Hicks + ECRYPTFS_MIN_PKT_LEN_SIZE)
18848399c0bSTyler Hicks /* 4 + ECRYPTFS_MAX_ENCRYPTED_KEY_BYTES comes from tag 65 packet format */
18948399c0bSTyler Hicks #define MAX_MSG_PKT_SIZE (PKT_TYPE_SIZE + PKT_CTR_SIZE \
19048399c0bSTyler Hicks + ECRYPTFS_MAX_PKT_LEN_SIZE \
19148399c0bSTyler Hicks + sizeof(struct ecryptfs_message) \
19248399c0bSTyler Hicks + 4 + ECRYPTFS_MAX_ENCRYPTED_KEY_BYTES)
19348399c0bSTyler Hicks #define PKT_TYPE_OFFSET 0
19448399c0bSTyler Hicks #define PKT_CTR_OFFSET PKT_TYPE_SIZE
19548399c0bSTyler Hicks #define PKT_LEN_OFFSET (PKT_TYPE_SIZE + PKT_CTR_SIZE)
19648399c0bSTyler Hicks
1978bf2debdSMichael Halcrow /**
1988bf2debdSMichael Halcrow * ecryptfs_miscdev_read - format and send message from queue
1992ecaf55dSTyler Hicks * @file: miscdevfs handle
2008bf2debdSMichael Halcrow * @buf: User buffer into which to copy the next message on the daemon queue
2018bf2debdSMichael Halcrow * @count: Amount of space available in @buf
2028bf2debdSMichael Halcrow * @ppos: Offset in file (ignored)
2038bf2debdSMichael Halcrow *
2048bf2debdSMichael Halcrow * Pulls the most recent message from the daemon queue, formats it for
2058bf2debdSMichael Halcrow * being sent via a miscdevfs handle, and copies it into @buf
2068bf2debdSMichael Halcrow *
2078bf2debdSMichael Halcrow * Returns the number of bytes copied into the user buffer
2088bf2debdSMichael Halcrow */
209f66e883eSMichael Halcrow static ssize_t
ecryptfs_miscdev_read(struct file * file,char __user * buf,size_t count,loff_t * ppos)2108bf2debdSMichael Halcrow ecryptfs_miscdev_read(struct file *file, char __user *buf, size_t count,
2118bf2debdSMichael Halcrow loff_t *ppos)
2128bf2debdSMichael Halcrow {
2132ecaf55dSTyler Hicks struct ecryptfs_daemon *daemon = file->private_data;
2148bf2debdSMichael Halcrow struct ecryptfs_msg_ctx *msg_ctx;
2158bf2debdSMichael Halcrow size_t packet_length_size;
21648399c0bSTyler Hicks char packet_length[ECRYPTFS_MAX_PKT_LEN_SIZE];
2178bf2debdSMichael Halcrow size_t i;
2188bf2debdSMichael Halcrow size_t total_length;
2198bf2debdSMichael Halcrow int rc;
2208bf2debdSMichael Halcrow
2218bf2debdSMichael Halcrow mutex_lock(&daemon->mux);
2228bf2debdSMichael Halcrow if (daemon->flags & ECRYPTFS_DAEMON_ZOMBIE) {
2238bf2debdSMichael Halcrow rc = 0;
2248bf2debdSMichael Halcrow printk(KERN_WARNING "%s: Attempt to read from zombified "
2258bf2debdSMichael Halcrow "daemon\n", __func__);
2268bf2debdSMichael Halcrow goto out_unlock_daemon;
2278bf2debdSMichael Halcrow }
2288bf2debdSMichael Halcrow if (daemon->flags & ECRYPTFS_DAEMON_IN_READ) {
2298bf2debdSMichael Halcrow rc = 0;
2308bf2debdSMichael Halcrow goto out_unlock_daemon;
2318bf2debdSMichael Halcrow }
2328bf2debdSMichael Halcrow /* This daemon will not go away so long as this flag is set */
2338bf2debdSMichael Halcrow daemon->flags |= ECRYPTFS_DAEMON_IN_READ;
2348bf2debdSMichael Halcrow check_list:
2358bf2debdSMichael Halcrow if (list_empty(&daemon->msg_ctx_out_queue)) {
2368bf2debdSMichael Halcrow mutex_unlock(&daemon->mux);
2378bf2debdSMichael Halcrow rc = wait_event_interruptible(
2388bf2debdSMichael Halcrow daemon->wait, !list_empty(&daemon->msg_ctx_out_queue));
2398bf2debdSMichael Halcrow mutex_lock(&daemon->mux);
2408bf2debdSMichael Halcrow if (rc < 0) {
2418bf2debdSMichael Halcrow rc = 0;
2428bf2debdSMichael Halcrow goto out_unlock_daemon;
2438bf2debdSMichael Halcrow }
2448bf2debdSMichael Halcrow }
2458bf2debdSMichael Halcrow if (daemon->flags & ECRYPTFS_DAEMON_ZOMBIE) {
2468bf2debdSMichael Halcrow rc = 0;
2478bf2debdSMichael Halcrow goto out_unlock_daemon;
2488bf2debdSMichael Halcrow }
2498bf2debdSMichael Halcrow if (list_empty(&daemon->msg_ctx_out_queue)) {
2508bf2debdSMichael Halcrow /* Something else jumped in since the
2518bf2debdSMichael Halcrow * wait_event_interruptable() and removed the
2528bf2debdSMichael Halcrow * message from the queue; try again */
2538bf2debdSMichael Halcrow goto check_list;
2548bf2debdSMichael Halcrow }
2558bf2debdSMichael Halcrow msg_ctx = list_first_entry(&daemon->msg_ctx_out_queue,
2568bf2debdSMichael Halcrow struct ecryptfs_msg_ctx, daemon_out_list);
2578bf2debdSMichael Halcrow BUG_ON(!msg_ctx);
2588bf2debdSMichael Halcrow mutex_lock(&msg_ctx->mux);
2598bf2debdSMichael Halcrow if (msg_ctx->msg) {
2608bf2debdSMichael Halcrow rc = ecryptfs_write_packet_length(packet_length,
2618bf2debdSMichael Halcrow msg_ctx->msg_size,
2628bf2debdSMichael Halcrow &packet_length_size);
2638bf2debdSMichael Halcrow if (rc) {
2648bf2debdSMichael Halcrow rc = 0;
2658bf2debdSMichael Halcrow printk(KERN_WARNING "%s: Error writing packet length; "
2668bf2debdSMichael Halcrow "rc = [%d]\n", __func__, rc);
2678bf2debdSMichael Halcrow goto out_unlock_msg_ctx;
2688bf2debdSMichael Halcrow }
2698bf2debdSMichael Halcrow } else {
2708bf2debdSMichael Halcrow packet_length_size = 0;
2718bf2debdSMichael Halcrow msg_ctx->msg_size = 0;
2728bf2debdSMichael Halcrow }
27348399c0bSTyler Hicks total_length = (PKT_TYPE_SIZE + PKT_CTR_SIZE + packet_length_size
27448399c0bSTyler Hicks + msg_ctx->msg_size);
2758bf2debdSMichael Halcrow if (count < total_length) {
2768bf2debdSMichael Halcrow rc = 0;
2778bf2debdSMichael Halcrow printk(KERN_WARNING "%s: Only given user buffer of "
278df261c52SMichael Halcrow "size [%zd], but we need [%zd] to read the "
2798bf2debdSMichael Halcrow "pending message\n", __func__, count, total_length);
2808bf2debdSMichael Halcrow goto out_unlock_msg_ctx;
2818bf2debdSMichael Halcrow }
28279bc12a0SAl Viro rc = -EFAULT;
28379bc12a0SAl Viro if (put_user(msg_ctx->type, buf))
2848bf2debdSMichael Halcrow goto out_unlock_msg_ctx;
28548399c0bSTyler Hicks if (put_user(cpu_to_be32(msg_ctx->counter),
28648399c0bSTyler Hicks (__be32 __user *)(&buf[PKT_CTR_OFFSET])))
28779bc12a0SAl Viro goto out_unlock_msg_ctx;
28848399c0bSTyler Hicks i = PKT_TYPE_SIZE + PKT_CTR_SIZE;
28979bc12a0SAl Viro if (msg_ctx->msg) {
29079bc12a0SAl Viro if (copy_to_user(&buf[i], packet_length, packet_length_size))
29179bc12a0SAl Viro goto out_unlock_msg_ctx;
29279bc12a0SAl Viro i += packet_length_size;
29379bc12a0SAl Viro if (copy_to_user(&buf[i], msg_ctx->msg, msg_ctx->msg_size))
29479bc12a0SAl Viro goto out_unlock_msg_ctx;
2958bf2debdSMichael Halcrow i += msg_ctx->msg_size;
2968bf2debdSMichael Halcrow }
2978bf2debdSMichael Halcrow rc = i;
2988bf2debdSMichael Halcrow list_del(&msg_ctx->daemon_out_list);
2998bf2debdSMichael Halcrow kfree(msg_ctx->msg);
3008bf2debdSMichael Halcrow msg_ctx->msg = NULL;
3018bf2debdSMichael Halcrow /* We do not expect a reply from the userspace daemon for any
3028bf2debdSMichael Halcrow * message type other than ECRYPTFS_MSG_REQUEST */
3038bf2debdSMichael Halcrow if (msg_ctx->type != ECRYPTFS_MSG_REQUEST)
3048bf2debdSMichael Halcrow ecryptfs_msg_ctx_alloc_to_free(msg_ctx);
3058bf2debdSMichael Halcrow out_unlock_msg_ctx:
3068bf2debdSMichael Halcrow mutex_unlock(&msg_ctx->mux);
3078bf2debdSMichael Halcrow out_unlock_daemon:
3088bf2debdSMichael Halcrow daemon->flags &= ~ECRYPTFS_DAEMON_IN_READ;
3098bf2debdSMichael Halcrow mutex_unlock(&daemon->mux);
3108bf2debdSMichael Halcrow return rc;
3118bf2debdSMichael Halcrow }
3128bf2debdSMichael Halcrow
3138bf2debdSMichael Halcrow /**
3148bf2debdSMichael Halcrow * ecryptfs_miscdev_response - miscdevess response to message previously sent to daemon
315*65bbb7b8SLee Jones * @daemon: eCryptfs daemon object
3168bf2debdSMichael Halcrow * @data: Bytes comprising struct ecryptfs_message
3178bf2debdSMichael Halcrow * @data_size: sizeof(struct ecryptfs_message) + data len
3188bf2debdSMichael Halcrow * @seq: Sequence number for miscdev response packet
3198bf2debdSMichael Halcrow *
3208bf2debdSMichael Halcrow * Returns zero on success; non-zero otherwise
3218bf2debdSMichael Halcrow */
ecryptfs_miscdev_response(struct ecryptfs_daemon * daemon,char * data,size_t data_size,u32 seq)3222ecaf55dSTyler Hicks static int ecryptfs_miscdev_response(struct ecryptfs_daemon *daemon, char *data,
3232ecaf55dSTyler Hicks size_t data_size, u32 seq)
3248bf2debdSMichael Halcrow {
3258bf2debdSMichael Halcrow struct ecryptfs_message *msg = (struct ecryptfs_message *)data;
3268bf2debdSMichael Halcrow int rc;
3278bf2debdSMichael Halcrow
3288bf2debdSMichael Halcrow if ((sizeof(*msg) + msg->data_len) != data_size) {
3298bf2debdSMichael Halcrow printk(KERN_WARNING "%s: (sizeof(*msg) + msg->data_len) = "
330df261c52SMichael Halcrow "[%zd]; data_size = [%zd]. Invalid packet.\n", __func__,
3318bf2debdSMichael Halcrow (sizeof(*msg) + msg->data_len), data_size);
3328bf2debdSMichael Halcrow rc = -EINVAL;
3338bf2debdSMichael Halcrow goto out;
3348bf2debdSMichael Halcrow }
3352ecaf55dSTyler Hicks rc = ecryptfs_process_response(daemon, msg, seq);
3368bf2debdSMichael Halcrow if (rc)
3378bf2debdSMichael Halcrow printk(KERN_ERR
3388bf2debdSMichael Halcrow "Error processing response message; rc = [%d]\n", rc);
3398bf2debdSMichael Halcrow out:
3408bf2debdSMichael Halcrow return rc;
3418bf2debdSMichael Halcrow }
3428bf2debdSMichael Halcrow
3438bf2debdSMichael Halcrow /**
3448bf2debdSMichael Halcrow * ecryptfs_miscdev_write - handle write to daemon miscdev handle
3452ecaf55dSTyler Hicks * @file: File for misc dev handle
3468bf2debdSMichael Halcrow * @buf: Buffer containing user data
3478bf2debdSMichael Halcrow * @count: Amount of data in @buf
3488bf2debdSMichael Halcrow * @ppos: Pointer to offset in file (ignored)
3498bf2debdSMichael Halcrow *
3508bf2debdSMichael Halcrow * Returns the number of bytes read from @buf
3518bf2debdSMichael Halcrow */
3528bf2debdSMichael Halcrow static ssize_t
ecryptfs_miscdev_write(struct file * file,const char __user * buf,size_t count,loff_t * ppos)3538bf2debdSMichael Halcrow ecryptfs_miscdev_write(struct file *file, const char __user *buf,
3548bf2debdSMichael Halcrow size_t count, loff_t *ppos)
3558bf2debdSMichael Halcrow {
35679bc12a0SAl Viro __be32 counter_nbo;
35779bc12a0SAl Viro u32 seq;
35848399c0bSTyler Hicks size_t packet_size, packet_size_length;
3598bf2debdSMichael Halcrow char *data;
36048399c0bSTyler Hicks unsigned char packet_size_peek[ECRYPTFS_MAX_PKT_LEN_SIZE];
3617f133504STyler Hicks ssize_t rc;
3628bf2debdSMichael Halcrow
363db10e556STyler Hicks if (count == 0) {
3647f133504STyler Hicks return 0;
36548399c0bSTyler Hicks } else if (count == MIN_NON_MSG_PKT_SIZE) {
366db10e556STyler Hicks /* Likely a harmless MSG_HELO or MSG_QUIT - no packet length */
367db10e556STyler Hicks goto memdup;
36848399c0bSTyler Hicks } else if (count < MIN_MSG_PKT_SIZE || count > MAX_MSG_PKT_SIZE) {
369db10e556STyler Hicks printk(KERN_WARNING "%s: Acceptable packet size range is "
3700996b67dSColin Ian King "[%d-%zu], but amount of data written is [%zu].\n",
37148399c0bSTyler Hicks __func__, MIN_MSG_PKT_SIZE, MAX_MSG_PKT_SIZE, count);
372db10e556STyler Hicks return -EINVAL;
373db10e556STyler Hicks }
374fd56d242SLi Zefan
37548399c0bSTyler Hicks if (copy_from_user(packet_size_peek, &buf[PKT_LEN_OFFSET],
376db10e556STyler Hicks sizeof(packet_size_peek))) {
377db10e556STyler Hicks printk(KERN_WARNING "%s: Error while inspecting packet size\n",
378db10e556STyler Hicks __func__);
379db10e556STyler Hicks return -EFAULT;
380db10e556STyler Hicks }
381db10e556STyler Hicks
382db10e556STyler Hicks rc = ecryptfs_parse_packet_length(packet_size_peek, &packet_size,
383db10e556STyler Hicks &packet_size_length);
384db10e556STyler Hicks if (rc) {
385db10e556STyler Hicks printk(KERN_WARNING "%s: Error parsing packet length; "
3867f133504STyler Hicks "rc = [%zd]\n", __func__, rc);
387db10e556STyler Hicks return rc;
388db10e556STyler Hicks }
389db10e556STyler Hicks
39048399c0bSTyler Hicks if ((PKT_TYPE_SIZE + PKT_CTR_SIZE + packet_size_length + packet_size)
39148399c0bSTyler Hicks != count) {
392db10e556STyler Hicks printk(KERN_WARNING "%s: Invalid packet size [%zu]\n", __func__,
393db10e556STyler Hicks packet_size);
394db10e556STyler Hicks return -EINVAL;
395db10e556STyler Hicks }
396db10e556STyler Hicks
397db10e556STyler Hicks memdup:
398fd56d242SLi Zefan data = memdup_user(buf, count);
399fd56d242SLi Zefan if (IS_ERR(data)) {
400fd56d242SLi Zefan printk(KERN_ERR "%s: memdup_user returned error [%ld]\n",
401fd56d242SLi Zefan __func__, PTR_ERR(data));
4027f133504STyler Hicks return PTR_ERR(data);
4038bf2debdSMichael Halcrow }
40448399c0bSTyler Hicks switch (data[PKT_TYPE_OFFSET]) {
4058bf2debdSMichael Halcrow case ECRYPTFS_MSG_RESPONSE:
40648399c0bSTyler Hicks if (count < (MIN_MSG_PKT_SIZE
40748399c0bSTyler Hicks + sizeof(struct ecryptfs_message))) {
4088bf2debdSMichael Halcrow printk(KERN_WARNING "%s: Minimum acceptable packet "
409df261c52SMichael Halcrow "size is [%zd], but amount of data written is "
410df261c52SMichael Halcrow "only [%zd]. Discarding response packet.\n",
4118bf2debdSMichael Halcrow __func__,
41248399c0bSTyler Hicks (MIN_MSG_PKT_SIZE
41348399c0bSTyler Hicks + sizeof(struct ecryptfs_message)), count);
4147f133504STyler Hicks rc = -EINVAL;
4158bf2debdSMichael Halcrow goto out_free;
4168bf2debdSMichael Halcrow }
41748399c0bSTyler Hicks memcpy(&counter_nbo, &data[PKT_CTR_OFFSET], PKT_CTR_SIZE);
4188bf2debdSMichael Halcrow seq = be32_to_cpu(counter_nbo);
4192ecaf55dSTyler Hicks rc = ecryptfs_miscdev_response(file->private_data,
42048399c0bSTyler Hicks &data[PKT_LEN_OFFSET + packet_size_length],
4212ecaf55dSTyler Hicks packet_size, seq);
4227f133504STyler Hicks if (rc) {
4238bf2debdSMichael Halcrow printk(KERN_WARNING "%s: Failed to deliver miscdev "
4247f133504STyler Hicks "response to requesting operation; rc = [%zd]\n",
4258bf2debdSMichael Halcrow __func__, rc);
4267f133504STyler Hicks goto out_free;
4277f133504STyler Hicks }
4288bf2debdSMichael Halcrow break;
4298bf2debdSMichael Halcrow case ECRYPTFS_MSG_HELO:
4308bf2debdSMichael Halcrow case ECRYPTFS_MSG_QUIT:
4318bf2debdSMichael Halcrow break;
4328bf2debdSMichael Halcrow default:
4338bf2debdSMichael Halcrow ecryptfs_printk(KERN_WARNING, "Dropping miscdev "
4348bf2debdSMichael Halcrow "message of unrecognized type [%d]\n",
4358bf2debdSMichael Halcrow data[0]);
4367f133504STyler Hicks rc = -EINVAL;
4377f133504STyler Hicks goto out_free;
4388bf2debdSMichael Halcrow }
4397f133504STyler Hicks rc = count;
4408bf2debdSMichael Halcrow out_free:
4418bf2debdSMichael Halcrow kfree(data);
4427f133504STyler Hicks return rc;
4438bf2debdSMichael Halcrow }
4448bf2debdSMichael Halcrow
4458bf2debdSMichael Halcrow
4468bf2debdSMichael Halcrow static const struct file_operations ecryptfs_miscdev_fops = {
44752f21999SAl Viro .owner = THIS_MODULE,
4488bf2debdSMichael Halcrow .open = ecryptfs_miscdev_open,
4498bf2debdSMichael Halcrow .poll = ecryptfs_miscdev_poll,
4508bf2debdSMichael Halcrow .read = ecryptfs_miscdev_read,
4518bf2debdSMichael Halcrow .write = ecryptfs_miscdev_write,
4528bf2debdSMichael Halcrow .release = ecryptfs_miscdev_release,
4536038f373SArnd Bergmann .llseek = noop_llseek,
4548bf2debdSMichael Halcrow };
4558bf2debdSMichael Halcrow
4568bf2debdSMichael Halcrow static struct miscdevice ecryptfs_miscdev = {
4578bf2debdSMichael Halcrow .minor = MISC_DYNAMIC_MINOR,
4588bf2debdSMichael Halcrow .name = "ecryptfs",
4598bf2debdSMichael Halcrow .fops = &ecryptfs_miscdev_fops
4608bf2debdSMichael Halcrow };
4618bf2debdSMichael Halcrow
4628bf2debdSMichael Halcrow /**
4638bf2debdSMichael Halcrow * ecryptfs_init_ecryptfs_miscdev
4648bf2debdSMichael Halcrow *
4658bf2debdSMichael Halcrow * Messages sent to the userspace daemon from the kernel are placed on
4668bf2debdSMichael Halcrow * a queue associated with the daemon. The next read against the
4678bf2debdSMichael Halcrow * miscdev handle by that daemon will return the oldest message placed
4688bf2debdSMichael Halcrow * on the message queue for the daemon.
4698bf2debdSMichael Halcrow *
4708bf2debdSMichael Halcrow * Returns zero on success; non-zero otherwise
4718bf2debdSMichael Halcrow */
ecryptfs_init_ecryptfs_miscdev(void)4727371a382SJerome Marchand int __init ecryptfs_init_ecryptfs_miscdev(void)
4738bf2debdSMichael Halcrow {
4748bf2debdSMichael Halcrow int rc;
4758bf2debdSMichael Halcrow
4768bf2debdSMichael Halcrow atomic_set(&ecryptfs_num_miscdev_opens, 0);
4778bf2debdSMichael Halcrow rc = misc_register(&ecryptfs_miscdev);
4788bf2debdSMichael Halcrow if (rc)
4798bf2debdSMichael Halcrow printk(KERN_ERR "%s: Failed to register miscellaneous device "
4808bf2debdSMichael Halcrow "for communications with userspace daemons; rc = [%d]\n",
4818bf2debdSMichael Halcrow __func__, rc);
4828bf2debdSMichael Halcrow return rc;
4838bf2debdSMichael Halcrow }
4848bf2debdSMichael Halcrow
4858bf2debdSMichael Halcrow /**
4868bf2debdSMichael Halcrow * ecryptfs_destroy_ecryptfs_miscdev
4878bf2debdSMichael Halcrow *
4888bf2debdSMichael Halcrow * All of the daemons must be exorcised prior to calling this
4898bf2debdSMichael Halcrow * function.
4908bf2debdSMichael Halcrow */
ecryptfs_destroy_ecryptfs_miscdev(void)4918bf2debdSMichael Halcrow void ecryptfs_destroy_ecryptfs_miscdev(void)
4928bf2debdSMichael Halcrow {
4938bf2debdSMichael Halcrow BUG_ON(atomic_read(&ecryptfs_num_miscdev_opens) != 0);
4948bf2debdSMichael Halcrow misc_deregister(&ecryptfs_miscdev);
4958bf2debdSMichael Halcrow }
496