diff mbox

[01/10] fs crypto: add basic definitions for per-file encryption

Message ID 1456428368-41527-2-git-send-email-jaegeuk@kernel.org (mailing list archive)
State New, archived
Headers show

Commit Message

Jaegeuk Kim Feb. 25, 2016, 7:25 p.m. UTC
This patch adds definitions for per-file encryption used by ext4 and f2fs.

Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
---
 include/linux/fs.h       |   8 ++
 include/linux/fscrypto.h | 239 +++++++++++++++++++++++++++++++++++++++++++++++
 include/uapi/linux/fs.h  |  18 ++++
 3 files changed, 265 insertions(+)
 create mode 100644 include/linux/fscrypto.h

Comments

Randy Dunlap Feb. 29, 2016, 5:41 a.m. UTC | #1
On 02/25/16 11:25, Jaegeuk Kim wrote:
> This patch adds definitions for per-file encryption used by ext4 and f2fs.
> 
> Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
> ---
>  include/linux/fs.h       |   8 ++
>  include/linux/fscrypto.h | 239 +++++++++++++++++++++++++++++++++++++++++++++++
>  include/uapi/linux/fs.h  |  18 ++++
>  3 files changed, 265 insertions(+)
>  create mode 100644 include/linux/fscrypto.h
> 
> diff --git a/include/linux/fs.h b/include/linux/fs.h
> index ae68100..d8f57cf 100644
> --- a/include/linux/fs.h
> +++ b/include/linux/fs.h
> @@ -53,6 +53,8 @@ struct swap_info_struct;
>  struct seq_file;
>  struct workqueue_struct;
>  struct iov_iter;
> +struct fscrypt_info;
> +struct fscrypt_operations;
>  
>  extern void __init inode_init(void);
>  extern void __init inode_init_early(void);
> @@ -678,6 +680,10 @@ struct inode {
>  	struct hlist_head	i_fsnotify_marks;
>  #endif
>  
> +#ifdef CONFIG_FS_ENCRYPTION
> +	struct fscrypt_info	*i_crypt_info;
> +#endif
> +
>  	void			*i_private; /* fs or device private pointer */
>  };
>  
> @@ -1323,6 +1329,8 @@ struct super_block {
>  #endif
>  	const struct xattr_handler **s_xattr;
>  
> +	const struct fscrypt_operations	*s_cop;
> +
>  	struct hlist_bl_head	s_anon;		/* anonymous dentries for (nfs) exporting */
>  	struct list_head	s_mounts;	/* list of mounts; _not_ for fs use */
>  	struct block_device	*s_bdev;
> diff --git a/include/linux/fscrypto.h b/include/linux/fscrypto.h
> new file mode 100644
> index 0000000..b0aed92
> --- /dev/null
> +++ b/include/linux/fscrypto.h
> @@ -0,0 +1,239 @@
> +/*
> + * General per-file encryption definition
> + *
> + * Copyright (C) 2015, Google, Inc.
> + *
> + * Written by Michael Halcrow, 2015.
> + * Modified by Jaegeuk Kim, 2015.
> + */
> +
> +#ifndef _LINUX_FSCRYPTO_H
> +#define _LINUX_FSCRYPTO_H
> +
> +#include <linux/key.h>
> +#include <linux/fs.h>
> +#include <linux/mm.h>
> +#include <linux/bio.h>
> +#include <linux/dcache.h>
> +#include <uapi/linux/fs.h>
> +
> +#define FS_KEY_DERIVATION_NONCE_SIZE		16
> +#define FS_ENCRYPTION_CONTEXT_FORMAT_V1		1
> +
> +#define FS_POLICY_FLAGS_PAD_4		0x00
> +#define FS_POLICY_FLAGS_PAD_8		0x01
> +#define FS_POLICY_FLAGS_PAD_16		0x02
> +#define FS_POLICY_FLAGS_PAD_32		0x03
> +#define FS_POLICY_FLAGS_PAD_MASK	0x03
> +#define FS_POLICY_FLAGS_VALID		0x03
> +
> +/* Encryption algorithms */
> +#define FS_ENCRYPTION_MODE_INVALID		0
> +#define FS_ENCRYPTION_MODE_AES_256_XTS		1
> +#define FS_ENCRYPTION_MODE_AES_256_GCM		2
> +#define FS_ENCRYPTION_MODE_AES_256_CBC		3
> +#define FS_ENCRYPTION_MODE_AES_256_CTS		4
> +
> +/**
> + * Encryption context for inode
> + *
> + * Protector format:
> + *  1 byte: Protector format (1 = this version)
> + *  1 byte: File contents encryption mode
> + *  1 byte: File names encryption mode
> + *  1 byte: Flags
> + *  8 bytes: Master Key descriptor
> + *  16 bytes: Encryption Key derivation nonce
> + */
> +struct fscrypt_context {
> +	char format;
> +	char contents_encryption_mode;
> +	char filenames_encryption_mode;
> +	char flags;
> +	char master_key_descriptor[FS_KEY_DESCRIPTOR_SIZE];
> +	char nonce[FS_KEY_DERIVATION_NONCE_SIZE];

how about u8 instead of char?

> +} __packed;
> +
> +/* Encryption parameters */
> +#define FS_XTS_TWEAK_SIZE		16
> +#define FS_AES_128_ECB_KEY_SIZE		16
> +#define FS_AES_256_GCM_KEY_SIZE		32
> +#define FS_AES_256_CBC_KEY_SIZE		32
> +#define FS_AES_256_CTS_KEY_SIZE		32
> +#define FS_AES_256_XTS_KEY_SIZE		64
> +#define FS_MAX_KEY_SIZE			64
> +
> +#define FS_KEY_DESC_PREFIX		"fscrypt:"
> +#define FS_KEY_DESC_PREFIX_SIZE		8
> +
> +/* This is passed in from userspace into the kernel keyring */
> +struct fscrypt_key {
> +	__u32 mode;
> +	char raw[FS_MAX_KEY_SIZE];
> +	__u32 size;
> +} __packed;
> +
> +struct fscrypt_info {
> +	char ci_data_mode;
> +	char ci_filename_mode;
> +	char ci_flags;

ditto

> +	struct crypto_ablkcipher *ci_ctfm;
> +	struct key *ci_keyring_key;
> +	char ci_master_key[FS_KEY_DESCRIPTOR_SIZE];
> +};
> +
> +#define FS_CTX_REQUIRES_FREE_ENCRYPT_FL		0x00000001
> +#define FS_WRITE_PATH_FL			0x00000002
> +
> +struct fscrypt_ctx {
> +	union {
> +		struct {
> +			struct page *bounce_page;	/* Ciphertext page */
> +			struct page *control_page;	/* Original page  */
> +		} w;
> +		struct {
> +			struct bio *bio;
> +			struct work_struct work;
> +		} r;
> +		struct list_head free_list;	/* Free list */
> +	};
> +	char flags;				/* Flags */
> +	char mode;				/* Encryption mode for tfm */
> +};
> +
> +struct fscrypt_completion_result {
> +	struct completion completion;
> +	int res;
> +};
> +
> +#define DECLARE_FS_COMPLETION_RESULT(ecr) \
> +	struct fscrypt_completion_result ecr = { \
> +		COMPLETION_INITIALIZER((ecr).completion), 0 }
> +
> +static inline int fscrypt_key_size(int mode)
> +{
> +	switch (mode) {
> +	case FS_ENCRYPTION_MODE_AES_256_XTS:
> +		return FS_AES_256_XTS_KEY_SIZE;
> +	case FS_ENCRYPTION_MODE_AES_256_GCM:
> +		return FS_AES_256_GCM_KEY_SIZE;
> +	case FS_ENCRYPTION_MODE_AES_256_CBC:
> +		return FS_AES_256_CBC_KEY_SIZE;
> +	case FS_ENCRYPTION_MODE_AES_256_CTS:
> +		return FS_AES_256_CTS_KEY_SIZE;
> +	default:
> +		BUG();
> +	}
> +	return 0;
> +}
> +
> +#define FS_FNAME_NUM_SCATTER_ENTRIES	4
> +#define FS_CRYPTO_BLOCK_SIZE		16
> +#define FS_FNAME_CRYPTO_DIGEST_SIZE	32
> +
> +/**
> + * For encrypted symlinks, the ciphertext length is stored at the beginning
> + * of the string in little-endian format.
> + */
> +struct fscrypt_symlink_data {
> +	__le16 len;
> +	char encrypted_path[1];
> +} __packed;
> +
> +/**
> + * This function is used to calculate the disk space required to
> + * store a filename of length l in encrypted symlink format.
> + */
> +static inline u32 fscrypt_symlink_data_len(u32 l)
> +{
> +	if (l < FS_CRYPTO_BLOCK_SIZE)
> +		l = FS_CRYPTO_BLOCK_SIZE;
> +	return (l + sizeof(struct fscrypt_symlink_data) - 1);
> +}
> +
> +struct fscrypt_str {
> +	unsigned char *name;
> +	u32 len;
> +};
> +
> +struct fscrypt_name {
> +	const struct qstr *usr_fname;
> +	struct fscrypt_str disk_name;
> +	u32 hash;
> +	u32 minor_hash;
> +	struct fscrypt_str crypto_buf;
> +};
> +
> +#define FSTR_INIT(n, l)		{ .name = n, .len = l }
> +#define FSTR_TO_QSTR(f)		QSTR_INIT((f)->name, (f)->len)
> +#define fname_name(p)		((p)->disk_name.name)
> +#define fname_len(p)		((p)->disk_name.len)
> +
> +/*
> + * crypto opertions for filesystems
> + */
> +struct fscrypt_operations {
> +	int (*get_context)(struct inode *, void *, size_t);
> +	int (*prepare_context)(struct inode *);
> +	int (*set_context)(struct inode *, const void *, size_t, void *);
> +	int (*dummy_context)(struct inode *);
> +	bool (*is_encrypted)(struct inode *);
> +	bool (*empty_dir)(struct inode *);
> +	unsigned (*max_namelen)(struct inode *);
> +};
> +
> +static inline bool fscrypt_dummy_context_enabled(struct inode *inode)
> +{
> +	if (inode->i_sb->s_cop->dummy_context &&
> +				inode->i_sb->s_cop->dummy_context(inode))
> +		return true;
> +	return false;
> +}
> +
> +static inline bool fscrypt_valid_contents_enc_mode(u32 mode)
> +{
> +	return (mode == FS_ENCRYPTION_MODE_AES_256_XTS);
> +}
> +
> +static inline bool fscrypt_valid_filenames_enc_mode(u32 mode)
> +{
> +	return (mode == FS_ENCRYPTION_MODE_AES_256_CTS);
> +}
> +
> +static inline u32 fscrypt_validate_encryption_key_size(u32 mode, u32 size)
> +{
> +	if (size == fscrypt_key_size(mode))
> +		return size;
> +	return 0;
> +}
> +
> +static inline bool fscrypt_is_dot_dotdot(const struct qstr *str)
> +{
> +	if (str->len == 1 && str->name[0] == '.')
> +		return true;
> +
> +	if (str->len == 2 && str->name[0] == '.' && str->name[1] == '.')
> +		return true;
> +
> +	return false;
> +}
> +
> +static inline struct page *fscrypt_control_page(struct page *page)
> +{
> +#ifdef CONFIG_FS_ENCRYPTION
> +	return ((struct fscrypt_ctx *)page_private(page))->w.control_page;
> +#else
> +	WARN_ON_ONCE(1);
> +	return ERR_PTR(-EINVAL);
> +#endif
> +}
> +
> +static inline int fscrypt_has_encryption_key(struct inode *inode)
> +{
> +#ifdef CONFIG_FS_ENCRYPTION
> +	return (inode->i_crypt_info != NULL);
> +#else
> +	return 0;
> +#endif
> +}
> +#endif	/* _LINUX_FSCRYPTO_H */
> diff --git a/include/uapi/linux/fs.h b/include/uapi/linux/fs.h
> index 149bec8..1d26276 100644
> --- a/include/uapi/linux/fs.h
> +++ b/include/uapi/linux/fs.h
> @@ -247,6 +247,24 @@ struct fsxattr {
>  #define FS_IOC_FSSETXATTR		_IOW ('X', 32, struct fsxattr)
>  
>  /*
> + * File system encryption support
> + */
> +/* Policy provided via an ioctl on the topmost directory */
> +#define FS_KEY_DESCRIPTOR_SIZE	8
> +
> +struct fscrypt_policy {
> +	char version;
> +	char contents_encryption_mode;
> +	char filenames_encryption_mode;
> +	char flags;
> +	char master_key_descriptor[FS_KEY_DESCRIPTOR_SIZE];

ditto

> +} __packed;
> +
> +#define FS_IOC_SET_ENCRYPTION_POLICY	_IOR('f', 19, struct fscrypt_policy)
> +#define FS_IOC_GET_ENCRYPTION_PWSALT	_IOW('f', 20, __u8[16])
> +#define FS_IOC_GET_ENCRYPTION_POLICY	_IOW('f', 21, struct fscrypt_policy)
> +
> +/*
>   * Inode flags (FS_IOC_GETFLAGS / FS_IOC_SETFLAGS)
>   *
>   * Note: for historical reasons, these flags were originally used and
>
Jaegeuk Kim March 1, 2016, 1:35 a.m. UTC | #2
On Sun, Feb 28, 2016 at 09:41:22PM -0800, Randy Dunlap wrote:
> On 02/25/16 11:25, Jaegeuk Kim wrote:
> > This patch adds definitions for per-file encryption used by ext4 and f2fs.
> > 
> > Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
> > ---
> >  include/linux/fs.h       |   8 ++
> >  include/linux/fscrypto.h | 239 +++++++++++++++++++++++++++++++++++++++++++++++
> >  include/uapi/linux/fs.h  |  18 ++++
> >  3 files changed, 265 insertions(+)
> >  create mode 100644 include/linux/fscrypto.h
> > 
> > diff --git a/include/linux/fs.h b/include/linux/fs.h
> > index ae68100..d8f57cf 100644
> > --- a/include/linux/fs.h
> > +++ b/include/linux/fs.h
> > @@ -53,6 +53,8 @@ struct swap_info_struct;
> >  struct seq_file;
> >  struct workqueue_struct;
> >  struct iov_iter;
> > +struct fscrypt_info;
> > +struct fscrypt_operations;
> >  
> >  extern void __init inode_init(void);
> >  extern void __init inode_init_early(void);
> > @@ -678,6 +680,10 @@ struct inode {
> >  	struct hlist_head	i_fsnotify_marks;
> >  #endif
> >  
> > +#ifdef CONFIG_FS_ENCRYPTION
> > +	struct fscrypt_info	*i_crypt_info;
> > +#endif
> > +
> >  	void			*i_private; /* fs or device private pointer */
> >  };
> >  
> > @@ -1323,6 +1329,8 @@ struct super_block {
> >  #endif
> >  	const struct xattr_handler **s_xattr;
> >  
> > +	const struct fscrypt_operations	*s_cop;
> > +
> >  	struct hlist_bl_head	s_anon;		/* anonymous dentries for (nfs) exporting */
> >  	struct list_head	s_mounts;	/* list of mounts; _not_ for fs use */
> >  	struct block_device	*s_bdev;
> > diff --git a/include/linux/fscrypto.h b/include/linux/fscrypto.h
> > new file mode 100644
> > index 0000000..b0aed92
> > --- /dev/null
> > +++ b/include/linux/fscrypto.h
> > @@ -0,0 +1,239 @@
> > +/*
> > + * General per-file encryption definition
> > + *
> > + * Copyright (C) 2015, Google, Inc.
> > + *
> > + * Written by Michael Halcrow, 2015.
> > + * Modified by Jaegeuk Kim, 2015.
> > + */
> > +
> > +#ifndef _LINUX_FSCRYPTO_H
> > +#define _LINUX_FSCRYPTO_H
> > +
> > +#include <linux/key.h>
> > +#include <linux/fs.h>
> > +#include <linux/mm.h>
> > +#include <linux/bio.h>
> > +#include <linux/dcache.h>
> > +#include <uapi/linux/fs.h>
> > +
> > +#define FS_KEY_DERIVATION_NONCE_SIZE		16
> > +#define FS_ENCRYPTION_CONTEXT_FORMAT_V1		1
> > +
> > +#define FS_POLICY_FLAGS_PAD_4		0x00
> > +#define FS_POLICY_FLAGS_PAD_8		0x01
> > +#define FS_POLICY_FLAGS_PAD_16		0x02
> > +#define FS_POLICY_FLAGS_PAD_32		0x03
> > +#define FS_POLICY_FLAGS_PAD_MASK	0x03
> > +#define FS_POLICY_FLAGS_VALID		0x03
> > +
> > +/* Encryption algorithms */
> > +#define FS_ENCRYPTION_MODE_INVALID		0
> > +#define FS_ENCRYPTION_MODE_AES_256_XTS		1
> > +#define FS_ENCRYPTION_MODE_AES_256_GCM		2
> > +#define FS_ENCRYPTION_MODE_AES_256_CBC		3
> > +#define FS_ENCRYPTION_MODE_AES_256_CTS		4
> > +
> > +/**
> > + * Encryption context for inode
> > + *
> > + * Protector format:
> > + *  1 byte: Protector format (1 = this version)
> > + *  1 byte: File contents encryption mode
> > + *  1 byte: File names encryption mode
> > + *  1 byte: Flags
> > + *  8 bytes: Master Key descriptor
> > + *  16 bytes: Encryption Key derivation nonce
> > + */
> > +struct fscrypt_context {
> > +	char format;
> > +	char contents_encryption_mode;
> > +	char filenames_encryption_mode;
> > +	char flags;
> > +	char master_key_descriptor[FS_KEY_DESCRIPTOR_SIZE];
> > +	char nonce[FS_KEY_DERIVATION_NONCE_SIZE];
> 
> how about u8 instead of char?

It seems that it needs to user u8 instead of char for other variables as well.
I'll take a look at all the usages.

Thanks,

> 
> > +} __packed;
> > +
> > +/* Encryption parameters */
> > +#define FS_XTS_TWEAK_SIZE		16
> > +#define FS_AES_128_ECB_KEY_SIZE		16
> > +#define FS_AES_256_GCM_KEY_SIZE		32
> > +#define FS_AES_256_CBC_KEY_SIZE		32
> > +#define FS_AES_256_CTS_KEY_SIZE		32
> > +#define FS_AES_256_XTS_KEY_SIZE		64
> > +#define FS_MAX_KEY_SIZE			64
> > +
> > +#define FS_KEY_DESC_PREFIX		"fscrypt:"
> > +#define FS_KEY_DESC_PREFIX_SIZE		8
> > +
> > +/* This is passed in from userspace into the kernel keyring */
> > +struct fscrypt_key {
> > +	__u32 mode;
> > +	char raw[FS_MAX_KEY_SIZE];
> > +	__u32 size;
> > +} __packed;
> > +
> > +struct fscrypt_info {
> > +	char ci_data_mode;
> > +	char ci_filename_mode;
> > +	char ci_flags;
> 
> ditto
> 
> > +	struct crypto_ablkcipher *ci_ctfm;
> > +	struct key *ci_keyring_key;
> > +	char ci_master_key[FS_KEY_DESCRIPTOR_SIZE];
> > +};
> > +
> > +#define FS_CTX_REQUIRES_FREE_ENCRYPT_FL		0x00000001
> > +#define FS_WRITE_PATH_FL			0x00000002
> > +
> > +struct fscrypt_ctx {
> > +	union {
> > +		struct {
> > +			struct page *bounce_page;	/* Ciphertext page */
> > +			struct page *control_page;	/* Original page  */
> > +		} w;
> > +		struct {
> > +			struct bio *bio;
> > +			struct work_struct work;
> > +		} r;
> > +		struct list_head free_list;	/* Free list */
> > +	};
> > +	char flags;				/* Flags */
> > +	char mode;				/* Encryption mode for tfm */
> > +};
> > +
> > +struct fscrypt_completion_result {
> > +	struct completion completion;
> > +	int res;
> > +};
> > +
> > +#define DECLARE_FS_COMPLETION_RESULT(ecr) \
> > +	struct fscrypt_completion_result ecr = { \
> > +		COMPLETION_INITIALIZER((ecr).completion), 0 }
> > +
> > +static inline int fscrypt_key_size(int mode)
> > +{
> > +	switch (mode) {
> > +	case FS_ENCRYPTION_MODE_AES_256_XTS:
> > +		return FS_AES_256_XTS_KEY_SIZE;
> > +	case FS_ENCRYPTION_MODE_AES_256_GCM:
> > +		return FS_AES_256_GCM_KEY_SIZE;
> > +	case FS_ENCRYPTION_MODE_AES_256_CBC:
> > +		return FS_AES_256_CBC_KEY_SIZE;
> > +	case FS_ENCRYPTION_MODE_AES_256_CTS:
> > +		return FS_AES_256_CTS_KEY_SIZE;
> > +	default:
> > +		BUG();
> > +	}
> > +	return 0;
> > +}
> > +
> > +#define FS_FNAME_NUM_SCATTER_ENTRIES	4
> > +#define FS_CRYPTO_BLOCK_SIZE		16
> > +#define FS_FNAME_CRYPTO_DIGEST_SIZE	32
> > +
> > +/**
> > + * For encrypted symlinks, the ciphertext length is stored at the beginning
> > + * of the string in little-endian format.
> > + */
> > +struct fscrypt_symlink_data {
> > +	__le16 len;
> > +	char encrypted_path[1];
> > +} __packed;
> > +
> > +/**
> > + * This function is used to calculate the disk space required to
> > + * store a filename of length l in encrypted symlink format.
> > + */
> > +static inline u32 fscrypt_symlink_data_len(u32 l)
> > +{
> > +	if (l < FS_CRYPTO_BLOCK_SIZE)
> > +		l = FS_CRYPTO_BLOCK_SIZE;
> > +	return (l + sizeof(struct fscrypt_symlink_data) - 1);
> > +}
> > +
> > +struct fscrypt_str {
> > +	unsigned char *name;
> > +	u32 len;
> > +};
> > +
> > +struct fscrypt_name {
> > +	const struct qstr *usr_fname;
> > +	struct fscrypt_str disk_name;
> > +	u32 hash;
> > +	u32 minor_hash;
> > +	struct fscrypt_str crypto_buf;
> > +};
> > +
> > +#define FSTR_INIT(n, l)		{ .name = n, .len = l }
> > +#define FSTR_TO_QSTR(f)		QSTR_INIT((f)->name, (f)->len)
> > +#define fname_name(p)		((p)->disk_name.name)
> > +#define fname_len(p)		((p)->disk_name.len)
> > +
> > +/*
> > + * crypto opertions for filesystems
> > + */
> > +struct fscrypt_operations {
> > +	int (*get_context)(struct inode *, void *, size_t);
> > +	int (*prepare_context)(struct inode *);
> > +	int (*set_context)(struct inode *, const void *, size_t, void *);
> > +	int (*dummy_context)(struct inode *);
> > +	bool (*is_encrypted)(struct inode *);
> > +	bool (*empty_dir)(struct inode *);
> > +	unsigned (*max_namelen)(struct inode *);
> > +};
> > +
> > +static inline bool fscrypt_dummy_context_enabled(struct inode *inode)
> > +{
> > +	if (inode->i_sb->s_cop->dummy_context &&
> > +				inode->i_sb->s_cop->dummy_context(inode))
> > +		return true;
> > +	return false;
> > +}
> > +
> > +static inline bool fscrypt_valid_contents_enc_mode(u32 mode)
> > +{
> > +	return (mode == FS_ENCRYPTION_MODE_AES_256_XTS);
> > +}
> > +
> > +static inline bool fscrypt_valid_filenames_enc_mode(u32 mode)
> > +{
> > +	return (mode == FS_ENCRYPTION_MODE_AES_256_CTS);
> > +}
> > +
> > +static inline u32 fscrypt_validate_encryption_key_size(u32 mode, u32 size)
> > +{
> > +	if (size == fscrypt_key_size(mode))
> > +		return size;
> > +	return 0;
> > +}
> > +
> > +static inline bool fscrypt_is_dot_dotdot(const struct qstr *str)
> > +{
> > +	if (str->len == 1 && str->name[0] == '.')
> > +		return true;
> > +
> > +	if (str->len == 2 && str->name[0] == '.' && str->name[1] == '.')
> > +		return true;
> > +
> > +	return false;
> > +}
> > +
> > +static inline struct page *fscrypt_control_page(struct page *page)
> > +{
> > +#ifdef CONFIG_FS_ENCRYPTION
> > +	return ((struct fscrypt_ctx *)page_private(page))->w.control_page;
> > +#else
> > +	WARN_ON_ONCE(1);
> > +	return ERR_PTR(-EINVAL);
> > +#endif
> > +}
> > +
> > +static inline int fscrypt_has_encryption_key(struct inode *inode)
> > +{
> > +#ifdef CONFIG_FS_ENCRYPTION
> > +	return (inode->i_crypt_info != NULL);
> > +#else
> > +	return 0;
> > +#endif
> > +}
> > +#endif	/* _LINUX_FSCRYPTO_H */
> > diff --git a/include/uapi/linux/fs.h b/include/uapi/linux/fs.h
> > index 149bec8..1d26276 100644
> > --- a/include/uapi/linux/fs.h
> > +++ b/include/uapi/linux/fs.h
> > @@ -247,6 +247,24 @@ struct fsxattr {
> >  #define FS_IOC_FSSETXATTR		_IOW ('X', 32, struct fsxattr)
> >  
> >  /*
> > + * File system encryption support
> > + */
> > +/* Policy provided via an ioctl on the topmost directory */
> > +#define FS_KEY_DESCRIPTOR_SIZE	8
> > +
> > +struct fscrypt_policy {
> > +	char version;
> > +	char contents_encryption_mode;
> > +	char filenames_encryption_mode;
> > +	char flags;
> > +	char master_key_descriptor[FS_KEY_DESCRIPTOR_SIZE];
> 
> ditto
> 
> > +} __packed;
> > +
> > +#define FS_IOC_SET_ENCRYPTION_POLICY	_IOR('f', 19, struct fscrypt_policy)
> > +#define FS_IOC_GET_ENCRYPTION_PWSALT	_IOW('f', 20, __u8[16])
> > +#define FS_IOC_GET_ENCRYPTION_POLICY	_IOW('f', 21, struct fscrypt_policy)
> > +
> > +/*
> >   * Inode flags (FS_IOC_GETFLAGS / FS_IOC_SETFLAGS)
> >   *
> >   * Note: for historical reasons, these flags were originally used and
> > 
> 
> 
> -- 
> ~Randy
--
To unsubscribe from this list: send the line "unsubscribe linux-fsdevel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Dan Williams March 11, 2016, 5 a.m. UTC | #3
On Mon, Feb 29, 2016 at 5:35 PM, Jaegeuk Kim <jaegeuk@kernel.org> wrote:
> On Sun, Feb 28, 2016 at 09:41:22PM -0800, Randy Dunlap wrote:
>> On 02/25/16 11:25, Jaegeuk Kim wrote:
>> > This patch adds definitions for per-file encryption used by ext4 and f2fs.
>> >
>> > Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
>> > ---
>> >  include/linux/fs.h       |   8 ++
>> >  include/linux/fscrypto.h | 239 +++++++++++++++++++++++++++++++++++++++++++++++
>> >  include/uapi/linux/fs.h  |  18 ++++
>> >  3 files changed, 265 insertions(+)
>> >  create mode 100644 include/linux/fscrypto.h
>> >
>> > diff --git a/include/linux/fs.h b/include/linux/fs.h
>> > index ae68100..d8f57cf 100644
>> > --- a/include/linux/fs.h
>> > +++ b/include/linux/fs.h
>> > @@ -53,6 +53,8 @@ struct swap_info_struct;
>> >  struct seq_file;
>> >  struct workqueue_struct;
>> >  struct iov_iter;
>> > +struct fscrypt_info;
>> > +struct fscrypt_operations;
>> >
>> >  extern void __init inode_init(void);
>> >  extern void __init inode_init_early(void);
>> > @@ -678,6 +680,10 @@ struct inode {
>> >     struct hlist_head       i_fsnotify_marks;
>> >  #endif
>> >
>> > +#ifdef CONFIG_FS_ENCRYPTION
>> > +   struct fscrypt_info     *i_crypt_info;
>> > +#endif
>> > +
>> >     void                    *i_private; /* fs or device private pointer */
>> >  };
>> >
>> > @@ -1323,6 +1329,8 @@ struct super_block {
>> >  #endif
>> >     const struct xattr_handler **s_xattr;
>> >
>> > +   const struct fscrypt_operations *s_cop;
>> > +
>> >     struct hlist_bl_head    s_anon;         /* anonymous dentries for (nfs) exporting */
>> >     struct list_head        s_mounts;       /* list of mounts; _not_ for fs use */
>> >     struct block_device     *s_bdev;
>> > diff --git a/include/linux/fscrypto.h b/include/linux/fscrypto.h
>> > new file mode 100644
>> > index 0000000..b0aed92
>> > --- /dev/null
>> > +++ b/include/linux/fscrypto.h
>> > @@ -0,0 +1,239 @@
>> > +/*
>> > + * General per-file encryption definition
>> > + *
>> > + * Copyright (C) 2015, Google, Inc.
>> > + *
>> > + * Written by Michael Halcrow, 2015.
>> > + * Modified by Jaegeuk Kim, 2015.
>> > + */
>> > +
>> > +#ifndef _LINUX_FSCRYPTO_H
>> > +#define _LINUX_FSCRYPTO_H
>> > +
>> > +#include <linux/key.h>
>> > +#include <linux/fs.h>
>> > +#include <linux/mm.h>
>> > +#include <linux/bio.h>
>> > +#include <linux/dcache.h>
>> > +#include <uapi/linux/fs.h>
>> > +
>> > +#define FS_KEY_DERIVATION_NONCE_SIZE               16
>> > +#define FS_ENCRYPTION_CONTEXT_FORMAT_V1            1
>> > +
>> > +#define FS_POLICY_FLAGS_PAD_4              0x00
>> > +#define FS_POLICY_FLAGS_PAD_8              0x01
>> > +#define FS_POLICY_FLAGS_PAD_16             0x02
>> > +#define FS_POLICY_FLAGS_PAD_32             0x03
>> > +#define FS_POLICY_FLAGS_PAD_MASK   0x03
>> > +#define FS_POLICY_FLAGS_VALID              0x03
>> > +
>> > +/* Encryption algorithms */
>> > +#define FS_ENCRYPTION_MODE_INVALID         0
>> > +#define FS_ENCRYPTION_MODE_AES_256_XTS             1
>> > +#define FS_ENCRYPTION_MODE_AES_256_GCM             2
>> > +#define FS_ENCRYPTION_MODE_AES_256_CBC             3
>> > +#define FS_ENCRYPTION_MODE_AES_256_CTS             4
>> > +
>> > +/**
>> > + * Encryption context for inode
>> > + *
>> > + * Protector format:
>> > + *  1 byte: Protector format (1 = this version)
>> > + *  1 byte: File contents encryption mode
>> > + *  1 byte: File names encryption mode
>> > + *  1 byte: Flags
>> > + *  8 bytes: Master Key descriptor
>> > + *  16 bytes: Encryption Key derivation nonce
>> > + */
>> > +struct fscrypt_context {
>> > +   char format;
>> > +   char contents_encryption_mode;
>> > +   char filenames_encryption_mode;
>> > +   char flags;
>> > +   char master_key_descriptor[FS_KEY_DESCRIPTOR_SIZE];
>> > +   char nonce[FS_KEY_DERIVATION_NONCE_SIZE];
>>
>> how about u8 instead of char?
>
> It seems that it needs to user u8 instead of char for other variables as well.
> I'll take a look at all the usages.

I think it needs to be __u8 otherwise I get this in a userspace program:

In file included from test/blk_namespaces.c:17:0:
/usr/include/linux/fs.h:256:2: error: unknown type name ‘u8’
  u8 version;
  ^
/usr/include/linux/fs.h:257:2: error: unknown type name ‘u8’
  u8 contents_encryption_mode;
  ^
/usr/include/linux/fs.h:258:2: error: unknown type name ‘u8’
  u8 filenames_encryption_mode;
  ^
/usr/include/linux/fs.h:259:2: error: unknown type name ‘u8’
  u8 flags;
  ^
/usr/include/linux/fs.h:260:2: error: unknown type name ‘u8’
  u8 master_key_descriptor[FS_KEY_DESCRIPTOR_SIZE];
  ^
--
To unsubscribe from this list: send the line "unsubscribe linux-fsdevel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Jaegeuk Kim March 11, 2016, 6:50 p.m. UTC | #4
Hi Dan,

On Thu, Mar 10, 2016 at 09:00:25PM -0800, Dan Williams wrote:
> On Mon, Feb 29, 2016 at 5:35 PM, Jaegeuk Kim <jaegeuk@kernel.org> wrote:
> > On Sun, Feb 28, 2016 at 09:41:22PM -0800, Randy Dunlap wrote:
> >> On 02/25/16 11:25, Jaegeuk Kim wrote:
> >> > This patch adds definitions for per-file encryption used by ext4 and f2fs.
> >> >
> >> > Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
> >> > ---
> >> >  include/linux/fs.h       |   8 ++
> >> >  include/linux/fscrypto.h | 239 +++++++++++++++++++++++++++++++++++++++++++++++
> >> >  include/uapi/linux/fs.h  |  18 ++++
> >> >  3 files changed, 265 insertions(+)
> >> >  create mode 100644 include/linux/fscrypto.h
> >> >
> >> > diff --git a/include/linux/fs.h b/include/linux/fs.h
> >> > index ae68100..d8f57cf 100644
> >> > --- a/include/linux/fs.h
> >> > +++ b/include/linux/fs.h
> >> > @@ -53,6 +53,8 @@ struct swap_info_struct;
> >> >  struct seq_file;
> >> >  struct workqueue_struct;
> >> >  struct iov_iter;
> >> > +struct fscrypt_info;
> >> > +struct fscrypt_operations;
> >> >
> >> >  extern void __init inode_init(void);
> >> >  extern void __init inode_init_early(void);
> >> > @@ -678,6 +680,10 @@ struct inode {
> >> >     struct hlist_head       i_fsnotify_marks;
> >> >  #endif
> >> >
> >> > +#ifdef CONFIG_FS_ENCRYPTION
> >> > +   struct fscrypt_info     *i_crypt_info;
> >> > +#endif
> >> > +
> >> >     void                    *i_private; /* fs or device private pointer */
> >> >  };
> >> >
> >> > @@ -1323,6 +1329,8 @@ struct super_block {
> >> >  #endif
> >> >     const struct xattr_handler **s_xattr;
> >> >
> >> > +   const struct fscrypt_operations *s_cop;
> >> > +
> >> >     struct hlist_bl_head    s_anon;         /* anonymous dentries for (nfs) exporting */
> >> >     struct list_head        s_mounts;       /* list of mounts; _not_ for fs use */
> >> >     struct block_device     *s_bdev;
> >> > diff --git a/include/linux/fscrypto.h b/include/linux/fscrypto.h
> >> > new file mode 100644
> >> > index 0000000..b0aed92
> >> > --- /dev/null
> >> > +++ b/include/linux/fscrypto.h
> >> > @@ -0,0 +1,239 @@
> >> > +/*
> >> > + * General per-file encryption definition
> >> > + *
> >> > + * Copyright (C) 2015, Google, Inc.
> >> > + *
> >> > + * Written by Michael Halcrow, 2015.
> >> > + * Modified by Jaegeuk Kim, 2015.
> >> > + */
> >> > +
> >> > +#ifndef _LINUX_FSCRYPTO_H
> >> > +#define _LINUX_FSCRYPTO_H
> >> > +
> >> > +#include <linux/key.h>
> >> > +#include <linux/fs.h>
> >> > +#include <linux/mm.h>
> >> > +#include <linux/bio.h>
> >> > +#include <linux/dcache.h>
> >> > +#include <uapi/linux/fs.h>
> >> > +
> >> > +#define FS_KEY_DERIVATION_NONCE_SIZE               16
> >> > +#define FS_ENCRYPTION_CONTEXT_FORMAT_V1            1
> >> > +
> >> > +#define FS_POLICY_FLAGS_PAD_4              0x00
> >> > +#define FS_POLICY_FLAGS_PAD_8              0x01
> >> > +#define FS_POLICY_FLAGS_PAD_16             0x02
> >> > +#define FS_POLICY_FLAGS_PAD_32             0x03
> >> > +#define FS_POLICY_FLAGS_PAD_MASK   0x03
> >> > +#define FS_POLICY_FLAGS_VALID              0x03
> >> > +
> >> > +/* Encryption algorithms */
> >> > +#define FS_ENCRYPTION_MODE_INVALID         0
> >> > +#define FS_ENCRYPTION_MODE_AES_256_XTS             1
> >> > +#define FS_ENCRYPTION_MODE_AES_256_GCM             2
> >> > +#define FS_ENCRYPTION_MODE_AES_256_CBC             3
> >> > +#define FS_ENCRYPTION_MODE_AES_256_CTS             4
> >> > +
> >> > +/**
> >> > + * Encryption context for inode
> >> > + *
> >> > + * Protector format:
> >> > + *  1 byte: Protector format (1 = this version)
> >> > + *  1 byte: File contents encryption mode
> >> > + *  1 byte: File names encryption mode
> >> > + *  1 byte: Flags
> >> > + *  8 bytes: Master Key descriptor
> >> > + *  16 bytes: Encryption Key derivation nonce
> >> > + */
> >> > +struct fscrypt_context {
> >> > +   char format;
> >> > +   char contents_encryption_mode;
> >> > +   char filenames_encryption_mode;
> >> > +   char flags;
> >> > +   char master_key_descriptor[FS_KEY_DESCRIPTOR_SIZE];
> >> > +   char nonce[FS_KEY_DERIVATION_NONCE_SIZE];
> >>
> >> how about u8 instead of char?
> >
> > It seems that it needs to user u8 instead of char for other variables as well.
> > I'll take a look at all the usages.
> 
> I think it needs to be __u8 otherwise I get this in a userspace program:
> 
> In file included from test/blk_namespaces.c:17:0:
> /usr/include/linux/fs.h:256:2: error: unknown type name ‘u8’
>   u8 version;
>   ^
> /usr/include/linux/fs.h:257:2: error: unknown type name ‘u8’
>   u8 contents_encryption_mode;
>   ^
> /usr/include/linux/fs.h:258:2: error: unknown type name ‘u8’
>   u8 filenames_encryption_mode;
>   ^
> /usr/include/linux/fs.h:259:2: error: unknown type name ‘u8’
>   u8 flags;
>   ^
> /usr/include/linux/fs.h:260:2: error: unknown type name ‘u8’
>   u8 master_key_descriptor[FS_KEY_DESCRIPTOR_SIZE];
>   ^

I realized that it needs to use __u8 as an exportable data type which can be
seen by user-space programs.

So, IMO, only fscrypt_policy should be exportable, and other structures need
to use u8.

Let me know, if I'm missing something.

Thanks,
--
To unsubscribe from this list: send the line "unsubscribe linux-fsdevel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
diff mbox

Patch

diff --git a/include/linux/fs.h b/include/linux/fs.h
index ae68100..d8f57cf 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -53,6 +53,8 @@  struct swap_info_struct;
 struct seq_file;
 struct workqueue_struct;
 struct iov_iter;
+struct fscrypt_info;
+struct fscrypt_operations;
 
 extern void __init inode_init(void);
 extern void __init inode_init_early(void);
@@ -678,6 +680,10 @@  struct inode {
 	struct hlist_head	i_fsnotify_marks;
 #endif
 
+#ifdef CONFIG_FS_ENCRYPTION
+	struct fscrypt_info	*i_crypt_info;
+#endif
+
 	void			*i_private; /* fs or device private pointer */
 };
 
@@ -1323,6 +1329,8 @@  struct super_block {
 #endif
 	const struct xattr_handler **s_xattr;
 
+	const struct fscrypt_operations	*s_cop;
+
 	struct hlist_bl_head	s_anon;		/* anonymous dentries for (nfs) exporting */
 	struct list_head	s_mounts;	/* list of mounts; _not_ for fs use */
 	struct block_device	*s_bdev;
diff --git a/include/linux/fscrypto.h b/include/linux/fscrypto.h
new file mode 100644
index 0000000..b0aed92
--- /dev/null
+++ b/include/linux/fscrypto.h
@@ -0,0 +1,239 @@ 
+/*
+ * General per-file encryption definition
+ *
+ * Copyright (C) 2015, Google, Inc.
+ *
+ * Written by Michael Halcrow, 2015.
+ * Modified by Jaegeuk Kim, 2015.
+ */
+
+#ifndef _LINUX_FSCRYPTO_H
+#define _LINUX_FSCRYPTO_H
+
+#include <linux/key.h>
+#include <linux/fs.h>
+#include <linux/mm.h>
+#include <linux/bio.h>
+#include <linux/dcache.h>
+#include <uapi/linux/fs.h>
+
+#define FS_KEY_DERIVATION_NONCE_SIZE		16
+#define FS_ENCRYPTION_CONTEXT_FORMAT_V1		1
+
+#define FS_POLICY_FLAGS_PAD_4		0x00
+#define FS_POLICY_FLAGS_PAD_8		0x01
+#define FS_POLICY_FLAGS_PAD_16		0x02
+#define FS_POLICY_FLAGS_PAD_32		0x03
+#define FS_POLICY_FLAGS_PAD_MASK	0x03
+#define FS_POLICY_FLAGS_VALID		0x03
+
+/* Encryption algorithms */
+#define FS_ENCRYPTION_MODE_INVALID		0
+#define FS_ENCRYPTION_MODE_AES_256_XTS		1
+#define FS_ENCRYPTION_MODE_AES_256_GCM		2
+#define FS_ENCRYPTION_MODE_AES_256_CBC		3
+#define FS_ENCRYPTION_MODE_AES_256_CTS		4
+
+/**
+ * Encryption context for inode
+ *
+ * Protector format:
+ *  1 byte: Protector format (1 = this version)
+ *  1 byte: File contents encryption mode
+ *  1 byte: File names encryption mode
+ *  1 byte: Flags
+ *  8 bytes: Master Key descriptor
+ *  16 bytes: Encryption Key derivation nonce
+ */
+struct fscrypt_context {
+	char format;
+	char contents_encryption_mode;
+	char filenames_encryption_mode;
+	char flags;
+	char master_key_descriptor[FS_KEY_DESCRIPTOR_SIZE];
+	char nonce[FS_KEY_DERIVATION_NONCE_SIZE];
+} __packed;
+
+/* Encryption parameters */
+#define FS_XTS_TWEAK_SIZE		16
+#define FS_AES_128_ECB_KEY_SIZE		16
+#define FS_AES_256_GCM_KEY_SIZE		32
+#define FS_AES_256_CBC_KEY_SIZE		32
+#define FS_AES_256_CTS_KEY_SIZE		32
+#define FS_AES_256_XTS_KEY_SIZE		64
+#define FS_MAX_KEY_SIZE			64
+
+#define FS_KEY_DESC_PREFIX		"fscrypt:"
+#define FS_KEY_DESC_PREFIX_SIZE		8
+
+/* This is passed in from userspace into the kernel keyring */
+struct fscrypt_key {
+	__u32 mode;
+	char raw[FS_MAX_KEY_SIZE];
+	__u32 size;
+} __packed;
+
+struct fscrypt_info {
+	char ci_data_mode;
+	char ci_filename_mode;
+	char ci_flags;
+	struct crypto_ablkcipher *ci_ctfm;
+	struct key *ci_keyring_key;
+	char ci_master_key[FS_KEY_DESCRIPTOR_SIZE];
+};
+
+#define FS_CTX_REQUIRES_FREE_ENCRYPT_FL		0x00000001
+#define FS_WRITE_PATH_FL			0x00000002
+
+struct fscrypt_ctx {
+	union {
+		struct {
+			struct page *bounce_page;	/* Ciphertext page */
+			struct page *control_page;	/* Original page  */
+		} w;
+		struct {
+			struct bio *bio;
+			struct work_struct work;
+		} r;
+		struct list_head free_list;	/* Free list */
+	};
+	char flags;				/* Flags */
+	char mode;				/* Encryption mode for tfm */
+};
+
+struct fscrypt_completion_result {
+	struct completion completion;
+	int res;
+};
+
+#define DECLARE_FS_COMPLETION_RESULT(ecr) \
+	struct fscrypt_completion_result ecr = { \
+		COMPLETION_INITIALIZER((ecr).completion), 0 }
+
+static inline int fscrypt_key_size(int mode)
+{
+	switch (mode) {
+	case FS_ENCRYPTION_MODE_AES_256_XTS:
+		return FS_AES_256_XTS_KEY_SIZE;
+	case FS_ENCRYPTION_MODE_AES_256_GCM:
+		return FS_AES_256_GCM_KEY_SIZE;
+	case FS_ENCRYPTION_MODE_AES_256_CBC:
+		return FS_AES_256_CBC_KEY_SIZE;
+	case FS_ENCRYPTION_MODE_AES_256_CTS:
+		return FS_AES_256_CTS_KEY_SIZE;
+	default:
+		BUG();
+	}
+	return 0;
+}
+
+#define FS_FNAME_NUM_SCATTER_ENTRIES	4
+#define FS_CRYPTO_BLOCK_SIZE		16
+#define FS_FNAME_CRYPTO_DIGEST_SIZE	32
+
+/**
+ * For encrypted symlinks, the ciphertext length is stored at the beginning
+ * of the string in little-endian format.
+ */
+struct fscrypt_symlink_data {
+	__le16 len;
+	char encrypted_path[1];
+} __packed;
+
+/**
+ * This function is used to calculate the disk space required to
+ * store a filename of length l in encrypted symlink format.
+ */
+static inline u32 fscrypt_symlink_data_len(u32 l)
+{
+	if (l < FS_CRYPTO_BLOCK_SIZE)
+		l = FS_CRYPTO_BLOCK_SIZE;
+	return (l + sizeof(struct fscrypt_symlink_data) - 1);
+}
+
+struct fscrypt_str {
+	unsigned char *name;
+	u32 len;
+};
+
+struct fscrypt_name {
+	const struct qstr *usr_fname;
+	struct fscrypt_str disk_name;
+	u32 hash;
+	u32 minor_hash;
+	struct fscrypt_str crypto_buf;
+};
+
+#define FSTR_INIT(n, l)		{ .name = n, .len = l }
+#define FSTR_TO_QSTR(f)		QSTR_INIT((f)->name, (f)->len)
+#define fname_name(p)		((p)->disk_name.name)
+#define fname_len(p)		((p)->disk_name.len)
+
+/*
+ * crypto opertions for filesystems
+ */
+struct fscrypt_operations {
+	int (*get_context)(struct inode *, void *, size_t);
+	int (*prepare_context)(struct inode *);
+	int (*set_context)(struct inode *, const void *, size_t, void *);
+	int (*dummy_context)(struct inode *);
+	bool (*is_encrypted)(struct inode *);
+	bool (*empty_dir)(struct inode *);
+	unsigned (*max_namelen)(struct inode *);
+};
+
+static inline bool fscrypt_dummy_context_enabled(struct inode *inode)
+{
+	if (inode->i_sb->s_cop->dummy_context &&
+				inode->i_sb->s_cop->dummy_context(inode))
+		return true;
+	return false;
+}
+
+static inline bool fscrypt_valid_contents_enc_mode(u32 mode)
+{
+	return (mode == FS_ENCRYPTION_MODE_AES_256_XTS);
+}
+
+static inline bool fscrypt_valid_filenames_enc_mode(u32 mode)
+{
+	return (mode == FS_ENCRYPTION_MODE_AES_256_CTS);
+}
+
+static inline u32 fscrypt_validate_encryption_key_size(u32 mode, u32 size)
+{
+	if (size == fscrypt_key_size(mode))
+		return size;
+	return 0;
+}
+
+static inline bool fscrypt_is_dot_dotdot(const struct qstr *str)
+{
+	if (str->len == 1 && str->name[0] == '.')
+		return true;
+
+	if (str->len == 2 && str->name[0] == '.' && str->name[1] == '.')
+		return true;
+
+	return false;
+}
+
+static inline struct page *fscrypt_control_page(struct page *page)
+{
+#ifdef CONFIG_FS_ENCRYPTION
+	return ((struct fscrypt_ctx *)page_private(page))->w.control_page;
+#else
+	WARN_ON_ONCE(1);
+	return ERR_PTR(-EINVAL);
+#endif
+}
+
+static inline int fscrypt_has_encryption_key(struct inode *inode)
+{
+#ifdef CONFIG_FS_ENCRYPTION
+	return (inode->i_crypt_info != NULL);
+#else
+	return 0;
+#endif
+}
+#endif	/* _LINUX_FSCRYPTO_H */
diff --git a/include/uapi/linux/fs.h b/include/uapi/linux/fs.h
index 149bec8..1d26276 100644
--- a/include/uapi/linux/fs.h
+++ b/include/uapi/linux/fs.h
@@ -247,6 +247,24 @@  struct fsxattr {
 #define FS_IOC_FSSETXATTR		_IOW ('X', 32, struct fsxattr)
 
 /*
+ * File system encryption support
+ */
+/* Policy provided via an ioctl on the topmost directory */
+#define FS_KEY_DESCRIPTOR_SIZE	8
+
+struct fscrypt_policy {
+	char version;
+	char contents_encryption_mode;
+	char filenames_encryption_mode;
+	char flags;
+	char master_key_descriptor[FS_KEY_DESCRIPTOR_SIZE];
+} __packed;
+
+#define FS_IOC_SET_ENCRYPTION_POLICY	_IOR('f', 19, struct fscrypt_policy)
+#define FS_IOC_GET_ENCRYPTION_PWSALT	_IOW('f', 20, __u8[16])
+#define FS_IOC_GET_ENCRYPTION_POLICY	_IOW('f', 21, struct fscrypt_policy)
+
+/*
  * Inode flags (FS_IOC_GETFLAGS / FS_IOC_SETFLAGS)
  *
  * Note: for historical reasons, these flags were originally used and