Commit f66e883e authored by Michael Halcrow's avatar Michael Halcrow Committed by Linus Torvalds

eCryptfs: integrate eCryptfs device handle into the module.

Update the versioning information.  Make the message types generic.  Add an
outgoing message queue to the daemon struct.  Make the functions to parse
and write the packet lengths available to the rest of the module.  Add
functions to create and destroy the daemon structs.  Clean up some of the
comments and make the code a little more consistent with itself.

[akpm@linux-foundation.org: printk fixes]
Signed-off-by: default avatarMichael Halcrow <mhalcrow@us.ibm.com>
Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent 8bf2debd
...@@ -4,4 +4,4 @@ ...@@ -4,4 +4,4 @@
obj-$(CONFIG_ECRYPT_FS) += ecryptfs.o obj-$(CONFIG_ECRYPT_FS) += ecryptfs.o
ecryptfs-objs := dentry.o file.o inode.o main.o super.o mmap.o read_write.o crypto.o keystore.o messaging.o netlink.o debug.o ecryptfs-objs := dentry.o file.o inode.o main.o super.o mmap.o read_write.o crypto.o keystore.o messaging.o netlink.o miscdev.o debug.o
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
* *
* Copyright (C) 1997-2003 Erez Zadok * Copyright (C) 1997-2003 Erez Zadok
* Copyright (C) 2001-2003 Stony Brook University * Copyright (C) 2001-2003 Stony Brook University
* Copyright (C) 2004-2007 International Business Machines Corp. * Copyright (C) 2004-2008 International Business Machines Corp.
* Author(s): Michael A. Halcrow <mahalcro@us.ibm.com> * Author(s): Michael A. Halcrow <mahalcro@us.ibm.com>
* Trevor S. Highland <trevor.highland@gmail.com> * Trevor S. Highland <trevor.highland@gmail.com>
* Tyler Hicks <tyhicks@ou.edu> * Tyler Hicks <tyhicks@ou.edu>
...@@ -49,11 +49,13 @@ ...@@ -49,11 +49,13 @@
#define ECRYPTFS_VERSIONING_POLICY 0x00000008 #define ECRYPTFS_VERSIONING_POLICY 0x00000008
#define ECRYPTFS_VERSIONING_XATTR 0x00000010 #define ECRYPTFS_VERSIONING_XATTR 0x00000010
#define ECRYPTFS_VERSIONING_MULTKEY 0x00000020 #define ECRYPTFS_VERSIONING_MULTKEY 0x00000020
#define ECRYPTFS_VERSIONING_DEVMISC 0x00000040
#define ECRYPTFS_VERSIONING_MASK (ECRYPTFS_VERSIONING_PASSPHRASE \ #define ECRYPTFS_VERSIONING_MASK (ECRYPTFS_VERSIONING_PASSPHRASE \
| ECRYPTFS_VERSIONING_PLAINTEXT_PASSTHROUGH \ | ECRYPTFS_VERSIONING_PLAINTEXT_PASSTHROUGH \
| ECRYPTFS_VERSIONING_PUBKEY \ | ECRYPTFS_VERSIONING_PUBKEY \
| ECRYPTFS_VERSIONING_XATTR \ | ECRYPTFS_VERSIONING_XATTR \
| ECRYPTFS_VERSIONING_MULTKEY) | ECRYPTFS_VERSIONING_MULTKEY \
| ECRYPTFS_VERSIONING_DEVMISC)
#define ECRYPTFS_MAX_PASSWORD_LENGTH 64 #define ECRYPTFS_MAX_PASSWORD_LENGTH 64
#define ECRYPTFS_MAX_PASSPHRASE_BYTES ECRYPTFS_MAX_PASSWORD_LENGTH #define ECRYPTFS_MAX_PASSPHRASE_BYTES ECRYPTFS_MAX_PASSWORD_LENGTH
#define ECRYPTFS_SALT_SIZE 8 #define ECRYPTFS_SALT_SIZE 8
...@@ -73,17 +75,14 @@ ...@@ -73,17 +75,14 @@
#define ECRYPTFS_DEFAULT_MSG_CTX_ELEMS 32 #define ECRYPTFS_DEFAULT_MSG_CTX_ELEMS 32
#define ECRYPTFS_DEFAULT_SEND_TIMEOUT HZ #define ECRYPTFS_DEFAULT_SEND_TIMEOUT HZ
#define ECRYPTFS_MAX_MSG_CTX_TTL (HZ*3) #define ECRYPTFS_MAX_MSG_CTX_TTL (HZ*3)
#define ECRYPTFS_NLMSG_HELO 100
#define ECRYPTFS_NLMSG_QUIT 101
#define ECRYPTFS_NLMSG_REQUEST 102
#define ECRYPTFS_NLMSG_RESPONSE 103
#define ECRYPTFS_MAX_PKI_NAME_BYTES 16 #define ECRYPTFS_MAX_PKI_NAME_BYTES 16
#define ECRYPTFS_DEFAULT_NUM_USERS 4 #define ECRYPTFS_DEFAULT_NUM_USERS 4
#define ECRYPTFS_MAX_NUM_USERS 32768 #define ECRYPTFS_MAX_NUM_USERS 32768
#define ECRYPTFS_TRANSPORT_NETLINK 0 #define ECRYPTFS_TRANSPORT_NETLINK 0
#define ECRYPTFS_TRANSPORT_CONNECTOR 1 #define ECRYPTFS_TRANSPORT_CONNECTOR 1
#define ECRYPTFS_TRANSPORT_RELAYFS 2 #define ECRYPTFS_TRANSPORT_RELAYFS 2
#define ECRYPTFS_DEFAULT_TRANSPORT ECRYPTFS_TRANSPORT_NETLINK #define ECRYPTFS_TRANSPORT_MISCDEV 3
#define ECRYPTFS_DEFAULT_TRANSPORT ECRYPTFS_TRANSPORT_MISCDEV
#define ECRYPTFS_XATTR_NAME "user.ecryptfs" #define ECRYPTFS_XATTR_NAME "user.ecryptfs"
#define RFC2440_CIPHER_DES3_EDE 0x02 #define RFC2440_CIPHER_DES3_EDE 0x02
...@@ -366,32 +365,62 @@ struct ecryptfs_auth_tok_list_item { ...@@ -366,32 +365,62 @@ struct ecryptfs_auth_tok_list_item {
}; };
struct ecryptfs_message { struct ecryptfs_message {
/* Can never be greater than ecryptfs_message_buf_len */
/* Used to find the parent msg_ctx */
/* Inherits from msg_ctx->index */
u32 index; u32 index;
u32 data_len; u32 data_len;
u8 data[]; u8 data[];
}; };
struct ecryptfs_msg_ctx { struct ecryptfs_msg_ctx {
#define ECRYPTFS_MSG_CTX_STATE_FREE 0x0001 #define ECRYPTFS_MSG_CTX_STATE_FREE 0x01
#define ECRYPTFS_MSG_CTX_STATE_PENDING 0x0002 #define ECRYPTFS_MSG_CTX_STATE_PENDING 0x02
#define ECRYPTFS_MSG_CTX_STATE_DONE 0x0003 #define ECRYPTFS_MSG_CTX_STATE_DONE 0x03
u32 state; #define ECRYPTFS_MSG_CTX_STATE_NO_REPLY 0x04
unsigned int index; u8 state;
unsigned int counter; #define ECRYPTFS_MSG_HELO 100
#define ECRYPTFS_MSG_QUIT 101
#define ECRYPTFS_MSG_REQUEST 102
#define ECRYPTFS_MSG_RESPONSE 103
u8 type;
u32 index;
/* Counter converts to a sequence number. Each message sent
* out for which we expect a response has an associated
* sequence number. The response must have the same sequence
* number as the counter for the msg_stc for the message to be
* valid. */
u32 counter;
size_t msg_size;
struct ecryptfs_message *msg; struct ecryptfs_message *msg;
struct task_struct *task; struct task_struct *task;
struct list_head node; struct list_head node;
struct list_head daemon_out_list;
struct mutex mux; struct mutex mux;
}; };
extern unsigned int ecryptfs_transport; extern unsigned int ecryptfs_transport;
struct ecryptfs_daemon_id { struct ecryptfs_daemon;
struct ecryptfs_daemon {
#define ECRYPTFS_DAEMON_IN_READ 0x00000001
#define ECRYPTFS_DAEMON_IN_POLL 0x00000002
#define ECRYPTFS_DAEMON_ZOMBIE 0x00000004
#define ECRYPTFS_DAEMON_MISCDEV_OPEN 0x00000008
u32 flags;
u32 num_queued_msg_ctx;
pid_t pid; pid_t pid;
uid_t uid; uid_t euid;
struct hlist_node id_chain; struct task_struct *task;
struct mutex mux;
struct list_head msg_ctx_out_queue;
wait_queue_head_t wait;
struct hlist_node euid_chain;
}; };
extern struct mutex ecryptfs_daemon_hash_mux;
static inline struct ecryptfs_file_info * static inline struct ecryptfs_file_info *
ecryptfs_file_to_private(struct file *file) ecryptfs_file_to_private(struct file *file)
{ {
...@@ -593,13 +622,13 @@ int ecryptfs_init_messaging(unsigned int transport); ...@@ -593,13 +622,13 @@ int ecryptfs_init_messaging(unsigned int transport);
void ecryptfs_release_messaging(unsigned int transport); void ecryptfs_release_messaging(unsigned int transport);
int ecryptfs_send_netlink(char *data, int data_len, int ecryptfs_send_netlink(char *data, int data_len,
struct ecryptfs_msg_ctx *msg_ctx, u16 msg_type, struct ecryptfs_msg_ctx *msg_ctx, u8 msg_type,
u16 msg_flags, pid_t daemon_pid); u16 msg_flags, pid_t daemon_pid);
int ecryptfs_init_netlink(void); int ecryptfs_init_netlink(void);
void ecryptfs_release_netlink(void); void ecryptfs_release_netlink(void);
int ecryptfs_send_connector(char *data, int data_len, int ecryptfs_send_connector(char *data, int data_len,
struct ecryptfs_msg_ctx *msg_ctx, u16 msg_type, struct ecryptfs_msg_ctx *msg_ctx, u8 msg_type,
u16 msg_flags, pid_t daemon_pid); u16 msg_flags, pid_t daemon_pid);
int ecryptfs_init_connector(void); int ecryptfs_init_connector(void);
void ecryptfs_release_connector(void); void ecryptfs_release_connector(void);
...@@ -642,5 +671,19 @@ int ecryptfs_read_lower_page_segment(struct page *page_for_ecryptfs, ...@@ -642,5 +671,19 @@ int ecryptfs_read_lower_page_segment(struct page *page_for_ecryptfs,
size_t offset_in_page, size_t size, size_t offset_in_page, size_t size,
struct inode *ecryptfs_inode); struct inode *ecryptfs_inode);
struct page *ecryptfs_get_locked_page(struct file *file, loff_t index); struct page *ecryptfs_get_locked_page(struct file *file, loff_t index);
int ecryptfs_exorcise_daemon(struct ecryptfs_daemon *daemon);
int ecryptfs_find_daemon_by_euid(struct ecryptfs_daemon **daemon, uid_t euid);
int ecryptfs_parse_packet_length(unsigned char *data, size_t *size,
size_t *length_size);
int ecryptfs_write_packet_length(char *dest, size_t size,
size_t *packet_size_length);
int ecryptfs_init_ecryptfs_miscdev(void);
void ecryptfs_destroy_ecryptfs_miscdev(void);
int 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);
void ecryptfs_msg_ctx_alloc_to_free(struct ecryptfs_msg_ctx *msg_ctx);
int
ecryptfs_spawn_daemon(struct ecryptfs_daemon **daemon, uid_t euid, pid_t pid);
#endif /* #ifndef ECRYPTFS_KERNEL_H */ #endif /* #ifndef ECRYPTFS_KERNEL_H */
...@@ -65,7 +65,7 @@ static int process_request_key_err(long err_code) ...@@ -65,7 +65,7 @@ static int process_request_key_err(long err_code)
} }
/** /**
* parse_packet_length * ecryptfs_parse_packet_length
* @data: Pointer to memory containing length at offset * @data: Pointer to memory containing length at offset
* @size: This function writes the decoded size to this memory * @size: This function writes the decoded size to this memory
* address; zero on error * address; zero on error
...@@ -73,7 +73,7 @@ static int process_request_key_err(long err_code) ...@@ -73,7 +73,7 @@ static int process_request_key_err(long err_code)
* *
* Returns zero on success; non-zero on error * Returns zero on success; non-zero on error
*/ */
static int parse_packet_length(unsigned char *data, size_t *size, int ecryptfs_parse_packet_length(unsigned char *data, size_t *size,
size_t *length_size) size_t *length_size)
{ {
int rc = 0; int rc = 0;
...@@ -105,7 +105,7 @@ static int parse_packet_length(unsigned char *data, size_t *size, ...@@ -105,7 +105,7 @@ static int parse_packet_length(unsigned char *data, size_t *size,
} }
/** /**
* write_packet_length * ecryptfs_write_packet_length
* @dest: The byte array target into which to write the length. Must * @dest: The byte array target into which to write the length. Must
* have at least 5 bytes allocated. * have at least 5 bytes allocated.
* @size: The length to write. * @size: The length to write.
...@@ -114,7 +114,7 @@ static int parse_packet_length(unsigned char *data, size_t *size, ...@@ -114,7 +114,7 @@ static int parse_packet_length(unsigned char *data, size_t *size,
* *
* Returns zero on success; non-zero on error. * Returns zero on success; non-zero on error.
*/ */
static int write_packet_length(char *dest, size_t size, int ecryptfs_write_packet_length(char *dest, size_t size,
size_t *packet_size_length) size_t *packet_size_length)
{ {
int rc = 0; int rc = 0;
...@@ -162,7 +162,7 @@ write_tag_64_packet(char *signature, struct ecryptfs_session_key *session_key, ...@@ -162,7 +162,7 @@ write_tag_64_packet(char *signature, struct ecryptfs_session_key *session_key,
goto out; goto out;
} }
message[i++] = ECRYPTFS_TAG_64_PACKET_TYPE; message[i++] = ECRYPTFS_TAG_64_PACKET_TYPE;
rc = write_packet_length(&message[i], ECRYPTFS_SIG_SIZE_HEX, rc = ecryptfs_write_packet_length(&message[i], ECRYPTFS_SIG_SIZE_HEX,
&packet_size_len); &packet_size_len);
if (rc) { if (rc) {
ecryptfs_printk(KERN_ERR, "Error generating tag 64 packet " ecryptfs_printk(KERN_ERR, "Error generating tag 64 packet "
...@@ -172,7 +172,8 @@ write_tag_64_packet(char *signature, struct ecryptfs_session_key *session_key, ...@@ -172,7 +172,8 @@ write_tag_64_packet(char *signature, struct ecryptfs_session_key *session_key,
i += packet_size_len; i += packet_size_len;
memcpy(&message[i], signature, ECRYPTFS_SIG_SIZE_HEX); memcpy(&message[i], signature, ECRYPTFS_SIG_SIZE_HEX);
i += ECRYPTFS_SIG_SIZE_HEX; i += ECRYPTFS_SIG_SIZE_HEX;
rc = write_packet_length(&message[i], session_key->encrypted_key_size, rc = ecryptfs_write_packet_length(&message[i],
session_key->encrypted_key_size,
&packet_size_len); &packet_size_len);
if (rc) { if (rc) {
ecryptfs_printk(KERN_ERR, "Error generating tag 64 packet " ecryptfs_printk(KERN_ERR, "Error generating tag 64 packet "
...@@ -225,7 +226,7 @@ parse_tag_65_packet(struct ecryptfs_session_key *session_key, u8 *cipher_code, ...@@ -225,7 +226,7 @@ parse_tag_65_packet(struct ecryptfs_session_key *session_key, u8 *cipher_code,
rc = -EIO; rc = -EIO;
goto out; goto out;
} }
rc = parse_packet_length(&data[i], &m_size, &data_len); rc = ecryptfs_parse_packet_length(&data[i], &m_size, &data_len);
if (rc) { if (rc) {
ecryptfs_printk(KERN_WARNING, "Error parsing packet length; " ecryptfs_printk(KERN_WARNING, "Error parsing packet length; "
"rc = [%d]\n", rc); "rc = [%d]\n", rc);
...@@ -304,7 +305,7 @@ write_tag_66_packet(char *signature, u8 cipher_code, ...@@ -304,7 +305,7 @@ write_tag_66_packet(char *signature, u8 cipher_code,
goto out; goto out;
} }
message[i++] = ECRYPTFS_TAG_66_PACKET_TYPE; message[i++] = ECRYPTFS_TAG_66_PACKET_TYPE;
rc = write_packet_length(&message[i], ECRYPTFS_SIG_SIZE_HEX, rc = ecryptfs_write_packet_length(&message[i], ECRYPTFS_SIG_SIZE_HEX,
&packet_size_len); &packet_size_len);
if (rc) { if (rc) {
ecryptfs_printk(KERN_ERR, "Error generating tag 66 packet " ecryptfs_printk(KERN_ERR, "Error generating tag 66 packet "
...@@ -315,7 +316,7 @@ write_tag_66_packet(char *signature, u8 cipher_code, ...@@ -315,7 +316,7 @@ write_tag_66_packet(char *signature, u8 cipher_code,
memcpy(&message[i], signature, ECRYPTFS_SIG_SIZE_HEX); memcpy(&message[i], signature, ECRYPTFS_SIG_SIZE_HEX);
i += ECRYPTFS_SIG_SIZE_HEX; i += ECRYPTFS_SIG_SIZE_HEX;
/* The encrypted key includes 1 byte cipher code and 2 byte checksum */ /* The encrypted key includes 1 byte cipher code and 2 byte checksum */
rc = write_packet_length(&message[i], crypt_stat->key_size + 3, rc = ecryptfs_write_packet_length(&message[i], crypt_stat->key_size + 3,
&packet_size_len); &packet_size_len);
if (rc) { if (rc) {
ecryptfs_printk(KERN_ERR, "Error generating tag 66 packet " ecryptfs_printk(KERN_ERR, "Error generating tag 66 packet "
...@@ -357,20 +358,25 @@ parse_tag_67_packet(struct ecryptfs_key_record *key_rec, ...@@ -357,20 +358,25 @@ parse_tag_67_packet(struct ecryptfs_key_record *key_rec,
/* verify that everything through the encrypted FEK size is present */ /* verify that everything through the encrypted FEK size is present */
if (message_len < 4) { if (message_len < 4) {
rc = -EIO; rc = -EIO;
printk(KERN_ERR "%s: message_len is [%Zd]; minimum acceptable "
"message length is [%d]\n", __func__, message_len, 4);
goto out; goto out;
} }
if (data[i++] != ECRYPTFS_TAG_67_PACKET_TYPE) { if (data[i++] != ECRYPTFS_TAG_67_PACKET_TYPE) {
ecryptfs_printk(KERN_ERR, "Type should be ECRYPTFS_TAG_67\n");
rc = -EIO; rc = -EIO;
printk(KERN_ERR "%s: Type should be ECRYPTFS_TAG_67\n",
__func__);
goto out; goto out;
} }
if (data[i++]) { if (data[i++]) {
ecryptfs_printk(KERN_ERR, "Status indicator has non zero value"
" [%d]\n", data[i-1]);
rc = -EIO; rc = -EIO;
printk(KERN_ERR "%s: Status indicator has non zero "
"value [%d]\n", __func__, data[i-1]);
goto out; goto out;
} }
rc = parse_packet_length(&data[i], &key_rec->enc_key_size, &data_len); rc = ecryptfs_parse_packet_length(&data[i], &key_rec->enc_key_size,
&data_len);
if (rc) { if (rc) {
ecryptfs_printk(KERN_WARNING, "Error parsing packet length; " ecryptfs_printk(KERN_WARNING, "Error parsing packet length; "
"rc = [%d]\n", rc); "rc = [%d]\n", rc);
...@@ -378,17 +384,17 @@ parse_tag_67_packet(struct ecryptfs_key_record *key_rec, ...@@ -378,17 +384,17 @@ parse_tag_67_packet(struct ecryptfs_key_record *key_rec,
} }
i += data_len; i += data_len;
if (message_len < (i + key_rec->enc_key_size)) { if (message_len < (i + key_rec->enc_key_size)) {
ecryptfs_printk(KERN_ERR, "message_len [%d]; max len is [%d]\n",
message_len, (i + key_rec->enc_key_size));
rc = -EIO; rc = -EIO;
printk(KERN_ERR "%s: message_len [%Zd]; max len is [%Zd]\n",
__func__, message_len, (i + key_rec->enc_key_size));
goto out; goto out;
} }
if (key_rec->enc_key_size > ECRYPTFS_MAX_ENCRYPTED_KEY_BYTES) { if (key_rec->enc_key_size > ECRYPTFS_MAX_ENCRYPTED_KEY_BYTES) {
ecryptfs_printk(KERN_ERR, "Encrypted key_size [%d] larger than " rc = -EIO;
"the maximum key size [%d]\n", printk(KERN_ERR "%s: Encrypted key_size [%Zd] larger than "
"the maximum key size [%d]\n", __func__,
key_rec->enc_key_size, key_rec->enc_key_size,
ECRYPTFS_MAX_ENCRYPTED_KEY_BYTES); ECRYPTFS_MAX_ENCRYPTED_KEY_BYTES);
rc = -EIO;
goto out; goto out;
} }
memcpy(key_rec->enc_key, &data[i], key_rec->enc_key_size); memcpy(key_rec->enc_key, &data[i], key_rec->enc_key_size);
...@@ -445,7 +451,7 @@ decrypt_pki_encrypted_session_key(struct ecryptfs_auth_tok *auth_tok, ...@@ -445,7 +451,7 @@ decrypt_pki_encrypted_session_key(struct ecryptfs_auth_tok *auth_tok,
rc = write_tag_64_packet(auth_tok_sig, &(auth_tok->session_key), rc = write_tag_64_packet(auth_tok_sig, &(auth_tok->session_key),
&netlink_message, &netlink_message_length); &netlink_message, &netlink_message_length);
if (rc) { if (rc) {
ecryptfs_printk(KERN_ERR, "Failed to write tag 64 packet"); ecryptfs_printk(KERN_ERR, "Failed to write tag 64 packet\n");
goto out; goto out;
} }
rc = ecryptfs_send_message(ecryptfs_transport, netlink_message, rc = ecryptfs_send_message(ecryptfs_transport, netlink_message,
...@@ -570,7 +576,7 @@ parse_tag_1_packet(struct ecryptfs_crypt_stat *crypt_stat, ...@@ -570,7 +576,7 @@ parse_tag_1_packet(struct ecryptfs_crypt_stat *crypt_stat,
goto out; goto out;
} }
(*new_auth_tok) = &auth_tok_list_item->auth_tok; (*new_auth_tok) = &auth_tok_list_item->auth_tok;
rc = parse_packet_length(&data[(*packet_size)], &body_size, rc = ecryptfs_parse_packet_length(&data[(*packet_size)], &body_size,
&length_size); &length_size);
if (rc) { if (rc) {
printk(KERN_WARNING "Error parsing packet length; " printk(KERN_WARNING "Error parsing packet length; "
...@@ -704,7 +710,7 @@ parse_tag_3_packet(struct ecryptfs_crypt_stat *crypt_stat, ...@@ -704,7 +710,7 @@ parse_tag_3_packet(struct ecryptfs_crypt_stat *crypt_stat,
goto out; goto out;
} }
(*new_auth_tok) = &auth_tok_list_item->auth_tok; (*new_auth_tok) = &auth_tok_list_item->auth_tok;
rc = parse_packet_length(&data[(*packet_size)], &body_size, rc = ecryptfs_parse_packet_length(&data[(*packet_size)], &body_size,
&length_size); &length_size);
if (rc) { if (rc) {
printk(KERN_WARNING "Error parsing packet length; rc = [%d]\n", printk(KERN_WARNING "Error parsing packet length; rc = [%d]\n",
...@@ -852,7 +858,7 @@ parse_tag_11_packet(unsigned char *data, unsigned char *contents, ...@@ -852,7 +858,7 @@ parse_tag_11_packet(unsigned char *data, unsigned char *contents,
rc = -EINVAL; rc = -EINVAL;
goto out; goto out;
} }
rc = parse_packet_length(&data[(*packet_size)], &body_size, rc = ecryptfs_parse_packet_length(&data[(*packet_size)], &body_size,
&length_size); &length_size);
if (rc) { if (rc) {
printk(KERN_WARNING "Invalid tag 11 packet format\n"); printk(KERN_WARNING "Invalid tag 11 packet format\n");
...@@ -1405,8 +1411,8 @@ write_tag_1_packet(char *dest, size_t *remaining_bytes, ...@@ -1405,8 +1411,8 @@ write_tag_1_packet(char *dest, size_t *remaining_bytes,
auth_tok->token.private_key.key_size; auth_tok->token.private_key.key_size;
rc = pki_encrypt_session_key(auth_tok, crypt_stat, key_rec); rc = pki_encrypt_session_key(auth_tok, crypt_stat, key_rec);
if (rc) { if (rc) {
ecryptfs_printk(KERN_ERR, "Failed to encrypt session key " printk(KERN_ERR "Failed to encrypt session key via a key "
"via a pki"); "module; rc = [%d]\n", rc);
goto out; goto out;
} }
if (ecryptfs_verbosity > 0) { if (ecryptfs_verbosity > 0) {
...@@ -1430,7 +1436,8 @@ write_tag_1_packet(char *dest, size_t *remaining_bytes, ...@@ -1430,7 +1436,8 @@ write_tag_1_packet(char *dest, size_t *remaining_bytes,
goto out; goto out;
} }
dest[(*packet_size)++] = ECRYPTFS_TAG_1_PACKET_TYPE; dest[(*packet_size)++] = ECRYPTFS_TAG_1_PACKET_TYPE;
rc = write_packet_length(&dest[(*packet_size)], (max_packet_size - 4), rc = ecryptfs_write_packet_length(&dest[(*packet_size)],
(max_packet_size - 4),
&packet_size_length); &packet_size_length);
if (rc) { if (rc) {
ecryptfs_printk(KERN_ERR, "Error generating tag 1 packet " ecryptfs_printk(KERN_ERR, "Error generating tag 1 packet "
...@@ -1489,8 +1496,9 @@ write_tag_11_packet(char *dest, size_t *remaining_bytes, char *contents, ...@@ -1489,8 +1496,9 @@ write_tag_11_packet(char *dest, size_t *remaining_bytes, char *contents,
goto out; goto out;
} }
dest[(*packet_length)++] = ECRYPTFS_TAG_11_PACKET_TYPE; dest[(*packet_length)++] = ECRYPTFS_TAG_11_PACKET_TYPE;
rc = write_packet_length(&dest[(*packet_length)], rc = ecryptfs_write_packet_length(&dest[(*packet_length)],
(max_packet_size - 4), &packet_size_length); (max_packet_size - 4),
&packet_size_length);
if (rc) { if (rc) {
printk(KERN_ERR "Error generating tag 11 packet header; cannot " printk(KERN_ERR "Error generating tag 11 packet header; cannot "
"generate packet length. rc = [%d]\n", rc); "generate packet length. rc = [%d]\n", rc);
...@@ -1682,7 +1690,8 @@ write_tag_3_packet(char *dest, size_t *remaining_bytes, ...@@ -1682,7 +1690,8 @@ write_tag_3_packet(char *dest, size_t *remaining_bytes,
dest[(*packet_size)++] = ECRYPTFS_TAG_3_PACKET_TYPE; dest[(*packet_size)++] = ECRYPTFS_TAG_3_PACKET_TYPE;
/* Chop off the Tag 3 identifier(1) and Tag 3 packet size(3) /* Chop off the Tag 3 identifier(1) and Tag 3 packet size(3)
* to get the number of octets in the actual Tag 3 packet */ * to get the number of octets in the actual Tag 3 packet */
rc = write_packet_length(&dest[(*packet_size)], (max_packet_size - 4), rc = ecryptfs_write_packet_length(&dest[(*packet_size)],
(max_packet_size - 4),
&packet_size_length); &packet_size_length);
if (rc) { if (rc) {
printk(KERN_ERR "Error generating tag 3 packet header; cannot " printk(KERN_ERR "Error generating tag 3 packet header; cannot "
......
/** /**
* eCryptfs: Linux filesystem encryption layer * eCryptfs: Linux filesystem encryption layer
* *
* Copyright (C) 2004-2006 International Business Machines Corp. * Copyright (C) 2004-2008 International Business Machines Corp.
* Author(s): Michael A. Halcrow <mhalcrow@us.ibm.com> * Author(s): Michael A. Halcrow <mhalcrow@us.ibm.com>
* Tyler Hicks <tyhicks@ou.edu> * Tyler Hicks <tyhicks@ou.edu>
* *
...@@ -26,13 +26,13 @@ static LIST_HEAD(ecryptfs_msg_ctx_free_list); ...@@ -26,13 +26,13 @@ static LIST_HEAD(ecryptfs_msg_ctx_free_list);
static LIST_HEAD(ecryptfs_msg_ctx_alloc_list); static LIST_HEAD(ecryptfs_msg_ctx_alloc_list);
static struct mutex ecryptfs_msg_ctx_lists_mux; static struct mutex ecryptfs_msg_ctx_lists_mux;
static struct hlist_head *ecryptfs_daemon_id_hash; static struct hlist_head *ecryptfs_daemon_hash;
static struct mutex ecryptfs_daemon_id_hash_mux; struct mutex ecryptfs_daemon_hash_mux;
static int ecryptfs_hash_buckets; static int ecryptfs_hash_buckets;
#define ecryptfs_uid_hash(uid) \ #define ecryptfs_uid_hash(uid) \
hash_long((unsigned long)uid, ecryptfs_hash_buckets) hash_long((unsigned long)uid, ecryptfs_hash_buckets)
static unsigned int ecryptfs_msg_counter; static u32 ecryptfs_msg_counter;
static struct ecryptfs_msg_ctx *ecryptfs_msg_ctx_arr; static struct ecryptfs_msg_ctx *ecryptfs_msg_ctx_arr;
/** /**
...@@ -40,9 +40,10 @@ static struct ecryptfs_msg_ctx *ecryptfs_msg_ctx_arr; ...@@ -40,9 +40,10 @@ static struct ecryptfs_msg_ctx *ecryptfs_msg_ctx_arr;
* @msg_ctx: The context that was acquired from the free list * @msg_ctx: The context that was acquired from the free list
* *
* Acquires a context element from the free list and locks the mutex * Acquires a context element from the free list and locks the mutex
* on the context. Returns zero on success; non-zero on error or upon * on the context. Sets the msg_ctx task to current. Returns zero on
* failure to acquire a free context element. Be sure to lock the * success; non-zero on error or upon failure to acquire a free
* list mutex before calling. * context element. Must be called with ecryptfs_msg_ctx_lists_mux
* held.
*/ */
static int ecryptfs_acquire_free_msg_ctx(struct ecryptfs_msg_ctx **msg_ctx) static int ecryptfs_acquire_free_msg_ctx(struct ecryptfs_msg_ctx **msg_ctx)
{ {
...@@ -50,11 +51,11 @@ static int ecryptfs_acquire_free_msg_ctx(struct ecryptfs_msg_ctx **msg_ctx) ...@@ -50,11 +51,11 @@ static int ecryptfs_acquire_free_msg_ctx(struct ecryptfs_msg_ctx **msg_ctx)
int rc; int rc;
if (list_empty(&ecryptfs_msg_ctx_free_list)) { if (list_empty(&ecryptfs_msg_ctx_free_list)) {
ecryptfs_printk(KERN_WARNING, "The eCryptfs free " printk(KERN_WARNING "%s: The eCryptfs free "
"context list is empty. It may be helpful to " "context list is empty. It may be helpful to "
"specify the ecryptfs_message_buf_len " "specify the ecryptfs_message_buf_len "
"parameter to be greater than the current " "parameter to be greater than the current "
"value of [%d]\n", ecryptfs_message_buf_len); "value of [%d]\n", __func__, ecryptfs_message_buf_len);
rc = -ENOMEM; rc = -ENOMEM;
goto out; goto out;
} }
...@@ -75,8 +76,7 @@ static int ecryptfs_acquire_free_msg_ctx(struct ecryptfs_msg_ctx **msg_ctx) ...@@ -75,8 +76,7 @@ static int ecryptfs_acquire_free_msg_ctx(struct ecryptfs_msg_ctx **msg_ctx)
* ecryptfs_msg_ctx_free_to_alloc * ecryptfs_msg_ctx_free_to_alloc
* @msg_ctx: The context to move from the free list to the alloc list * @msg_ctx: The context to move from the free list to the alloc list
* *
* Be sure to lock the list mutex and the context mutex before * Must be called with ecryptfs_msg_ctx_lists_mux held.
* calling.
*/ */
static void ecryptfs_msg_ctx_free_to_alloc(struct ecryptfs_msg_ctx *msg_ctx) static void ecryptfs_msg_ctx_free_to_alloc(struct ecryptfs_msg_ctx *msg_ctx)
{ {
...@@ -89,36 +89,37 @@ static void ecryptfs_msg_ctx_free_to_alloc(struct ecryptfs_msg_ctx *msg_ctx) ...@@ -89,36 +89,37 @@ static void ecryptfs_msg_ctx_free_to_alloc(struct ecryptfs_msg_ctx *msg_ctx)
* ecryptfs_msg_ctx_alloc_to_free * ecryptfs_msg_ctx_alloc_to_free
* @msg_ctx: The context to move from the alloc list to the free list * @msg_ctx: The context to move from the alloc list to the free list
* *
* Be sure to lock the list mutex and the context mutex before * Must be called with ecryptfs_msg_ctx_lists_mux held.
* calling.
*/ */
static void ecryptfs_msg_ctx_alloc_to_free(struct ecryptfs_msg_ctx *msg_ctx) void ecryptfs_msg_ctx_alloc_to_free(struct ecryptfs_msg_ctx *msg_ctx)
{ {
list_move(&(msg_ctx->node), &ecryptfs_msg_ctx_free_list); list_move(&(msg_ctx->node), &ecryptfs_msg_ctx_free_list);
if (msg_ctx->msg) if (msg_ctx->msg)
kfree(msg_ctx->msg); kfree(msg_ctx->msg);
msg_ctx->msg = NULL;
msg_ctx->state = ECRYPTFS_MSG_CTX_STATE_FREE; msg_ctx->state = ECRYPTFS_MSG_CTX_STATE_FREE;
} }
/** /**
* ecryptfs_find_daemon_id * ecryptfs_find_daemon_by_euid
* @uid: The user id which maps to the desired daemon id * @euid: The effective user id which maps to the desired daemon id
* @id: If return value is zero, points to the desired daemon id * @daemon: If return value is zero, points to the desired daemon pointer
* pointer *
* Must be called with ecryptfs_daemon_hash_mux held.
*
* Search the hash list for the given user id.
* *
* Search the hash list for the given user id. Returns zero if the * Returns zero if the user id exists in the list; non-zero otherwise.
* user id exists in the list; non-zero otherwise. The daemon id hash
* mutex should be held before calling this function.
*/ */
static int ecryptfs_find_daemon_id(uid_t uid, struct ecryptfs_daemon_id **id) int ecryptfs_find_daemon_by_euid(struct ecryptfs_daemon **daemon, uid_t euid)
{ {
struct hlist_node *elem; struct hlist_node *elem;
int rc; int rc;
hlist_for_each_entry(*id, elem, hlist_for_each_entry(*daemon, elem,
&ecryptfs_daemon_id_hash[ecryptfs_uid_hash(uid)], &ecryptfs_daemon_hash[ecryptfs_uid_hash(euid)],
id_chain) { euid_chain) {
if ((*id)->uid == uid) { if ((*daemon)->euid == euid) {
rc = 0; rc = 0;
goto out; goto out;
} }
...@@ -128,181 +129,291 @@ static int ecryptfs_find_daemon_id(uid_t uid, struct ecryptfs_daemon_id **id) ...@@ -128,181 +129,291 @@ static int ecryptfs_find_daemon_id(uid_t uid, struct ecryptfs_daemon_id **id)
return rc; return rc;
} }
static int ecryptfs_send_raw_message(unsigned int transport, u16 msg_type, static int
pid_t pid) ecryptfs_send_message_locked(unsigned int transport, char *data, int data_len,
u8 msg_type, struct ecryptfs_msg_ctx **msg_ctx);
/**
* ecryptfs_send_raw_message
* @transport: Transport type
* @msg_type: Message type
* @daemon: Daemon struct for recipient of message
*
* A raw message is one that does not include an ecryptfs_message
* struct. It simply has a type.
*
* Must be called with ecryptfs_daemon_hash_mux held.
*
* Returns zero on success; non-zero otherwise
*/
static int ecryptfs_send_raw_message(unsigned int transport, u8 msg_type,
struct ecryptfs_daemon *daemon)
{ {
struct ecryptfs_msg_ctx *msg_ctx;
int rc; int rc;
switch(transport) { switch(transport) {
case ECRYPTFS_TRANSPORT_NETLINK: case ECRYPTFS_TRANSPORT_NETLINK:
rc = ecryptfs_send_netlink(NULL, 0, NULL, msg_type, 0, pid); rc = ecryptfs_send_netlink(NULL, 0, NULL, msg_type, 0,
daemon->pid);
break;
case ECRYPTFS_TRANSPORT_MISCDEV:
rc = ecryptfs_send_message_locked(transport, NULL, 0, msg_type,
&msg_ctx);
if (rc) {
printk(KERN_ERR "%s: Error whilst attempting to send "
"message via procfs; rc = [%d]\n", __func__, rc);
goto out;
}
/* Raw messages are logically context-free (e.g., no
* reply is expected), so we set the state of the
* ecryptfs_msg_ctx object to indicate that it should
* be freed as soon as the transport sends out the message. */
mutex_lock(&msg_ctx->mux);
msg_ctx->state = ECRYPTFS_MSG_CTX_STATE_NO_REPLY;
mutex_unlock(&msg_ctx->mux);
break; break;
case ECRYPTFS_TRANSPORT_CONNECTOR: case ECRYPTFS_TRANSPORT_CONNECTOR:
case ECRYPTFS_TRANSPORT_RELAYFS: case ECRYPTFS_TRANSPORT_RELAYFS:
default: default:
rc = -ENOSYS; rc = -ENOSYS;
} }
out:
return rc;
}
/**
* ecryptfs_spawn_daemon - Create and initialize a new daemon struct
* @daemon: Pointer to set to newly allocated daemon struct
* @euid: Effective user id for the daemon
* @pid: Process id for the daemon
*
* Must be called ceremoniously while in possession of
* ecryptfs_sacred_daemon_hash_mux
*
* Returns zero on success; non-zero otherwise
*/
int
ecryptfs_spawn_daemon(struct ecryptfs_daemon **daemon, uid_t euid, pid_t pid)
{
int rc = 0;
(*daemon) = kzalloc(sizeof(**daemon), GFP_KERNEL);
if (!(*daemon)) {
rc = -ENOMEM;
printk(KERN_ERR "%s: Failed to allocate [%Zd] bytes of "
"GFP_KERNEL memory\n", __func__, sizeof(**daemon));
goto out;
}
(*daemon)->euid = euid;
(*daemon)->pid = pid;
(*daemon)->task = current;
mutex_init(&(*daemon)->mux);
INIT_LIST_HEAD(&(*daemon)->msg_ctx_out_queue);
init_waitqueue_head(&(*daemon)->wait);
(*daemon)->num_queued_msg_ctx = 0;
hlist_add_head(&(*daemon)->euid_chain,
&ecryptfs_daemon_hash[ecryptfs_uid_hash(euid)]);
out:
return rc; return rc;
} }
/** /**
* ecryptfs_process_helo * ecryptfs_process_helo
* @transport: The underlying transport (netlink, etc.) * @transport: The underlying transport (netlink, etc.)
* @uid: The user ID owner of the message * @euid: The user ID owner of the message
* @pid: The process ID for the userspace program that sent the * @pid: The process ID for the userspace program that sent the
* message * message
* *
* Adds the uid and pid values to the daemon id hash. If a uid * Adds the euid and pid values to the daemon euid hash. If an euid
* already has a daemon pid registered, the daemon will be * already has a daemon pid registered, the daemon will be
* unregistered before the new daemon id is put into the hash list. * unregistered before the new daemon is put into the hash list.
* Returns zero after adding a new daemon id to the hash list; * Returns zero after adding a new daemon to the hash list;
* non-zero otherwise. * non-zero otherwise.
*/ */
int ecryptfs_process_helo(unsigned int transport, uid_t uid, pid_t pid) int ecryptfs_process_helo(unsigned int transport, uid_t euid, pid_t pid)
{ {
struct ecryptfs_daemon_id *new_id; struct ecryptfs_daemon *new_daemon;
struct ecryptfs_daemon_id *old_id; struct ecryptfs_daemon *old_daemon;
int rc; int rc;
mutex_lock(&ecryptfs_daemon_id_hash_mux); mutex_lock(&ecryptfs_daemon_hash_mux);
new_id = kmalloc(sizeof(*new_id), GFP_KERNEL); rc = ecryptfs_find_daemon_by_euid(&old_daemon, euid);
if (!new_id) { if (rc != 0) {
rc = -ENOMEM;
ecryptfs_printk(KERN_ERR, "Failed to allocate memory; unable "
"to register daemon [%d] for user [%d]\n",
pid, uid);
goto unlock;
}
if (!ecryptfs_find_daemon_id(uid, &old_id)) {
printk(KERN_WARNING "Received request from user [%d] " printk(KERN_WARNING "Received request from user [%d] "
"to register daemon [%d]; unregistering daemon " "to register daemon [%d]; unregistering daemon "
"[%d]\n", uid, pid, old_id->pid); "[%d]\n", euid, pid, old_daemon->pid);
hlist_del(&old_id->id_chain); rc = ecryptfs_send_raw_message(transport, ECRYPTFS_MSG_QUIT,
rc = ecryptfs_send_raw_message(transport, ECRYPTFS_NLMSG_QUIT, old_daemon);
old_id->pid);
if (rc) if (rc)
printk(KERN_WARNING "Failed to send QUIT " printk(KERN_WARNING "Failed to send QUIT "
"message to daemon [%d]; rc = [%d]\n", "message to daemon [%d]; rc = [%d]\n",
old_id->pid, rc); old_daemon->pid, rc);
kfree(old_id); hlist_del(&old_daemon->euid_chain);
kfree(old_daemon);
} }
new_id->uid = uid; rc = ecryptfs_spawn_daemon(&new_daemon, euid, pid);
new_id->pid = pid; if (rc)
hlist_add_head(&new_id->id_chain, printk(KERN_ERR "%s: The gods are displeased with this attempt "
&ecryptfs_daemon_id_hash[ecryptfs_uid_hash(uid)]); "to create a new daemon object for euid [%d]; pid [%d]; "
rc = 0; "rc = [%d]\n", __func__, euid, pid, rc);
unlock: mutex_unlock(&ecryptfs_daemon_hash_mux);
mutex_unlock(&ecryptfs_daemon_id_hash_mux); return rc;
}
/**
* ecryptfs_exorcise_daemon - Destroy the daemon struct
*
* Must be called ceremoniously while in possession of
* ecryptfs_daemon_hash_mux and the daemon's own mux.
*/
int ecryptfs_exorcise_daemon(struct ecryptfs_daemon *daemon)
{
struct ecryptfs_msg_ctx *msg_ctx, *msg_ctx_tmp;
int rc = 0;
mutex_lock(&daemon->mux);
if ((daemon->flags & ECRYPTFS_DAEMON_IN_READ)
|| (daemon->flags & ECRYPTFS_DAEMON_IN_POLL)) {
rc = -EBUSY;
printk(KERN_WARNING "%s: Attempt to destroy daemon with pid "
"[%d], but it is in the midst of a read or a poll\n",
__func__, daemon->pid);
mutex_unlock(&daemon->mux);
goto out;
}
list_for_each_entry_safe(msg_ctx, msg_ctx_tmp,
&daemon->msg_ctx_out_queue, daemon_out_list) {
list_del(&msg_ctx->daemon_out_list);
daemon->num_queued_msg_ctx--;
printk(KERN_WARNING "%s: Warning: dropping message that is in "
"the out queue of a dying daemon\n", __func__);
ecryptfs_msg_ctx_alloc_to_free(msg_ctx);
}
hlist_del(&daemon->euid_chain);
if (daemon->task)
wake_up_process(daemon->task);
mutex_unlock(&daemon->mux);
memset(daemon, 0, sizeof(*daemon));
kfree(daemon);
out:
return rc; return rc;
} }
/** /**
* ecryptfs_process_quit * ecryptfs_process_quit
* @uid: The user ID owner of the message * @euid: The user ID owner of the message
* @pid: The process ID for the userspace program that sent the * @pid: The process ID for the userspace program that sent the
* message * message
* *
* Deletes the corresponding daemon id for the given uid and pid, if * Deletes the corresponding daemon for the given euid and pid, if
* it is the registered that is requesting the deletion. Returns zero * it is the registered that is requesting the deletion. Returns zero
* after deleting the desired daemon id; non-zero otherwise. * after deleting the desired daemon; non-zero otherwise.
*/ */
int ecryptfs_process_quit(uid_t uid, pid_t pid) int ecryptfs_process_quit(uid_t euid, pid_t pid)
{ {
struct ecryptfs_daemon_id *id; struct ecryptfs_daemon *daemon;
int rc; int rc;
mutex_lock(&ecryptfs_daemon_id_hash_mux); mutex_lock(&ecryptfs_daemon_hash_mux);
if (ecryptfs_find_daemon_id(uid, &id)) { rc = ecryptfs_find_daemon_by_euid(&daemon, euid);
rc = -EINVAL; if (rc || !daemon) {
ecryptfs_printk(KERN_ERR, "Received request from user [%d] to "
"unregister unrecognized daemon [%d]\n", uid,
pid);
goto unlock;
}
if (id->pid != pid) {
rc = -EINVAL; rc = -EINVAL;
ecryptfs_printk(KERN_WARNING, "Received request from user [%d] " printk(KERN_ERR "Received request from user [%d] to "
"with pid [%d] to unregister daemon [%d]\n", "unregister unrecognized daemon [%d]\n", euid, pid);
uid, pid, id->pid); goto out_unlock;
goto unlock;
} }
hlist_del(&id->id_chain); rc = ecryptfs_exorcise_daemon(daemon);
kfree(id); out_unlock:
rc = 0; mutex_unlock(&ecryptfs_daemon_hash_mux);
unlock:
mutex_unlock(&ecryptfs_daemon_id_hash_mux);
return rc; return rc;
} }
/** /**
* ecryptfs_process_reponse * ecryptfs_process_reponse
* @msg: The ecryptfs message received; the caller should sanity check * @msg: The ecryptfs message received; the caller should sanity check
* msg->data_len * msg->data_len and free the memory
* @pid: The process ID of the userspace application that sent the * @pid: The process ID of the userspace application that sent the
* message * message
* @seq: The sequence number of the message * @seq: The sequence number of the message; must match the sequence
* number for the existing message context waiting for this
* response
*
* Processes a response message after sending an operation request to
* userspace. Some other process is awaiting this response. Before
* sending out its first communications, the other process allocated a
* msg_ctx from the ecryptfs_msg_ctx_arr at a particular index. The
* response message contains this index so that we can copy over the
* response message into the msg_ctx that the process holds a
* reference to. The other process is going to wake up, check to see
* that msg_ctx->state == ECRYPTFS_MSG_CTX_STATE_DONE, and then
* proceed to read off and process the response message. Returns zero
* upon delivery to desired context element; non-zero upon delivery
* failure or error.
* *
* Processes a response message after sending a operation request to * Returns zero on success; non-zero otherwise
* userspace. Returns zero upon delivery to desired context element;
* non-zero upon delivery failure or error.
*/ */
int ecryptfs_process_response(struct ecryptfs_message *msg, uid_t uid, int ecryptfs_process_response(struct ecryptfs_message *msg, uid_t euid,
pid_t pid, u32 seq) pid_t pid, u32 seq)
{ {
struct ecryptfs_daemon_id *id; struct ecryptfs_daemon *daemon;
struct ecryptfs_msg_ctx *msg_ctx; struct ecryptfs_msg_ctx *msg_ctx;
int msg_size; size_t msg_size;
int rc; int rc;
if (msg->index >= ecryptfs_message_buf_len) { if (msg->index >= ecryptfs_message_buf_len) {
rc = -EINVAL; rc = -EINVAL;
ecryptfs_printk(KERN_ERR, "Attempt to reference " printk(KERN_ERR "%s: Attempt to reference "
"context buffer at index [%d]; maximum " "context buffer at index [%d]; maximum "
"allowable is [%d]\n", msg->index, "allowable is [%d]\n", __func__, msg->index,
(ecryptfs_message_buf_len - 1)); (ecryptfs_message_buf_len - 1));
goto out; goto out;
} }
msg_ctx = &ecryptfs_msg_ctx_arr[msg->index]; msg_ctx = &ecryptfs_msg_ctx_arr[msg->index];
mutex_lock(&msg_ctx->mux); mutex_lock(&msg_ctx->mux);
if (ecryptfs_find_daemon_id(msg_ctx->task->euid, &id)) { mutex_lock(&ecryptfs_daemon_hash_mux);
rc = ecryptfs_find_daemon_by_euid(&daemon, msg_ctx->task->euid);
mutex_unlock(&ecryptfs_daemon_hash_mux);
if (rc) {
rc = -EBADMSG; rc = -EBADMSG;
ecryptfs_printk(KERN_WARNING, "User [%d] received a " printk(KERN_WARNING "%s: User [%d] received a "
"message response from process [%d] but does " "message response from process [%d] but does "
"not have a registered daemon\n", "not have a registered daemon\n", __func__,
msg_ctx->task->euid, pid); msg_ctx->task->euid, pid);
goto wake_up; goto wake_up;
} }
if (msg_ctx->task->euid != uid) { if (msg_ctx->task->euid != euid) {
rc = -EBADMSG; rc = -EBADMSG;
ecryptfs_printk(KERN_WARNING, "Received message from user " printk(KERN_WARNING "%s: Received message from user "
"[%d]; expected message from user [%d]\n", "[%d]; expected message from user [%d]\n", __func__,
uid, msg_ctx->task->euid); euid, msg_ctx->task->euid);
goto unlock; goto unlock;
} }
if (id->pid != pid) { if (daemon->pid != pid) {
rc = -EBADMSG; rc = -EBADMSG;
ecryptfs_printk(KERN_ERR, "User [%d] received a " printk(KERN_ERR "%s: User [%d] sent a message response "
"message response from an unrecognized " "from an unrecognized process [%d]\n",
"process [%d]\n", msg_ctx->task->euid, pid); __func__, msg_ctx->task->euid, pid);
goto unlock; goto unlock;
} }
if (msg_ctx->state != ECRYPTFS_MSG_CTX_STATE_PENDING) { if (msg_ctx->state != ECRYPTFS_MSG_CTX_STATE_PENDING) {
rc = -EINVAL; rc = -EINVAL;
ecryptfs_printk(KERN_WARNING, "Desired context element is not " printk(KERN_WARNING "%s: Desired context element is not "
"pending a response\n"); "pending a response\n", __func__);
goto unlock; goto unlock;
} else if (msg_ctx->counter != seq) { } else if (msg_ctx->counter != seq) {
rc = -EINVAL; rc = -EINVAL;
ecryptfs_printk(KERN_WARNING, "Invalid message sequence; " printk(KERN_WARNING "%s: Invalid message sequence; "
"expected [%d]; received [%d]\n", "expected [%d]; received [%d]\n", __func__,
msg_ctx->counter, seq); msg_ctx->counter, seq);
goto unlock; goto unlock;
} }
msg_size = sizeof(*msg) + msg->data_len; msg_size = (sizeof(*msg) + msg->data_len);
msg_ctx->msg = kmalloc(msg_size, GFP_KERNEL); msg_ctx->msg = kmalloc(msg_size, GFP_KERNEL);
if (!msg_ctx->msg) { if (!msg_ctx->msg) {
rc = -ENOMEM; rc = -ENOMEM;
ecryptfs_printk(KERN_ERR, "Failed to allocate memory\n"); printk(KERN_ERR "%s: Failed to allocate [%Zd] bytes of "
"GFP_KERNEL memory\n", __func__, msg_size);
goto unlock; goto unlock;
} }
memcpy(msg_ctx->msg, msg, msg_size); memcpy(msg_ctx->msg, msg, msg_size);
...@@ -317,34 +428,37 @@ int ecryptfs_process_response(struct ecryptfs_message *msg, uid_t uid, ...@@ -317,34 +428,37 @@ int ecryptfs_process_response(struct ecryptfs_message *msg, uid_t uid,
} }
/** /**
* ecryptfs_send_message * ecryptfs_send_message_locked
* @transport: The transport over which to send the message (i.e., * @transport: The transport over which to send the message (i.e.,
* netlink) * netlink)
* @data: The data to send * @data: The data to send
* @data_len: The length of data * @data_len: The length of data
* @msg_ctx: The message context allocated for the send * @msg_ctx: The message context allocated for the send
*
* Must be called with ecryptfs_daemon_hash_mux held.
*
* Returns zero on success; non-zero otherwise
*/ */
int ecryptfs_send_message(unsigned int transport, char *data, int data_len, static int
struct ecryptfs_msg_ctx **msg_ctx) ecryptfs_send_message_locked(unsigned int transport, char *data, int data_len,
u8 msg_type, struct ecryptfs_msg_ctx **msg_ctx)
{ {
struct ecryptfs_daemon_id *id; struct ecryptfs_daemon *daemon;
int rc; int rc;
mutex_lock(&ecryptfs_daemon_id_hash_mux); rc = ecryptfs_find_daemon_by_euid(&daemon, current->euid);
if (ecryptfs_find_daemon_id(current->euid, &id)) { if (rc || !daemon) {
mutex_unlock(&ecryptfs_daemon_id_hash_mux);
rc = -ENOTCONN; rc = -ENOTCONN;
ecryptfs_printk(KERN_ERR, "User [%d] does not have a daemon " printk(KERN_ERR "%s: User [%d] does not have a daemon "
"registered\n", current->euid); "registered\n", __func__, current->euid);
goto out; goto out;
} }
mutex_unlock(&ecryptfs_daemon_id_hash_mux);
mutex_lock(&ecryptfs_msg_ctx_lists_mux); mutex_lock(&ecryptfs_msg_ctx_lists_mux);
rc = ecryptfs_acquire_free_msg_ctx(msg_ctx); rc = ecryptfs_acquire_free_msg_ctx(msg_ctx);
if (rc) { if (rc) {
mutex_unlock(&ecryptfs_msg_ctx_lists_mux); mutex_unlock(&ecryptfs_msg_ctx_lists_mux);
ecryptfs_printk(KERN_WARNING, "Could not claim a free " printk(KERN_WARNING "%s: Could not claim a free "
"context element\n"); "context element\n", __func__);
goto out; goto out;
} }
ecryptfs_msg_ctx_free_to_alloc(*msg_ctx); ecryptfs_msg_ctx_free_to_alloc(*msg_ctx);
...@@ -352,22 +466,49 @@ int ecryptfs_send_message(unsigned int transport, char *data, int data_len, ...@@ -352,22 +466,49 @@ int ecryptfs_send_message(unsigned int transport, char *data, int data_len,
mutex_unlock(&ecryptfs_msg_ctx_lists_mux); mutex_unlock(&ecryptfs_msg_ctx_lists_mux);
switch (transport) { switch (transport) {
case ECRYPTFS_TRANSPORT_NETLINK: case ECRYPTFS_TRANSPORT_NETLINK:
rc = ecryptfs_send_netlink(data, data_len, *msg_ctx, rc = ecryptfs_send_netlink(data, data_len, *msg_ctx, msg_type,
ECRYPTFS_NLMSG_REQUEST, 0, id->pid); 0, daemon->pid);
break;
case ECRYPTFS_TRANSPORT_MISCDEV:
rc = ecryptfs_send_miscdev(data, data_len, *msg_ctx, msg_type,
0, daemon);
break; break;
case ECRYPTFS_TRANSPORT_CONNECTOR: case ECRYPTFS_TRANSPORT_CONNECTOR:
case ECRYPTFS_TRANSPORT_RELAYFS: case ECRYPTFS_TRANSPORT_RELAYFS:
default: default:
rc = -ENOSYS; rc = -ENOSYS;
} }
if (rc) { if (rc)
printk(KERN_ERR "Error attempting to send message to userspace " printk(KERN_ERR "%s: Error attempting to send message to "
"daemon; rc = [%d]\n", rc); "userspace daemon; rc = [%d]\n", __func__, rc);
}
out: out:
return rc; return rc;
} }
/**
* ecryptfs_send_message
* @transport: The transport over which to send the message (i.e.,
* netlink)
* @data: The data to send
* @data_len: The length of data
* @msg_ctx: The message context allocated for the send
*
* Grabs ecryptfs_daemon_hash_mux.
*
* Returns zero on success; non-zero otherwise
*/
int ecryptfs_send_message(unsigned int transport, char *data, int data_len,
struct ecryptfs_msg_ctx **msg_ctx)
{
int rc;
mutex_lock(&ecryptfs_daemon_hash_mux);
rc = ecryptfs_send_message_locked(transport, data, data_len,
ECRYPTFS_MSG_REQUEST, msg_ctx);
mutex_unlock(&ecryptfs_daemon_hash_mux);
return rc;
}
/** /**
* ecryptfs_wait_for_response * ecryptfs_wait_for_response
* @msg_ctx: The context that was assigned when sending a message * @msg_ctx: The context that was assigned when sending a message
...@@ -377,7 +518,7 @@ int ecryptfs_send_message(unsigned int transport, char *data, int data_len, ...@@ -377,7 +518,7 @@ int ecryptfs_send_message(unsigned int transport, char *data, int data_len,
* of time exceeds ecryptfs_message_wait_timeout. If zero is * of time exceeds ecryptfs_message_wait_timeout. If zero is
* returned, msg will point to a valid message from userspace; a * returned, msg will point to a valid message from userspace; a
* non-zero value is returned upon failure to receive a message or an * non-zero value is returned upon failure to receive a message or an
* error occurs. * error occurs. Callee must free @msg on success.
*/ */
int ecryptfs_wait_for_response(struct ecryptfs_msg_ctx *msg_ctx, int ecryptfs_wait_for_response(struct ecryptfs_msg_ctx *msg_ctx,
struct ecryptfs_message **msg) struct ecryptfs_message **msg)
...@@ -413,32 +554,32 @@ int ecryptfs_init_messaging(unsigned int transport) ...@@ -413,32 +554,32 @@ int ecryptfs_init_messaging(unsigned int transport)
if (ecryptfs_number_of_users > ECRYPTFS_MAX_NUM_USERS) { if (ecryptfs_number_of_users > ECRYPTFS_MAX_NUM_USERS) {
ecryptfs_number_of_users = ECRYPTFS_MAX_NUM_USERS; ecryptfs_number_of_users = ECRYPTFS_MAX_NUM_USERS;
ecryptfs_printk(KERN_WARNING, "Specified number of users is " printk(KERN_WARNING "%s: Specified number of users is "
"too large, defaulting to [%d] users\n", "too large, defaulting to [%d] users\n", __func__,
ecryptfs_number_of_users); ecryptfs_number_of_users);
} }
mutex_init(&ecryptfs_daemon_id_hash_mux); mutex_init(&ecryptfs_daemon_hash_mux);
mutex_lock(&ecryptfs_daemon_id_hash_mux); mutex_lock(&ecryptfs_daemon_hash_mux);
ecryptfs_hash_buckets = 1; ecryptfs_hash_buckets = 1;
while (ecryptfs_number_of_users >> ecryptfs_hash_buckets) while (ecryptfs_number_of_users >> ecryptfs_hash_buckets)
ecryptfs_hash_buckets++; ecryptfs_hash_buckets++;
ecryptfs_daemon_id_hash = kmalloc(sizeof(struct hlist_head) ecryptfs_daemon_hash = kmalloc((sizeof(struct hlist_head)
* ecryptfs_hash_buckets, GFP_KERNEL); * ecryptfs_hash_buckets), GFP_KERNEL);
if (!ecryptfs_daemon_id_hash) { if (!ecryptfs_daemon_hash) {
rc = -ENOMEM; rc = -ENOMEM;
ecryptfs_printk(KERN_ERR, "Failed to allocate memory\n"); printk(KERN_ERR "%s: Failed to allocate memory\n", __func__);
mutex_unlock(&ecryptfs_daemon_id_hash_mux); mutex_unlock(&ecryptfs_daemon_hash_mux);
goto out; goto out;
} }
for (i = 0; i < ecryptfs_hash_buckets; i++) for (i = 0; i < ecryptfs_hash_buckets; i++)
INIT_HLIST_HEAD(&ecryptfs_daemon_id_hash[i]); INIT_HLIST_HEAD(&ecryptfs_daemon_hash[i]);
mutex_unlock(&ecryptfs_daemon_id_hash_mux); mutex_unlock(&ecryptfs_daemon_hash_mux);
ecryptfs_msg_ctx_arr = kmalloc((sizeof(struct ecryptfs_msg_ctx) ecryptfs_msg_ctx_arr = kmalloc((sizeof(struct ecryptfs_msg_ctx)
* ecryptfs_message_buf_len), GFP_KERNEL); * ecryptfs_message_buf_len),
GFP_KERNEL);
if (!ecryptfs_msg_ctx_arr) { if (!ecryptfs_msg_ctx_arr) {
rc = -ENOMEM; rc = -ENOMEM;
ecryptfs_printk(KERN_ERR, "Failed to allocate memory\n"); printk(KERN_ERR "%s: Failed to allocate memory\n", __func__);
goto out; goto out;
} }
mutex_init(&ecryptfs_msg_ctx_lists_mux); mutex_init(&ecryptfs_msg_ctx_lists_mux);
...@@ -446,6 +587,7 @@ int ecryptfs_init_messaging(unsigned int transport) ...@@ -446,6 +587,7 @@ int ecryptfs_init_messaging(unsigned int transport)
ecryptfs_msg_counter = 0; ecryptfs_msg_counter = 0;
for (i = 0; i < ecryptfs_message_buf_len; i++) { for (i = 0; i < ecryptfs_message_buf_len; i++) {
INIT_LIST_HEAD(&ecryptfs_msg_ctx_arr[i].node); INIT_LIST_HEAD(&ecryptfs_msg_ctx_arr[i].node);
INIT_LIST_HEAD(&ecryptfs_msg_ctx_arr[i].daemon_out_list);
mutex_init(&ecryptfs_msg_ctx_arr[i].mux); mutex_init(&ecryptfs_msg_ctx_arr[i].mux);
mutex_lock(&ecryptfs_msg_ctx_arr[i].mux); mutex_lock(&ecryptfs_msg_ctx_arr[i].mux);
ecryptfs_msg_ctx_arr[i].index = i; ecryptfs_msg_ctx_arr[i].index = i;
...@@ -464,6 +606,11 @@ int ecryptfs_init_messaging(unsigned int transport) ...@@ -464,6 +606,11 @@ int ecryptfs_init_messaging(unsigned int transport)
if (rc) if (rc)
ecryptfs_release_messaging(transport); ecryptfs_release_messaging(transport);
break; break;
case ECRYPTFS_TRANSPORT_MISCDEV:
rc = ecryptfs_init_ecryptfs_miscdev();
if (rc)
ecryptfs_release_messaging(transport);
break;
case ECRYPTFS_TRANSPORT_CONNECTOR: case ECRYPTFS_TRANSPORT_CONNECTOR:
case ECRYPTFS_TRANSPORT_RELAYFS: case ECRYPTFS_TRANSPORT_RELAYFS:
default: default:
...@@ -488,27 +635,37 @@ void ecryptfs_release_messaging(unsigned int transport) ...@@ -488,27 +635,37 @@ void ecryptfs_release_messaging(unsigned int transport)
kfree(ecryptfs_msg_ctx_arr); kfree(ecryptfs_msg_ctx_arr);
mutex_unlock(&ecryptfs_msg_ctx_lists_mux); mutex_unlock(&ecryptfs_msg_ctx_lists_mux);
} }
if (ecryptfs_daemon_id_hash) { if (ecryptfs_daemon_hash) {
struct hlist_node *elem; struct hlist_node *elem;
struct ecryptfs_daemon_id *id; struct ecryptfs_daemon *daemon;
int i; int i;
mutex_lock(&ecryptfs_daemon_id_hash_mux); mutex_lock(&ecryptfs_daemon_hash_mux);
for (i = 0; i < ecryptfs_hash_buckets; i++) { for (i = 0; i < ecryptfs_hash_buckets; i++) {
hlist_for_each_entry(id, elem, int rc;
&ecryptfs_daemon_id_hash[i],
id_chain) { hlist_for_each_entry(daemon, elem,
hlist_del(elem); &ecryptfs_daemon_hash[i],
kfree(id); euid_chain) {
rc = ecryptfs_exorcise_daemon(daemon);
if (rc)
printk(KERN_ERR "%s: Error whilst "
"attempting to destroy daemon; "
"rc = [%d]. Dazed and confused, "
"but trying to continue.\n",
__func__, rc);
} }
} }
kfree(ecryptfs_daemon_id_hash); kfree(ecryptfs_daemon_hash);
mutex_unlock(&ecryptfs_daemon_id_hash_mux); mutex_unlock(&ecryptfs_daemon_hash_mux);
} }
switch(transport) { switch(transport) {
case ECRYPTFS_TRANSPORT_NETLINK: case ECRYPTFS_TRANSPORT_NETLINK:
ecryptfs_release_netlink(); ecryptfs_release_netlink();
break; break;
case ECRYPTFS_TRANSPORT_MISCDEV:
ecryptfs_destroy_ecryptfs_miscdev();
break;
case ECRYPTFS_TRANSPORT_CONNECTOR: case ECRYPTFS_TRANSPORT_CONNECTOR:
case ECRYPTFS_TRANSPORT_RELAYFS: case ECRYPTFS_TRANSPORT_RELAYFS:
default: default:
......
...@@ -196,7 +196,7 @@ int ecryptfs_send_miscdev(char *data, size_t data_size, ...@@ -196,7 +196,7 @@ int ecryptfs_send_miscdev(char *data, size_t data_size,
if (!msg_ctx->msg) { if (!msg_ctx->msg) {
rc = -ENOMEM; rc = -ENOMEM;
printk(KERN_ERR "%s: Out of memory whilst attempting " printk(KERN_ERR "%s: Out of memory whilst attempting "
"to kmalloc(%d, GFP_KERNEL)\n", __func__, "to kmalloc(%Zd, GFP_KERNEL)\n", __func__,
(sizeof(*msg_ctx->msg) + data_size)); (sizeof(*msg_ctx->msg) + data_size));
goto out_unlock; goto out_unlock;
} }
...@@ -232,7 +232,7 @@ int ecryptfs_send_miscdev(char *data, size_t data_size, ...@@ -232,7 +232,7 @@ int ecryptfs_send_miscdev(char *data, size_t data_size,
* *
* Returns the number of bytes copied into the user buffer * Returns the number of bytes copied into the user buffer
*/ */
static int static ssize_t
ecryptfs_miscdev_read(struct file *file, char __user *buf, size_t count, ecryptfs_miscdev_read(struct file *file, char __user *buf, size_t count,
loff_t *ppos) loff_t *ppos)
{ {
......
...@@ -44,7 +44,7 @@ static struct sock *ecryptfs_nl_sock; ...@@ -44,7 +44,7 @@ static struct sock *ecryptfs_nl_sock;
* upon sending the message; non-zero upon error. * upon sending the message; non-zero upon error.
*/ */
int ecryptfs_send_netlink(char *data, int data_len, int ecryptfs_send_netlink(char *data, int data_len,
struct ecryptfs_msg_ctx *msg_ctx, u16 msg_type, struct ecryptfs_msg_ctx *msg_ctx, u8 msg_type,
u16 msg_flags, pid_t daemon_pid) u16 msg_flags, pid_t daemon_pid)
{ {
struct sk_buff *skb; struct sk_buff *skb;
...@@ -176,20 +176,20 @@ static void ecryptfs_receive_nl_message(struct sk_buff *skb) ...@@ -176,20 +176,20 @@ static void ecryptfs_receive_nl_message(struct sk_buff *skb)
goto free; goto free;
} }
switch (nlh->nlmsg_type) { switch (nlh->nlmsg_type) {
case ECRYPTFS_NLMSG_RESPONSE: case ECRYPTFS_MSG_RESPONSE:
if (ecryptfs_process_nl_response(skb)) { if (ecryptfs_process_nl_response(skb)) {
ecryptfs_printk(KERN_WARNING, "Failed to " ecryptfs_printk(KERN_WARNING, "Failed to "
"deliver netlink response to " "deliver netlink response to "
"requesting operation\n"); "requesting operation\n");
} }
break; break;
case ECRYPTFS_NLMSG_HELO: case ECRYPTFS_MSG_HELO:
if (ecryptfs_process_nl_helo(skb)) { if (ecryptfs_process_nl_helo(skb)) {
ecryptfs_printk(KERN_WARNING, "Failed to " ecryptfs_printk(KERN_WARNING, "Failed to "
"fulfill HELO request\n"); "fulfill HELO request\n");
} }
break; break;
case ECRYPTFS_NLMSG_QUIT: case ECRYPTFS_MSG_QUIT:
if (ecryptfs_process_nl_quit(skb)) { if (ecryptfs_process_nl_quit(skb)) {
ecryptfs_printk(KERN_WARNING, "Failed to " ecryptfs_printk(KERN_WARNING, "Failed to "
"fulfill QUIT request\n"); "fulfill QUIT request\n");
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment