xref: /OK3568_Linux_fs/kernel/fs/configfs/symlink.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-or-later
2*4882a593Smuzhiyun /* -*- mode: c; c-basic-offset: 8; -*-
3*4882a593Smuzhiyun  * vim: noexpandtab sw=8 ts=8 sts=0:
4*4882a593Smuzhiyun  *
5*4882a593Smuzhiyun  * symlink.c - operations for configfs symlinks.
6*4882a593Smuzhiyun  *
7*4882a593Smuzhiyun  * Based on sysfs:
8*4882a593Smuzhiyun  * 	sysfs is Copyright (C) 2001, 2002, 2003 Patrick Mochel
9*4882a593Smuzhiyun  *
10*4882a593Smuzhiyun  * configfs Copyright (C) 2005 Oracle.  All rights reserved.
11*4882a593Smuzhiyun  */
12*4882a593Smuzhiyun 
13*4882a593Smuzhiyun #include <linux/fs.h>
14*4882a593Smuzhiyun #include <linux/module.h>
15*4882a593Smuzhiyun #include <linux/namei.h>
16*4882a593Smuzhiyun #include <linux/slab.h>
17*4882a593Smuzhiyun 
18*4882a593Smuzhiyun #include <linux/configfs.h>
19*4882a593Smuzhiyun #include "configfs_internal.h"
20*4882a593Smuzhiyun 
21*4882a593Smuzhiyun /* Protects attachments of new symlinks */
22*4882a593Smuzhiyun DEFINE_MUTEX(configfs_symlink_mutex);
23*4882a593Smuzhiyun 
item_depth(struct config_item * item)24*4882a593Smuzhiyun static int item_depth(struct config_item * item)
25*4882a593Smuzhiyun {
26*4882a593Smuzhiyun 	struct config_item * p = item;
27*4882a593Smuzhiyun 	int depth = 0;
28*4882a593Smuzhiyun 	do { depth++; } while ((p = p->ci_parent) && !configfs_is_root(p));
29*4882a593Smuzhiyun 	return depth;
30*4882a593Smuzhiyun }
31*4882a593Smuzhiyun 
item_path_length(struct config_item * item)32*4882a593Smuzhiyun static int item_path_length(struct config_item * item)
33*4882a593Smuzhiyun {
34*4882a593Smuzhiyun 	struct config_item * p = item;
35*4882a593Smuzhiyun 	int length = 1;
36*4882a593Smuzhiyun 	do {
37*4882a593Smuzhiyun 		length += strlen(config_item_name(p)) + 1;
38*4882a593Smuzhiyun 		p = p->ci_parent;
39*4882a593Smuzhiyun 	} while (p && !configfs_is_root(p));
40*4882a593Smuzhiyun 	return length;
41*4882a593Smuzhiyun }
42*4882a593Smuzhiyun 
fill_item_path(struct config_item * item,char * buffer,int length)43*4882a593Smuzhiyun static void fill_item_path(struct config_item * item, char * buffer, int length)
44*4882a593Smuzhiyun {
45*4882a593Smuzhiyun 	struct config_item * p;
46*4882a593Smuzhiyun 
47*4882a593Smuzhiyun 	--length;
48*4882a593Smuzhiyun 	for (p = item; p && !configfs_is_root(p); p = p->ci_parent) {
49*4882a593Smuzhiyun 		int cur = strlen(config_item_name(p));
50*4882a593Smuzhiyun 
51*4882a593Smuzhiyun 		/* back up enough to print this bus id with '/' */
52*4882a593Smuzhiyun 		length -= cur;
53*4882a593Smuzhiyun 		memcpy(buffer + length, config_item_name(p), cur);
54*4882a593Smuzhiyun 		*(buffer + --length) = '/';
55*4882a593Smuzhiyun 	}
56*4882a593Smuzhiyun }
57*4882a593Smuzhiyun 
configfs_get_target_path(struct config_item * item,struct config_item * target,char * path)58*4882a593Smuzhiyun static int configfs_get_target_path(struct config_item *item,
59*4882a593Smuzhiyun 		struct config_item *target, char *path)
60*4882a593Smuzhiyun {
61*4882a593Smuzhiyun 	int depth, size;
62*4882a593Smuzhiyun 	char *s;
63*4882a593Smuzhiyun 
64*4882a593Smuzhiyun 	depth = item_depth(item);
65*4882a593Smuzhiyun 	size = item_path_length(target) + depth * 3 - 1;
66*4882a593Smuzhiyun 	if (size > PATH_MAX)
67*4882a593Smuzhiyun 		return -ENAMETOOLONG;
68*4882a593Smuzhiyun 
69*4882a593Smuzhiyun 	pr_debug("%s: depth = %d, size = %d\n", __func__, depth, size);
70*4882a593Smuzhiyun 
71*4882a593Smuzhiyun 	for (s = path; depth--; s += 3)
72*4882a593Smuzhiyun 		strcpy(s,"../");
73*4882a593Smuzhiyun 
74*4882a593Smuzhiyun 	fill_item_path(target, path, size);
75*4882a593Smuzhiyun 	pr_debug("%s: path = '%s'\n", __func__, path);
76*4882a593Smuzhiyun 	return 0;
77*4882a593Smuzhiyun }
78*4882a593Smuzhiyun 
create_link(struct config_item * parent_item,struct config_item * item,struct dentry * dentry)79*4882a593Smuzhiyun static int create_link(struct config_item *parent_item,
80*4882a593Smuzhiyun 		       struct config_item *item,
81*4882a593Smuzhiyun 		       struct dentry *dentry)
82*4882a593Smuzhiyun {
83*4882a593Smuzhiyun 	struct configfs_dirent *target_sd = item->ci_dentry->d_fsdata;
84*4882a593Smuzhiyun 	char *body;
85*4882a593Smuzhiyun 	int ret;
86*4882a593Smuzhiyun 
87*4882a593Smuzhiyun 	if (!configfs_dirent_is_ready(target_sd))
88*4882a593Smuzhiyun 		return -ENOENT;
89*4882a593Smuzhiyun 
90*4882a593Smuzhiyun 	body = kzalloc(PAGE_SIZE, GFP_KERNEL);
91*4882a593Smuzhiyun 	if (!body)
92*4882a593Smuzhiyun 		return -ENOMEM;
93*4882a593Smuzhiyun 
94*4882a593Smuzhiyun 	configfs_get(target_sd);
95*4882a593Smuzhiyun 	spin_lock(&configfs_dirent_lock);
96*4882a593Smuzhiyun 	if (target_sd->s_type & CONFIGFS_USET_DROPPING) {
97*4882a593Smuzhiyun 		spin_unlock(&configfs_dirent_lock);
98*4882a593Smuzhiyun 		configfs_put(target_sd);
99*4882a593Smuzhiyun 		kfree(body);
100*4882a593Smuzhiyun 		return -ENOENT;
101*4882a593Smuzhiyun 	}
102*4882a593Smuzhiyun 	target_sd->s_links++;
103*4882a593Smuzhiyun 	spin_unlock(&configfs_dirent_lock);
104*4882a593Smuzhiyun 	ret = configfs_get_target_path(parent_item, item, body);
105*4882a593Smuzhiyun 	if (!ret)
106*4882a593Smuzhiyun 		ret = configfs_create_link(target_sd, parent_item->ci_dentry,
107*4882a593Smuzhiyun 					   dentry, body);
108*4882a593Smuzhiyun 	if (ret) {
109*4882a593Smuzhiyun 		spin_lock(&configfs_dirent_lock);
110*4882a593Smuzhiyun 		target_sd->s_links--;
111*4882a593Smuzhiyun 		spin_unlock(&configfs_dirent_lock);
112*4882a593Smuzhiyun 		configfs_put(target_sd);
113*4882a593Smuzhiyun 		kfree(body);
114*4882a593Smuzhiyun 	}
115*4882a593Smuzhiyun 	return ret;
116*4882a593Smuzhiyun }
117*4882a593Smuzhiyun 
118*4882a593Smuzhiyun 
get_target(const char * symname,struct path * path,struct config_item ** target,struct super_block * sb)119*4882a593Smuzhiyun static int get_target(const char *symname, struct path *path,
120*4882a593Smuzhiyun 		      struct config_item **target, struct super_block *sb)
121*4882a593Smuzhiyun {
122*4882a593Smuzhiyun 	int ret;
123*4882a593Smuzhiyun 
124*4882a593Smuzhiyun 	ret = kern_path(symname, LOOKUP_FOLLOW|LOOKUP_DIRECTORY, path);
125*4882a593Smuzhiyun 	if (!ret) {
126*4882a593Smuzhiyun 		if (path->dentry->d_sb == sb) {
127*4882a593Smuzhiyun 			*target = configfs_get_config_item(path->dentry);
128*4882a593Smuzhiyun 			if (!*target) {
129*4882a593Smuzhiyun 				ret = -ENOENT;
130*4882a593Smuzhiyun 				path_put(path);
131*4882a593Smuzhiyun 			}
132*4882a593Smuzhiyun 		} else {
133*4882a593Smuzhiyun 			ret = -EPERM;
134*4882a593Smuzhiyun 			path_put(path);
135*4882a593Smuzhiyun 		}
136*4882a593Smuzhiyun 	}
137*4882a593Smuzhiyun 
138*4882a593Smuzhiyun 	return ret;
139*4882a593Smuzhiyun }
140*4882a593Smuzhiyun 
141*4882a593Smuzhiyun 
configfs_symlink(struct inode * dir,struct dentry * dentry,const char * symname)142*4882a593Smuzhiyun int configfs_symlink(struct inode *dir, struct dentry *dentry, const char *symname)
143*4882a593Smuzhiyun {
144*4882a593Smuzhiyun 	int ret;
145*4882a593Smuzhiyun 	struct path path;
146*4882a593Smuzhiyun 	struct configfs_dirent *sd;
147*4882a593Smuzhiyun 	struct config_item *parent_item;
148*4882a593Smuzhiyun 	struct config_item *target_item = NULL;
149*4882a593Smuzhiyun 	const struct config_item_type *type;
150*4882a593Smuzhiyun 
151*4882a593Smuzhiyun 	sd = dentry->d_parent->d_fsdata;
152*4882a593Smuzhiyun 	/*
153*4882a593Smuzhiyun 	 * Fake invisibility if dir belongs to a group/default groups hierarchy
154*4882a593Smuzhiyun 	 * being attached
155*4882a593Smuzhiyun 	 */
156*4882a593Smuzhiyun 	if (!configfs_dirent_is_ready(sd))
157*4882a593Smuzhiyun 		return -ENOENT;
158*4882a593Smuzhiyun 
159*4882a593Smuzhiyun 	parent_item = configfs_get_config_item(dentry->d_parent);
160*4882a593Smuzhiyun 	type = parent_item->ci_type;
161*4882a593Smuzhiyun 
162*4882a593Smuzhiyun 	ret = -EPERM;
163*4882a593Smuzhiyun 	if (!type || !type->ct_item_ops ||
164*4882a593Smuzhiyun 	    !type->ct_item_ops->allow_link)
165*4882a593Smuzhiyun 		goto out_put;
166*4882a593Smuzhiyun 
167*4882a593Smuzhiyun 	/*
168*4882a593Smuzhiyun 	 * This is really sick.  What they wanted was a hybrid of
169*4882a593Smuzhiyun 	 * link(2) and symlink(2) - they wanted the target resolved
170*4882a593Smuzhiyun 	 * at syscall time (as link(2) would've done), be a directory
171*4882a593Smuzhiyun 	 * (which link(2) would've refused to do) *AND* be a deep
172*4882a593Smuzhiyun 	 * fucking magic, making the target busy from rmdir POV.
173*4882a593Smuzhiyun 	 * symlink(2) is nothing of that sort, and the locking it
174*4882a593Smuzhiyun 	 * gets matches the normal symlink(2) semantics.  Without
175*4882a593Smuzhiyun 	 * attempts to resolve the target (which might very well
176*4882a593Smuzhiyun 	 * not even exist yet) done prior to locking the parent
177*4882a593Smuzhiyun 	 * directory.  This perversion, OTOH, needs to resolve
178*4882a593Smuzhiyun 	 * the target, which would lead to obvious deadlocks if
179*4882a593Smuzhiyun 	 * attempted with any directories locked.
180*4882a593Smuzhiyun 	 *
181*4882a593Smuzhiyun 	 * Unfortunately, that garbage is userland ABI and we should've
182*4882a593Smuzhiyun 	 * said "no" back in 2005.  Too late now, so we get to
183*4882a593Smuzhiyun 	 * play very ugly games with locking.
184*4882a593Smuzhiyun 	 *
185*4882a593Smuzhiyun 	 * Try *ANYTHING* of that sort in new code, and you will
186*4882a593Smuzhiyun 	 * really regret it.  Just ask yourself - what could a BOFH
187*4882a593Smuzhiyun 	 * do to me and do I want to find it out first-hand?
188*4882a593Smuzhiyun 	 *
189*4882a593Smuzhiyun 	 *  AV, a thoroughly annoyed bastard.
190*4882a593Smuzhiyun 	 */
191*4882a593Smuzhiyun 	inode_unlock(dir);
192*4882a593Smuzhiyun 	ret = get_target(symname, &path, &target_item, dentry->d_sb);
193*4882a593Smuzhiyun 	inode_lock(dir);
194*4882a593Smuzhiyun 	if (ret)
195*4882a593Smuzhiyun 		goto out_put;
196*4882a593Smuzhiyun 
197*4882a593Smuzhiyun 	if (dentry->d_inode || d_unhashed(dentry))
198*4882a593Smuzhiyun 		ret = -EEXIST;
199*4882a593Smuzhiyun 	else
200*4882a593Smuzhiyun 		ret = inode_permission(dir, MAY_WRITE | MAY_EXEC);
201*4882a593Smuzhiyun 	if (!ret)
202*4882a593Smuzhiyun 		ret = type->ct_item_ops->allow_link(parent_item, target_item);
203*4882a593Smuzhiyun 	if (!ret) {
204*4882a593Smuzhiyun 		mutex_lock(&configfs_symlink_mutex);
205*4882a593Smuzhiyun 		ret = create_link(parent_item, target_item, dentry);
206*4882a593Smuzhiyun 		mutex_unlock(&configfs_symlink_mutex);
207*4882a593Smuzhiyun 		if (ret && type->ct_item_ops->drop_link)
208*4882a593Smuzhiyun 			type->ct_item_ops->drop_link(parent_item,
209*4882a593Smuzhiyun 						     target_item);
210*4882a593Smuzhiyun 	}
211*4882a593Smuzhiyun 
212*4882a593Smuzhiyun 	config_item_put(target_item);
213*4882a593Smuzhiyun 	path_put(&path);
214*4882a593Smuzhiyun 
215*4882a593Smuzhiyun out_put:
216*4882a593Smuzhiyun 	config_item_put(parent_item);
217*4882a593Smuzhiyun 	return ret;
218*4882a593Smuzhiyun }
219*4882a593Smuzhiyun 
configfs_unlink(struct inode * dir,struct dentry * dentry)220*4882a593Smuzhiyun int configfs_unlink(struct inode *dir, struct dentry *dentry)
221*4882a593Smuzhiyun {
222*4882a593Smuzhiyun 	struct configfs_dirent *sd = dentry->d_fsdata, *target_sd;
223*4882a593Smuzhiyun 	struct config_item *parent_item;
224*4882a593Smuzhiyun 	const struct config_item_type *type;
225*4882a593Smuzhiyun 	int ret;
226*4882a593Smuzhiyun 
227*4882a593Smuzhiyun 	ret = -EPERM;  /* What lack-of-symlink returns */
228*4882a593Smuzhiyun 	if (!(sd->s_type & CONFIGFS_ITEM_LINK))
229*4882a593Smuzhiyun 		goto out;
230*4882a593Smuzhiyun 
231*4882a593Smuzhiyun 	target_sd = sd->s_element;
232*4882a593Smuzhiyun 
233*4882a593Smuzhiyun 	parent_item = configfs_get_config_item(dentry->d_parent);
234*4882a593Smuzhiyun 	type = parent_item->ci_type;
235*4882a593Smuzhiyun 
236*4882a593Smuzhiyun 	spin_lock(&configfs_dirent_lock);
237*4882a593Smuzhiyun 	list_del_init(&sd->s_sibling);
238*4882a593Smuzhiyun 	spin_unlock(&configfs_dirent_lock);
239*4882a593Smuzhiyun 	configfs_drop_dentry(sd, dentry->d_parent);
240*4882a593Smuzhiyun 	dput(dentry);
241*4882a593Smuzhiyun 	configfs_put(sd);
242*4882a593Smuzhiyun 
243*4882a593Smuzhiyun 	/*
244*4882a593Smuzhiyun 	 * drop_link() must be called before
245*4882a593Smuzhiyun 	 * decrementing target's ->s_links, so that the order of
246*4882a593Smuzhiyun 	 * drop_link(this, target) and drop_item(target) is preserved.
247*4882a593Smuzhiyun 	 */
248*4882a593Smuzhiyun 	if (type && type->ct_item_ops &&
249*4882a593Smuzhiyun 	    type->ct_item_ops->drop_link)
250*4882a593Smuzhiyun 		type->ct_item_ops->drop_link(parent_item,
251*4882a593Smuzhiyun 					       target_sd->s_element);
252*4882a593Smuzhiyun 
253*4882a593Smuzhiyun 	spin_lock(&configfs_dirent_lock);
254*4882a593Smuzhiyun 	target_sd->s_links--;
255*4882a593Smuzhiyun 	spin_unlock(&configfs_dirent_lock);
256*4882a593Smuzhiyun 	configfs_put(target_sd);
257*4882a593Smuzhiyun 
258*4882a593Smuzhiyun 	config_item_put(parent_item);
259*4882a593Smuzhiyun 
260*4882a593Smuzhiyun 	ret = 0;
261*4882a593Smuzhiyun 
262*4882a593Smuzhiyun out:
263*4882a593Smuzhiyun 	return ret;
264*4882a593Smuzhiyun }
265*4882a593Smuzhiyun 
266*4882a593Smuzhiyun const struct inode_operations configfs_symlink_inode_operations = {
267*4882a593Smuzhiyun 	.get_link = simple_get_link,
268*4882a593Smuzhiyun 	.setattr = configfs_setattr,
269*4882a593Smuzhiyun };
270*4882a593Smuzhiyun 
271