ubifs: Add skeleton for fscrypto
This is the first building block to provide file level encryption on UBIFS. Signed-off-by: Richard Weinberger <richard@nod.at>
This commit is contained in:
		
							parent
							
								
									6a5e98ab7d
								
							
						
					
					
						commit
						d475a50745
					
				| @ -50,3 +50,14 @@ config UBIFS_ATIME_SUPPORT | ||||
| 	  strictatime is the "heavy", relatime is "lighter", etc. | ||||
| 
 | ||||
| 	  If unsure, say 'N' | ||||
| 
 | ||||
| config UBIFS_FS_ENCRYPTION | ||||
| 	bool "UBIFS Encryption" | ||||
| 	depends on UBIFS_FS | ||||
| 	select FS_ENCRYPTION | ||||
| 	default n | ||||
| 	help | ||||
| 	  Enable encryption of UBIFS files and directories. This | ||||
| 	  feature is similar to ecryptfs, but it is more memory | ||||
| 	  efficient since it avoids caching the encrypted and | ||||
| 	  decrypted pages in the page cache. | ||||
|  | ||||
| @ -5,3 +5,4 @@ ubifs-y += tnc.o master.o scan.o replay.o log.o commit.o gc.o orphan.o | ||||
| ubifs-y += budget.o find.o tnc_commit.o compress.o lpt.o lprops.o | ||||
| ubifs-y += recovery.o ioctl.o lpt_commit.o tnc_misc.o xattr.o debug.o | ||||
| ubifs-y += misc.o | ||||
| ubifs-$(CONFIG_UBIFS_FS_ENCRYPTION) += crypto.o | ||||
|  | ||||
							
								
								
									
										46
									
								
								fs/ubifs/crypto.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										46
									
								
								fs/ubifs/crypto.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,46 @@ | ||||
| #include "ubifs.h" | ||||
| 
 | ||||
| static int ubifs_crypt_get_context(struct inode *inode, void *ctx, size_t len) | ||||
| { | ||||
| 	return ubifs_xattr_get(inode, UBIFS_XATTR_NAME_ENCRYPTION_CONTEXT, | ||||
| 			       ctx, len); | ||||
| } | ||||
| 
 | ||||
| static int ubifs_crypt_set_context(struct inode *inode, const void *ctx, | ||||
| 				   size_t len, void *fs_data) | ||||
| { | ||||
| 	return ubifs_xattr_set(inode, UBIFS_XATTR_NAME_ENCRYPTION_CONTEXT, | ||||
| 			       ctx, len, 0); | ||||
| } | ||||
| 
 | ||||
| static bool ubifs_crypt_empty_dir(struct inode *inode) | ||||
| { | ||||
| 	return ubifs_check_dir_empty(inode) == 0; | ||||
| } | ||||
| 
 | ||||
| static unsigned int ubifs_crypt_max_namelen(struct inode *inode) | ||||
| { | ||||
| 	if (S_ISLNK(inode->i_mode)) | ||||
| 		return UBIFS_MAX_INO_DATA; | ||||
| 	else | ||||
| 		return UBIFS_MAX_NLEN; | ||||
| } | ||||
| 
 | ||||
| static int ubifs_key_prefix(struct inode *inode, u8 **key) | ||||
| { | ||||
| 	static char prefix[] = "ubifs:"; | ||||
| 
 | ||||
| 	*key = prefix; | ||||
| 
 | ||||
| 	return sizeof(prefix) - 1; | ||||
| } | ||||
| 
 | ||||
| struct fscrypt_operations ubifs_crypt_operations = { | ||||
| 	.flags			= FS_CFLG_INPLACE_ENCRYPTION, | ||||
| 	.get_context		= ubifs_crypt_get_context, | ||||
| 	.set_context		= ubifs_crypt_set_context, | ||||
| 	.is_encrypted		= ubifs_crypt_is_encrypted, | ||||
| 	.empty_dir		= ubifs_crypt_empty_dir, | ||||
| 	.max_namelen		= ubifs_crypt_max_namelen, | ||||
| 	.key_prefix		= ubifs_key_prefix, | ||||
| }; | ||||
| @ -85,11 +85,26 @@ static int inherit_flags(const struct inode *dir, umode_t mode) | ||||
|  * initializes it. Returns new inode in case of success and an error code in | ||||
|  * case of failure. | ||||
|  */ | ||||
| struct inode *ubifs_new_inode(struct ubifs_info *c, const struct inode *dir, | ||||
| struct inode *ubifs_new_inode(struct ubifs_info *c, struct inode *dir, | ||||
| 			      umode_t mode) | ||||
| { | ||||
| 	int err; | ||||
| 	struct inode *inode; | ||||
| 	struct ubifs_inode *ui; | ||||
| 	bool encrypted = false; | ||||
| 
 | ||||
| 	if (ubifs_crypt_is_encrypted(dir)) { | ||||
| 		err = fscrypt_get_encryption_info(dir); | ||||
| 		if (err) { | ||||
| 			ubifs_err(c, "fscrypt_get_encryption_info failed: %i", err); | ||||
| 			return ERR_PTR(err); | ||||
| 		} | ||||
| 
 | ||||
| 		if (!fscrypt_has_encryption_key(dir)) | ||||
| 			return ERR_PTR(-EPERM); | ||||
| 
 | ||||
| 		encrypted = true; | ||||
| 	} | ||||
| 
 | ||||
| 	inode = new_inode(c->vfs_sb); | ||||
| 	ui = ubifs_inode(inode); | ||||
| @ -165,6 +180,17 @@ struct inode *ubifs_new_inode(struct ubifs_info *c, const struct inode *dir, | ||||
| 	 */ | ||||
| 	ui->creat_sqnum = ++c->max_sqnum; | ||||
| 	spin_unlock(&c->cnt_lock); | ||||
| 
 | ||||
| 	if (encrypted) { | ||||
| 		err = fscrypt_inherit_context(dir, inode, &encrypted, true); | ||||
| 		if (err) { | ||||
| 			ubifs_err(c, "fscrypt_inherit_context failed: %i", err); | ||||
| 			make_bad_inode(inode); | ||||
| 			iput(inode); | ||||
| 			return ERR_PTR(err); | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	return inode; | ||||
| } | ||||
| 
 | ||||
|  | ||||
| @ -181,6 +181,41 @@ long ubifs_ioctl(struct file *file, unsigned int cmd, unsigned long arg) | ||||
| 		mnt_drop_write_file(file); | ||||
| 		return err; | ||||
| 	} | ||||
| 	case FS_IOC_SET_ENCRYPTION_POLICY: { | ||||
| #ifdef CONFIG_UBIFS_FS_ENCRYPTION | ||||
| 		struct fscrypt_policy policy; | ||||
| 
 | ||||
| 		if (copy_from_user(&policy, | ||||
| 				   (struct fscrypt_policy __user *)arg, | ||||
| 				   sizeof(policy))) | ||||
| 			return -EFAULT; | ||||
| 
 | ||||
| 		err = fscrypt_process_policy(file, &policy); | ||||
| 
 | ||||
| 		return err; | ||||
| #else | ||||
| 		return -EOPNOTSUPP; | ||||
| #endif | ||||
| 	} | ||||
| 	case FS_IOC_GET_ENCRYPTION_POLICY: { | ||||
| #ifdef CONFIG_UBIFS_FS_ENCRYPTION | ||||
| 		struct fscrypt_policy policy; | ||||
| 
 | ||||
| 		if (!ubifs_crypt_is_encrypted(inode)) | ||||
| 			return -ENOENT; | ||||
| 
 | ||||
| 		err = fscrypt_get_policy(inode, &policy); | ||||
| 		if (err) | ||||
| 			return err; | ||||
| 
 | ||||
| 		if (copy_to_user((void __user *)arg, &policy, sizeof(policy))) | ||||
| 			return -EFAULT; | ||||
| 
 | ||||
| 		return 0; | ||||
| #else | ||||
| 		return -EOPNOTSUPP; | ||||
| #endif | ||||
| 	} | ||||
| 
 | ||||
| 	default: | ||||
| 		return -ENOTTY; | ||||
|  | ||||
| @ -380,6 +380,9 @@ out: | ||||
| 	} | ||||
| done: | ||||
| 	clear_inode(inode); | ||||
| #ifdef CONFIG_UBIFS_FS_ENCRYPTION | ||||
| 	fscrypt_put_encryption_info(inode, NULL); | ||||
| #endif | ||||
| } | ||||
| 
 | ||||
| static void ubifs_dirty_inode(struct inode *inode, int flags) | ||||
| @ -1995,6 +1998,12 @@ static struct ubifs_info *alloc_ubifs_info(struct ubi_volume_desc *ubi) | ||||
| 	return c; | ||||
| } | ||||
| 
 | ||||
| #ifndef CONFIG_UBIFS_FS_ENCRYPTION | ||||
| struct fscrypt_operations ubifs_crypt_operations = { | ||||
| 	.is_encrypted		= ubifs_crypt_is_encrypted, | ||||
| }; | ||||
| #endif | ||||
| 
 | ||||
| static int ubifs_fill_super(struct super_block *sb, void *data, int silent) | ||||
| { | ||||
| 	struct ubifs_info *c = sb->s_fs_info; | ||||
| @ -2041,6 +2050,7 @@ static int ubifs_fill_super(struct super_block *sb, void *data, int silent) | ||||
| 		sb->s_maxbytes = c->max_inode_sz = MAX_LFS_FILESIZE; | ||||
| 	sb->s_op = &ubifs_super_operations; | ||||
| 	sb->s_xattr = ubifs_xattr_handlers; | ||||
| 	sb->s_cop = &ubifs_crypt_operations; | ||||
| 
 | ||||
| 	mutex_lock(&c->umount_mutex); | ||||
| 	err = mount_ubifs(c); | ||||
|  | ||||
| @ -316,6 +316,7 @@ enum { | ||||
|  * UBIFS_APPEND_FL: writes to the inode may only append data | ||||
|  * UBIFS_DIRSYNC_FL: I/O on this directory inode has to be synchronous | ||||
|  * UBIFS_XATTR_FL: this inode is the inode for an extended attribute value | ||||
|  * UBIFS_CRYPT_FL: use encryption for this inode | ||||
|  * | ||||
|  * Note, these are on-flash flags which correspond to ioctl flags | ||||
|  * (@FS_COMPR_FL, etc). They have the same values now, but generally, do not | ||||
| @ -328,6 +329,7 @@ enum { | ||||
| 	UBIFS_APPEND_FL    = 0x08, | ||||
| 	UBIFS_DIRSYNC_FL   = 0x10, | ||||
| 	UBIFS_XATTR_FL     = 0x20, | ||||
| 	UBIFS_CRYPT_FL     = 0x40, | ||||
| }; | ||||
| 
 | ||||
| /* Inode flag bits used by UBIFS */ | ||||
|  | ||||
| @ -38,6 +38,7 @@ | ||||
| #include <linux/backing-dev.h> | ||||
| #include <linux/security.h> | ||||
| #include <linux/xattr.h> | ||||
| #include <linux/fscrypto.h> | ||||
| #include "ubifs-media.h" | ||||
| 
 | ||||
| /* Version of this UBIFS implementation */ | ||||
| @ -1724,7 +1725,7 @@ int ubifs_update_time(struct inode *inode, struct timespec *time, int flags); | ||||
| #endif | ||||
| 
 | ||||
| /* dir.c */ | ||||
| struct inode *ubifs_new_inode(struct ubifs_info *c, const struct inode *dir, | ||||
| struct inode *ubifs_new_inode(struct ubifs_info *c, struct inode *dir, | ||||
| 			      umode_t mode); | ||||
| int ubifs_getattr(struct vfsmount *mnt, struct dentry *dentry, | ||||
| 		  struct kstat *stat); | ||||
| @ -1773,10 +1774,44 @@ void ubifs_compress(const struct ubifs_info *c, const void *in_buf, int in_len, | ||||
| int ubifs_decompress(const struct ubifs_info *c, const void *buf, int len, | ||||
| 		     void *out, int *out_len, int compr_type); | ||||
| 
 | ||||
| extern struct fscrypt_operations ubifs_crypt_operations; | ||||
| 
 | ||||
| #include "debug.h" | ||||
| #include "misc.h" | ||||
| #include "key.h" | ||||
| 
 | ||||
| #ifndef CONFIG_UBIFS_FS_ENCRYPTION | ||||
| #define fscrypt_set_d_op(i) | ||||
| #define fscrypt_get_ctx                 fscrypt_notsupp_get_ctx | ||||
| #define fscrypt_release_ctx             fscrypt_notsupp_release_ctx | ||||
| #define fscrypt_encrypt_page            fscrypt_notsupp_encrypt_page | ||||
| #define fscrypt_decrypt_page            fscrypt_notsupp_decrypt_page | ||||
| #define fscrypt_decrypt_bio_pages       fscrypt_notsupp_decrypt_bio_pages | ||||
| #define fscrypt_pullback_bio_page       fscrypt_notsupp_pullback_bio_page | ||||
| #define fscrypt_restore_control_page    fscrypt_notsupp_restore_control_page | ||||
| #define fscrypt_zeroout_range           fscrypt_notsupp_zeroout_range | ||||
| #define fscrypt_process_policy          fscrypt_notsupp_process_policy | ||||
| #define fscrypt_get_policy              fscrypt_notsupp_get_policy | ||||
| #define fscrypt_has_permitted_context   fscrypt_notsupp_has_permitted_context | ||||
| #define fscrypt_inherit_context         fscrypt_notsupp_inherit_context | ||||
| #define fscrypt_get_encryption_info     fscrypt_notsupp_get_encryption_info | ||||
| #define fscrypt_put_encryption_info     fscrypt_notsupp_put_encryption_info | ||||
| #define fscrypt_setup_filename          fscrypt_notsupp_setup_filename | ||||
| #define fscrypt_free_filename           fscrypt_notsupp_free_filename | ||||
| #define fscrypt_fname_encrypted_size    fscrypt_notsupp_fname_encrypted_size | ||||
| #define fscrypt_fname_alloc_buffer      fscrypt_notsupp_fname_alloc_buffer | ||||
| #define fscrypt_fname_free_buffer       fscrypt_notsupp_fname_free_buffer | ||||
| #define fscrypt_fname_disk_to_usr       fscrypt_notsupp_fname_disk_to_usr | ||||
| #define fscrypt_fname_usr_to_disk       fscrypt_notsupp_fname_usr_to_disk | ||||
| #endif | ||||
| 
 | ||||
| static inline bool ubifs_crypt_is_encrypted(struct inode *inode) | ||||
| { | ||||
| 	struct ubifs_inode *ui = ubifs_inode(inode); | ||||
| 
 | ||||
| 	return ui->flags & UBIFS_CRYPT_FL; | ||||
| } | ||||
| 
 | ||||
| /* Normal UBIFS messages */ | ||||
| __printf(2, 3) | ||||
| void ubifs_msg(const struct ubifs_info *c, const char *fmt, ...); | ||||
|  | ||||
| @ -158,6 +158,15 @@ static int create_xattr(struct ubifs_info *c, struct inode *host, | ||||
| 	host_ui->xattr_size += CALC_XATTR_BYTES(size); | ||||
| 	host_ui->xattr_names += nm->len; | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * We handle UBIFS_XATTR_NAME_ENCRYPTION_CONTEXT here because we | ||||
| 	 * have to set the UBIFS_CRYPT_FL flag on the host inode. | ||||
| 	 * To avoid multiple updates of the same inode in the same operation, | ||||
| 	 * let's do it here. | ||||
| 	 */ | ||||
| 	if (strcmp(nm->name, UBIFS_XATTR_NAME_ENCRYPTION_CONTEXT) == 0) | ||||
| 		host_ui->flags |= UBIFS_CRYPT_FL; | ||||
| 
 | ||||
| 	err = ubifs_jnl_update(c, host, nm, inode, 0, 1); | ||||
| 	if (err) | ||||
| 		goto out_cancel; | ||||
| @ -173,6 +182,7 @@ out_cancel: | ||||
| 	host_ui->xattr_size -= CALC_DENT_SIZE(nm->len); | ||||
| 	host_ui->xattr_size -= CALC_XATTR_BYTES(size); | ||||
| 	host_ui->xattr_names -= nm->len; | ||||
| 	host_ui->flags &= ~UBIFS_CRYPT_FL; | ||||
| 	mutex_unlock(&host_ui->ui_mutex); | ||||
| out_free: | ||||
| 	make_bad_inode(inode); | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user