Creation of Cybook 2416 (actually Gen4) repository

This commit is contained in:
mlt
2009-12-18 17:10:00 +00:00
committed by godzil
commit 76f20f4d40
13791 changed files with 6812321 additions and 0 deletions

7
fs/ecryptfs/Makefile Normal file
View File

@@ -0,0 +1,7 @@
#
# Makefile for the Linux 2.6 eCryptfs
#
obj-$(CONFIG_ECRYPT_FS) += ecryptfs.o
ecryptfs-objs := dentry.o file.o inode.o main.o super.o mmap.o crypto.o keystore.o messaging.o netlink.o debug.o

1831
fs/ecryptfs/crypto.c Normal file

File diff suppressed because it is too large Load Diff

123
fs/ecryptfs/debug.c Normal file
View File

@@ -0,0 +1,123 @@
/**
* eCryptfs: Linux filesystem encryption layer
* Functions only useful for debugging.
*
* Copyright (C) 2006 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 "ecryptfs_kernel.h"
/**
* ecryptfs_dump_auth_tok - debug function to print auth toks
*
* This function will print the contents of an ecryptfs authentication
* token.
*/
void ecryptfs_dump_auth_tok(struct ecryptfs_auth_tok *auth_tok)
{
char salt[ECRYPTFS_SALT_SIZE * 2 + 1];
char sig[ECRYPTFS_SIG_SIZE_HEX + 1];
ecryptfs_printk(KERN_DEBUG, "Auth tok at mem loc [%p]:\n",
auth_tok);
if (auth_tok->flags & ECRYPTFS_PRIVATE_KEY) {
ecryptfs_printk(KERN_DEBUG, " * private key type\n");
ecryptfs_printk(KERN_DEBUG, " * (NO PRIVATE KEY SUPPORT "
"IN ECRYPTFS VERSION 0.1)\n");
} else {
ecryptfs_printk(KERN_DEBUG, " * passphrase type\n");
ecryptfs_to_hex(salt, auth_tok->token.password.salt,
ECRYPTFS_SALT_SIZE);
salt[ECRYPTFS_SALT_SIZE * 2] = '\0';
ecryptfs_printk(KERN_DEBUG, " * salt = [%s]\n", salt);
if (auth_tok->token.password.flags &
ECRYPTFS_PERSISTENT_PASSWORD) {
ecryptfs_printk(KERN_DEBUG, " * persistent\n");
}
memcpy(sig, auth_tok->token.password.signature,
ECRYPTFS_SIG_SIZE_HEX);
sig[ECRYPTFS_SIG_SIZE_HEX] = '\0';
ecryptfs_printk(KERN_DEBUG, " * signature = [%s]\n", sig);
}
ecryptfs_printk(KERN_DEBUG, " * session_key.flags = [0x%x]\n",
auth_tok->session_key.flags);
if (auth_tok->session_key.flags
& ECRYPTFS_USERSPACE_SHOULD_TRY_TO_DECRYPT)
ecryptfs_printk(KERN_DEBUG,
" * Userspace decrypt request set\n");
if (auth_tok->session_key.flags
& ECRYPTFS_USERSPACE_SHOULD_TRY_TO_ENCRYPT)
ecryptfs_printk(KERN_DEBUG,
" * Userspace encrypt request set\n");
if (auth_tok->session_key.flags & ECRYPTFS_CONTAINS_DECRYPTED_KEY) {
ecryptfs_printk(KERN_DEBUG, " * Contains decrypted key\n");
ecryptfs_printk(KERN_DEBUG,
" * session_key.decrypted_key_size = [0x%x]\n",
auth_tok->session_key.decrypted_key_size);
ecryptfs_printk(KERN_DEBUG, " * Decrypted session key "
"dump:\n");
if (ecryptfs_verbosity > 0)
ecryptfs_dump_hex(auth_tok->session_key.decrypted_key,
ECRYPTFS_DEFAULT_KEY_BYTES);
}
if (auth_tok->session_key.flags & ECRYPTFS_CONTAINS_ENCRYPTED_KEY) {
ecryptfs_printk(KERN_DEBUG, " * Contains encrypted key\n");
ecryptfs_printk(KERN_DEBUG,
" * session_key.encrypted_key_size = [0x%x]\n",
auth_tok->session_key.encrypted_key_size);
ecryptfs_printk(KERN_DEBUG, " * Encrypted session key "
"dump:\n");
if (ecryptfs_verbosity > 0)
ecryptfs_dump_hex(auth_tok->session_key.encrypted_key,
auth_tok->session_key.
encrypted_key_size);
}
}
/**
* ecryptfs_dump_hex - debug hex printer
* @data: string of bytes to be printed
* @bytes: number of bytes to print
*
* Dump hexadecimal representation of char array
*/
void ecryptfs_dump_hex(char *data, int bytes)
{
int i = 0;
int add_newline = 1;
if (ecryptfs_verbosity < 1)
return;
if (bytes != 0) {
printk(KERN_DEBUG "0x%.2x.", (unsigned char)data[i]);
i++;
}
while (i < bytes) {
printk("0x%.2x.", (unsigned char)data[i]);
i++;
if (i % 16 == 0) {
printk("\n");
add_newline = 0;
} else
add_newline = 1;
}
if (add_newline)
printk("\n");
}

95
fs/ecryptfs/dentry.c Normal file
View File

@@ -0,0 +1,95 @@
/**
* eCryptfs: Linux filesystem encryption layer
*
* Copyright (C) 1997-2003 Erez Zadok
* Copyright (C) 2001-2003 Stony Brook University
* Copyright (C) 2004-2006 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/dcache.h>
#include <linux/namei.h>
#include <linux/mount.h>
#include <linux/fs_stack.h>
#include "ecryptfs_kernel.h"
/**
* ecryptfs_d_revalidate - revalidate an ecryptfs dentry
* @dentry: The ecryptfs dentry
* @nd: The associated nameidata
*
* Called when the VFS needs to revalidate a dentry. This
* is called whenever a name lookup finds a dentry in the
* dcache. Most filesystems leave this as NULL, because all their
* dentries in the dcache are valid.
*
* Returns 1 if valid, 0 otherwise.
*
*/
static int ecryptfs_d_revalidate(struct dentry *dentry, struct nameidata *nd)
{
struct dentry *lower_dentry = ecryptfs_dentry_to_lower(dentry);
struct vfsmount *lower_mnt = ecryptfs_dentry_to_lower_mnt(dentry);
struct dentry *dentry_save;
struct vfsmount *vfsmount_save;
int rc = 1;
if (!lower_dentry->d_op || !lower_dentry->d_op->d_revalidate)
goto out;
dentry_save = nd->dentry;
vfsmount_save = nd->mnt;
nd->dentry = lower_dentry;
nd->mnt = lower_mnt;
rc = lower_dentry->d_op->d_revalidate(lower_dentry, nd);
nd->dentry = dentry_save;
nd->mnt = vfsmount_save;
if (dentry->d_inode) {
struct inode *lower_inode =
ecryptfs_inode_to_lower(dentry->d_inode);
fsstack_copy_attr_all(dentry->d_inode, lower_inode, NULL);
}
out:
return rc;
}
struct kmem_cache *ecryptfs_dentry_info_cache;
/**
* ecryptfs_d_release
* @dentry: The ecryptfs dentry
*
* Called when a dentry is really deallocated.
*/
static void ecryptfs_d_release(struct dentry *dentry)
{
if (ecryptfs_dentry_to_private(dentry)) {
if (ecryptfs_dentry_to_lower(dentry)) {
mntput(ecryptfs_dentry_to_lower_mnt(dentry));
dput(ecryptfs_dentry_to_lower(dentry));
}
kmem_cache_free(ecryptfs_dentry_info_cache,
ecryptfs_dentry_to_private(dentry));
}
return;
}
struct dentry_operations ecryptfs_dops = {
.d_revalidate = ecryptfs_d_revalidate,
.d_release = ecryptfs_d_release,
};

View File

