1 ext4 crypto: add symlink encryption
3 Signed-off-by: Uday Savagaonkar <savagaon@google.com>
4 Signed-off-by: Theodore Ts'o <tytso@mit.edu>
7 fs/ext4/ext4_crypto.h | 20 ++++++++++++
8 fs/ext4/inode.c | 5 +--
9 fs/ext4/namei.c | 85 +++++++++++++++++++++++++++++++++++++------------
10 fs/ext4/symlink.c | 96 +++++++++++++++++++++++++++++++++++++++++++++++++++++++-
11 5 files changed, 184 insertions(+), 23 deletions(-)
13 diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h
14 index 98a5617..c79db59 100644
17 @@ -2221,6 +2221,7 @@ extern int ext4_group_add_blocks(handle_t *handle, struct super_block *sb,
18 extern int ext4_trim_fs(struct super_block *, struct fstrim_range *);
21 +int ext4_inode_is_fast_symlink(struct inode *inode);
22 struct buffer_head *ext4_getblk(handle_t *, struct inode *, ext4_lblk_t, int);
23 struct buffer_head *ext4_bread(handle_t *, struct inode *, ext4_lblk_t, int);
24 int ext4_get_block_write(struct inode *inode, sector_t iblock,
25 diff --git a/fs/ext4/ext4_crypto.h b/fs/ext4/ext4_crypto.h
26 index f7d46e8..c2ba35a 100644
27 --- a/fs/ext4/ext4_crypto.h
28 +++ b/fs/ext4/ext4_crypto.h
29 @@ -124,4 +124,24 @@ struct ext4_fname_crypto_ctx {
30 unsigned ctfm_key_is_ready : 1;
34 + * For encrypted symlinks, the ciphertext length is stored at the beginning
35 + * of the string in little-endian format.
37 +struct ext4_encrypted_symlink_data {
39 + char encrypted_path[1];
40 +} __attribute__((__packed__));
43 + * This function is used to calculate the disk space required to
44 + * store a filename of length l in encrypted symlink format.
46 +static inline u32 encrypted_symlink_data_len(u32 l)
48 + if (l < EXT4_CRYPTO_BLOCK_SIZE)
49 + l = EXT4_CRYPTO_BLOCK_SIZE;
50 + return (l + sizeof(struct ext4_encrypted_symlink_data) - 1);
53 #endif /* _EXT4_CRYPTO_H */
54 diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c
55 index 9cc660c..a8e1975 100644
58 @@ -141,7 +141,7 @@ static int ext4_meta_trans_blocks(struct inode *inode, int lblocks,
60 * Test whether an inode is a fast symlink.
62 -static int ext4_inode_is_fast_symlink(struct inode *inode)
63 +int ext4_inode_is_fast_symlink(struct inode *inode)
65 int ea_blocks = EXT4_I(inode)->i_file_acl ?
66 EXT4_CLUSTER_SIZE(inode->i_sb) >> 9 : 0;
67 @@ -4175,7 +4175,8 @@ struct inode *ext4_iget(struct super_block *sb, unsigned long ino)
68 inode->i_op = &ext4_dir_inode_operations;
69 inode->i_fop = &ext4_dir_operations;
70 } else if (S_ISLNK(inode->i_mode)) {
71 - if (ext4_inode_is_fast_symlink(inode)) {
72 + if (ext4_inode_is_fast_symlink(inode) &&
73 + !ext4_encrypted_inode(inode)) {
74 inode->i_op = &ext4_fast_symlink_inode_operations;
75 nd_terminate_link(ei->i_data, inode->i_size,
76 sizeof(ei->i_data) - 1);
77 diff --git a/fs/ext4/namei.c b/fs/ext4/namei.c
78 index ffd97aa..0e57e70 100644
81 @@ -3185,16 +3185,24 @@ static int ext4_symlink(struct inode *dir,
85 - int l, err, retries = 0;
86 + int err, len = strlen(symname);
88 + bool encryption_required;
89 + struct ext4_str disk_link;
90 + struct ext4_encrypted_symlink_data *sd = NULL;
92 - l = strlen(symname)+1;
93 - if (l > dir->i_sb->s_blocksize)
94 + disk_link.len = len + 1;
95 + disk_link.name = (char *) symname;
97 + encryption_required = ext4_encrypted_inode(dir);
98 + if (encryption_required)
99 + disk_link.len = encrypted_symlink_data_len(len) + 1;
100 + if (disk_link.len > dir->i_sb->s_blocksize)
101 return -ENAMETOOLONG;
103 dquot_initialize(dir);
105 - if (l > EXT4_N_BLOCKS * 4) {
106 + if ((disk_link.len > EXT4_N_BLOCKS * 4)) {
108 * For non-fast symlinks, we just allocate inode and put it on
109 * orphan list in the first transaction => we need bitmap,
110 @@ -3213,16 +3221,49 @@ static int ext4_symlink(struct inode *dir,
111 credits = EXT4_DATA_TRANS_BLOCKS(dir->i_sb) +
112 EXT4_INDEX_EXTRA_TRANS_BLOCKS + 3;
116 inode = ext4_new_inode_start_handle(dir, S_IFLNK|S_IRWXUGO,
117 &dentry->d_name, 0, NULL,
118 EXT4_HT_DIR, credits);
119 handle = ext4_journal_current_handle();
120 - err = PTR_ERR(inode);
123 + if (IS_ERR(inode)) {
125 + ext4_journal_stop(handle);
126 + return PTR_ERR(inode);
129 + if (encryption_required) {
130 + struct ext4_fname_crypto_ctx *ctx = NULL;
132 + struct ext4_str ostr;
134 + sd = kzalloc(disk_link.len, GFP_NOFS);
137 + goto err_drop_inode;
139 + err = ext4_inherit_context(dir, inode);
141 + goto err_drop_inode;
142 + ctx = ext4_get_fname_crypto_ctx(inode,
143 + inode->i_sb->s_blocksize);
144 + if (IS_ERR_OR_NULL(ctx)) {
145 + /* We just set the policy, so ctx should not be NULL */
146 + err = (ctx == NULL) ? -EIO : PTR_ERR(ctx);
147 + goto err_drop_inode;
149 + istr.name = (const unsigned char *) symname;
151 + ostr.name = sd->encrypted_path;
152 + err = ext4_fname_usr_to_disk(ctx, &istr, &ostr);
153 + ext4_put_fname_crypto_ctx(&ctx);
155 + goto err_drop_inode;
156 + sd->len = cpu_to_le16(ostr.len);
157 + disk_link.name = (char *) sd;
160 - if (l > EXT4_N_BLOCKS * 4) {
161 + if ((disk_link.len > EXT4_N_BLOCKS * 4)) {
162 inode->i_op = &ext4_symlink_inode_operations;
163 ext4_set_aops(inode);
165 @@ -3238,9 +3279,10 @@ retry:
167 err = ext4_orphan_add(handle, inode);
168 ext4_journal_stop(handle);
172 - err = __page_symlink(inode, symname, l, 1);
173 + err = __page_symlink(inode, disk_link.name, disk_link.len, 1);
177 @@ -3252,34 +3294,37 @@ retry:
178 EXT4_INDEX_EXTRA_TRANS_BLOCKS + 1);
179 if (IS_ERR(handle)) {
180 err = PTR_ERR(handle);
185 err = ext4_orphan_del(handle, inode);
187 - ext4_journal_stop(handle);
188 - clear_nlink(inode);
193 /* clear the extent format for fast symlink */
194 ext4_clear_inode_flag(inode, EXT4_INODE_EXTENTS);
195 - inode->i_op = &ext4_fast_symlink_inode_operations;
196 - memcpy((char *)&EXT4_I(inode)->i_data, symname, l);
197 - inode->i_size = l-1;
198 + inode->i_op = encryption_required ?
199 + &ext4_symlink_inode_operations :
200 + &ext4_fast_symlink_inode_operations;
201 + memcpy((char *)&EXT4_I(inode)->i_data, disk_link.name,
203 + inode->i_size = disk_link.len - 1;
205 EXT4_I(inode)->i_disksize = inode->i_size;
206 err = ext4_add_nondir(handle, dentry, inode);
207 if (!err && IS_DIRSYNC(dir))
208 ext4_handle_sync(handle);
212 ext4_journal_stop(handle);
213 - if (err == -ENOSPC && ext4_should_retry_alloc(dir->i_sb, &retries))
219 + ext4_journal_stop(handle);
221 + clear_nlink(inode);
222 unlock_new_inode(inode);
225 diff --git a/fs/ext4/symlink.c b/fs/ext4/symlink.c
226 index ff37119..3f72274 100644
227 --- a/fs/ext4/symlink.c
228 +++ b/fs/ext4/symlink.c
233 +#ifdef CONFIG_EXT4_FS_ENCRYPTION
234 static void *ext4_follow_link(struct dentry *dentry, struct nameidata *nd)
236 + struct page *cpage = NULL;
237 + char *caddr, *paddr = NULL;
238 + struct ext4_str cstr, pstr;
239 + struct inode *inode = dentry->d_inode;
240 + struct ext4_fname_crypto_ctx *ctx = NULL;
241 + struct ext4_encrypted_symlink_data *sd;
242 + loff_t size = min_t(loff_t, i_size_read(inode), PAGE_SIZE - 1);
244 + u32 plen, max_size = inode->i_sb->s_blocksize;
246 + if (!ext4_encrypted_inode(inode))
247 + return page_follow_link_light(dentry, nd);
249 + ctx = ext4_get_fname_crypto_ctx(inode, inode->i_sb->s_blocksize);
253 + if (ext4_inode_is_fast_symlink(inode)) {
254 + caddr = (char *) EXT4_I(dentry->d_inode)->i_data;
255 + max_size = sizeof(EXT4_I(dentry->d_inode)->i_data);
257 + cpage = read_mapping_page(inode->i_mapping, 0, NULL);
258 + if (IS_ERR(cpage)) {
259 + ext4_put_fname_crypto_ctx(&ctx);
262 + caddr = kmap(cpage);
266 + /* Symlink is encrypted */
267 + sd = (struct ext4_encrypted_symlink_data *)caddr;
268 + cstr.name = sd->encrypted_path;
269 + cstr.len = le32_to_cpu(sd->len);
271 + sizeof(struct ext4_encrypted_symlink_data) - 1) >
273 + /* Symlink data on the disk is corrupted */
277 + plen = (cstr.len < EXT4_FNAME_CRYPTO_DIGEST_SIZE*2) ?
278 + EXT4_FNAME_CRYPTO_DIGEST_SIZE*2 : cstr.len;
279 + paddr = kmalloc(plen + 1, GFP_NOFS);
285 + res = _ext4_fname_disk_to_usr(ctx, &cstr, &pstr);
288 + /* Null-terminate the name */
291 + nd_set_link(nd, paddr);
292 + ext4_put_fname_crypto_ctx(&ctx);
295 + page_cache_release(cpage);
299 + ext4_put_fname_crypto_ctx(&ctx);
302 + page_cache_release(cpage);
305 + return ERR_PTR(res);
308 +static void ext4_put_link(struct dentry *dentry, struct nameidata *nd,
311 + struct page *page = cookie;
314 + kfree(nd_get_link(nd));
317 + page_cache_release(page);
322 +static void *ext4_follow_fast_link(struct dentry *dentry, struct nameidata *nd)
324 struct ext4_inode_info *ei = EXT4_I(dentry->d_inode);
325 nd_set_link(nd, (char *) ei->i_data);
327 @@ -32,8 +121,13 @@ static void *ext4_follow_link(struct dentry *dentry, struct nameidata *nd)
329 const struct inode_operations ext4_symlink_inode_operations = {
330 .readlink = generic_readlink,
331 +#ifdef CONFIG_EXT4_FS_ENCRYPTION
332 + .follow_link = ext4_follow_link,
333 + .put_link = ext4_put_link,
335 .follow_link = page_follow_link_light,
336 .put_link = page_put_link,
338 .setattr = ext4_setattr,
339 .setxattr = generic_setxattr,
340 .getxattr = generic_getxattr,
341 @@ -43,7 +137,7 @@ const struct inode_operations ext4_symlink_inode_operations = {
343 const struct inode_operations ext4_fast_symlink_inode_operations = {
344 .readlink = generic_readlink,
345 - .follow_link = ext4_follow_link,
346 + .follow_link = ext4_follow_fast_link,
347 .setattr = ext4_setattr,
348 .setxattr = generic_setxattr,
349 .getxattr = generic_getxattr,