xref: /kernel/linux/linux-6.6/fs/sharefs/inode.c (revision 62306a36)
1// SPDX-License-Identifier: GPL-2.0-only
2/*
3 * fs/sharefs/inode.c
4 *
5 * Copyright (c) 1998-2022 Erez Zadok
6 * Copyright (c) 2009	   Shrikar Archak
7 * Copyright (c) 2003-2022 Stony Brook University
8 * Copyright (c) 2003-2022 The Research Foundation of SUNY
9 * Copyright (c) 2023 Huawei Device Co., Ltd.
10 */
11
12#include "sharefs.h"
13#ifdef CONFIG_SHAREFS_SUPPORT_WRITE
14#include "authentication.h"
15#endif
16
17static int sharefs_getattr(struct mnt_idmap *idmap, const struct path *path, struct kstat *stat,
18                          u32 request_mask, unsigned int flags)
19{
20	struct path lower_path;
21	int ret;
22
23	sharefs_get_lower_path(path->dentry, &lower_path);
24	ret = vfs_getattr(&lower_path, stat, request_mask, flags);
25	stat->ino = d_inode(path->dentry)->i_ino;
26	stat->uid = d_inode(path->dentry)->i_uid;
27	stat->gid = d_inode(path->dentry)->i_gid;
28	stat->mode = d_inode(path->dentry)->i_mode;
29	stat->dev = 0;
30	stat->rdev = 0;
31	sharefs_put_lower_path(path->dentry, &lower_path);
32
33	return ret;
34}
35
36static ssize_t sharefs_listxattr(struct dentry *dentry, char *buffer, size_t buffer_size)
37{
38	int err;
39	struct dentry *lower_dentry;
40	struct path lower_path;
41
42	sharefs_get_lower_path(dentry, &lower_path);
43	lower_dentry = lower_path.dentry;
44	if (!(d_inode(lower_dentry)->i_opflags & IOP_XATTR)) {
45		err = -EOPNOTSUPP;
46		goto out;
47	}
48	err = vfs_listxattr(lower_dentry, buffer, buffer_size);
49	if (err)
50		goto out;
51	fsstack_copy_attr_atime(d_inode(dentry),
52				d_inode(lower_path.dentry));
53out:
54	sharefs_put_lower_path(dentry, &lower_path);
55	return err;
56}
57
58static int sharefs_permission(struct mnt_idmap *idmap, struct inode *inode, int mask)
59{
60#ifdef CONFIG_SHAREFS_SUPPORT_OVERRIDE
61	return 0;
62#endif
63	unsigned short mode = inode->i_mode;
64	kuid_t cur_uid = current_fsuid();
65	if (uid_eq(cur_uid, ROOT_UID))
66		return 0;
67	if (uid_eq(cur_uid, inode->i_uid)) {
68		mode >>= 6;
69	} else if (in_group_p(inode->i_gid)) {
70		mode >>= 3;
71	}
72
73	if ((mask & ~mode & (MAY_READ | MAY_WRITE | MAY_EXEC)) == 0)
74		return 0;
75
76	return -EACCES;
77}
78
79#ifdef CONFIG_SHAREFS_SUPPORT_WRITE
80static int sharefs_create(struct inode *dir, struct dentry *dentry,
81			 umode_t mode, bool want_excl)
82{
83	int err;
84	struct dentry *lower_dentry;
85	struct dentry *lower_parent_dentry = NULL;
86	struct path lower_path;
87	const struct cred *saved_cred = NULL;
88	__u16 child_perm;
89
90	saved_cred = sharefs_override_file_fsids(dir, &child_perm);
91	if (!saved_cred) {
92		err = -ENOMEM;
93		return err;
94	}
95
96	sharefs_get_lower_path(dentry, &lower_path);
97	lower_dentry = lower_path.dentry;
98	lower_parent_dentry = lock_parent(lower_dentry);
99	err = vfs_create(d_inode(lower_parent_dentry), lower_dentry, mode,
100			 want_excl);
101	if (err)
102		goto out;
103	err = sharefs_interpose(dentry, dir->i_sb, &lower_path);
104	if (err)
105		goto out;
106	fsstack_copy_attr_times(dir, sharefs_lower_inode(dir));
107	fsstack_copy_inode_size(dir, d_inode(lower_parent_dentry));
108
109out:
110	unlock_dir(lower_parent_dentry);
111	sharefs_put_lower_path(dentry, &lower_path);
112	sharefs_revert_fsids(saved_cred);
113	return err;
114}
115
116static int sharefs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
117{
118	int err;
119	struct dentry *lower_dentry;
120	struct dentry *lower_parent_dentry = NULL;
121	struct path lower_path;
122	const struct cred *saved_cred = NULL;
123	__u16 child_perm;
124
125	saved_cred = sharefs_override_file_fsids(dir, &child_perm);
126	if (!saved_cred) {
127		err = -ENOMEM;
128		return err;
129	}
130
131	sharefs_get_lower_path(dentry, &lower_path);
132	lower_dentry = lower_path.dentry;
133	lower_parent_dentry = lock_parent(lower_dentry);
134	err = vfs_mkdir(d_inode(lower_parent_dentry), lower_dentry, mode);
135	if (err)
136		goto out;
137
138	err = sharefs_interpose(dentry, dir->i_sb, &lower_path);
139	if (err)
140		goto out;
141
142	fsstack_copy_attr_times(dir, sharefs_lower_inode(dir));
143	fsstack_copy_inode_size(dir, d_inode(lower_parent_dentry));
144	/* update number of links on parent directory */
145	set_nlink(dir, sharefs_lower_inode(dir)->i_nlink);
146
147out:
148	unlock_dir(lower_parent_dentry);
149	sharefs_put_lower_path(dentry, &lower_path);
150	sharefs_revert_fsids(saved_cred);
151	return err;
152}
153
154static int sharefs_unlink(struct inode *dir, struct dentry *dentry)
155{
156	int err;
157	struct dentry *lower_dentry = NULL;
158	struct inode *lower_dir_inode = sharefs_lower_inode(dir);
159	struct dentry *lower_dir_dentry = NULL;
160	struct path lower_path;
161
162	sharefs_get_lower_path(dentry, &lower_path);
163	lower_dentry = lower_path.dentry;
164	dget(lower_dentry);
165	lower_dir_dentry = lock_parent(lower_dentry);
166	err = vfs_unlink(lower_dir_inode, lower_dentry, NULL);
167	if (err)
168		goto out;
169	fsstack_copy_attr_times(dir, lower_dir_inode);
170	fsstack_copy_inode_size(dir, lower_dir_inode);
171	set_nlink(dentry->d_inode,
172		  sharefs_lower_inode(dentry->d_inode)->i_nlink);
173	dentry->d_inode->i_ctime = dir->i_ctime;
174	d_drop(dentry);
175
176out:
177	unlock_dir(lower_dir_dentry);
178	dput(lower_dentry);
179	sharefs_put_lower_path(dentry, &lower_path);
180	return err;
181}
182
183static int sharefs_rmdir(struct inode *dir, struct dentry *dentry)
184{
185	int err;
186	struct dentry *lower_dentry;
187	struct dentry *lower_dir_dentry;
188	struct path lower_path;
189
190	sharefs_get_lower_path(dentry, &lower_path);
191	lower_dentry = lower_path.dentry;
192	lower_dir_dentry = lock_parent(lower_dentry);
193	err = vfs_rmdir(lower_dir_dentry->d_inode, lower_dentry);
194	if (err)
195		goto out;
196
197	d_drop(dentry);
198	if (dentry->d_inode)
199		clear_nlink(dentry->d_inode);
200	fsstack_copy_attr_times(dir, lower_dir_dentry->d_inode);
201	fsstack_copy_inode_size(dir, lower_dir_dentry->d_inode);
202	set_nlink(dir, lower_dir_dentry->d_inode->i_nlink);
203
204out:
205	unlock_dir(lower_dir_dentry);
206	sharefs_put_lower_path(dentry, &lower_path);
207	return err;
208}
209
210static int sharefs_rename(struct inode *old_dir, struct dentry *old_dentry,
211				struct inode *new_dir, struct dentry *new_dentry,
212				unsigned int flags)
213{
214	int err;
215	struct dentry *lower_old_dentry = NULL;
216	struct dentry *lower_new_dentry = NULL;
217	struct dentry *lower_old_dir_dentry = NULL;
218	struct dentry *lower_new_dir_dentry = NULL;
219	struct dentry *trap = NULL;
220	struct path lower_old_path, lower_new_path;
221
222	if (flags)
223		return -EINVAL;
224
225	sharefs_get_lower_path(old_dentry, &lower_old_path);
226	sharefs_get_lower_path(new_dentry, &lower_new_path);
227	lower_old_dentry = lower_old_path.dentry;
228	lower_new_dentry = lower_new_path.dentry;
229	lower_old_dir_dentry = dget_parent(lower_old_dentry);
230	lower_new_dir_dentry = dget_parent(lower_new_dentry);
231	trap = lock_rename(lower_old_dir_dentry, lower_new_dir_dentry);
232	/* source should not be ancestor of target */
233	if (trap == lower_old_dentry) {
234		err = -EINVAL;
235		goto out;
236	}
237	/* target should not be ancestor of source */
238	if (trap == lower_new_dentry) {
239		err = -ENOTEMPTY;
240		goto out;
241	}
242
243	err = vfs_rename(lower_old_dir_dentry->d_inode, lower_old_dentry,
244			 lower_new_dir_dentry->d_inode, lower_new_dentry,
245			 NULL, 0);
246	if (err)
247		goto out;
248
249	fsstack_copy_attr_all(new_dir, lower_new_dir_dentry->d_inode);
250	fsstack_copy_inode_size(new_dir, lower_new_dir_dentry->d_inode);
251	if (new_dir != old_dir) {
252		fsstack_copy_attr_all(old_dir,
253				    lower_old_dir_dentry->d_inode);
254		fsstack_copy_inode_size(old_dir,
255					lower_old_dir_dentry->d_inode);
256	}
257
258out:
259	unlock_rename(lower_old_dir_dentry, lower_new_dir_dentry);
260	dput(lower_old_dir_dentry);
261	dput(lower_new_dir_dentry);
262	sharefs_put_lower_path(old_dentry, &lower_old_path);
263	sharefs_put_lower_path(new_dentry, &lower_new_path);
264	return err;
265}
266
267static int sharefs_setattr(struct dentry *dentry, struct iattr *ia)
268{
269	int err;
270	struct dentry *lower_dentry;
271	struct inode *inode;
272	struct inode *lower_inode;
273	struct path lower_path;
274	struct iattr lower_ia;
275
276	inode = dentry->d_inode;
277	/*
278	 * Check if user has permission to change inode.  We don't check if
279	 * this user can change the lower inode: that should happen when
280	 * calling notify_change on the lower inode.
281	 */
282
283	err = setattr_prepare(dentry, ia);
284	if (err)
285		goto out_err;
286
287	sharefs_get_lower_path(dentry, &lower_path);
288	lower_dentry = lower_path.dentry;
289	lower_inode = sharefs_lower_inode(inode);
290
291	/* prepare our own lower struct iattr (with the lower file) */
292	memcpy(&lower_ia, ia, sizeof(lower_ia));
293	if (ia->ia_valid & ATTR_FILE)
294		lower_ia.ia_file = sharefs_lower_file(ia->ia_file);
295
296	/*
297	 * If shrinking, first truncate upper level to cancel writing dirty
298	 * pages beyond the new eof; and also if its' maxbytes is more
299	 * limiting (fail with -EFBIG before making any change to the lower
300	 * level).  There is no need to vmtruncate the upper level
301	 * afterwards in the other cases: we fsstack_copy_inode_size from
302	 * the lower level.
303	 */
304	if (ia->ia_valid & ATTR_SIZE) {
305		err = inode_newsize_ok(inode, ia->ia_size);
306		if (err)
307			goto out;
308		truncate_setsize(inode, ia->ia_size);
309	}
310
311	/*
312	 * mode change is for clearing setuid/setgid bits. Allow lower fs
313	 * to interpret this in its own way.
314	 */
315	if (lower_ia.ia_valid & (ATTR_KILL_SUID | ATTR_KILL_SGID))
316		lower_ia.ia_valid &= ~ATTR_MODE;
317
318	/* notify the (possibly copied-up) lower inode */
319	/*
320	 * Note: we use lower_dentry->d_inode, because lower_inode may be
321	 * unlinked (no inode->i_sb and i_ino==0.  This happens if someone
322	 * tries to open(), unlink(), then ftruncate() a file.
323	 */
324
325	inode_lock(d_inode(lower_dentry));
326	err = notify_change(lower_dentry, &lower_ia, /* note: lower_ia */
327			    NULL);
328	inode_unlock(d_inode(lower_dentry));
329
330	if (err)
331		goto out;
332
333	/* get attributes from the lower inode */
334	fsstack_copy_attr_all(inode, lower_inode);
335	/*
336	 * Not running fsstack_copy_inode_size(inode, lower_inode), because
337	 * VFS should update our inode size, and notify_change on
338	 * lower_inode should update its size.
339	 */
340
341out:
342	sharefs_put_lower_path(dentry, &lower_path);
343out_err:
344	return err;
345}
346#endif
347
348const struct inode_operations sharefs_symlink_iops = {
349	.permission	= sharefs_permission,
350	.getattr	= sharefs_getattr,
351	.get_link	= NULL,
352	.listxattr	= sharefs_listxattr,
353};
354
355const struct inode_operations sharefs_dir_iops = {
356	.lookup		= sharefs_lookup,
357	.permission	= sharefs_permission,
358	.getattr	= sharefs_getattr,
359	.listxattr	= sharefs_listxattr,
360#ifdef CONFIG_SHAREFS_SUPPORT_WRITE
361	.unlink		= sharefs_unlink,
362	.rmdir		= sharefs_rmdir,
363	.rename		= sharefs_rename,
364	.create		= sharefs_create,
365	.mkdir		= sharefs_mkdir,
366	.setattr	= sharefs_setattr,
367#endif
368};
369
370const struct inode_operations sharefs_main_iops = {
371	.permission	= sharefs_permission,
372	.getattr	= sharefs_getattr,
373	.listxattr	= sharefs_listxattr,
374#ifdef CONFIG_SHAREFS_SUPPORT_WRITE
375	.setattr        = sharefs_setattr,
376#endif
377};
378