@@ -0,0 +1,584 @@
/**
* eCryptfs: Linux filesystem encryption layer
* Kernel declarations.
*
* Copyright (C) 1997-2003 Erez Zadok
* Copyright (C) 2001-2003 Stony Brook University
* Copyright (C) 2004-2007 International Business Machines Corp.
* Author(s): Michael A. Halcrow <mahalcro@us.ibm.com>
* Trevor S. Highland <trevor.highland@gmail.com>
* Tyler Hicks <tyhicks@ou.edu>
*
* 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.
*/
#ifndef ECRYPTFS_KERNEL_H
#define ECRYPTFS_KERNEL_H
#include <keys/user-type.h>
#include <linux/fs.h>
#include <linux/fs_stack.h>
#include <linux/namei.h>
#include <linux/scatterlist.h>
#include <linux/hash.h>
/* Version verification for shared data structures w/ userspace */
#define ECRYPTFS_VERSION_MAJOR 0x00
#define ECRYPTFS_VERSION_MINOR 0x04
#define ECRYPTFS_SUPPORTED_FILE_VERSION 0x02
/* These flags indicate which features are supported by the kernel
* module; userspace tools such as the mount helper read
* ECRYPTFS_VERSIONING_MASK from a sysfs handle in order to determine
* how to behave. */
#define ECRYPTFS_VERSIONING_PASSPHRASE 0x00000001
#define ECRYPTFS_VERSIONING_PUBKEY 0x00000002
#define ECRYPTFS_VERSIONING_PLAINTEXT_PASSTHROUGH 0x00000004
#define ECRYPTFS_VERSIONING_POLICY 0x00000008
#define ECRYPTFS_VERSIONING_XATTR 0x00000010
#define ECRYPTFS_VERSIONING_MASK (ECRYPTFS_VERSIONING_PASSPHRASE \
| ECRYPTFS_VERSIONING_PLAINTEXT_PASSTHROUGH \
| ECRYPTFS_VERSIONING_PUBKEY \
| ECRYPTFS_VERSIONING_XATTR)
#define ECRYPTFS_MAX_PASSWORD_LENGTH 64
#define ECRYPTFS_MAX_PASSPHRASE_BYTES ECRYPTFS_MAX_PASSWORD_LENGTH
#define ECRYPTFS_SALT_SIZE 8
#define ECRYPTFS_SALT_SIZE_HEX (ECRYPTFS_SALT_SIZE*2)
/* The original signature size is only for what is stored on disk; all
* in-memory representations are expanded hex, so it better adapted to
* be passed around or referenced on the command line */
#define ECRYPTFS_SIG_SIZE 8
#define ECRYPTFS_SIG_SIZE_HEX (ECRYPTFS_SIG_SIZE*2)
#define ECRYPTFS_PASSWORD_SIG_SIZE ECRYPTFS_SIG_SIZE_HEX
#define ECRYPTFS_MAX_KEY_BYTES 64
#define ECRYPTFS_MAX_ENCRYPTED_KEY_BYTES 512
#define ECRYPTFS_DEFAULT_IV_BYTES 16
#define ECRYPTFS_FILE_VERSION 0x02
#define ECRYPTFS_DEFAULT_HEADER_EXTENT_SIZE 8192
#define ECRYPTFS_DEFAULT_EXTENT_SIZE 4096
#define ECRYPTFS_MINIMUM_HEADER_EXTENT_SIZE 8192
#define ECRYPTFS_DEFAULT_MSG_CTX_ELEMS 32
#define ECRYPTFS_DEFAULT_SEND_TIMEOUT HZ
#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_DEFAULT_NUM_USERS 4
#define ECRYPTFS_MAX_NUM_USERS 32768
#define ECRYPTFS_TRANSPORT_NETLINK 0
#define ECRYPTFS_TRANSPORT_CONNECTOR 1
#define ECRYPTFS_TRANSPORT_RELAYFS 2
#define ECRYPTFS_DEFAULT_TRANSPORT ECRYPTFS_TRANSPORT_NETLINK
#define ECRYPTFS_XATTR_NAME "user.ecryptfs"
#define RFC2440_CIPHER_DES3_EDE 0x02
#define RFC2440_CIPHER_CAST_5 0x03
#define RFC2440_CIPHER_BLOWFISH 0x04
#define RFC2440_CIPHER_AES_128 0x07
#define RFC2440_CIPHER_AES_192 0x08
#define RFC2440_CIPHER_AES_256 0x09
#define RFC2440_CIPHER_TWOFISH 0x0a
#define RFC2440_CIPHER_CAST_6 0x0b
#define RFC2440_CIPHER_RSA 0x01
/**
* For convenience, we may need to pass around the encrypted session
* key between kernel and userspace because the authentication token
* may not be extractable. For example, the TPM may not release the
* private key, instead requiring the encrypted data and returning the
* decrypted data.
*/
struct ecryptfs_session_key {
#define ECRYPTFS_USERSPACE_SHOULD_TRY_TO_DECRYPT 0x00000001
#define ECRYPTFS_USERSPACE_SHOULD_TRY_TO_ENCRYPT 0x00000002
#define ECRYPTFS_CONTAINS_DECRYPTED_KEY 0x00000004
#define ECRYPTFS_CONTAINS_ENCRYPTED_KEY 0x00000008
u32 flags;
u32 encrypted_key_size;
u32 decrypted_key_size;
u8 encrypted_key[ECRYPTFS_MAX_ENCRYPTED_KEY_BYTES];
u8 decrypted_key[ECRYPTFS_MAX_KEY_BYTES];
};
struct ecryptfs_password {
u32 password_bytes;
s32 hash_algo;
u32 hash_iterations;
u32 session_key_encryption_key_bytes;
#define ECRYPTFS_PERSISTENT_PASSWORD 0x01
#define ECRYPTFS_SESSION_KEY_ENCRYPTION_KEY_SET 0x02
u32 flags;
/* Iterated-hash concatenation of salt and passphrase */
u8 session_key_encryption_key[ECRYPTFS_MAX_KEY_BYTES];
u8 signature[ECRYPTFS_PASSWORD_SIG_SIZE + 1];
/* Always in expanded hex */
u8 salt[ECRYPTFS_SALT_SIZE];
};
enum ecryptfs_token_types {ECRYPTFS_PASSWORD, ECRYPTFS_PRIVATE_KEY};
struct ecryptfs_private_key {
u32 key_size;
u32 data_len;
u8 signature[ECRYPTFS_PASSWORD_SIG_SIZE + 1];
char pki_type[ECRYPTFS_MAX_PKI_NAME_BYTES + 1];
u8 data[];
};
/* May be a password or a private key */
struct ecryptfs_auth_tok {
u16 version; /* 8-bit major and 8-bit minor */
u16 token_type;
u32 flags;
struct ecryptfs_session_key session_key;
u8 reserved[32];
union {
struct ecryptfs_password password;
struct ecryptfs_private_key private_key;
} token;
} __attribute__ ((packed));
void ecryptfs_dump_auth_tok(struct ecryptfs_auth_tok *auth_tok);
extern void ecryptfs_to_hex(char *dst, char *src, size_t src_size);
extern void ecryptfs_from_hex(char *dst, char *src, int dst_size);
struct ecryptfs_key_record {
unsigned char type;
size_t enc_key_size;
unsigned char sig[ECRYPTFS_SIG_SIZE];
unsigned char enc_key[ECRYPTFS_MAX_ENCRYPTED_KEY_BYTES];
};
struct ecryptfs_auth_tok_list {
struct ecryptfs_auth_tok *auth_tok;
struct list_head list;
};
struct ecryptfs_crypt_stat;
struct ecryptfs_mount_crypt_stat;
struct ecryptfs_page_crypt_context {
struct page *page;
#define ECRYPTFS_PREPARE_COMMIT_MODE 0
#define ECRYPTFS_WRITEPAGE_MODE 1
unsigned int mode;
union {
struct file *lower_file;
struct writeback_control *wbc;
} param;
};
static inline struct ecryptfs_auth_tok *
ecryptfs_get_key_payload_data(struct key *key)
{
return (struct ecryptfs_auth_tok *)
(((struct user_key_payload*)key->payload.data)->data);
}
#define ECRYPTFS_SUPER_MAGIC 0xf15f
#define ECRYPTFS_MAX_KEYSET_SIZE 1024
#define ECRYPTFS_MAX_CIPHER_NAME_SIZE 32
#define ECRYPTFS_MAX_NUM_ENC_KEYS 64
#define ECRYPTFS_MAX_NUM_KEYSIGS 2 /* TODO: Make this a linked list */
#define ECRYPTFS_MAX_IV_BYTES 16 /* 128 bits */
#define ECRYPTFS_SALT_BYTES 2
#define MAGIC_ECRYPTFS_MARKER 0x3c81b7f5
#define MAGIC_ECRYPTFS_MARKER_SIZE_BYTES 8 /* 4*2 */
#define ECRYPTFS_FILE_SIZE_BYTES 8
#define ECRYPTFS_DEFAULT_CIPHER "aes"
#define ECRYPTFS_DEFAULT_KEY_BYTES 16
#define ECRYPTFS_DEFAULT_HASH "md5"
#define ECRYPTFS_TAG_1_PACKET_TYPE 0x01
#define ECRYPTFS_TAG_3_PACKET_TYPE 0x8C
#define ECRYPTFS_TAG_11_PACKET_TYPE 0xED
#define ECRYPTFS_TAG_64_PACKET_TYPE 0x40
#define ECRYPTFS_TAG_65_PACKET_TYPE 0x41
#define ECRYPTFS_TAG_66_PACKET_TYPE 0x42
#define ECRYPTFS_TAG_67_PACKET_TYPE 0x43
#define MD5_DIGEST_SIZE 16
/**
* This is the primary struct associated with each encrypted file.
*
* TODO: cache align/pack?
*/
struct ecryptfs_crypt_stat {
#define ECRYPTFS_STRUCT_INITIALIZED 0x00000001
#define ECRYPTFS_POLICY_APPLIED 0x00000002
#define ECRYPTFS_NEW_FILE 0x00000004
#define ECRYPTFS_ENCRYPTED 0x00000008
#define ECRYPTFS_SECURITY_WARNING 0x00000010
#define ECRYPTFS_ENABLE_HMAC 0x00000020
#define ECRYPTFS_ENCRYPT_IV_PAGES 0x00000040
#define ECRYPTFS_KEY_VALID 0x00000080
#define ECRYPTFS_METADATA_IN_XATTR 0x00000100
#define ECRYPTFS_VIEW_AS_ENCRYPTED 0x00000200
u32 flags;
unsigned int file_version;
size_t iv_bytes;
size_t num_keysigs;
size_t header_extent_size;
size_t num_header_extents_at_front;
size_t extent_size; /* Data extent size; default is 4096 */
size_t key_size;
size_t extent_shift;
unsigned int extent_mask;
struct ecryptfs_mount_crypt_stat *mount_crypt_stat;
struct crypto_blkcipher *tfm;
struct crypto_hash *hash_tfm; /* Crypto context for generating
* the initialization vectors */
unsigned char cipher[ECRYPTFS_MAX_CIPHER_NAME_SIZE];
unsigned char key[ECRYPTFS_MAX_KEY_BYTES];
unsigned char root_iv[ECRYPTFS_MAX_IV_BYTES];
unsigned char keysigs[ECRYPTFS_MAX_NUM_KEYSIGS][ECRYPTFS_SIG_SIZE_HEX];
struct mutex cs_tfm_mutex;
struct mutex cs_hash_tfm_mutex;
struct mutex cs_mutex;
};
/* inode private data. */
struct ecryptfs_inode_info {
struct inode vfs_inode;
struct inode *wii_inode;
struct ecryptfs_crypt_stat crypt_stat;
};
/* dentry private data. Each dentry must keep track of a lower
* vfsmount too. */
struct ecryptfs_dentry_info {
struct path lower_path;
struct ecryptfs_crypt_stat *crypt_stat;
};
/**
* This struct is to enable a mount-wide passphrase/salt combo. This
* is more or less a stopgap to provide similar functionality to other
* crypto filesystems like EncFS or CFS until full policy support is
* implemented in eCryptfs.
*/
struct ecryptfs_mount_crypt_stat {
/* Pointers to memory we do not own, do not free these */
#define ECRYPTFS_PLAINTEXT_PASSTHROUGH_ENABLED 0x00000001
#define ECRYPTFS_XATTR_METADATA_ENABLED 0x00000002
#define ECRYPTFS_ENCRYPTED_VIEW_ENABLED 0x00000004
u32 flags;
struct ecryptfs_auth_tok *global_auth_tok;
struct key *global_auth_tok_key;
size_t global_default_cipher_key_size;
struct crypto_blkcipher *global_key_tfm;
struct mutex global_key_tfm_mutex;
unsigned char global_default_cipher_name[ECRYPTFS_MAX_CIPHER_NAME_SIZE
+ 1];
unsigned char global_auth_tok_sig[ECRYPTFS_SIG_SIZE_HEX + 1];
};
/* superblock private data. */
struct ecryptfs_sb_info {
struct super_block *wsi_sb;
struct ecryptfs_mount_crypt_stat mount_crypt_stat;
};
/* file private data. */
struct ecryptfs_file_info {
struct file *wfi_file;
struct ecryptfs_crypt_stat *crypt_stat;
};
/* auth_tok <=> encrypted_session_key mappings */
struct ecryptfs_auth_tok_list_item {
unsigned char encrypted_session_key[ECRYPTFS_MAX_KEY_BYTES];
struct list_head list;
struct ecryptfs_auth_tok auth_tok;
};
struct ecryptfs_message {
u32 index;
u32 data_len;
u8 data[];
};
struct ecryptfs_msg_ctx {
#define ECRYPTFS_MSG_CTX_STATE_FREE 0x0001
#define ECRYPTFS_MSG_CTX_STATE_PENDING 0x0002
#define ECRYPTFS_MSG_CTX_STATE_DONE 0x0003
u32 state;
unsigned int index;
unsigned int counter;
struct ecryptfs_message *msg;
struct task_struct *task;
struct list_head node;
struct mutex mux;
};
extern unsigned int ecryptfs_transport;
struct ecryptfs_daemon_id {
pid_t pid;
uid_t uid;
struct hlist_node id_chain;
};
static inline struct ecryptfs_file_info *
ecryptfs_file_to_private(struct file *file)
{
return (struct ecryptfs_file_info *)file->private_data;
}
static inline void
ecryptfs_set_file_private(struct file *file,
struct ecryptfs_file_info *file_info)
{
file->private_data = file_info;
}
static inline struct file *ecryptfs_file_to_lower(struct file *file)
{
return ((struct ecryptfs_file_info *)file->private_data)->wfi_file;
}
static inline void
ecryptfs_set_file_lower(struct file *file, struct file *lower_file)
{
((struct ecryptfs_file_info *)file->private_data)->wfi_file =
lower_file;
}
static inline struct ecryptfs_inode_info *
ecryptfs_inode_to_private(struct inode *inode)
{
return container_of(inode, struct ecryptfs_inode_info, vfs_inode);
}
static inline struct inode *ecryptfs_inode_to_lower(struct inode *inode)
{
return ecryptfs_inode_to_private(inode)->wii_inode;
}
static inline void
ecryptfs_set_inode_lower(struct inode *inode, struct inode *lower_inode)
{
ecryptfs_inode_to_private(inode)->wii_inode = lower_inode;
}
static inline struct ecryptfs_sb_info *
ecryptfs_superblock_to_private(struct super_block *sb)
{
return (struct ecryptfs_sb_info *)sb->s_fs_info;
}
static inline void
ecryptfs_set_superblock_private(struct super_block *sb,
struct ecryptfs_sb_info *sb_info)
{
sb->s_fs_info = sb_info;
}
static inline struct super_block *
ecryptfs_superblock_to_lower(struct super_block *sb)
{
return ((struct ecryptfs_sb_info *)sb->s_fs_info)->wsi_sb;
}
static inline void
ecryptfs_set_superblock_lower(struct super_block *sb,
struct super_block *lower_sb)
{
((struct ecryptfs_sb_info *)sb->s_fs_info)->wsi_sb = lower_sb;
}
static inline struct ecryptfs_dentry_info *
ecryptfs_dentry_to_private(struct dentry *dentry)
{
return (struct ecryptfs_dentry_info *)dentry->d_fsdata;
}
static inline void
ecryptfs_set_dentry_private(struct dentry *dentry,
struct ecryptfs_dentry_info *dentry_info)
{
dentry->d_fsdata = dentry_info;
}
static inline struct dentry *
ecryptfs_dentry_to_lower(struct dentry *dentry)
{
return ((struct ecryptfs_dentry_info *)dentry->d_fsdata)->lower_path.dentry;
}
static inline void
ecryptfs_set_dentry_lower(struct dentry *dentry, struct dentry *lower_dentry)
{
((struct ecryptfs_dentry_info *)dentry->d_fsdata)->lower_path.dentry =
lower_dentry;
}
static inline struct vfsmount *
ecryptfs_dentry_to_lower_mnt(struct dentry *dentry)
{
return ((struct ecryptfs_dentry_info *)dentry->d_fsdata)->lower_path.mnt;
}
static inline void
ecryptfs_set_dentry_lower_mnt(struct dentry *dentry, struct vfsmount *lower_mnt)
{
((struct ecryptfs_dentry_info *)dentry->d_fsdata)->lower_path.mnt =
lower_mnt;
}
#define ecryptfs_printk(type, fmt, arg...) \
__ecryptfs_printk(type "%s: " fmt, __FUNCTION__, ## arg);
void __ecryptfs_printk(const char *fmt, ...);
extern const struct file_operations ecryptfs_main_fops;
extern const struct file_operations ecryptfs_dir_fops;
extern const struct inode_operations ecryptfs_main_iops;
extern const struct inode_operations ecryptfs_dir_iops;
extern const struct inode_operations ecryptfs_symlink_iops;
extern const struct super_operations ecryptfs_sops;
extern struct dentry_operations ecryptfs_dops;
extern struct address_space_operations ecryptfs_aops;
extern int ecryptfs_verbosity;
extern unsigned int ecryptfs_message_buf_len;
extern signed long ecryptfs_message_wait_timeout;
extern unsigned int ecryptfs_number_of_users;
extern struct kmem_cache *ecryptfs_auth_tok_list_item_cache;
extern struct kmem_cache *ecryptfs_file_info_cache;
extern struct kmem_cache *ecryptfs_dentry_info_cache;
extern struct kmem_cache *ecryptfs_inode_info_cache;
extern struct kmem_cache *ecryptfs_sb_info_cache;
extern struct kmem_cache *ecryptfs_header_cache_0;
extern struct kmem_cache *ecryptfs_header_cache_1;
extern struct kmem_cache *ecryptfs_header_cache_2;
extern struct kmem_cache *ecryptfs_xattr_cache;
extern struct kmem_cache *ecryptfs_lower_page_cache;
extern struct kmem_cache *ecryptfs_key_record_cache;
int ecryptfs_interpose(struct dentry *hidden_dentry,
struct dentry *this_dentry, struct super_block *sb,
int flag);
int ecryptfs_fill_zeros(struct file *file, loff_t new_length);
int ecryptfs_decode_filename(struct ecryptfs_crypt_stat *crypt_stat,
const char *name, int length,
char **decrypted_name);
int ecryptfs_encode_filename(struct ecryptfs_crypt_stat *crypt_stat,
const char *name, int length,
char **encoded_name);
struct dentry *ecryptfs_lower_dentry(struct dentry *this_dentry);
void ecryptfs_dump_hex(char *data, int bytes);
int virt_to_scatterlist(const void *addr, int size, struct scatterlist *sg,
int sg_size);
int ecryptfs_compute_root_iv(struct ecryptfs_crypt_stat *crypt_stat);
void ecryptfs_rotate_iv(unsigned char *iv);
void ecryptfs_init_crypt_stat(struct ecryptfs_crypt_stat *crypt_stat);
void ecryptfs_destruct_crypt_stat(struct ecryptfs_crypt_stat *crypt_stat);
void ecryptfs_destruct_mount_crypt_stat(
struct ecryptfs_mount_crypt_stat *mount_crypt_stat);
int ecryptfs_init_crypt_ctx(struct ecryptfs_crypt_stat *crypt_stat);
int ecryptfs_crypto_api_algify_cipher_name(char **algified_name,
char *cipher_name,
char *chaining_modifier);
#define ECRYPTFS_LOWER_I_MUTEX_NOT_HELD 0
#define ECRYPTFS_LOWER_I_MUTEX_HELD 1
int ecryptfs_write_inode_size_to_metadata(struct file *lower_file,
struct inode *lower_inode,
struct inode *inode,
struct dentry *ecryptfs_dentry,
int lower_i_mutex_held);
int ecryptfs_get_lower_page(struct page **lower_page, struct inode *lower_inode,
struct file *lower_file,
unsigned long lower_page_index, int byte_offset,
int region_bytes);
int
ecryptfs_commit_lower_page(struct page *lower_page, struct inode *lower_inode,
struct file *lower_file, int byte_offset,
int region_size);
int ecryptfs_copy_page_to_lower(struct page *page, struct inode *lower_inode,
struct file *lower_file);
int ecryptfs_do_readpage(struct file *file, struct page *page,
pgoff_t lower_page_index);
int ecryptfs_writepage_and_release_lower_page(struct page *lower_page,
struct inode *lower_inode,
struct writeback_control *wbc);
int ecryptfs_encrypt_page(struct ecryptfs_page_crypt_context *ctx);
int ecryptfs_decrypt_page(struct file *file, struct page *page);
int ecryptfs_write_metadata(struct dentry *ecryptfs_dentry,
struct file *lower_file);
int ecryptfs_read_metadata(struct dentry *ecryptfs_dentry,
struct file *lower_file);
int ecryptfs_new_file_context(struct dentry *ecryptfs_dentry);
int ecryptfs_read_and_validate_header_region(char *data, struct dentry *dentry,
struct vfsmount *mnt);
int ecryptfs_read_and_validate_xattr_region(char *page_virt,
struct dentry *ecryptfs_dentry);
u16 ecryptfs_code_for_cipher_string(struct ecryptfs_crypt_stat *crypt_stat);
int ecryptfs_cipher_code_to_string(char *str, u16 cipher_code);
void ecryptfs_set_default_sizes(struct ecryptfs_crypt_stat *crypt_stat);
int ecryptfs_generate_key_packet_set(char *dest_base,
struct ecryptfs_crypt_stat *crypt_stat,
struct dentry *ecryptfs_dentry,
size_t *len, size_t max);
int process_request_key_err(long err_code);
int
ecryptfs_parse_packet_set(struct ecryptfs_crypt_stat *crypt_stat,
unsigned char *src, struct dentry *ecryptfs_dentry);
int ecryptfs_truncate(struct dentry *dentry, loff_t new_length);
int
ecryptfs_process_cipher(struct crypto_blkcipher **key_tfm, char *cipher_name,
size_t *key_size);
int ecryptfs_inode_test(struct inode *inode, void *candidate_lower_inode);
int ecryptfs_inode_set(struct inode *inode, void *lower_inode);
void ecryptfs_init_inode(struct inode *inode, struct inode *lower_inode);
int ecryptfs_open_lower_file(struct file **lower_file,
struct dentry *lower_dentry,
struct vfsmount *lower_mnt, int flags);
int ecryptfs_close_lower_file(struct file *lower_file);
ssize_t ecryptfs_getxattr(struct dentry *dentry, const char *name, void *value,
size_t size);
int
ecryptfs_setxattr(struct dentry *dentry, const char *name, const void *value,
size_t size, int flags);
int ecryptfs_read_xattr_region(char *page_virt, struct dentry *ecryptfs_dentry);
int ecryptfs_process_helo(unsigned int transport, uid_t uid, pid_t pid);
int ecryptfs_process_quit(uid_t uid, pid_t pid);
int ecryptfs_process_response(struct ecryptfs_message *msg, uid_t uid,
pid_t pid, u32 seq);
int ecryptfs_send_message(unsigned int transport, char *data, int data_len,
struct ecryptfs_msg_ctx **msg_ctx);
int ecryptfs_wait_for_response(struct ecryptfs_msg_ctx *msg_ctx,
struct ecryptfs_message **emsg);
int ecryptfs_init_messaging(unsigned int transport);
void ecryptfs_release_messaging(unsigned int transport);
int ecryptfs_send_netlink(char *data, int data_len,
struct ecryptfs_msg_ctx *msg_ctx, u16 msg_type,
u16 msg_flags, pid_t daemon_pid);
int ecryptfs_init_netlink(void);
void ecryptfs_release_netlink(void);
int ecryptfs_send_connector(char *data, int data_len,
struct ecryptfs_msg_ctx *msg_ctx, u16 msg_type,
u16 msg_flags, pid_t daemon_pid);
int ecryptfs_init_connector(void);
void ecryptfs_release_connector(void);
void
ecryptfs_write_header_metadata(char *virt,
struct ecryptfs_crypt_stat *crypt_stat,
size_t *written);
#endif /* #ifndef ECRYPTFS_KERNEL_H */

460
fs/ecryptfs/file.c Normal file
View File

@@ -0,0 +1,460 @@
/**
* eCryptfs: Linux filesystem encryption layer
*
* Copyright (C) 1997-2004 Erez Zadok
* Copyright (C) 2001-2004 Stony Brook University
* Copyright (C) 2004-2007 International Business Machines Corp.
* Author(s): Michael A. Halcrow <mhalcrow@us.ibm.com>
* Michael C. Thompson <mcthomps@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/file.h>
#include <linux/poll.h>
#include <linux/mount.h>
#include <linux/pagemap.h>
#include <linux/security.h>
#include <linux/smp_lock.h>
#include <linux/compat.h>
#include <linux/fs_stack.h>
#include "ecryptfs_kernel.h"
/**
* ecryptfs_llseek
* @file: File we are seeking in
* @offset: The offset to seek to
* @origin: 2 - offset from i_size; 1 - offset from f_pos
*
* Returns the position we have seeked to, or negative on error
*/
static loff_t ecryptfs_llseek(struct file *file, loff_t offset, int origin)
{
loff_t rv;
loff_t new_end_pos;
int rc;
int expanding_file = 0;
struct inode *inode = file->f_mapping->host;
/* If our offset is past the end of our file, we're going to
* need to grow it so we have a valid length of 0's */
new_end_pos = offset;
switch (origin) {
case 2:
new_end_pos += i_size_read(inode);
expanding_file = 1;
break;
case 1:
new_end_pos += file->f_pos;
if (new_end_pos > i_size_read(inode)) {
ecryptfs_printk(KERN_DEBUG, "new_end_pos(=[0x%.16x]) "
"> i_size_read(inode)(=[0x%.16x])\n",
new_end_pos, i_size_read(inode));
expanding_file = 1;
}
break;
default:
if (new_end_pos > i_size_read(inode)) {
ecryptfs_printk(KERN_DEBUG, "new_end_pos(=[0x%.16x]) "
"> i_size_read(inode)(=[0x%.16x])\n",
new_end_pos, i_size_read(inode));
expanding_file = 1;
}
}
ecryptfs_printk(KERN_DEBUG, "new_end_pos = [0x%.16x]\n", new_end_pos);
if (expanding_file) {
rc = ecryptfs_truncate(file->f_path.dentry, new_end_pos);
if (rc) {
rv = rc;
ecryptfs_printk(KERN_ERR, "Error on attempt to "
"truncate to (higher) offset [0x%.16x];"
" rc = [%d]\n", new_end_pos, rc);
goto out;
}
}
rv = generic_file_llseek(file, offset, origin);
out:
return rv;
}
/**
* ecryptfs_read_update_atime
*
* generic_file_read updates the atime of upper layer inode. But, it
* doesn't give us a chance to update the atime of the lower layer
* inode. This function is a wrapper to generic_file_read. It
* updates the atime of the lower level inode if generic_file_read
* returns without any errors. This is to be used only for file reads.
* The function to be used for directory reads is ecryptfs_read.
*/
static ssize_t ecryptfs_read_update_atime(struct kiocb *iocb,
const struct iovec *iov,
unsigned long nr_segs, loff_t pos)
{
int rc;
struct dentry *lower_dentry;
struct vfsmount *lower_vfsmount;
struct file *file = iocb->ki_filp;
rc = generic_file_aio_read(iocb, iov, nr_segs, pos);
/*
* Even though this is a async interface, we need to wait
* for IO to finish to update atime
*/
if (-EIOCBQUEUED == rc)
rc = wait_on_sync_kiocb(iocb);
if (rc >= 0) {
lower_dentry = ecryptfs_dentry_to_lower(file->f_path.dentry);
lower_vfsmount = ecryptfs_dentry_to_lower_mnt(file->f_path.dentry);
touch_atime(lower_vfsmount, lower_dentry);
}
return rc;
}
struct ecryptfs_getdents_callback {
void *dirent;
struct dentry *dentry;
filldir_t filldir;
int err;
int filldir_called;
int entries_written;
};
/* Inspired by generic filldir in fs/readir.c */
static int
ecryptfs_filldir(void *dirent, const char *name, int namelen, loff_t offset,
u64 ino, unsigned int d_type)
{
struct ecryptfs_crypt_stat *crypt_stat;
struct ecryptfs_getdents_callback *buf =
(struct ecryptfs_getdents_callback *)dirent;
int rc;
int decoded_length;
char *decoded_name;
crypt_stat = ecryptfs_dentry_to_private(buf->dentry)->crypt_stat;
buf->filldir_called++;
decoded_length = ecryptfs_decode_filename(crypt_stat, name, namelen,
&decoded_name);
if (decoded_length < 0) {
rc = decoded_length;
goto out;
}
rc = buf->filldir(buf->dirent, decoded_name, decoded_length, offset,
ino, d_type);
kfree(decoded_name);
if (rc >= 0)
buf->entries_written++;
out:
return rc;
}
/**
* ecryptfs_readdir
* @file: The ecryptfs file struct
* @dirent: Directory entry
* @filldir: The filldir callback function
*/
static int ecryptfs_readdir(struct file *file, void *dirent, filldir_t filldir)
{
int rc;
struct file *lower_file;
struct inode *inode;
struct ecryptfs_getdents_callback buf;
lower_file = ecryptfs_file_to_lower(file);
lower_file->f_pos = file->f_pos;
inode = file->f_path.dentry->d_inode;
memset(&buf, 0, sizeof(buf));
buf.dirent = dirent;
buf.dentry = file->f_path.dentry;
buf.filldir = filldir;
retry:
buf.filldir_called = 0;
buf.entries_written = 0;
buf.err = 0;
rc = vfs_readdir(lower_file, ecryptfs_filldir, (void *)&buf);
if (buf.err)
rc = buf.err;
if (buf.filldir_called && !buf.entries_written)
goto retry;
file->f_pos = lower_file->f_pos;
if (rc >= 0)
fsstack_copy_attr_atime(inode, lower_file->f_path.dentry->d_inode);
return rc;
}
struct kmem_cache *ecryptfs_file_info_cache;
int ecryptfs_open_lower_file(struct file **lower_file,
struct dentry *lower_dentry,
struct vfsmount *lower_mnt, int flags)
{
int rc = 0;
flags |= O_LARGEFILE;
dget(lower_dentry);
mntget(lower_mnt);
*lower_file = dentry_open(lower_dentry, lower_mnt, flags);
if (IS_ERR(*lower_file)) {
printk(KERN_ERR "Error opening lower file for lower_dentry "
"[0x%p], lower_mnt [0x%p], and flags [0x%x]\n",
lower_dentry, lower_mnt, flags);
rc = PTR_ERR(*lower_file);
*lower_file = NULL;
goto out;
}
out:
return rc;
}
int ecryptfs_close_lower_file(struct file *lower_file)
{
fput(lower_file);
return 0;
}
/**
* ecryptfs_open
* @inode: inode speciying file to open
* @file: Structure to return filled in
*
* Opens the file specified by inode.
*
* Returns zero on success; non-zero otherwise
*/
static int ecryptfs_open(struct inode *inode, struct file *file)
{
int rc = 0;
struct ecryptfs_crypt_stat *crypt_stat = NULL;
struct ecryptfs_mount_crypt_stat *mount_crypt_stat;
struct dentry *ecryptfs_dentry = file->f_path.dentry;
/* Private value of ecryptfs_dentry allocated in
* ecryptfs_lookup() */
struct dentry *lower_dentry = ecryptfs_dentry_to_lower(ecryptfs_dentry);
struct inode *lower_inode = NULL;
struct file *lower_file = NULL;
struct vfsmount *lower_mnt;
struct ecryptfs_file_info *file_info;
int lower_flags;
mount_crypt_stat = &ecryptfs_superblock_to_private(
ecryptfs_dentry->d_sb)->mount_crypt_stat;
if ((mount_crypt_stat->flags & ECRYPTFS_ENCRYPTED_VIEW_ENABLED)
&& ((file->f_flags & O_WRONLY) || (file->f_flags & O_RDWR)
|| (file->f_flags & O_CREAT) || (file->f_flags & O_TRUNC)
|| (file->f_flags & O_APPEND))) {
printk(KERN_WARNING "Mount has encrypted view enabled; "
"files may only be read\n");
rc = -EPERM;
goto out;
}
/* Released in ecryptfs_release or end of function if failure */
file_info = kmem_cache_zalloc(ecryptfs_file_info_cache, GFP_KERNEL);
ecryptfs_set_file_private(file, file_info);
if (!file_info) {
ecryptfs_printk(KERN_ERR,
"Error attempting to allocate memory\n");
rc = -ENOMEM;
goto out;
}
lower_dentry = ecryptfs_dentry_to_lower(ecryptfs_dentry);
crypt_stat = &ecryptfs_inode_to_private(inode)->crypt_stat;
mutex_lock(&crypt_stat->cs_mutex);
if (!(crypt_stat->flags & ECRYPTFS_POLICY_APPLIED)) {
ecryptfs_printk(KERN_DEBUG, "Setting flags for stat...\n");
/* Policy code enabled in future release */
crypt_stat->flags |= ECRYPTFS_POLICY_APPLIED;
crypt_stat->flags |= ECRYPTFS_ENCRYPTED;
}
mutex_unlock(&crypt_stat->cs_mutex);
lower_flags = file->f_flags;
if ((lower_flags & O_ACCMODE) == O_WRONLY)
lower_flags = (lower_flags & O_ACCMODE) | O_RDWR;
if (file->f_flags & O_APPEND)
lower_flags &= ~O_APPEND;
lower_mnt = ecryptfs_dentry_to_lower_mnt(ecryptfs_dentry);
/* Corresponding fput() in ecryptfs_release() */
if ((rc = ecryptfs_open_lower_file(&lower_file, lower_dentry, lower_mnt,
lower_flags))) {
ecryptfs_printk(KERN_ERR, "Error opening lower file\n");
goto out_puts;
}
ecryptfs_set_file_lower(file, lower_file);
/* Isn't this check the same as the one in lookup? */
lower_inode = lower_dentry->d_inode;
if (S_ISDIR(ecryptfs_dentry->d_inode->i_mode)) {
ecryptfs_printk(KERN_DEBUG, "This is a directory\n");
crypt_stat->flags &= ~(ECRYPTFS_ENCRYPTED);
rc = 0;
goto out;
}
mutex_lock(&crypt_stat->cs_mutex);
if (!(crypt_stat->flags & ECRYPTFS_POLICY_APPLIED)
|| !(crypt_stat->flags & ECRYPTFS_KEY_VALID)) {
rc = ecryptfs_read_metadata(ecryptfs_dentry, lower_file);
if (rc) {
ecryptfs_printk(KERN_DEBUG,
"Valid headers not found\n");
if (!(mount_crypt_stat->flags
& ECRYPTFS_PLAINTEXT_PASSTHROUGH_ENABLED)) {
rc = -EIO;
printk(KERN_WARNING "Attempt to read file that "
"is not in a valid eCryptfs format, "
"and plaintext passthrough mode is not "
"enabled; returning -EIO\n");
mutex_unlock(&crypt_stat->cs_mutex);
goto out_puts;
}
rc = 0;
crypt_stat->flags &= ~(ECRYPTFS_ENCRYPTED);
mutex_unlock(&crypt_stat->cs_mutex);
goto out;
}
}
mutex_unlock(&crypt_stat->cs_mutex);
ecryptfs_printk(KERN_DEBUG, "inode w/ addr = [0x%p], i_ino = [0x%.16x] "
"size: [0x%.16x]\n", inode, inode->i_ino,
i_size_read(inode));
ecryptfs_set_file_lower(file, lower_file);
goto out;
out_puts:
mntput(lower_mnt);
dput(lower_dentry);
kmem_cache_free(ecryptfs_file_info_cache,
ecryptfs_file_to_private(file));
out:
return rc;
}
static int ecryptfs_flush(struct file *file, fl_owner_t td)
{
int rc = 0;
struct file *lower_file = NULL;
lower_file = ecryptfs_file_to_lower(file);
if (lower_file->f_op && lower_file->f_op->flush)
rc = lower_file->f_op->flush(lower_file, td);
return rc;
}
static int ecryptfs_release(struct inode *inode, struct file *file)
{
struct file *lower_file = ecryptfs_file_to_lower(file);
struct ecryptfs_file_info *file_info = ecryptfs_file_to_private(file);
struct inode *lower_inode = ecryptfs_inode_to_lower(inode);
int rc;
if ((rc = ecryptfs_close_lower_file(lower_file))) {
printk(KERN_ERR "Error closing lower_file\n");
goto out;
}
inode->i_blocks = lower_inode->i_blocks;
kmem_cache_free(ecryptfs_file_info_cache, file_info);
out:
return rc;
}
static int
ecryptfs_fsync(struct file *file, struct dentry *dentry, int datasync)
{
struct file *lower_file = ecryptfs_file_to_lower(file);
struct dentry *lower_dentry = ecryptfs_dentry_to_lower(dentry);
struct inode *lower_inode = lower_dentry->d_inode;
int rc = -EINVAL;
if (lower_inode->i_fop->fsync) {
mutex_lock(&lower_inode->i_mutex);
rc = lower_inode->i_fop->fsync(lower_file, lower_dentry,
datasync);
mutex_unlock(&lower_inode->i_mutex);
}
return rc;
}
static int ecryptfs_fasync(int fd, struct file *file, int flag)
{
int rc = 0;
struct file *lower_file = NULL;
lower_file = ecryptfs_file_to_lower(file);
if (lower_file->f_op && lower_file->f_op->fasync)
rc = lower_file->f_op->fasync(fd, lower_file, flag);
return rc;
}
static ssize_t ecryptfs_sendfile(struct file *file, loff_t * ppos,
size_t count, read_actor_t actor, void *target)
{
struct file *lower_file = NULL;
int rc = -EINVAL;
lower_file = ecryptfs_file_to_lower(file);
if (lower_file->f_op && lower_file->f_op->sendfile)
rc = lower_file->f_op->sendfile(lower_file, ppos, count,
actor, target);
return rc;
}
static int ecryptfs_ioctl(struct inode *inode, struct file *file,
unsigned int cmd, unsigned long arg);
const struct file_operations ecryptfs_dir_fops = {
.readdir = ecryptfs_readdir,
.ioctl = ecryptfs_ioctl,
.mmap = generic_file_mmap,
.open = ecryptfs_open,
.flush = ecryptfs_flush,
.release = ecryptfs_release,
.fsync = ecryptfs_fsync,
.fasync = ecryptfs_fasync,
.sendfile = ecryptfs_sendfile,
};
const struct file_operations ecryptfs_main_fops = {
.llseek = ecryptfs_llseek,
.read = do_sync_read,
.aio_read = ecryptfs_read_update_atime,
.write = do_sync_write,
.aio_write = generic_file_aio_write,
.readdir = ecryptfs_readdir,
.ioctl = ecryptfs_ioctl,
.mmap = generic_file_mmap,
.open = ecryptfs_open,
.flush = ecryptfs_flush,
.release = ecryptfs_release,
.fsync = ecryptfs_fsync,
.fasync = ecryptfs_fasync,
.sendfile = ecryptfs_sendfile,
};
static int
ecryptfs_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
unsigned long arg)
{
int rc = 0;
struct file *lower_file = NULL;
if (ecryptfs_file_to_private(file))
lower_file = ecryptfs_file_to_lower(file);
if (lower_file && lower_file->f_op && lower_file->f_op->ioctl)
rc = lower_file->f_op->ioctl(ecryptfs_inode_to_lower(inode),
lower_file, cmd, arg);
else
rc = -ENOTTY;
return rc;
}

