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