xref: /openbmc/linux/fs/ext4/symlink.c (revision 9ec3a646fe09970f801ab15e0f1694060b9f19af)
1ac27a0ecSDave Kleikamp /*
2617ba13bSMingming Cao  *  linux/fs/ext4/symlink.c
3ac27a0ecSDave Kleikamp  *
4ac27a0ecSDave Kleikamp  * Only fast symlinks left here - the rest is done by generic code. AV, 1999
5ac27a0ecSDave Kleikamp  *
6ac27a0ecSDave Kleikamp  * Copyright (C) 1992, 1993, 1994, 1995
7ac27a0ecSDave Kleikamp  * Remy Card (card@masi.ibp.fr)
8ac27a0ecSDave Kleikamp  * Laboratoire MASI - Institut Blaise Pascal
9ac27a0ecSDave Kleikamp  * Universite Pierre et Marie Curie (Paris VI)
10ac27a0ecSDave Kleikamp  *
11ac27a0ecSDave Kleikamp  *  from
12ac27a0ecSDave Kleikamp  *
13ac27a0ecSDave Kleikamp  *  linux/fs/minix/symlink.c
14ac27a0ecSDave Kleikamp  *
15ac27a0ecSDave Kleikamp  *  Copyright (C) 1991, 1992  Linus Torvalds
16ac27a0ecSDave Kleikamp  *
17617ba13bSMingming Cao  *  ext4 symlink handling code
18ac27a0ecSDave Kleikamp  */
19ac27a0ecSDave Kleikamp 
20ac27a0ecSDave Kleikamp #include <linux/fs.h>
21ac27a0ecSDave Kleikamp #include <linux/namei.h>
223dcf5451SChristoph Hellwig #include "ext4.h"
23ac27a0ecSDave Kleikamp #include "xattr.h"
24ac27a0ecSDave Kleikamp 
25f348c252STheodore Ts'o #ifdef CONFIG_EXT4_FS_ENCRYPTION
26617ba13bSMingming Cao static void *ext4_follow_link(struct dentry *dentry, struct nameidata *nd)
27ac27a0ecSDave Kleikamp {
28f348c252STheodore Ts'o 	struct page *cpage = NULL;
29f348c252STheodore Ts'o 	char *caddr, *paddr = NULL;
30f348c252STheodore Ts'o 	struct ext4_str cstr, pstr;
31*9ec3a646SLinus Torvalds 	struct inode *inode = d_inode(dentry);
32f348c252STheodore Ts'o 	struct ext4_fname_crypto_ctx *ctx = NULL;
33f348c252STheodore Ts'o 	struct ext4_encrypted_symlink_data *sd;
34f348c252STheodore Ts'o 	loff_t size = min_t(loff_t, i_size_read(inode), PAGE_SIZE - 1);
35f348c252STheodore Ts'o 	int res;
36f348c252STheodore Ts'o 	u32 plen, max_size = inode->i_sb->s_blocksize;
37f348c252STheodore Ts'o 
38f348c252STheodore Ts'o 	if (!ext4_encrypted_inode(inode))
39f348c252STheodore Ts'o 		return page_follow_link_light(dentry, nd);
40f348c252STheodore Ts'o 
41f348c252STheodore Ts'o 	ctx = ext4_get_fname_crypto_ctx(inode, inode->i_sb->s_blocksize);
42f348c252STheodore Ts'o 	if (IS_ERR(ctx))
43f348c252STheodore Ts'o 		return ctx;
44f348c252STheodore Ts'o 
45f348c252STheodore Ts'o 	if (ext4_inode_is_fast_symlink(inode)) {
46*9ec3a646SLinus Torvalds 		caddr = (char *) EXT4_I(inode)->i_data;
47*9ec3a646SLinus Torvalds 		max_size = sizeof(EXT4_I(inode)->i_data);
48f348c252STheodore Ts'o 	} else {
49f348c252STheodore Ts'o 		cpage = read_mapping_page(inode->i_mapping, 0, NULL);
50f348c252STheodore Ts'o 		if (IS_ERR(cpage)) {
51f348c252STheodore Ts'o 			ext4_put_fname_crypto_ctx(&ctx);
52f348c252STheodore Ts'o 			return cpage;
53f348c252STheodore Ts'o 		}
54f348c252STheodore Ts'o 		caddr = kmap(cpage);
55f348c252STheodore Ts'o 		caddr[size] = 0;
56f348c252STheodore Ts'o 	}
57f348c252STheodore Ts'o 
58f348c252STheodore Ts'o 	/* Symlink is encrypted */
59f348c252STheodore Ts'o 	sd = (struct ext4_encrypted_symlink_data *)caddr;
60f348c252STheodore Ts'o 	cstr.name = sd->encrypted_path;
61f348c252STheodore Ts'o 	cstr.len  = le32_to_cpu(sd->len);
62f348c252STheodore Ts'o 	if ((cstr.len +
63f348c252STheodore Ts'o 	     sizeof(struct ext4_encrypted_symlink_data) - 1) >
64f348c252STheodore Ts'o 	    max_size) {
65f348c252STheodore Ts'o 		/* Symlink data on the disk is corrupted */
66f348c252STheodore Ts'o 		res = -EIO;
67f348c252STheodore Ts'o 		goto errout;
68f348c252STheodore Ts'o 	}
69f348c252STheodore Ts'o 	plen = (cstr.len < EXT4_FNAME_CRYPTO_DIGEST_SIZE*2) ?
70f348c252STheodore Ts'o 		EXT4_FNAME_CRYPTO_DIGEST_SIZE*2 : cstr.len;
71f348c252STheodore Ts'o 	paddr = kmalloc(plen + 1, GFP_NOFS);
72f348c252STheodore Ts'o 	if (!paddr) {
73f348c252STheodore Ts'o 		res = -ENOMEM;
74f348c252STheodore Ts'o 		goto errout;
75f348c252STheodore Ts'o 	}
76f348c252STheodore Ts'o 	pstr.name = paddr;
77f348c252STheodore Ts'o 	res = _ext4_fname_disk_to_usr(ctx, &cstr, &pstr);
78f348c252STheodore Ts'o 	if (res < 0)
79f348c252STheodore Ts'o 		goto errout;
80f348c252STheodore Ts'o 	/* Null-terminate the name */
81f348c252STheodore Ts'o 	if (res <= plen)
82f348c252STheodore Ts'o 		paddr[res] = '\0';
83f348c252STheodore Ts'o 	nd_set_link(nd, paddr);
84f348c252STheodore Ts'o 	ext4_put_fname_crypto_ctx(&ctx);
85f348c252STheodore Ts'o 	if (cpage) {
86f348c252STheodore Ts'o 		kunmap(cpage);
87f348c252STheodore Ts'o 		page_cache_release(cpage);
88f348c252STheodore Ts'o 	}
89f348c252STheodore Ts'o 	return NULL;
90f348c252STheodore Ts'o errout:
91f348c252STheodore Ts'o 	ext4_put_fname_crypto_ctx(&ctx);
92f348c252STheodore Ts'o 	if (cpage) {
93f348c252STheodore Ts'o 		kunmap(cpage);
94f348c252STheodore Ts'o 		page_cache_release(cpage);
95f348c252STheodore Ts'o 	}
96f348c252STheodore Ts'o 	kfree(paddr);
97f348c252STheodore Ts'o 	return ERR_PTR(res);
98f348c252STheodore Ts'o }
99f348c252STheodore Ts'o 
100f348c252STheodore Ts'o static void ext4_put_link(struct dentry *dentry, struct nameidata *nd,
101f348c252STheodore Ts'o 			  void *cookie)
102f348c252STheodore Ts'o {
103f348c252STheodore Ts'o 	struct page *page = cookie;
104f348c252STheodore Ts'o 
105f348c252STheodore Ts'o 	if (!page) {
106f348c252STheodore Ts'o 		kfree(nd_get_link(nd));
107f348c252STheodore Ts'o 	} else {
108f348c252STheodore Ts'o 		kunmap(page);
109f348c252STheodore Ts'o 		page_cache_release(page);
110f348c252STheodore Ts'o 	}
111f348c252STheodore Ts'o }
112f348c252STheodore Ts'o #endif
113f348c252STheodore Ts'o 
114f348c252STheodore Ts'o static void *ext4_follow_fast_link(struct dentry *dentry, struct nameidata *nd)
115f348c252STheodore Ts'o {
1162b0143b5SDavid Howells 	struct ext4_inode_info *ei = EXT4_I(d_inode(dentry));
117ac27a0ecSDave Kleikamp 	nd_set_link(nd, (char *) ei->i_data);
118ac27a0ecSDave Kleikamp 	return NULL;
119ac27a0ecSDave Kleikamp }
120ac27a0ecSDave Kleikamp 
121754661f1SArjan van de Ven const struct inode_operations ext4_symlink_inode_operations = {
122ac27a0ecSDave Kleikamp 	.readlink	= generic_readlink,
123f348c252STheodore Ts'o #ifdef CONFIG_EXT4_FS_ENCRYPTION
124f348c252STheodore Ts'o 	.follow_link    = ext4_follow_link,
125f348c252STheodore Ts'o 	.put_link       = ext4_put_link,
126f348c252STheodore Ts'o #else
127ac27a0ecSDave Kleikamp 	.follow_link	= page_follow_link_light,
128ac27a0ecSDave Kleikamp 	.put_link	= page_put_link,
129f348c252STheodore Ts'o #endif
130256a4535SDmitry Monakhov 	.setattr	= ext4_setattr,
131ac27a0ecSDave Kleikamp 	.setxattr	= generic_setxattr,
132ac27a0ecSDave Kleikamp 	.getxattr	= generic_getxattr,
133617ba13bSMingming Cao 	.listxattr	= ext4_listxattr,
134ac27a0ecSDave Kleikamp 	.removexattr	= generic_removexattr,
135ac27a0ecSDave Kleikamp };
136ac27a0ecSDave Kleikamp 
137754661f1SArjan van de Ven const struct inode_operations ext4_fast_symlink_inode_operations = {
138ac27a0ecSDave Kleikamp 	.readlink	= generic_readlink,
139f348c252STheodore Ts'o 	.follow_link    = ext4_follow_fast_link,
140256a4535SDmitry Monakhov 	.setattr	= ext4_setattr,
141ac27a0ecSDave Kleikamp 	.setxattr	= generic_setxattr,
142ac27a0ecSDave Kleikamp 	.getxattr	= generic_getxattr,
143617ba13bSMingming Cao 	.listxattr	= ext4_listxattr,
144ac27a0ecSDave Kleikamp 	.removexattr	= generic_removexattr,
145ac27a0ecSDave Kleikamp };
146