1026
fs/ecryptfs/inode.c Normal file

File diff suppressed because it is too large Load Diff

1734
fs/ecryptfs/keystore.c Normal file

File diff suppressed because it is too large Load Diff

881
fs/ecryptfs/main.c Normal file
View File

@@ -0,0 +1,881 @@
/**
* eCryptfs: Linux filesystem encryption layer
*
* Copyright (C) 1997-2003 Erez Zadok
* Copyright (C) 2001-2003 Stony Brook University
* Copyright (C) 2004-2007 International Business Machines Corp.
* Author(s): Michael A. Halcrow <mahalcro@us.ibm.com>
* Michael C. Thompson <mcthomps@us.ibm.com>
* Tyler Hicks <tyhicks@ou.edu>
*
* 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/dcache.h>
#include <linux/file.h>
#include <linux/module.h>
#include <linux/namei.h>
#include <linux/skbuff.h>
#include <linux/crypto.h>
#include <linux/netlink.h>
#include <linux/mount.h>
#include <linux/dcache.h>
#include <linux/pagemap.h>
#include <linux/key.h>
#include <linux/parser.h>
#include <linux/fs_stack.h>
#include "ecryptfs_kernel.h"
/**
* Module parameter that defines the ecryptfs_verbosity level.
*/
int ecryptfs_verbosity = 0;
module_param(ecryptfs_verbosity, int, 0);
MODULE_PARM_DESC(ecryptfs_verbosity,
"Initial verbosity level (0 or 1; defaults to "
"0, which is Quiet)");
/**
* Module parameter that defines the number of netlink message buffer
* elements
*/
unsigned int ecryptfs_message_buf_len = ECRYPTFS_DEFAULT_MSG_CTX_ELEMS;
module_param(ecryptfs_message_buf_len, uint, 0);
MODULE_PARM_DESC(ecryptfs_message_buf_len,
"Number of message buffer elements");
/**
* Module parameter that defines the maximum guaranteed amount of time to wait
* for a response through netlink. The actual sleep time will be, more than
* likely, a small amount greater than this specified value, but only less if
* the netlink message successfully arrives.
*/
signed long ecryptfs_message_wait_timeout = ECRYPTFS_MAX_MSG_CTX_TTL / HZ;
module_param(ecryptfs_message_wait_timeout, long, 0);
MODULE_PARM_DESC(ecryptfs_message_wait_timeout,
"Maximum number of seconds that an operation will "
"sleep while waiting for a message response from "
"userspace");
/**
* Module parameter that is an estimate of the maximum number of users
* that will be concurrently using eCryptfs. Set this to the right
* value to balance performance and memory use.
*/
unsigned int ecryptfs_number_of_users = ECRYPTFS_DEFAULT_NUM_USERS;
module_param(ecryptfs_number_of_users, uint, 0);
MODULE_PARM_DESC(ecryptfs_number_of_users, "An estimate of the number of "
"concurrent users of eCryptfs");
unsigned int ecryptfs_transport = ECRYPTFS_DEFAULT_TRANSPORT;
void __ecryptfs_printk(const char *fmt, ...)
{
va_list args;
va_start(args, fmt);
if (fmt[1] == '7') { /* KERN_DEBUG */
if (ecryptfs_verbosity >= 1)
vprintk(fmt, args);
} else
vprintk(fmt, args);
va_end(args);
}
/**
* ecryptfs_interpose
* @lower_dentry: Existing dentry in the lower filesystem
* @dentry: ecryptfs' dentry
* @sb: ecryptfs's super_block
* @flag: If set to true, then d_add is called, else d_instantiate is called
*
* Interposes upper and lower dentries.
*
* Returns zero on success; non-zero otherwise
*/
int ecryptfs_interpose(struct dentry *lower_dentry, struct dentry *dentry,
struct super_block *sb, int flag)
{
struct inode *lower_inode;
struct inode *inode;
int rc = 0;
lower_inode = lower_dentry->d_inode;
if (lower_inode->i_sb != ecryptfs_superblock_to_lower(sb)) {
rc = -EXDEV;
goto out;
}
if (!igrab(lower_inode)) {
rc = -ESTALE;
goto out;
}
inode = iget5_locked(sb, (unsigned long)lower_inode,
ecryptfs_inode_test, ecryptfs_inode_set,
lower_inode);
if (!inode) {
rc = -EACCES;
iput(lower_inode);
goto out;
}
if (inode->i_state & I_NEW)
unlock_new_inode(inode);
else
iput(lower_inode);
if (S_ISLNK(lower_inode->i_mode))
inode->i_op = &ecryptfs_symlink_iops;
else if (S_ISDIR(lower_inode->i_mode))
inode->i_op = &ecryptfs_dir_iops;
if (S_ISDIR(lower_inode->i_mode))
inode->i_fop = &ecryptfs_dir_fops;
if (special_file(lower_inode->i_mode))
init_special_inode(inode, lower_inode->i_mode,
lower_inode->i_rdev);
dentry->d_op = &ecryptfs_dops;
if (flag)
d_add(dentry, inode);
else
d_instantiate(dentry, inode);
fsstack_copy_attr_all(inode, lower_inode, NULL);
/* This size will be overwritten for real files w/ headers and
* other metadata */
fsstack_copy_inode_size(inode, lower_inode);
out:
return rc;
}
enum { ecryptfs_opt_sig, ecryptfs_opt_ecryptfs_sig, ecryptfs_opt_debug,
ecryptfs_opt_ecryptfs_debug, ecryptfs_opt_cipher,
ecryptfs_opt_ecryptfs_cipher, ecryptfs_opt_ecryptfs_key_bytes,
ecryptfs_opt_passthrough, ecryptfs_opt_xattr_metadata,
ecryptfs_opt_encrypted_view, ecryptfs_opt_err };
static match_table_t tokens = {
{ecryptfs_opt_sig, "sig=%s"},
{ecryptfs_opt_ecryptfs_sig, "ecryptfs_sig=%s"},
{ecryptfs_opt_debug, "debug=%u"},
{ecryptfs_opt_ecryptfs_debug, "ecryptfs_debug=%u"},
{ecryptfs_opt_cipher, "cipher=%s"},
{ecryptfs_opt_ecryptfs_cipher, "ecryptfs_cipher=%s"},
{ecryptfs_opt_ecryptfs_key_bytes, "ecryptfs_key_bytes=%u"},
{ecryptfs_opt_passthrough, "ecryptfs_passthrough"},
{ecryptfs_opt_xattr_metadata, "ecryptfs_xattr_metadata"},
{ecryptfs_opt_encrypted_view, "ecryptfs_encrypted_view"},
{ecryptfs_opt_err, NULL}
};
/**
* ecryptfs_verify_version
* @version: The version number to confirm
*
* Returns zero on good version; non-zero otherwise
*/
static int ecryptfs_verify_version(u16 version)
{
int rc = 0;
unsigned char major;
unsigned char minor;
major = ((version >> 8) & 0xFF);
minor = (version & 0xFF);
if (major != ECRYPTFS_VERSION_MAJOR) {
ecryptfs_printk(KERN_ERR, "Major version number mismatch. "
"Expected [%d]; got [%d]\n",
ECRYPTFS_VERSION_MAJOR, major);
rc = -EINVAL;
goto out;
}
if (minor != ECRYPTFS_VERSION_MINOR) {
ecryptfs_printk(KERN_ERR, "Minor version number mismatch. "
"Expected [%d]; got [%d]\n",
ECRYPTFS_VERSION_MINOR, minor);
rc = -EINVAL;
goto out;
}
out:
return rc;
}
/**
* ecryptfs_parse_options
* @sb: The ecryptfs super block
* @options: The options pased to the kernel
*
* Parse mount options:
* debug=N - ecryptfs_verbosity level for debug output
* sig=XXX - description(signature) of the key to use
*
* Returns the dentry object of the lower-level (lower/interposed)
* directory; We want to mount our stackable file system on top of
* that lower directory.
*
* The signature of the key to use must be the description of a key
* already in the keyring. Mounting will fail if the key can not be
* found.
*
* Returns zero on success; non-zero on error
*/
static int ecryptfs_parse_options(struct super_block *sb, char *options)
{
char *p;
int rc = 0;
int sig_set = 0;
int cipher_name_set = 0;
int cipher_key_bytes;
int cipher_key_bytes_set = 0;
struct key *auth_tok_key = NULL;
struct ecryptfs_auth_tok *auth_tok = NULL;
struct ecryptfs_mount_crypt_stat *mount_crypt_stat =
&ecryptfs_superblock_to_private(sb)->mount_crypt_stat;
substring_t args[MAX_OPT_ARGS];
int token;
char *sig_src;
char *sig_dst;
char *debug_src;
char *cipher_name_dst;
char *cipher_name_src;
char *cipher_key_bytes_src;
int cipher_name_len;
if (!options) {
rc = -EINVAL;
goto out;
}
while ((p = strsep(&options, ",")) != NULL) {
if (!*p)
continue;
token = match_token(p, tokens, args);
switch (token) {
case ecryptfs_opt_sig:
case ecryptfs_opt_ecryptfs_sig:
sig_src = args[0].from;
sig_dst =
mount_crypt_stat->global_auth_tok_sig;
memcpy(sig_dst, sig_src, ECRYPTFS_SIG_SIZE_HEX);
sig_dst[ECRYPTFS_SIG_SIZE_HEX] = '\0';
ecryptfs_printk(KERN_DEBUG,
"The mount_crypt_stat "
"global_auth_tok_sig set to: "
"[%s]\n", sig_dst);
sig_set = 1;
break;
case ecryptfs_opt_debug:
case ecryptfs_opt_ecryptfs_debug:
debug_src = args[0].from;
ecryptfs_verbosity =
(int)simple_strtol(debug_src, &debug_src,
0);
ecryptfs_printk(KERN_DEBUG,
"Verbosity set to [%d]" "\n",
ecryptfs_verbosity);
break;
case ecryptfs_opt_cipher:
case ecryptfs_opt_ecryptfs_cipher:
cipher_name_src = args[0].from;
cipher_name_dst =
mount_crypt_stat->
global_default_cipher_name;
strncpy(cipher_name_dst, cipher_name_src,
ECRYPTFS_MAX_CIPHER_NAME_SIZE);
ecryptfs_printk(KERN_DEBUG,
"The mount_crypt_stat "
"global_default_cipher_name set to: "
"[%s]\n", cipher_name_dst);
cipher_name_set = 1;
break;
case ecryptfs_opt_ecryptfs_key_bytes:
cipher_key_bytes_src = args[0].from;
cipher_key_bytes =
(int)simple_strtol(cipher_key_bytes_src,
&cipher_key_bytes_src, 0);
mount_crypt_stat->global_default_cipher_key_size =
cipher_key_bytes;
ecryptfs_printk(KERN_DEBUG,
"The mount_crypt_stat "
"global_default_cipher_key_size "
"set to: [%d]\n", mount_crypt_stat->
global_default_cipher_key_size);
cipher_key_bytes_set = 1;
break;
case ecryptfs_opt_passthrough:
mount_crypt_stat->flags |=
ECRYPTFS_PLAINTEXT_PASSTHROUGH_ENABLED;
break;
case ecryptfs_opt_xattr_metadata:
mount_crypt_stat->flags |=
ECRYPTFS_XATTR_METADATA_ENABLED;
break;
case ecryptfs_opt_encrypted_view:
mount_crypt_stat->flags |=
ECRYPTFS_XATTR_METADATA_ENABLED;
mount_crypt_stat->flags |=
ECRYPTFS_ENCRYPTED_VIEW_ENABLED;
break;
case ecryptfs_opt_err:
default:
ecryptfs_printk(KERN_WARNING,
"eCryptfs: unrecognized option '%s'\n",
p);
}
}
/* Do not support lack of mount-wide signature in 0.1
* release */
if (!sig_set) {
rc = -EINVAL;
ecryptfs_printk(KERN_ERR, "You must supply a valid "
"passphrase auth tok signature as a mount "
"parameter; see the eCryptfs README\n");
goto out;
}
if (!cipher_name_set) {
cipher_name_len = strlen(ECRYPTFS_DEFAULT_CIPHER);
if (unlikely(cipher_name_len
>= ECRYPTFS_MAX_CIPHER_NAME_SIZE)) {
rc = -EINVAL;
BUG();
goto out;
}
memcpy(mount_crypt_stat->global_default_cipher_name,
ECRYPTFS_DEFAULT_CIPHER, cipher_name_len);
mount_crypt_stat->global_default_cipher_name[cipher_name_len]
= '\0';
}
if (!cipher_key_bytes_set) {
mount_crypt_stat->global_default_cipher_key_size = 0;
}
rc = ecryptfs_process_cipher(
&mount_crypt_stat->global_key_tfm,
mount_crypt_stat->global_default_cipher_name,
&mount_crypt_stat->global_default_cipher_key_size);
if (rc) {
printk(KERN_ERR "Error attempting to initialize cipher [%s] "
"with key size [%Zd] bytes; rc = [%d]\n",
mount_crypt_stat->global_default_cipher_name,
mount_crypt_stat->global_default_cipher_key_size, rc);
mount_crypt_stat->global_key_tfm = NULL;
mount_crypt_stat->global_auth_tok_key = NULL;
rc = -EINVAL;
goto out;
}
mutex_init(&mount_crypt_stat->global_key_tfm_mutex);
ecryptfs_printk(KERN_DEBUG, "Requesting the key with description: "
"[%s]\n", mount_crypt_stat->global_auth_tok_sig);
/* The reference to this key is held until umount is done The
* call to key_put is done in ecryptfs_put_super() */
auth_tok_key = request_key(&key_type_user,
mount_crypt_stat->global_auth_tok_sig,
NULL);
if (!auth_tok_key || IS_ERR(auth_tok_key)) {
ecryptfs_printk(KERN_ERR, "Could not find key with "
"description: [%s]\n",
mount_crypt_stat->global_auth_tok_sig);
process_request_key_err(PTR_ERR(auth_tok_key));
rc = -EINVAL;
goto out;
}
auth_tok = ecryptfs_get_key_payload_data(auth_tok_key);
if (ecryptfs_verify_version(auth_tok->version)) {
ecryptfs_printk(KERN_ERR, "Data structure version mismatch. "
"Userspace tools must match eCryptfs kernel "
"module with major version [%d] and minor "
"version [%d]\n", ECRYPTFS_VERSION_MAJOR,
ECRYPTFS_VERSION_MINOR);
rc = -EINVAL;
goto out;
}
if (auth_tok->token_type != ECRYPTFS_PASSWORD
&& auth_tok->token_type != ECRYPTFS_PRIVATE_KEY) {
ecryptfs_printk(KERN_ERR, "Invalid auth_tok structure "
"returned from key query\n");
rc = -EINVAL;
goto out;
}
mount_crypt_stat->global_auth_tok_key = auth_tok_key;
mount_crypt_stat->global_auth_tok = auth_tok;
out:
return rc;
}
struct kmem_cache *ecryptfs_sb_info_cache;
/**
* ecryptfs_fill_super
* @sb: The ecryptfs super block
* @raw_data: The options passed to mount
* @silent: Not used but required by function prototype
*
* Sets up what we can of the sb, rest is done in ecryptfs_read_super
*
* Returns zero on success; non-zero otherwise
*/
static int
ecryptfs_fill_super(struct super_block *sb, void *raw_data, int silent)
{
int rc = 0;
/* Released in ecryptfs_put_super() */
ecryptfs_set_superblock_private(sb,
kmem_cache_zalloc(ecryptfs_sb_info_cache,
GFP_KERNEL));
if (!ecryptfs_superblock_to_private(sb)) {
ecryptfs_printk(KERN_WARNING, "Out of memory\n");
rc = -ENOMEM;
goto out;
}
sb->s_op = &ecryptfs_sops;
/* Released through deactivate_super(sb) from get_sb_nodev */
sb->s_root = d_alloc(NULL, &(const struct qstr) {
.hash = 0,.name = "/",.len = 1});
if (!sb->s_root) {
ecryptfs_printk(KERN_ERR, "d_alloc failed\n");
rc = -ENOMEM;
goto out;
}
sb->s_root->d_op = &ecryptfs_dops;
sb->s_root->d_sb = sb;
sb->s_root->d_parent = sb->s_root;
/* Released in d_release when dput(sb->s_root) is called */
/* through deactivate_super(sb) from get_sb_nodev() */
ecryptfs_set_dentry_private(sb->s_root,
kmem_cache_zalloc(ecryptfs_dentry_info_cache,
GFP_KERNEL));
if (!ecryptfs_dentry_to_private(sb->s_root)) {
ecryptfs_printk(KERN_ERR,
"dentry_info_cache alloc failed\n");
rc = -ENOMEM;
goto out;
}
rc = 0;
out:
/* Should be able to rely on deactivate_super called from
* get_sb_nodev */
return rc;
}
/**
* ecryptfs_read_super
* @sb: The ecryptfs super block
* @dev_name: The path to mount over
*
* Read the super block of the lower filesystem, and use
* ecryptfs_interpose to create our initial inode and super block
* struct.
*/
static int ecryptfs_read_super(struct super_block *sb, const char *dev_name)
{
int rc;
struct nameidata nd;
struct dentry *lower_root;
struct vfsmount *lower_mnt;
memset(&nd, 0, sizeof(struct nameidata));
rc = path_lookup(dev_name, LOOKUP_FOLLOW | LOOKUP_DIRECTORY, &nd);
if (rc) {
ecryptfs_printk(KERN_WARNING, "path_lookup() failed\n");
goto out;
}
lower_root = nd.dentry;
lower_mnt = nd.mnt;
ecryptfs_set_superblock_lower(sb, lower_root->d_sb);
sb->s_maxbytes = lower_root->d_sb->s_maxbytes;
ecryptfs_set_dentry_lower(sb->s_root, lower_root);
ecryptfs_set_dentry_lower_mnt(sb->s_root, lower_mnt);
if ((rc = ecryptfs_interpose(lower_root, sb->s_root, sb, 0)))
goto out_free;
rc = 0;
goto out;
out_free:
path_release(&nd);
out:
return rc;
}
/**
* ecryptfs_get_sb
* @fs_type
* @flags
* @dev_name: The path to mount over
* @raw_data: The options passed into the kernel
*
* The whole ecryptfs_get_sb process is broken into 4 functions:
* ecryptfs_parse_options(): handle options passed to ecryptfs, if any
* ecryptfs_fill_super(): used by get_sb_nodev, fills out the super_block
* with as much information as it can before needing
* the lower filesystem.
* ecryptfs_read_super(): this accesses the lower filesystem and uses
* ecryptfs_interpolate to perform most of the linking
* ecryptfs_interpolate(): links the lower filesystem into ecryptfs
*/
static int ecryptfs_get_sb(struct file_system_type *fs_type, int flags,
const char *dev_name, void *raw_data,
struct vfsmount *mnt)
{
int rc;
struct super_block *sb;
rc = get_sb_nodev(fs_type, flags, raw_data, ecryptfs_fill_super, mnt);
if (rc < 0) {
printk(KERN_ERR "Getting sb failed; rc = [%d]\n", rc);
goto out;
}
sb = mnt->mnt_sb;
rc = ecryptfs_parse_options(sb, raw_data);
if (rc) {
printk(KERN_ERR "Error parsing options; rc = [%d]\n", rc);
goto out_abort;
}
rc = ecryptfs_read_super(sb, dev_name);
if (rc) {
printk(KERN_ERR "Reading sb failed; rc = [%d]\n", rc);
goto out_abort;
}
goto out;
out_abort:
dput(sb->s_root);
up_write(&sb->s_umount);
deactivate_super(sb);
out:
return rc;
}
/**
* ecryptfs_kill_block_super
* @sb: The ecryptfs super block
*
* Used to bring the superblock down and free the private data.
* Private data is free'd in ecryptfs_put_super()
*/
static void ecryptfs_kill_block_super(struct super_block *sb)
{
generic_shutdown_super(sb);
}
static struct file_system_type ecryptfs_fs_type = {
.owner = THIS_MODULE,
.name = "ecryptfs",
.get_sb = ecryptfs_get_sb,
.kill_sb = ecryptfs_kill_block_super,
.fs_flags = 0
};
/**
* inode_info_init_once
*
* Initializes the ecryptfs_inode_info_cache when it is created
*/
static void
inode_info_init_once(void *vptr, struct kmem_cache *cachep, unsigned long flags)
{
struct ecryptfs_inode_info *ei = (struct ecryptfs_inode_info *)vptr;
if ((flags & (SLAB_CTOR_VERIFY | SLAB_CTOR_CONSTRUCTOR)) ==
SLAB_CTOR_CONSTRUCTOR)
inode_init_once(&ei->vfs_inode);
}
static struct ecryptfs_cache_info {
struct kmem_cache **cache;
const char *name;
size_t size;
void (*ctor)(void*, struct kmem_cache *, unsigned long);
} ecryptfs_cache_infos[] = {
{
.cache = &ecryptfs_auth_tok_list_item_cache,
.name = "ecryptfs_auth_tok_list_item",
.size = sizeof(struct ecryptfs_auth_tok_list_item),
},
{
.cache = &ecryptfs_file_info_cache,
.name = "ecryptfs_file_cache",
.size = sizeof(struct ecryptfs_file_info),
},
{
.cache = &ecryptfs_dentry_info_cache,
.name = "ecryptfs_dentry_info_cache",
.size = sizeof(struct ecryptfs_dentry_info),
},
{
.cache = &ecryptfs_inode_info_cache,
.name = "ecryptfs_inode_cache",
.size = sizeof(struct ecryptfs_inode_info),
.ctor = inode_info_init_once,
},
{
.cache = &ecryptfs_sb_info_cache,
.name = "ecryptfs_sb_cache",
.size = sizeof(struct ecryptfs_sb_info),
},
{
.cache = &ecryptfs_header_cache_0,
.name = "ecryptfs_headers_0",
.size = PAGE_CACHE_SIZE,
},
{
.cache = &ecryptfs_header_cache_1,
.name = "ecryptfs_headers_1",
.size = PAGE_CACHE_SIZE,
},
{
.cache = &ecryptfs_header_cache_2,
.name = "ecryptfs_headers_2",
.size = PAGE_CACHE_SIZE,
},
{
.cache = &ecryptfs_xattr_cache,
.name = "ecryptfs_xattr_cache",
.size = PAGE_CACHE_SIZE,
},
{
.cache = &ecryptfs_lower_page_cache,
.name = "ecryptfs_lower_page_cache",
.size = PAGE_CACHE_SIZE,
},
{
.cache = &ecryptfs_key_record_cache,
.name = "ecryptfs_key_record_cache",
.size = sizeof(struct ecryptfs_key_record),
},
};
static void ecryptfs_free_kmem_caches(void)
{
int i;
for (i = 0; i < ARRAY_SIZE(ecryptfs_cache_infos); i++) {
struct ecryptfs_cache_info *info;
info = &ecryptfs_cache_infos[i];
if (*(info->cache))
kmem_cache_destroy(*(info->cache));
}
}
/**
* ecryptfs_init_kmem_caches
*
* Returns zero on success; non-zero otherwise
*/
static int ecryptfs_init_kmem_caches(void)
{
int i;
for (i = 0; i < ARRAY_SIZE(ecryptfs_cache_infos); i++) {
struct ecryptfs_cache_info *info;
info = &ecryptfs_cache_infos[i];
*(info->cache) = kmem_cache_create(info->name, info->size,
0, SLAB_HWCACHE_ALIGN, info->ctor, NULL);
if (!*(info->cache)) {
ecryptfs_free_kmem_caches();
ecryptfs_printk(KERN_WARNING, "%s: "
"kmem_cache_create failed\n",
info->name);
return -ENOMEM;
}
}
return 0;
}
struct ecryptfs_obj {
char *name;
struct list_head slot_list;
struct kobject kobj;
};
struct ecryptfs_attribute {
struct attribute attr;
ssize_t(*show) (struct ecryptfs_obj *, char *);
ssize_t(*store) (struct ecryptfs_obj *, const char *, size_t);
};
static ssize_t
ecryptfs_attr_store(struct kobject *kobj,
struct attribute *attr, const char *buf, size_t len)
{
struct ecryptfs_obj *obj = container_of(kobj, struct ecryptfs_obj,
kobj);
struct ecryptfs_attribute *attribute =
container_of(attr, struct ecryptfs_attribute, attr);
return (attribute->store ? attribute->store(obj, buf, len) : 0);
}
static ssize_t
ecryptfs_attr_show(struct kobject *kobj, struct attribute *attr, char *buf)
{
struct ecryptfs_obj *obj = container_of(kobj, struct ecryptfs_obj,
kobj);
struct ecryptfs_attribute *attribute =
container_of(attr, struct ecryptfs_attribute, attr);
return (attribute->show ? attribute->show(obj, buf) : 0);
}
static struct sysfs_ops ecryptfs_sysfs_ops = {
.show = ecryptfs_attr_show,
.store = ecryptfs_attr_store
};
static struct kobj_type ecryptfs_ktype = {
.sysfs_ops = &ecryptfs_sysfs_ops
};
static decl_subsys(ecryptfs, &ecryptfs_ktype, NULL);
static ssize_t version_show(struct ecryptfs_obj *obj, char *buff)
{
return snprintf(buff, PAGE_SIZE, "%d\n", ECRYPTFS_VERSIONING_MASK);
}
static struct ecryptfs_attribute sysfs_attr_version = __ATTR_RO(version);
static struct ecryptfs_version_str_map_elem {
u32 flag;
char *str;
} ecryptfs_version_str_map[] = {
{ECRYPTFS_VERSIONING_PASSPHRASE, "passphrase"},
{ECRYPTFS_VERSIONING_PUBKEY, "pubkey"},
{ECRYPTFS_VERSIONING_PLAINTEXT_PASSTHROUGH, "plaintext passthrough"},
{ECRYPTFS_VERSIONING_POLICY, "policy"},
{ECRYPTFS_VERSIONING_XATTR, "metadata in extended attribute"}
};
static ssize_t version_str_show(struct ecryptfs_obj *obj, char *buff)
{
int i;
int remaining = PAGE_SIZE;
int total_written = 0;
buff[0] = '\0';
for (i = 0; i < ARRAY_SIZE(ecryptfs_version_str_map); i++) {
int entry_size;
if (!(ECRYPTFS_VERSIONING_MASK
& ecryptfs_version_str_map[i].flag))
continue;
entry_size = strlen(ecryptfs_version_str_map[i].str);
if ((entry_size + 2) > remaining)
goto out;
memcpy(buff, ecryptfs_version_str_map[i].str, entry_size);
buff[entry_size++] = '\n';
buff[entry_size] = '\0';
buff += entry_size;
total_written += entry_size;
remaining -= entry_size;
}
out:
return total_written;
}
static struct ecryptfs_attribute sysfs_attr_version_str = __ATTR_RO(version_str);
static int do_sysfs_registration(void)
{
int rc;
if ((rc = subsystem_register(&ecryptfs_subsys))) {
printk(KERN_ERR
"Unable to register ecryptfs sysfs subsystem\n");
goto out;
}
rc = sysfs_create_file(&ecryptfs_subsys.kset.kobj,
&sysfs_attr_version.attr);
if (rc) {
printk(KERN_ERR
"Unable to create ecryptfs version attribute\n");
subsystem_unregister(&ecryptfs_subsys);
goto out;
}
rc = sysfs_create_file(&ecryptfs_subsys.kset.kobj,
&sysfs_attr_version_str.attr);
if (rc) {
printk(KERN_ERR
"Unable to create ecryptfs version_str attribute\n");
sysfs_remove_file(&ecryptfs_subsys.kset.kobj,
&sysfs_attr_version.attr);
subsystem_unregister(&ecryptfs_subsys);
goto out;
}
out:
return rc;
}
static int __init ecryptfs_init(void)
{
int rc;
if (ECRYPTFS_DEFAULT_EXTENT_SIZE > PAGE_CACHE_SIZE) {
rc = -EINVAL;
ecryptfs_printk(KERN_ERR, "The eCryptfs extent size is "
"larger than the host's page size, and so "
"eCryptfs cannot run on this system. The "
"default eCryptfs extent size is [%d] bytes; "
"the page size is [%d] bytes.\n",
ECRYPTFS_DEFAULT_EXTENT_SIZE, PAGE_CACHE_SIZE);
goto out;
}
rc = ecryptfs_init_kmem_caches();
if (rc) {
printk(KERN_ERR
"Failed to allocate one or more kmem_cache objects\n");
goto out;
}
rc = register_filesystem(&ecryptfs_fs_type);
if (rc) {
printk(KERN_ERR "Failed to register filesystem\n");
ecryptfs_free_kmem_caches();
goto out;
}
kset_set_kset_s(&ecryptfs_subsys, fs_subsys);
sysfs_attr_version.attr.owner = THIS_MODULE;
sysfs_attr_version_str.attr.owner = THIS_MODULE;
rc = do_sysfs_registration();
if (rc) {
printk(KERN_ERR "sysfs registration failed\n");
unregister_filesystem(&ecryptfs_fs_type);
ecryptfs_free_kmem_caches();
goto out;
}
rc = ecryptfs_init_messaging(ecryptfs_transport);
if (rc) {
ecryptfs_printk(KERN_ERR, "Failure occured while attempting to "
"initialize the eCryptfs netlink socket\n");
}
out:
return rc;
}
static void __exit ecryptfs_exit(void)
{
sysfs_remove_file(&ecryptfs_subsys.kset.kobj,
&sysfs_attr_version.attr);
sysfs_remove_file(&ecryptfs_subsys.kset.kobj,
&sysfs_attr_version_str.attr);
subsystem_unregister(&ecryptfs_subsys);
ecryptfs_release_messaging(ecryptfs_transport);
unregister_filesystem(&ecryptfs_fs_type);
ecryptfs_free_kmem_caches();
}
MODULE_AUTHOR("Michael A. Halcrow <mhalcrow@us.ibm.com>");
MODULE_DESCRIPTION("eCryptfs");
MODULE_LICENSE("GPL");
module_init(ecryptfs_init)
module_exit(ecryptfs_exit)

516
fs/ecryptfs/messaging.c Normal file
View File

@@ -0,0 +1,516 @@
/**
* eCryptfs: Linux filesystem encryption layer
*
* Copyright (C) 2004-2006 International Business Machines Corp.
* Author(s): Michael A. Halcrow <mhalcrow@us.ibm.com>
* Tyler Hicks <tyhicks@ou.edu>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version
* 2 as published by the Free Software Foundation.
*
* 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 "ecryptfs_kernel.h"
static LIST_HEAD(ecryptfs_msg_ctx_free_list);
static LIST_HEAD(ecryptfs_msg_ctx_alloc_list);
static struct mutex ecryptfs_msg_ctx_lists_mux;
static struct hlist_head *ecryptfs_daemon_id_hash;
static struct mutex ecryptfs_daemon_id_hash_mux;
static int ecryptfs_hash_buckets;
#define ecryptfs_uid_hash(uid) \
hash_long((unsigned long)uid, ecryptfs_hash_buckets)
static unsigned int ecryptfs_msg_counter;
static struct ecryptfs_msg_ctx *ecryptfs_msg_ctx_arr;
/**
* ecryptfs_acquire_free_msg_ctx
* @msg_ctx: The context that was acquired from the free list
*
* 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
* failure to acquire a free context element. Be sure to lock the
* list mutex before calling.
*/
static int ecryptfs_acquire_free_msg_ctx(struct ecryptfs_msg_ctx **msg_ctx)
{
struct list_head *p;
int rc;
if (list_empty(&ecryptfs_msg_ctx_free_list)) {
ecryptfs_printk(KERN_WARNING, "The eCryptfs free "
"context list is empty. It may be helpful to "
"specify the ecryptfs_message_buf_len "
"parameter to be greater than the current "
"value of [%d]\n", ecryptfs_message_buf_len);
rc = -ENOMEM;
goto out;
}
list_for_each(p, &ecryptfs_msg_ctx_free_list) {
*msg_ctx = list_entry(p, struct ecryptfs_msg_ctx, node);
if (mutex_trylock(&(*msg_ctx)->mux)) {
(*msg_ctx)->task = current;
rc = 0;
goto out;
}
}
rc = -ENOMEM;
out:
return rc;
}
/**
* ecryptfs_msg_ctx_free_to_alloc
* @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
* calling.
*/
static void ecryptfs_msg_ctx_free_to_alloc(struct ecryptfs_msg_ctx *msg_ctx)
{
list_move(&msg_ctx->node, &ecryptfs_msg_ctx_alloc_list);
msg_ctx->state = ECRYPTFS_MSG_CTX_STATE_PENDING;
msg_ctx->counter = ++ecryptfs_msg_counter;
}
/**
* ecryptfs_msg_ctx_alloc_to_free
* @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
* calling.
*/
static void ecryptfs_msg_ctx_alloc_to_free(struct ecryptfs_msg_ctx *msg_ctx)
{
list_move(&(msg_ctx->node), &ecryptfs_msg_ctx_free_list);
if (msg_ctx->msg)
kfree(msg_ctx->msg);
msg_ctx->state = ECRYPTFS_MSG_CTX_STATE_FREE;
}
/**
* ecryptfs_find_daemon_id
* @uid: The user id which maps to the desired daemon id
* @id: If return value is zero, points to the desired daemon id
* pointer
*
* Search the hash list for the given user id. Returns zero if the
* 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)
{
struct hlist_node *elem;
int rc;
hlist_for_each_entry(*id, elem,
&ecryptfs_daemon_id_hash[ecryptfs_uid_hash(uid)],
id_chain) {
if ((*id)->uid == uid) {
rc = 0;
goto out;
}
}
rc = -EINVAL;
out:
return rc;
}
static int ecryptfs_send_raw_message(unsigned int transport, u16 msg_type,
pid_t pid)
{
int rc;
switch(transport) {
case ECRYPTFS_TRANSPORT_NETLINK:
rc = ecryptfs_send_netlink(NULL, 0, NULL, msg_type, 0, pid);
break;
case ECRYPTFS_TRANSPORT_CONNECTOR:
case ECRYPTFS_TRANSPORT_RELAYFS:
default:
rc = -ENOSYS;
}
return rc;
}
/**
* ecryptfs_process_helo
* @transport: The underlying transport (netlink, etc.)
* @uid: The user ID owner of the message
* @pid: The process ID for the userspace program that sent the
* message
*
* Adds the uid and pid values to the daemon id hash. If a uid
* already has a daemon pid registered, the daemon will be
* unregistered before the new daemon id is put into the hash list.
* Returns zero after adding a new daemon id to the hash list;
* non-zero otherwise.
*/
int ecryptfs_process_helo(unsigned int transport, uid_t uid, pid_t pid)
{
struct ecryptfs_daemon_id *new_id;
struct ecryptfs_daemon_id *old_id;
int rc;
mutex_lock(&ecryptfs_daemon_id_hash_mux);
new_id = kmalloc(sizeof(*new_id), GFP_KERNEL);
if (!new_id) {
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] "
"to register daemon [%d]; unregistering daemon "
"[%d]\n", uid, pid, old_id->pid);
hlist_del(&old_id->id_chain);
rc = ecryptfs_send_raw_message(transport, ECRYPTFS_NLMSG_QUIT,
old_id->pid);
if (rc)
printk(KERN_WARNING "Failed to send QUIT "
"message to daemon [%d]; rc = [%d]\n",
old_id->pid, rc);
kfree(old_id);
}
new_id->uid = uid;
new_id->pid = pid;
hlist_add_head(&new_id->id_chain,
&ecryptfs_daemon_id_hash[ecryptfs_uid_hash(uid)]);
rc = 0;
unlock:
mutex_unlock(&ecryptfs_daemon_id_hash_mux);
return rc;
}
/**
* ecryptfs_process_quit
* @uid: The user ID owner of the message
* @pid: The process ID for the userspace program that sent the
* message
*
* Deletes the corresponding daemon id for the given uid and pid, if
* it is the registered that is requesting the deletion. Returns zero
* after deleting the desired daemon id; non-zero otherwise.
*/
int ecryptfs_process_quit(uid_t uid, pid_t pid)
{
struct ecryptfs_daemon_id *id;
int rc;
mutex_lock(&ecryptfs_daemon_id_hash_mux);
if (ecryptfs_find_daemon_id(uid, &id)) {
rc = -EINVAL;
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;
ecryptfs_printk(KERN_WARNING, "Received request from user [%d] "
"with pid [%d] to unregister daemon [%d]\n",
uid, pid, id->pid);
goto unlock;
}
hlist_del(&id->id_chain);
kfree(id);
rc = 0;
unlock:
mutex_unlock(&ecryptfs_daemon_id_hash_mux);
return rc;
}
/**
* ecryptfs_process_reponse
* @msg: The ecryptfs message received; the caller should sanity check
* msg->data_len
* @pid: The process ID of the userspace application that sent the
* message
* @seq: The sequence number of the message
*
* Processes a response message after sending a operation request to
* 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,
pid_t pid, u32 seq)
{
struct ecryptfs_daemon_id *id;
struct ecryptfs_msg_ctx *msg_ctx;
int msg_size;
int rc;
if (msg->index >= ecryptfs_message_buf_len) {
rc = -EINVAL;
ecryptfs_printk(KERN_ERR, "Attempt to reference "
"context buffer at index [%d]; maximum "
"allowable is [%d]\n", msg->index,
(ecryptfs_message_buf_len - 1));
goto out;
}
msg_ctx = &ecryptfs_msg_ctx_arr[msg->index];
mutex_lock(&msg_ctx->mux);
if (ecryptfs_find_daemon_id(msg_ctx->task->euid, &id)) {
rc = -EBADMSG;
ecryptfs_printk(KERN_WARNING, "User [%d] received a "
"message response from process [%d] but does "
"not have a registered daemon\n",
msg_ctx->task->euid, pid);
goto wake_up;
}
if (msg_ctx->task->euid != uid) {
rc = -EBADMSG;
ecryptfs_printk(KERN_WARNING, "Received message from user "
"[%d]; expected message from user [%d]\n",
uid, msg_ctx->task->euid);
goto unlock;
}
if (id->pid != pid) {
rc = -EBADMSG;
ecryptfs_printk(KERN_ERR, "User [%d] received a "
"message response from an unrecognized "
"process [%d]\n", msg_ctx->task->euid, pid);
goto unlock;
}
if (msg_ctx->state != ECRYPTFS_MSG_CTX_STATE_PENDING) {
rc = -EINVAL;
ecryptfs_printk(KERN_WARNING, "Desired context element is not "
"pending a response\n");
goto unlock;
} else if (msg_ctx->counter != seq) {
rc = -EINVAL;
ecryptfs_printk(KERN_WARNING, "Invalid message sequence; "
"expected [%d]; received [%d]\n",
msg_ctx->counter, seq);
goto unlock;
}
msg_size = sizeof(*msg) + msg->data_len;
msg_ctx->msg = kmalloc(msg_size, GFP_KERNEL);
if (!msg_ctx->msg) {
rc = -ENOMEM;
ecryptfs_printk(KERN_ERR, "Failed to allocate memory\n");
goto unlock;
}
memcpy(msg_ctx->msg, msg, msg_size);
msg_ctx->state = ECRYPTFS_MSG_CTX_STATE_DONE;
rc = 0;
wake_up:
wake_up_process(msg_ctx->task);
unlock:
mutex_unlock(&msg_ctx->mux);
out:
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
*/
int ecryptfs_send_message(unsigned int transport, char *data, int data_len,
struct ecryptfs_msg_ctx **msg_ctx)
{
struct ecryptfs_daemon_id *id;
int rc;
mutex_lock(&ecryptfs_daemon_id_hash_mux);
if (ecryptfs_find_daemon_id(current->euid, &id)) {
mutex_unlock(&ecryptfs_daemon_id_hash_mux);
rc = -ENOTCONN;
ecryptfs_printk(KERN_ERR, "User [%d] does not have a daemon "
"registered\n", current->euid);
goto out;
}
mutex_unlock(&ecryptfs_daemon_id_hash_mux);
mutex_lock(&ecryptfs_msg_ctx_lists_mux);
rc = ecryptfs_acquire_free_msg_ctx(msg_ctx);
if (rc) {
mutex_unlock(&ecryptfs_msg_ctx_lists_mux);
ecryptfs_printk(KERN_WARNING, "Could not claim a free "
"context element\n");
goto out;
}
ecryptfs_msg_ctx_free_to_alloc(*msg_ctx);
mutex_unlock(&(*msg_ctx)->mux);
mutex_unlock(&ecryptfs_msg_ctx_lists_mux);
switch (transport) {
case ECRYPTFS_TRANSPORT_NETLINK:
rc = ecryptfs_send_netlink(data, data_len, *msg_ctx,
ECRYPTFS_NLMSG_REQUEST, 0, id->pid);
break;
case ECRYPTFS_TRANSPORT_CONNECTOR:
case ECRYPTFS_TRANSPORT_RELAYFS:
default:
rc = -ENOSYS;
}
if (rc) {
printk(KERN_ERR "Error attempting to send message to userspace "
"daemon; rc = [%d]\n", rc);
}
out:
return rc;
}
/**
* ecryptfs_wait_for_response
* @msg_ctx: The context that was assigned when sending a message
* @msg: The incoming message from userspace; not set if rc != 0
*
* Sleeps until awaken by ecryptfs_receive_message or until the amount
* of time exceeds ecryptfs_message_wait_timeout. If zero is
* returned, msg will point to a valid message from userspace; a
* non-zero value is returned upon failure to receive a message or an
* error occurs.
*/
int ecryptfs_wait_for_response(struct ecryptfs_msg_ctx *msg_ctx,
struct ecryptfs_message **msg)
{
signed long timeout = ecryptfs_message_wait_timeout * HZ;
int rc = 0;
sleep:
timeout = schedule_timeout_interruptible(timeout);
mutex_lock(&ecryptfs_msg_ctx_lists_mux);
mutex_lock(&msg_ctx->mux);
if (msg_ctx->state != ECRYPTFS_MSG_CTX_STATE_DONE) {
if (timeout) {
mutex_unlock(&msg_ctx->mux);
mutex_unlock(&ecryptfs_msg_ctx_lists_mux);
goto sleep;
}
rc = -ENOMSG;
} else {
*msg = msg_ctx->msg;
msg_ctx->msg = NULL;
}
ecryptfs_msg_ctx_alloc_to_free(msg_ctx);
mutex_unlock(&msg_ctx->mux);
mutex_unlock(&ecryptfs_msg_ctx_lists_mux);
return rc;
}
int ecryptfs_init_messaging(unsigned int transport)
{
int i;
int rc = 0;
if (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 "
"too large, defaulting to [%d] users\n",
ecryptfs_number_of_users);
}
mutex_init(&ecryptfs_daemon_id_hash_mux);
mutex_lock(&ecryptfs_daemon_id_hash_mux);
ecryptfs_hash_buckets = 0;
while (ecryptfs_number_of_users >> ++ecryptfs_hash_buckets);
ecryptfs_daemon_id_hash = kmalloc(sizeof(struct hlist_head)
* ecryptfs_hash_buckets, GFP_KERNEL);
if (!ecryptfs_daemon_id_hash) {
rc = -ENOMEM;
ecryptfs_printk(KERN_ERR, "Failed to allocate memory\n");
goto out;
}
for (i = 0; i < ecryptfs_hash_buckets; i++)
INIT_HLIST_HEAD(&ecryptfs_daemon_id_hash[i]);
mutex_unlock(&ecryptfs_daemon_id_hash_mux);
ecryptfs_msg_ctx_arr = kmalloc((sizeof(struct ecryptfs_msg_ctx)
* ecryptfs_message_buf_len), GFP_KERNEL);
if (!ecryptfs_msg_ctx_arr) {
rc = -ENOMEM;
ecryptfs_printk(KERN_ERR, "Failed to allocate memory\n");
goto out;
}
mutex_init(&ecryptfs_msg_ctx_lists_mux);
mutex_lock(&ecryptfs_msg_ctx_lists_mux);
ecryptfs_msg_counter = 0;
for (i = 0; i < ecryptfs_message_buf_len; i++) {
INIT_LIST_HEAD(&ecryptfs_msg_ctx_arr[i].node);
mutex_init(&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].state = ECRYPTFS_MSG_CTX_STATE_FREE;
ecryptfs_msg_ctx_arr[i].counter = 0;
ecryptfs_msg_ctx_arr[i].task = NULL;
ecryptfs_msg_ctx_arr[i].msg = NULL;
list_add_tail(&ecryptfs_msg_ctx_arr[i].node,
&ecryptfs_msg_ctx_free_list);
mutex_unlock(&ecryptfs_msg_ctx_arr[i].mux);
}
mutex_unlock(&ecryptfs_msg_ctx_lists_mux);
switch(transport) {
case ECRYPTFS_TRANSPORT_NETLINK:
rc = ecryptfs_init_netlink();
if (rc)
ecryptfs_release_messaging(transport);
break;
case ECRYPTFS_TRANSPORT_CONNECTOR:
case ECRYPTFS_TRANSPORT_RELAYFS:
default:
rc = -ENOSYS;
}
out:
return rc;
}
void ecryptfs_release_messaging(unsigned int transport)
{
if (ecryptfs_msg_ctx_arr) {
int i;
mutex_lock(&ecryptfs_msg_ctx_lists_mux);
for (i = 0; i < ecryptfs_message_buf_len; i++) {
mutex_lock(&ecryptfs_msg_ctx_arr[i].mux);
if (ecryptfs_msg_ctx_arr[i].msg)
kfree(ecryptfs_msg_ctx_arr[i].msg);
mutex_unlock(&ecryptfs_msg_ctx_arr[i].mux);
}
kfree(ecryptfs_msg_ctx_arr);
mutex_unlock(&ecryptfs_msg_ctx_lists_mux);
}
if (ecryptfs_daemon_id_hash) {
struct hlist_node *elem;
struct ecryptfs_daemon_id *id;
int i;
mutex_lock(&ecryptfs_daemon_id_hash_mux);
for (i = 0; i < ecryptfs_hash_buckets; i++) {
hlist_for_each_entry(id, elem,
&ecryptfs_daemon_id_hash[i],
id_chain) {
hlist_del(elem);
kfree(id);
}
}
kfree(ecryptfs_daemon_id_hash);
mutex_unlock(&ecryptfs_daemon_id_hash_mux);
}
switch(transport) {
case ECRYPTFS_TRANSPORT_NETLINK:
ecryptfs_release_netlink();
break;
case ECRYPTFS_TRANSPORT_CONNECTOR:
case ECRYPTFS_TRANSPORT_RELAYFS:
default:
break;
}
return;
}

830
fs/ecryptfs/mmap.c Normal file
View File

@@ -0,0 +1,830 @@
/**
* eCryptfs: Linux filesystem encryption layer
* This is where eCryptfs coordinates the symmetric encryption and
* decryption of the file data as it passes between the lower
* encrypted file and the upper decrypted file.
*
* Copyright (C) 1997-2003 Erez Zadok
* Copyright (C) 2001-2003 Stony Brook University
* Copyright (C) 2004-2007 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/pagemap.h>
#include <linux/writeback.h>
#include <linux/page-flags.h>
#include <linux/mount.h>
#include <linux/file.h>
#include <linux/crypto.h>
#include <linux/scatterlist.h>
#include "ecryptfs_kernel.h"
struct kmem_cache *ecryptfs_lower_page_cache;
/**
* ecryptfs_get1page
*
* Get one page from cache or lower f/s, return error otherwise.
*
* Returns unlocked and up-to-date page (if ok), with increased
* refcnt.
*/
static struct page *ecryptfs_get1page(struct file *file, int index)
{
struct page *page;
struct dentry *dentry;
struct inode *inode;
struct address_space *mapping;
dentry = file->f_path.dentry;
inode = dentry->d_inode;
mapping = inode->i_mapping;
page = read_cache_page(mapping, index,
(filler_t *)mapping->a_ops->readpage,
(void *)file);
if (IS_ERR(page))
goto out;
wait_on_page_locked(page);
out:
return page;
}
static
int write_zeros(struct file *file, pgoff_t index, int start, int num_zeros);
/**
* ecryptfs_fill_zeros
* @file: The ecryptfs file
* @new_length: The new length of the data in the underlying file;
* everything between the prior end of the file and the
* new end of the file will be filled with zero's.
* new_length must be greater than current length
*
* Function for handling lseek-ing past the end of the file.
*
* This function does not support shrinking, only growing a file.
*
* Returns zero on success; non-zero otherwise.
*/
int ecryptfs_fill_zeros(struct file *file, loff_t new_length)
{
int rc = 0;
struct dentry *dentry = file->f_path.dentry;
struct inode *inode = dentry->d_inode;
pgoff_t old_end_page_index = 0;
pgoff_t index = old_end_page_index;
int old_end_pos_in_page = -1;
pgoff_t new_end_page_index;
int new_end_pos_in_page;
loff_t cur_length = i_size_read(inode);
if (cur_length != 0) {
index = old_end_page_index =
((cur_length - 1) >> PAGE_CACHE_SHIFT);
old_end_pos_in_page = ((cur_length - 1) & ~PAGE_CACHE_MASK);
}
new_end_page_index = ((new_length - 1) >> PAGE_CACHE_SHIFT);
new_end_pos_in_page = ((new_length - 1) & ~PAGE_CACHE_MASK);
ecryptfs_printk(KERN_DEBUG, "old_end_page_index = [0x%.16x]; "
"old_end_pos_in_page = [%d]; "
"new_end_page_index = [0x%.16x]; "
"new_end_pos_in_page = [%d]\n",
old_end_page_index, old_end_pos_in_page,
new_end_page_index, new_end_pos_in_page);
if (old_end_page_index == new_end_page_index) {
/* Start and end are in the same page; we just need to
* set a portion of the existing page to zero's */
rc = write_zeros(file, index, (old_end_pos_in_page + 1),
(new_end_pos_in_page - old_end_pos_in_page));
if (rc)
ecryptfs_printk(KERN_ERR, "write_zeros(file=[%p], "
"index=[0x%.16x], "
"old_end_pos_in_page=[d], "
"(PAGE_CACHE_SIZE - new_end_pos_in_page"
"=[%d]"
")=[d]) returned [%d]\n", file, index,
old_end_pos_in_page,
new_end_pos_in_page,
(PAGE_CACHE_SIZE - new_end_pos_in_page),
rc);
goto out;
}
/* Fill the remainder of the previous last page with zeros */
rc = write_zeros(file, index, (old_end_pos_in_page + 1),
((PAGE_CACHE_SIZE - 1) - old_end_pos_in_page));
if (rc) {
ecryptfs_printk(KERN_ERR, "write_zeros(file=[%p], "
"index=[0x%.16x], old_end_pos_in_page=[d], "
"(PAGE_CACHE_SIZE - old_end_pos_in_page)=[d]) "
"returned [%d]\n", file, index,
old_end_pos_in_page,
(PAGE_CACHE_SIZE - old_end_pos_in_page), rc);
goto out;
}
index++;
while (index < new_end_page_index) {
/* Fill all intermediate pages with zeros */
rc = write_zeros(file, index, 0, PAGE_CACHE_SIZE);
if (rc) {
ecryptfs_printk(KERN_ERR, "write_zeros(file=[%p], "
"index=[0x%.16x], "
"old_end_pos_in_page=[d], "
"(PAGE_CACHE_SIZE - new_end_pos_in_page"
"=[%d]"
")=[d]) returned [%d]\n", file, index,
old_end_pos_in_page,
new_end_pos_in_page,
(PAGE_CACHE_SIZE - new_end_pos_in_page),
rc);
goto out;
}
index++;
}
/* Fill the portion at the beginning of the last new page with
* zero's */
rc = write_zeros(file, index, 0, (new_end_pos_in_page + 1));
if (rc) {
ecryptfs_printk(KERN_ERR, "write_zeros(file="
"[%p], index=[0x%.16x], 0, "
"new_end_pos_in_page=[%d]"
"returned [%d]\n", file, index,
new_end_pos_in_page, rc);
goto out;
}
out:
return rc;
}
/**
* ecryptfs_writepage
* @page: Page that is locked before this call is made
*
* Returns zero on success; non-zero otherwise
*/
static int ecryptfs_writepage(struct page *page, struct writeback_control *wbc)
{
struct ecryptfs_page_crypt_context ctx;
int rc;
ctx.page = page;
ctx.mode = ECRYPTFS_WRITEPAGE_MODE;
ctx.param.wbc = wbc;
rc = ecryptfs_encrypt_page(&ctx);
if (rc) {
ecryptfs_printk(KERN_WARNING, "Error encrypting "
"page (upper index [0x%.16x])\n", page->index);
ClearPageUptodate(page);
goto out;
}
SetPageUptodate(page);
unlock_page(page);
out:
return rc;
}
/**
* Reads the data from the lower file file at index lower_page_index
* and copies that data into page.
*
* @param page Page to fill
* @param lower_page_index Index of the page in the lower file to get
*/
int ecryptfs_do_readpage(struct file *file, struct page *page,
pgoff_t lower_page_index)
{
int rc;
struct dentry *dentry;
struct file *lower_file;
struct dentry *lower_dentry;
struct inode *inode;
struct inode *lower_inode;
char *page_data;
struct page *lower_page = NULL;
char *lower_page_data;
const struct address_space_operations *lower_a_ops;
dentry = file->f_path.dentry;
lower_file = ecryptfs_file_to_lower(file);
lower_dentry = ecryptfs_dentry_to_lower(dentry);
inode = dentry->d_inode;
lower_inode = ecryptfs_inode_to_lower(inode);
lower_a_ops = lower_inode->i_mapping->a_ops;
lower_page = read_cache_page(lower_inode->i_mapping, lower_page_index,
(filler_t *)lower_a_ops->readpage,
(void *)lower_file);
if (IS_ERR(lower_page)) {
rc = PTR_ERR(lower_page);
lower_page = NULL;
ecryptfs_printk(KERN_ERR, "Error reading from page cache\n");
goto out;
}
wait_on_page_locked(lower_page);
page_data = kmap_atomic(page, KM_USER0);
lower_page_data = kmap_atomic(lower_page, KM_USER1);
memcpy(page_data, lower_page_data, PAGE_CACHE_SIZE);
kunmap_atomic(lower_page_data, KM_USER1);
kunmap_atomic(page_data, KM_USER0);
flush_dcache_page(page);
rc = 0;
out:
if (likely(lower_page))
page_cache_release(lower_page);
if (rc == 0)
SetPageUptodate(page);
else
ClearPageUptodate(page);
return rc;
}
/**
* Header Extent:
* Octets 0-7: Unencrypted file size (big-endian)
* Octets 8-15: eCryptfs special marker
* Octets 16-19: Flags
* Octet 16: File format version number (between 0 and 255)
* Octets 17-18: Reserved
* Octet 19: Bit 1 (lsb): Reserved
* Bit 2: Encrypted?
* Bits 3-8: Reserved
* Octets 20-23: Header extent size (big-endian)
* Octets 24-25: Number of header extents at front of file
* (big-endian)
* Octet 26: Begin RFC 2440 authentication token packet set
*/
static void set_header_info(char *page_virt,
struct ecryptfs_crypt_stat *crypt_stat)
{
size_t written;
int save_num_header_extents_at_front =
crypt_stat->num_header_extents_at_front;
crypt_stat->num_header_extents_at_front = 1;
ecryptfs_write_header_metadata(page_virt + 20, crypt_stat, &written);
crypt_stat->num_header_extents_at_front =
save_num_header_extents_at_front;
}
/**
* ecryptfs_readpage
* @file: This is an ecryptfs file
* @page: ecryptfs associated page to stick the read data into
*
* Read in a page, decrypting if necessary.
*
* Returns zero on success; non-zero on error.
*/
static int ecryptfs_readpage(struct file *file, struct page *page)
{
int rc = 0;
struct ecryptfs_crypt_stat *crypt_stat;
BUG_ON(!(file && file->f_path.dentry && file->f_path.dentry->d_inode));
crypt_stat = &ecryptfs_inode_to_private(file->f_path.dentry->d_inode)
->crypt_stat;
if (!crypt_stat
|| !(crypt_stat->flags & ECRYPTFS_ENCRYPTED)
|| (crypt_stat->flags & ECRYPTFS_NEW_FILE)) {
ecryptfs_printk(KERN_DEBUG,
"Passing through unencrypted page\n");
rc = ecryptfs_do_readpage(file, page, page->index);
if (rc) {
ecryptfs_printk(KERN_ERR, "Error reading page; rc = "
"[%d]\n", rc);
goto out;
}
} else if (crypt_stat->flags & ECRYPTFS_VIEW_AS_ENCRYPTED) {
if (crypt_stat->flags & ECRYPTFS_METADATA_IN_XATTR) {
int num_pages_in_header_region =
(crypt_stat->header_extent_size
/ PAGE_CACHE_SIZE);
if (page->index < num_pages_in_header_region) {
char *page_virt;
page_virt = kmap_atomic(page, KM_USER0);
memset(page_virt, 0, PAGE_CACHE_SIZE);
if (page->index == 0) {
rc = ecryptfs_read_xattr_region(
page_virt, file->f_path.dentry);
set_header_info(page_virt, crypt_stat);
}
kunmap_atomic(page_virt, KM_USER0);
flush_dcache_page(page);
if (rc) {
printk(KERN_ERR "Error reading xattr "
"region\n");
goto out;
}
} else {
rc = ecryptfs_do_readpage(
file, page,
(page->index
- num_pages_in_header_region));
if (rc) {
printk(KERN_ERR "Error reading page; "
"rc = [%d]\n", rc);
goto out;
}
}
} else {
rc = ecryptfs_do_readpage(file, page, page->index);
if (rc) {
printk(KERN_ERR "Error reading page; rc = "
"[%d]\n", rc);
goto out;
}
}
} else {
rc = ecryptfs_decrypt_page(file, page);
if (rc) {
ecryptfs_printk(KERN_ERR, "Error decrypting page; "
"rc = [%d]\n", rc);
goto out;
}
}
SetPageUptodate(page);
out:
if (rc)
ClearPageUptodate(page);
ecryptfs_printk(KERN_DEBUG, "Unlocking page with index = [0x%.16x]\n",
page->index);
unlock_page(page);
return rc;
}
/**
* Called with lower inode mutex held.
*/
static int fill_zeros_to_end_of_page(struct page *page, unsigned int to)
{
struct inode *inode = page->mapping->host;
int end_byte_in_page;
char *page_virt;
if ((i_size_read(inode) / PAGE_CACHE_SIZE) != page->index)
goto out;
end_byte_in_page = i_size_read(inode) % PAGE_CACHE_SIZE;
if (to > end_byte_in_page)
end_byte_in_page = to;
page_virt = kmap_atomic(page, KM_USER0);
memset((page_virt + end_byte_in_page), 0,
(PAGE_CACHE_SIZE - end_byte_in_page));
kunmap_atomic(page_virt, KM_USER0);
flush_dcache_page(page);
out:
return 0;
}
static int ecryptfs_prepare_write(struct file *file, struct page *page,
unsigned from, unsigned to)
{
int rc = 0;
if (from == 0 && to == PAGE_CACHE_SIZE)
goto out; /* If we are writing a full page, it will be
up to date. */
if (!PageUptodate(page))
rc = ecryptfs_do_readpage(file, page, page->index);
out:
return rc;
}
int ecryptfs_writepage_and_release_lower_page(struct page *lower_page,
struct inode *lower_inode,
struct writeback_control *wbc)
{
int rc = 0;
rc = lower_inode->i_mapping->a_ops->writepage(lower_page, wbc);
if (rc) {
ecryptfs_printk(KERN_ERR, "Error calling lower writepage(); "
"rc = [%d]\n", rc);
goto out;
}
lower_inode->i_mtime = lower_inode->i_ctime = CURRENT_TIME;
page_cache_release(lower_page);
out:
return rc;
}
static
void ecryptfs_release_lower_page(struct page *lower_page, int page_locked)
{
if (page_locked)
unlock_page(lower_page);
page_cache_release(lower_page);
}
/**
* ecryptfs_write_inode_size_to_header
*
* Writes the lower file size to the first 8 bytes of the header.
*
* Returns zero on success; non-zero on error.
*/
static int ecryptfs_write_inode_size_to_header(struct file *lower_file,
struct inode *lower_inode,
struct inode *inode)
{
int rc = 0;
struct page *header_page;
char *header_virt;
const struct address_space_operations *lower_a_ops;
u64 file_size;
retry:
header_page = grab_cache_page(lower_inode->i_mapping, 0);
if (!header_page) {
ecryptfs_printk(KERN_ERR, "grab_cache_page for "
"lower_page_index 0 failed\n");
rc = -EINVAL;
goto out;
}
lower_a_ops = lower_inode->i_mapping->a_ops;
rc = lower_a_ops->prepare_write(lower_file, header_page, 0, 8);
if (rc) {
if (rc == AOP_TRUNCATED_PAGE) {
ecryptfs_release_lower_page(header_page, 0);
goto retry;
} else
ecryptfs_release_lower_page(header_page, 1);
goto out;
}
file_size = (u64)i_size_read(inode);
ecryptfs_printk(KERN_DEBUG, "Writing size: [0x%.16x]\n", file_size);
file_size = cpu_to_be64(file_size);
header_virt = kmap_atomic(header_page, KM_USER0);
memcpy(header_virt, &file_size, sizeof(u64));
kunmap_atomic(header_virt, KM_USER0);
flush_dcache_page(header_page);
rc = lower_a_ops->commit_write(lower_file, header_page, 0, 8);
if (rc < 0)
ecryptfs_printk(KERN_ERR, "Error commiting header page "
"write\n");
if (rc == AOP_TRUNCATED_PAGE) {
ecryptfs_release_lower_page(header_page, 0);
goto retry;
} else
ecryptfs_release_lower_page(header_page, 1);
lower_inode->i_mtime = lower_inode->i_ctime = CURRENT_TIME;
mark_inode_dirty_sync(inode);
out:
return rc;
}
static int ecryptfs_write_inode_size_to_xattr(struct inode *lower_inode,
struct inode *inode,
struct dentry *ecryptfs_dentry,
int lower_i_mutex_held)
{
ssize_t size;
void *xattr_virt;
struct dentry *lower_dentry;
u64 file_size;
int rc;
xattr_virt = kmem_cache_alloc(ecryptfs_xattr_cache, GFP_KERNEL);
if (!xattr_virt) {
printk(KERN_ERR "Out of memory whilst attempting to write "
"inode size to xattr\n");
rc = -ENOMEM;
goto out;
}
lower_dentry = ecryptfs_dentry_to_lower(ecryptfs_dentry);
if (!lower_dentry->d_inode->i_op->getxattr ||
!lower_dentry->d_inode->i_op->setxattr) {
printk(KERN_WARNING
"No support for setting xattr in lower filesystem\n");
rc = -ENOSYS;
kmem_cache_free(ecryptfs_xattr_cache, xattr_virt);
goto out;
}
if (!lower_i_mutex_held)
mutex_lock(&lower_dentry->d_inode->i_mutex);
size = lower_dentry->d_inode->i_op->getxattr(lower_dentry,
ECRYPTFS_XATTR_NAME,
xattr_virt,
PAGE_CACHE_SIZE);
if (!lower_i_mutex_held)
mutex_unlock(&lower_dentry->d_inode->i_mutex);
if (size < 0)
size = 8;
file_size = (u64)i_size_read(inode);
file_size = cpu_to_be64(file_size);
memcpy(xattr_virt, &file_size, sizeof(u64));
if (!lower_i_mutex_held)
mutex_lock(&lower_dentry->d_inode->i_mutex);
rc = lower_dentry->d_inode->i_op->setxattr(lower_dentry,
ECRYPTFS_XATTR_NAME,
xattr_virt, size, 0);
if (!lower_i_mutex_held)
mutex_unlock(&lower_dentry->d_inode->i_mutex);
if (rc)
printk(KERN_ERR "Error whilst attempting to write inode size "
"to lower file xattr; rc = [%d]\n", rc);
kmem_cache_free(ecryptfs_xattr_cache, xattr_virt);
out:
return rc;
}
int
ecryptfs_write_inode_size_to_metadata(struct file *lower_file,
struct inode *lower_inode,
struct inode *inode,
struct dentry *ecryptfs_dentry,
int lower_i_mutex_held)
{
struct ecryptfs_crypt_stat *crypt_stat;
crypt_stat = &ecryptfs_inode_to_private(inode)->crypt_stat;
if (crypt_stat->flags & ECRYPTFS_METADATA_IN_XATTR)
return ecryptfs_write_inode_size_to_xattr(lower_inode, inode,
ecryptfs_dentry,
lower_i_mutex_held);
else
return ecryptfs_write_inode_size_to_header(lower_file,
lower_inode,
inode);
}
int ecryptfs_get_lower_page(struct page **lower_page, struct inode *lower_inode,
struct file *lower_file,
unsigned long lower_page_index, int byte_offset,
int region_bytes)
{
int rc = 0;
retry:
*lower_page = grab_cache_page(lower_inode->i_mapping, lower_page_index);
if (!(*lower_page)) {
rc = -EINVAL;
ecryptfs_printk(KERN_ERR, "Error attempting to grab "
"lower page with index [0x%.16x]\n",
lower_page_index);
goto out;
}
rc = lower_inode->i_mapping->a_ops->prepare_write(lower_file,
(*lower_page),
byte_offset,
region_bytes);
if (rc) {
if (rc == AOP_TRUNCATED_PAGE) {
ecryptfs_release_lower_page(*lower_page, 0);
goto retry;
} else {
ecryptfs_printk(KERN_ERR, "prepare_write for "
"lower_page_index = [0x%.16x] failed; rc = "
"[%d]\n", lower_page_index, rc);
ecryptfs_release_lower_page(*lower_page, 1);
(*lower_page) = NULL;
}
}
out:
return rc;
}
/**
* ecryptfs_commit_lower_page
*
* Returns zero on success; non-zero on error
*/
int
ecryptfs_commit_lower_page(struct page *lower_page, struct inode *lower_inode,
struct file *lower_file, int byte_offset,
int region_size)
{
int page_locked = 1;
int rc = 0;
rc = lower_inode->i_mapping->a_ops->commit_write(
lower_file, lower_page, byte_offset, region_size);
if (rc == AOP_TRUNCATED_PAGE)
page_locked = 0;
if (rc < 0) {
ecryptfs_printk(KERN_ERR,
"Error committing write; rc = [%d]\n", rc);
} else
rc = 0;
ecryptfs_release_lower_page(lower_page, page_locked);
return rc;
}
/**
* ecryptfs_copy_page_to_lower
*
* Used for plaintext pass-through; no page index interpolation
* required.
*/
int ecryptfs_copy_page_to_lower(struct page *page, struct inode *lower_inode,
struct file *lower_file)
{
int rc = 0;
struct page *lower_page;
rc = ecryptfs_get_lower_page(&lower_page, lower_inode, lower_file,
page->index, 0, PAGE_CACHE_SIZE);
if (rc) {
ecryptfs_printk(KERN_ERR, "Error attempting to get page "
"at index [0x%.16x]\n", page->index);
goto out;
}
/* TODO: aops */
memcpy((char *)page_address(lower_page), page_address(page),
PAGE_CACHE_SIZE);
rc = ecryptfs_commit_lower_page(lower_page, lower_inode, lower_file,
0, PAGE_CACHE_SIZE);
if (rc)
ecryptfs_printk(KERN_ERR, "Error attempting to commit page "
"at index [0x%.16x]\n", page->index);
out:
return rc;
}
struct kmem_cache *ecryptfs_xattr_cache;
/**
* ecryptfs_commit_write
* @file: The eCryptfs file object
* @page: The eCryptfs page
* @from: Ignored (we rotate the page IV on each write)
* @to: Ignored
*
* This is where we encrypt the data and pass the encrypted data to
* the lower filesystem. In OpenPGP-compatible mode, we operate on
* entire underlying packets.
*/
static int ecryptfs_commit_write(struct file *file, struct page *page,
unsigned from, unsigned to)
{
struct ecryptfs_page_crypt_context ctx;
loff_t pos;
struct inode *inode;
struct inode *lower_inode;
struct file *lower_file;
struct ecryptfs_crypt_stat *crypt_stat;
int rc;
inode = page->mapping->host;
lower_inode = ecryptfs_inode_to_lower(inode);
lower_file = ecryptfs_file_to_lower(file);
mutex_lock(&lower_inode->i_mutex);
crypt_stat = &ecryptfs_inode_to_private(file->f_path.dentry->d_inode)
->crypt_stat;
if (crypt_stat->flags & ECRYPTFS_NEW_FILE) {
ecryptfs_printk(KERN_DEBUG, "ECRYPTFS_NEW_FILE flag set in "
"crypt_stat at memory location [%p]\n", crypt_stat);
crypt_stat->flags &= ~(ECRYPTFS_NEW_FILE);
} else
ecryptfs_printk(KERN_DEBUG, "Not a new file\n");
ecryptfs_printk(KERN_DEBUG, "Calling fill_zeros_to_end_of_page"
"(page w/ index = [0x%.16x], to = [%d])\n", page->index,
to);
rc = fill_zeros_to_end_of_page(page, to);
if (rc) {
ecryptfs_printk(KERN_WARNING, "Error attempting to fill "
"zeros in page with index = [0x%.16x]\n",
page->index);
goto out;
}
ctx.page = page;
ctx.mode = ECRYPTFS_PREPARE_COMMIT_MODE;
ctx.param.lower_file = lower_file;
rc = ecryptfs_encrypt_page(&ctx);
if (rc) {
ecryptfs_printk(KERN_WARNING, "Error encrypting page (upper "
"index [0x%.16x])\n", page->index);
goto out;
}
inode->i_blocks = lower_inode->i_blocks;
pos = (page->index << PAGE_CACHE_SHIFT) + to;
if (pos > i_size_read(inode)) {
i_size_write(inode, pos);
ecryptfs_printk(KERN_DEBUG, "Expanded file size to "
"[0x%.16x]\n", i_size_read(inode));
}
rc = ecryptfs_write_inode_size_to_metadata(lower_file, lower_inode,
inode, file->f_dentry,
ECRYPTFS_LOWER_I_MUTEX_HELD);
if (rc)
printk(KERN_ERR "Error writing inode size to metadata; "
"rc = [%d]\n", rc);
lower_inode->i_mtime = lower_inode->i_ctime = CURRENT_TIME;
mark_inode_dirty_sync(inode);
out:
if (rc < 0)
ClearPageUptodate(page);
else
SetPageUptodate(page);
mutex_unlock(&lower_inode->i_mutex);
return rc;
}
/**
* write_zeros
* @file: The ecryptfs file
* @index: The index in which we are writing
* @start: The position after the last block of data
* @num_zeros: The number of zeros to write
*
* Write a specified number of zero's to a page.
*
* (start + num_zeros) must be less than or equal to PAGE_CACHE_SIZE
*/
static
int write_zeros(struct file *file, pgoff_t index, int start, int num_zeros)
{
int rc = 0;
struct page *tmp_page;
char *tmp_page_virt;
tmp_page = ecryptfs_get1page(file, index);
if (IS_ERR(tmp_page)) {
ecryptfs_printk(KERN_ERR, "Error getting page at index "
"[0x%.16x]\n", index);
rc = PTR_ERR(tmp_page);
goto out;
}
rc = ecryptfs_prepare_write(file, tmp_page, start, start + num_zeros);
if (rc) {
ecryptfs_printk(KERN_ERR, "Error preparing to write zero's "
"to remainder of page at index [0x%.16x]\n",
index);
page_cache_release(tmp_page);
goto out;
}
tmp_page_virt = kmap_atomic(tmp_page, KM_USER0);
memset(((char *)tmp_page_virt + start), 0, num_zeros);
kunmap_atomic(tmp_page_virt, KM_USER0);
flush_dcache_page(tmp_page);
rc = ecryptfs_commit_write(file, tmp_page, start, start + num_zeros);
if (rc < 0) {
ecryptfs_printk(KERN_ERR, "Error attempting to write zero's "
"to remainder of page at index [0x%.16x]\n",
index);
page_cache_release(tmp_page);
goto out;
}
rc = 0;
page_cache_release(tmp_page);
out:
return rc;
}
static sector_t ecryptfs_bmap(struct address_space *mapping, sector_t block)
{
int rc = 0;
struct inode *inode;
struct inode *lower_inode;
inode = (struct inode *)mapping->host;
lower_inode = ecryptfs_inode_to_lower(inode);
if (lower_inode->i_mapping->a_ops->bmap)
rc = lower_inode->i_mapping->a_ops->bmap(lower_inode->i_mapping,
block);
return rc;
}
static void ecryptfs_sync_page(struct page *page)
{
struct inode *inode;
struct inode *lower_inode;
struct page *lower_page;
inode = page->mapping->host;
lower_inode = ecryptfs_inode_to_lower(inode);
/* NOTE: Recently swapped with grab_cache_page(), since
* sync_page() just makes sure that pending I/O gets done. */
lower_page = find_lock_page(lower_inode->i_mapping, page->index);
if (!lower_page) {
ecryptfs_printk(KERN_DEBUG, "find_lock_page failed\n");
return;
}
lower_page->mapping->a_ops->sync_page(lower_page);
ecryptfs_printk(KERN_DEBUG, "Unlocking page with index = [0x%.16x]\n",
lower_page->index);
unlock_page(lower_page);
page_cache_release(lower_page);
}
struct address_space_operations ecryptfs_aops = {
.writepage = ecryptfs_writepage,
.readpage = ecryptfs_readpage,
.prepare_write = ecryptfs_prepare_write,
.commit_write = ecryptfs_commit_write,
.bmap = ecryptfs_bmap,
.sync_page = ecryptfs_sync_page,
};

255
fs/ecryptfs/netlink.c Normal file
View File

@@ -0,0 +1,255 @@
/**
* eCryptfs: Linux filesystem encryption layer
*
* Copyright (C) 2004-2006 International Business Machines Corp.
* Author(s): Michael A. Halcrow <mhalcrow@us.ibm.com>
* Tyler Hicks <tyhicks@ou.edu>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version
* 2 as published by the Free Software Foundation.
*
* 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 <net/sock.h>
#include <linux/hash.h>
#include <linux/random.h>
#include "ecryptfs_kernel.h"
static struct sock *ecryptfs_nl_sock;
/**
* ecryptfs_send_netlink
* @data: The data to include as the payload
* @data_len: The byte count of the data
* @msg_ctx: The netlink context that will be used to handle the
* response message
* @msg_type: The type of netlink message to send
* @msg_flags: The flags to include in the netlink header
* @daemon_pid: The process id of the daemon to send the message to
*
* Sends the data to the specified daemon pid and uses the netlink
* context element to store the data needed for validation upon
* receiving the response. The data and the netlink context can be
* null if just sending a netlink header is sufficient. Returns zero
* upon sending the message; non-zero upon error.
*/
int ecryptfs_send_netlink(char *data, int data_len,
struct ecryptfs_msg_ctx *msg_ctx, u16 msg_type,
u16 msg_flags, pid_t daemon_pid)
{
struct sk_buff *skb;
struct nlmsghdr *nlh;
struct ecryptfs_message *msg;
size_t payload_len;
int rc;
payload_len = ((data && data_len) ? (sizeof(*msg) + data_len) : 0);
skb = alloc_skb(NLMSG_SPACE(payload_len), GFP_KERNEL);
if (!skb) {
rc = -ENOMEM;
ecryptfs_printk(KERN_ERR, "Failed to allocate socket buffer\n");
goto out;
}
nlh = NLMSG_PUT(skb, daemon_pid, msg_ctx ? msg_ctx->counter : 0,
msg_type, payload_len);
nlh->nlmsg_flags = msg_flags;
if (msg_ctx && payload_len) {
msg = (struct ecryptfs_message *)NLMSG_DATA(nlh);
msg->index = msg_ctx->index;
msg->data_len = data_len;
memcpy(msg->data, data, data_len);
}
rc = netlink_unicast(ecryptfs_nl_sock, skb, daemon_pid, 0);
if (rc < 0) {
ecryptfs_printk(KERN_ERR, "Failed to send eCryptfs netlink "
"message; rc = [%d]\n", rc);
goto out;
}
rc = 0;
goto out;
nlmsg_failure:
rc = -EMSGSIZE;
kfree_skb(skb);
out:
return rc;
}
/**
* ecryptfs_process_nl_reponse
* @skb: The socket buffer containing the netlink message of state
* RESPONSE
*
* Processes a response message after sending a operation request to
* userspace. Attempts to assign the msg to a netlink context element
* at the index specified in the msg. The sk_buff and nlmsghdr must
* be validated before this function. Returns zero upon delivery to
* desired context element; non-zero upon delivery failure or error.
*/
static int ecryptfs_process_nl_response(struct sk_buff *skb)
{
struct nlmsghdr *nlh = (struct nlmsghdr*)skb->data;
struct ecryptfs_message *msg = NLMSG_DATA(nlh);
int rc;
if (skb->len - NLMSG_HDRLEN - sizeof(*msg) != msg->data_len) {
rc = -EINVAL;
ecryptfs_printk(KERN_ERR, "Received netlink message with "
"incorrectly specified data length\n");
goto out;
}
rc = ecryptfs_process_response(msg, NETLINK_CREDS(skb)->uid,
NETLINK_CREDS(skb)->pid, nlh->nlmsg_seq);
if (rc)
printk(KERN_ERR
"Error processing response message; rc = [%d]\n", rc);
out:
return rc;
}
/**
* ecryptfs_process_nl_helo
* @skb: The socket buffer containing the nlmsghdr in HELO state
*
* Gets uid and pid of the skb and adds the values to the daemon id
* hash. Returns zero after adding a new daemon id to the hash list;
* non-zero otherwise.
*/
static int ecryptfs_process_nl_helo(struct sk_buff *skb)
{
int rc;
rc = ecryptfs_process_helo(ECRYPTFS_TRANSPORT_NETLINK,
NETLINK_CREDS(skb)->uid,
NETLINK_CREDS(skb)->pid);
if (rc)
printk(KERN_WARNING "Error processing HELO; rc = [%d]\n", rc);
return rc;
}
/**
* ecryptfs_process_nl_quit
* @skb: The socket buffer containing the nlmsghdr in QUIT state
*
* Gets uid and pid of the skb and deletes the corresponding daemon
* id, if it is the registered that is requesting the
* deletion. Returns zero after deleting the desired daemon id;
* non-zero otherwise.
*/
static int ecryptfs_process_nl_quit(struct sk_buff *skb)
{
int rc;
rc = ecryptfs_process_quit(NETLINK_CREDS(skb)->uid,
NETLINK_CREDS(skb)->pid);
if (rc)
printk(KERN_WARNING
"Error processing QUIT message; rc = [%d]\n", rc);
return rc;
}
/**
* ecryptfs_receive_nl_message
*
* Callback function called by netlink system when a message arrives.
* If the message looks to be valid, then an attempt is made to assign
* it to its desired netlink context element and wake up the process
* that is waiting for a response.
*/
static void ecryptfs_receive_nl_message(struct sock *sk, int len)
{
struct sk_buff *skb;
struct nlmsghdr *nlh;
int rc = 0; /* skb_recv_datagram requires this */
receive:
skb = skb_recv_datagram(sk, 0, 0, &rc);
if (rc == -EINTR)
goto receive;
else if (rc < 0) {
ecryptfs_printk(KERN_ERR, "Error occurred while "
"receiving eCryptfs netlink message; "
"rc = [%d]\n", rc);
return;
}
nlh = (struct nlmsghdr *)skb->data;
if (!NLMSG_OK(nlh, skb->len)) {
ecryptfs_printk(KERN_ERR, "Received corrupt netlink "
"message\n");
goto free;
}
switch (nlh->nlmsg_type) {
case ECRYPTFS_NLMSG_RESPONSE:
if (ecryptfs_process_nl_response(skb)) {
ecryptfs_printk(KERN_WARNING, "Failed to "
"deliver netlink response to "
"requesting operation\n");
}
break;
case ECRYPTFS_NLMSG_HELO:
if (ecryptfs_process_nl_helo(skb)) {
ecryptfs_printk(KERN_WARNING, "Failed to "
"fulfill HELO request\n");
}
break;
case ECRYPTFS_NLMSG_QUIT:
if (ecryptfs_process_nl_quit(skb)) {
ecryptfs_printk(KERN_WARNING, "Failed to "
"fulfill QUIT request\n");
}
break;
default:
ecryptfs_printk(KERN_WARNING, "Dropping netlink "
"message of unrecognized type [%d]\n",
nlh->nlmsg_type);
break;
}
free:
kfree_skb(skb);
}
/**
* ecryptfs_init_netlink
*
* Initializes the daemon id hash list, netlink context array, and
* necessary locks. Returns zero upon success; non-zero upon error.
*/
int ecryptfs_init_netlink(void)
{
int rc;
ecryptfs_nl_sock = netlink_kernel_create(NETLINK_ECRYPTFS, 0,
ecryptfs_receive_nl_message,
THIS_MODULE);
if (!ecryptfs_nl_sock) {
rc = -EIO;
ecryptfs_printk(KERN_ERR, "Failed to create netlink socket\n");
goto out;
}
ecryptfs_nl_sock->sk_sndtimeo = ECRYPTFS_DEFAULT_SEND_TIMEOUT;
rc = 0;
out:
return rc;
}
/**
* ecryptfs_release_netlink
*
* Frees all memory used by the netlink context array and releases the
* netlink socket.
*/
void ecryptfs_release_netlink(void)
{
if (ecryptfs_nl_sock && ecryptfs_nl_sock->sk_socket)
sock_release(ecryptfs_nl_sock->sk_socket);
ecryptfs_nl_sock = NULL;
}

180
fs/ecryptfs/super.c Normal file
View File

@@ -0,0 +1,180 @@
/**
* eCryptfs: Linux filesystem encryption layer
*
* Copyright (C) 1997-2003 Erez Zadok
* Copyright (C) 2001-2003 Stony Brook University
* Copyright (C) 2004-2006 International Business Machines Corp.
* Author(s): Michael A. Halcrow <mahalcro@us.ibm.com>
* Michael C. Thompson <mcthomps@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/fs.h>
#include <linux/mount.h>
#include <linux/key.h>
#include <linux/seq_file.h>
#include <linux/crypto.h>
#include "ecryptfs_kernel.h"
struct kmem_cache *ecryptfs_inode_info_cache;
/**
* ecryptfs_alloc_inode - allocate an ecryptfs inode
* @sb: Pointer to the ecryptfs super block
*
* Called to bring an inode into existence.
*
* Only handle allocation, setting up structures should be done in
* ecryptfs_read_inode. This is because the kernel, between now and
* then, will 0 out the private data pointer.
*
* Returns a pointer to a newly allocated inode, NULL otherwise
*/
static struct inode *ecryptfs_alloc_inode(struct super_block *sb)
{
struct ecryptfs_inode_info *ecryptfs_inode;
struct inode *inode = NULL;
ecryptfs_inode = kmem_cache_alloc(ecryptfs_inode_info_cache,
GFP_KERNEL);
if (unlikely(!ecryptfs_inode))
goto out;
ecryptfs_init_crypt_stat(&ecryptfs_inode->crypt_stat);
inode = &ecryptfs_inode->vfs_inode;
out:
return inode;
}
/**
* ecryptfs_destroy_inode
* @inode: The ecryptfs inode
*
* This is used during the final destruction of the inode.
* All allocation of memory related to the inode, including allocated
* memory in the crypt_stat struct, will be released here.
* There should be no chance that this deallocation will be missed.
*/
static void ecryptfs_destroy_inode(struct inode *inode)
{
struct ecryptfs_inode_info *inode_info;
inode_info = ecryptfs_inode_to_private(inode);
ecryptfs_destruct_crypt_stat(&inode_info->crypt_stat);
kmem_cache_free(ecryptfs_inode_info_cache, inode_info);
}
/**
* ecryptfs_init_inode
* @inode: The ecryptfs inode
*
* Set up the ecryptfs inode.
*/
void ecryptfs_init_inode(struct inode *inode, struct inode *lower_inode)
{
ecryptfs_set_inode_lower(inode, lower_inode);
inode->i_ino = lower_inode->i_ino;
inode->i_version++;
inode->i_op = &ecryptfs_main_iops;
inode->i_fop = &ecryptfs_main_fops;
inode->i_mapping->a_ops = &ecryptfs_aops;
}
/**
* ecryptfs_put_super
* @sb: Pointer to the ecryptfs super block
*
* Final actions when unmounting a file system.
* This will handle deallocation and release of our private data.
*/
static void ecryptfs_put_super(struct super_block *sb)
{
struct ecryptfs_sb_info *sb_info = ecryptfs_superblock_to_private(sb);
ecryptfs_destruct_mount_crypt_stat(&sb_info->mount_crypt_stat);
kmem_cache_free(ecryptfs_sb_info_cache, sb_info);
ecryptfs_set_superblock_private(sb, NULL);
}
/**
* ecryptfs_statfs
* @sb: The ecryptfs super block
* @buf: The struct kstatfs to fill in with stats
*
* Get the filesystem statistics. Currently, we let this pass right through
* to the lower filesystem and take no action ourselves.
*/
static int ecryptfs_statfs(struct dentry *dentry, struct kstatfs *buf)
{
return vfs_statfs(ecryptfs_dentry_to_lower(dentry), buf);
}
/**
* ecryptfs_clear_inode
* @inode - The ecryptfs inode
*
* Called by iput() when the inode reference count reached zero
* and the inode is not hashed anywhere. Used to clear anything
* that needs to be, before the inode is completely destroyed and put
* on the inode free list. We use this to drop out reference to the
* lower inode.
*/
static void ecryptfs_clear_inode(struct inode *inode)
{
iput(ecryptfs_inode_to_lower(inode));
}
/**
* ecryptfs_show_options
*
* Prints the directory we are currently mounted over.
* Returns zero on success; non-zero otherwise
*/
static int ecryptfs_show_options(struct seq_file *m, struct vfsmount *mnt)
{
struct super_block *sb = mnt->mnt_sb;
struct dentry *lower_root_dentry = ecryptfs_dentry_to_lower(sb->s_root);
struct vfsmount *lower_mnt = ecryptfs_dentry_to_lower_mnt(sb->s_root);
char *tmp_page;
char *path;
int rc = 0;
tmp_page = (char *)__get_free_page(GFP_KERNEL);
if (!tmp_page) {
rc = -ENOMEM;
goto out;
}
path = d_path(lower_root_dentry, lower_mnt, tmp_page, PAGE_SIZE);
if (IS_ERR(path)) {
rc = PTR_ERR(path);
goto out;
}
seq_printf(m, ",dir=%s", path);
free_page((unsigned long)tmp_page);
out:
return rc;
}
const struct super_operations ecryptfs_sops = {
.alloc_inode = ecryptfs_alloc_inode,
.destroy_inode = ecryptfs_destroy_inode,
.drop_inode = generic_delete_inode,
.put_super = ecryptfs_put_super,
.statfs = ecryptfs_statfs,
.remount_fs = NULL,
.clear_inode = ecryptfs_clear_inode,
.show_options = ecryptfs_show_options
};